shwstppr commented on code in PR #10140: URL: https://github.com/apache/cloudstack/pull/10140#discussion_r1922242112
########## server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java: ########## @@ -748,6 +819,151 @@ private Backup.VolumeInfo getVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, return null; } + @Override + public void updateDiskOfferingSizeFromBackup(List<DiskOfferingInfo> dataDiskOfferingsInfo, Backup backup) { + List<DiskOfferingInfo> dataDiskOfferingsInfoFromBackup = getDataDiskOfferingListFromBackup(backup); + int index = 0; + for(DiskOfferingInfo diskOfferingInfo : dataDiskOfferingsInfo) { + diskOfferingInfo.setSize(Math.max(diskOfferingInfo.getSize(), dataDiskOfferingsInfoFromBackup.get(index).getSize())); + index++; + } + } + + @Override + public DiskOfferingInfo getRootDiskOfferingInfoFromBackup(Backup backup) { + String diskOfferingIdsDetail = backup.getDetail(ApiConstants.DISK_OFFERING_IDS); + if (diskOfferingIdsDetail == null) { + return null; + } + String [] diskOfferingIds = diskOfferingIdsDetail.split(","); + String [] deviceIds = backup.getDetail(ApiConstants.DEVICE_IDS).split(","); + String [] diskSizes = backup.getDetail(ApiConstants.DISK_SIZES).split(","); + + for (int i = 0; i < diskOfferingIds.length; i++) { + if (deviceIds[i].equals("0")) { + DiskOfferingVO diskOffering = diskOfferingDao.findByUuid(diskOfferingIds[i]); + if (diskOffering == null) { + throw new CloudRuntimeException("Unable to find the root disk offering with uuid (" + diskOfferingIds[i] + ") stored in backup. Please specify a valid root disk offering id while creating the instance"); + } + Long size = Long.parseLong(diskSizes[i]) / (1024 * 1024 * 1024); + return new DiskOfferingInfo(diskOffering, size, null, null, 0L); + } + } + return null; + } + + @Override + public List<DiskOfferingInfo> getDataDiskOfferingListFromBackup(Backup backup) { + String diskOfferingIdsDetail = backup.getDetail(ApiConstants.DISK_OFFERING_IDS); + if (diskOfferingIdsDetail == null) { + return null; + } + + String [] diskOfferingIds = diskOfferingIdsDetail.split(","); + String [] deviceIds = backup.getDetail(ApiConstants.DEVICE_IDS).split(","); + String [] diskSizes = backup.getDetail(ApiConstants.DISK_SIZES).split(","); + String [] minIopsList = backup.getDetail(ApiConstants.MIN_IOPS).split(","); + String [] maxIopsList = backup.getDetail(ApiConstants.MAX_IOPS).split(","); + + List<DiskOfferingInfo> diskOfferingInfoList = new ArrayList<>(); + for (int i = 0; i < diskOfferingIds.length; i++) { + Long deviceId = Long.parseLong(deviceIds[i]); + if (deviceId == 0) { + continue; + } + DiskOfferingVO diskOffering = diskOfferingDao.findByUuid(diskOfferingIds[i]); + if (diskOffering == null) { + throw new CloudRuntimeException("Unable to find the disk offering with uuid (" + diskOfferingIds[i] + ") stored in backup. Please specify a valid disk offering id while creating the instance"); + } + Long size = Long.parseLong(diskSizes[i]) / (1024 * 1024 * 1024); + Long minIops = (diskOffering.isCustomizedIops() != null && diskOffering.isCustomizedIops() && !minIopsList[i].equals("null")) ? + Long.parseLong(minIopsList[i]) : null; + Long maxIops = (diskOffering.isCustomizedIops() != null && diskOffering.isCustomizedIops() && !maxIopsList[i].equals("null")) ? + Long.parseLong(maxIopsList[i]) : null; + diskOfferingInfoList.add(new DiskOfferingInfo(diskOffering, size, minIops, maxIops, deviceId)); + } + return diskOfferingInfoList; + } + + @Override + public boolean restoreBackupToVM(final Long backupId, final Long vmId) throws ResourceUnavailableException { + final BackupVO backup = backupDao.findById(backupId); + if (backup == null) { + throw new CloudRuntimeException("Backup " + backupId + " does not exist"); + } + validateBackupForZone(backup.getZoneId()); + + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(vmId); + if (vm == null) { + throw new CloudRuntimeException("VM ID " + backup.getVmId() + " couldn't be found on existing or removed VMs"); + } + accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); + + if (vm.getRemoved() != null) { + throw new CloudRuntimeException("VM is removed from CloudStack"); + } + if (vm.getRemoved() != null) { + throw new CloudRuntimeException("VM should be in the stopped state"); + } + if (!vm.getState().equals(VirtualMachine.State.Stopped)) { + throw new CloudRuntimeException("Existing VM should be stopped before being restored from backup"); + } + + List<Backup.VolumeInfo> backupVolumes = backup.getBackedUpVolumes(); + if (backupVolumes == null) { + throw new CloudRuntimeException("Backed-up volumes not found"); + } + + List<VolumeVO> vmVolumes = volumeDao.findByInstance(vmId); + if (vmVolumes.size() != backupVolumes.size()) { + throw new CloudRuntimeException("Unable to restore VM with the current backup as the backup has different number of disks as the VM"); + } + + BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(backup.getBackupOfferingId()); + if (offering == null) { + String errorMessage = "Failed to find backup offering of the VM backup."; + throw new CloudRuntimeException("Failed to find backup offering of the VM backup."); + } + if ("networker".equals(offering.getProvider())) { + throw new CloudRuntimeException("Create instance from VM is not supported for Networker Backup plugin."); + } + + String backupDetailsInMessage = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "uuid", "externalId", "newVMId", "type", "status", "date"); + try { + updateVmState(vm, VirtualMachine.Event.RestoringRequested, VirtualMachine.State.Restoring); + updateVolumeState(vm, Volume.Event.RestoreRequested, Volume.State.Restoring); + ActionEventUtils.onStartedActionEvent(User.UID_SYSTEM, vm.getAccountId(), EventTypes.EVENT_VM_BACKUP_RESTORE, + String.format("Restoring VM %s from backup %s", vm.getUuid(), backup.getUuid()), + vm.getId(), ApiCommandResourceType.VirtualMachine.toString(), + true, 0); + + String host = null; + String dataStore = null; + if (!"nas".equals(offering.getProvider())) { + Pair<HostVO, StoragePoolVO> restoreInfo = getRestoreVolumeHostAndDatastore(vm); + host = restoreInfo.first().getPrivateIpAddress(); + dataStore = restoreInfo.second().getUuid(); + } + final BackupProvider backupProvider = getBackupProvider(offering.getProvider()); + if (!backupProvider.restoreBackupToVM(vm, backup, host, dataStore)) { + ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, vm.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_BACKUP_RESTORE, + String.format("Failed to restore VM %s from backup %s", vm.getInstanceName(), backup.getUuid()), + vm.getId(), ApiCommandResourceType.VirtualMachine.toString(),0); + throw new CloudRuntimeException("Error restoring VM from backup with uuid " + backup.getUuid()); + } + // The restore process is executed by a backup provider outside of ACS, I am using the catch-all (Exception) to + // ensure that no provider-side exception is missed. Therefore, we have a proper handling of exceptions, and rollbacks if needed. + } catch (Exception e) { Review Comment: @abh1sar up to you. Catching all will also mask any NPEs. -- 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