abh1sar commented on code in PR #10140: URL: https://github.com/apache/cloudstack/pull/10140#discussion_r2228962984
########## server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java: ########## @@ -1959,8 +1959,7 @@ private Pair<String, String> handleCheckAndRepairVolumeJob(Long vmId, Long volum } else if (jobResult instanceof ResourceAllocationException) { throw (ResourceAllocationException)jobResult; } else if (jobResult instanceof Throwable) { - Throwable throwable = (Throwable) jobResult; - throw new RuntimeException(String.format("Unexpected exception: %s", throwable.getMessage()), throwable); + throw new RuntimeException("Unexpected exception", (Throwable) jobResult); Review Comment: To be honest, I don't remember why I changed this code (it might be a offshoot from one of the merges). will revert this change. ########## server/src/main/java/com/cloud/vm/UserVmManagerImpl.java: ########## @@ -9317,6 +9391,234 @@ public boolean unmanageUserVM(Long vmId) { return true; } + private void updateDetailsWithRootDiskAttributes(Map<String, String> details, VmDiskInfo rootVmDiskInfo) { + details.put(VmDetailConstants.ROOT_DISK_SIZE, rootVmDiskInfo.getSize().toString()); + if (rootVmDiskInfo.getMinIops() != null) { + details.put(MIN_IOPS, rootVmDiskInfo.getMinIops().toString()); + } + if (rootVmDiskInfo.getMaxIops() != null) { + details.put(MAX_IOPS, rootVmDiskInfo.getMaxIops().toString()); + } + } + + private void checkRootDiskSizeAgainstBackup(Long instanceVolumeSize,DiskOffering rootDiskOffering, Long backupVolumeSize) { + Long instanceRootDiskSize = rootDiskOffering.isCustomized() ? instanceVolumeSize : rootDiskOffering.getDiskSize() / GiB_TO_BYTES; + if (instanceRootDiskSize < backupVolumeSize) { + throw new InvalidParameterValueException( + String.format("Instance volume root disk size %d[GiB] cannot be less than the backed-up volume size %d[GiB].", + instanceVolumeSize, backupVolumeSize)); + } + } + + @Override + public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws InsufficientCapacityException, ResourceAllocationException, ResourceUnavailableException { + if (!backupManager.canCreateInstanceFromBackup(cmd.getBackupId())) { + throw new CloudRuntimeException("Create instance from backup is not supported for this provider."); + } + DataCenter zone = _dcDao.findById(cmd.getZoneId()); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find zone by id=" + cmd.getZoneId()); + } + + BackupVO backup = backupDao.findById(cmd.getBackupId()); + if (backup == null) { + throw new InvalidParameterValueException("Backup " + cmd.getBackupId() + " does not exist"); + } + if (backup.getZoneId() != cmd.getZoneId()) { + throw new InvalidParameterValueException("Instance should be created in the same zone as the backup"); + } + backupManager.validateBackupForZone(backup.getZoneId()); + backupDao.loadDetails(backup); + + verifyDetails(cmd.getDetails()); + + UserVmVO backupVm = _vmDao.findByIdIncludingRemoved(backup.getVmId()); + HypervisorType hypervisorType = backupVm.getHypervisorType(); + + Long serviceOfferingId = cmd.getServiceOfferingId(); + ServiceOffering serviceOffering; + if (serviceOfferingId != null) { + serviceOffering = serviceOfferingDao.findById(serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException("Unable to find service offering: " + serviceOffering.getId()); + } + } else { + String serviceOfferingUuid = backup.getDetail(ApiConstants.SERVICE_OFFERING_ID); + if (serviceOfferingUuid == null) { + throw new CloudRuntimeException("Backup doesn't contain service offering uuid. Please specify a valid service offering id while creating the instance"); + } + serviceOffering = serviceOfferingDao.findByUuid(serviceOfferingUuid); + if (serviceOffering == null) { + throw new CloudRuntimeException("Unable to find service offering with the uuid stored in backup. Please specify a valid service offering id while creating instance"); + } + } + verifyServiceOffering(cmd, serviceOffering); + + VirtualMachineTemplate template; + if (cmd.getTemplateId() != null) { + Long templateId = cmd.getTemplateId(); + template = _templateDao.findById(templateId); + if (template == null) { + throw new InvalidParameterValueException("Unable to use template " + templateId); + } + } else { + String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID); + if (templateUuid == null) { + throw new CloudRuntimeException("Backup doesn't contain Template uuid. Please specify a valid Template/ISO while creating the instance"); + } + template = _templateDao.findByUuid(templateUuid); + if (template == null) { + throw new CloudRuntimeException("Unable to find template associated with the backup. Please specify a valid Template/ISO while creating instance"); + } + } + verifyTemplate(cmd, template, serviceOffering.getId()); + + Long size = cmd.getSize(); + + Long diskOfferingId = cmd.getDiskOfferingId(); + Boolean isIso = template.getFormat().equals(ImageFormat.ISO); + if (diskOfferingId != null) { + if (!isIso) { + throw new InvalidParameterValueException(ApiConstants.DISK_OFFERING_ID + " parameter is supported for creating instance from backup only for ISO. For creating VMs with templates, please use the parameter " + ApiConstants.DATADISKS_DETAILS); + } + DiskOffering diskOffering = _diskOfferingDao.findById(diskOfferingId); + if (diskOffering == null) { + throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId); + } + if (diskOffering.isComputeOnly()) { + throw new InvalidParameterValueException(String.format("The disk offering %s provided is directly mapped to a service offering, please provide an individual disk offering", diskOffering)); + } + } + + Long overrideDiskOfferingId = cmd.getOverrideDiskOfferingId(); + + VmDiskInfo rootVmDiskInfoFromBackup = backupManager.getRootDiskInfoFromBackup(backup); + + if (isIso) { + if (diskOfferingId == null) { + diskOfferingId = rootVmDiskInfoFromBackup.getDiskOffering().getId(); + updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup); + size = rootVmDiskInfoFromBackup.getSize(); + } else { + DiskOffering rootDiskOffering = _diskOfferingDao.findById(diskOfferingId); + checkRootDiskSizeAgainstBackup(size, rootDiskOffering, rootVmDiskInfoFromBackup.getSize()); + } + } else { + if (overrideDiskOfferingId == null) { + overrideDiskOfferingId = serviceOffering.getDiskOfferingId(); + updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup); + } else { + DiskOffering overrideDiskOffering = _diskOfferingDao.findById(overrideDiskOfferingId); + if (overrideDiskOffering.isComputeOnly()) { + updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup); + } else { + String diskSizeFromDetails = cmd.getDetails().get(VmDetailConstants.ROOT_DISK_SIZE); + Long rootDiskSize = diskSizeFromDetails == null ? null : Long.parseLong(diskSizeFromDetails); + checkRootDiskSizeAgainstBackup(rootDiskSize, overrideDiskOffering, rootVmDiskInfoFromBackup.getSize()); + } + } + } + + List<VmDiskInfo> dataDiskInfoList = cmd.getDataDiskInfoList(); + if (dataDiskInfoList != null) { + backupManager.checkVmDisksSizeAgainstBackup(dataDiskInfoList, backup); + } else { + dataDiskInfoList = backupManager.getDataDiskInfoListFromBackup(backup); + } + + List<Long> networkIds = cmd.getNetworkIds(); + Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId()); + LinkedHashMap<Integer, Long> userVmNetworkMap = getVmOvfNetworkMapping(zone, owner, template, cmd.getVmNetworkMap()); + if (MapUtils.isNotEmpty(userVmNetworkMap)) { + networkIds = new ArrayList<>(userVmNetworkMap.values()); + } + + Map<Long, IpAddresses> ipToNetworkMap = cmd.getIpToNetworkMap(); + if (networkIds == null && ipToNetworkMap == null) { + networkIds = new ArrayList<Long>(); + ipToNetworkMap = backupManager.getIpToNetworkMapFromBackup(backup, cmd.getPreserveIp(), networkIds); + } + + UserVm vm = createVirtualMachine(cmd, zone, owner, serviceOffering, template, hypervisorType, diskOfferingId, size, overrideDiskOfferingId, dataDiskInfoList, networkIds, ipToNetworkMap, null, null); + + String vmSettingsFromBackup = backup.getDetail(ApiConstants.VM_SETTINGS); + if (vm != null && vmSettingsFromBackup != null) { + UserVmVO vmVO = _vmDao.findById(vm.getId()); + Map<String, String> details = vmInstanceDetailsDao.listDetailsKeyPairs(vm.getId()); + vmVO.setDetails(details); + + Type type = new TypeToken<Map<String, String>>(){}.getType(); + Map<String, String> vmDetailsFromBackup = new Gson().fromJson(vmSettingsFromBackup, type); + for (Entry<String, String> entry : vmDetailsFromBackup.entrySet()) { + if (!details.containsKey(entry.getKey())) { + vmVO.setDetail(entry.getKey(), entry.getValue()); + } + } + _vmDao.saveDetails(vmVO); + } + + return vm; + } + + @Override + public UserVm restoreVMFromBackup(CreateVMFromBackupCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException { + long vmId = cmd.getEntityId(); + Map<Long, DiskOffering> diskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap(); + Map<VirtualMachineProfile.Param, Object> additonalParams = new HashMap<>(); + UserVm vm; + + try { + vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null); + + boolean status = stopVirtualMachine(CallContext.current().getCallingUserId(), vm.getId()) ; Review Comment: The volumes need to be placed on the primary storages which will happen when VM is started. Stop is then needed because restore only works on stopped VMs. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@cloudstack.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org