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

Reply via email to