shwstppr commented on code in PR #10140:
URL: https://github.com/apache/cloudstack/pull/10140#discussion_r1917875143
##########
server/src/main/java/com/cloud/vm/UserVmManagerImpl.java:
##########
@@ -6139,6 +6186,11 @@ public UserVm createVirtualMachine(DeployVMCmd cmd)
throws InsufficientCapacityE
}
}
+ List<DiskOfferingInfo> dataDiskOfferingsInfo =
cmd.getDataDiskOfferingsInfo();
+ if (dataDiskOfferingsInfo != null && diskOfferingId != null) {
Review Comment:
If diskOfferingId is the ID of just another data disk, is it better to
generate a diskOfferingInfo using it and use a single variable
dataDiskOfferingsInfo in the subsequent method calls?
##########
api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java:
##########
@@ -147,6 +148,13 @@ public class DeployVMCmd extends
BaseAsyncCreateCustomIdCmd implements SecurityG
since = "4.4")
private Long rootdisksize;
+ @Parameter(name = ApiConstants.DATADISKS_DETAILS,
Review Comment:
@abh1sar is it possible to use the existing details param here?
##########
server/src/main/java/com/cloud/vm/UserVmManagerImpl.java:
##########
@@ -1009,32 +1011,40 @@ public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd)
throws ResourceUnavailableExce
throw new InvalidParameterValueException("Vm " + userVm + " should
be stopped to do SSH Key reset");
}
- if (cmd.getNames() == null || cmd.getNames().isEmpty()) {
+ List<String> names = cmd.getNames();
+ if (names == null || names.isEmpty()) {
Review Comment:
use StringUtils?
##########
api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java:
##########
@@ -102,6 +103,10 @@ public class BackupResponse extends BaseResponse {
@Param(description = "zone name")
private String zone;
+ @SerializedName(ApiConstants.VM_DETAILS)
+ @Param(description = "Lists the vm specific details for the backup")
Review Comment:
since attribute here
##########
server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java:
##########
@@ -273,10 +292,62 @@ public boolean deleteBackupOffering(final Long
offeringId) {
throw new CloudRuntimeException("Backup offering is assigned to
VMs, remove the assignment(s) in order to remove the offering.");
}
- validateForZone(offering.getZoneId());
+ validateBackupForZone(offering.getZoneId());
return backupOfferingDao.remove(offering.getId());
}
+ @Override
+ public Map<String, String> getVmDetailsForBackup(VirtualMachine vm) {
+ HashMap<String, String> details = new HashMap<>();
+ details.put(ApiConstants.HYPERVISOR,
vm.getHypervisorType().toString());
+ ServiceOffering serviceOffering =
entityManager.findById(ServiceOffering.class, vm.getServiceOfferingId());
Review Comment:
Any reason ServiceOfferingDao, VmTemplateDao can't be used here?
##########
plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/NetworkerBackupProvider.java:
##########
@@ -117,6 +122,12 @@ public class NetworkerBackupProvider extends AdapterBase
implements BackupProvid
@Inject
private VMInstanceDao vmInstanceDao;
+ @Inject
+ private EntityManager entityManager;
Review Comment:
Can we use `*Daos` instead?
##########
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);
Review Comment:
These details will be stored only for new backups, what happens if an older
backup is used? Does the user need to provide inputs in that case?
##########
plugins/backup/networker/src/main/java/org/apache/cloudstack/backup/networker/NetworkerClient.java:
##########
@@ -22,6 +22,7 @@
import com.cloud.vm.VirtualMachine;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
+
Review Comment:
Changes in this file can be reverted maybe
##########
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()));
Review Comment:
It this used for fixed size offerings as well? Could there be a case with
offering of size 5GB having volume of size 7GB?
##########
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");
Review Comment:
Maybe better to use more generic message..."VM can not found"?
##########
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())) {
Review Comment:
maybe better to define in the provider itself -
`offering.getProvider().supportsInstanceFromBackup()`
##########
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) {
+ logger.error(String.format("Failed to restore backup [%s] due to:
[%s].", backupDetailsInMessage, e.getMessage()), e);
Review Comment:
ActionEventUtils.onFailedActionEvent?
##########
ui/public/locales/en.json:
##########
@@ -2626,11 +2628,13 @@
"label.bucket.policy": "Bucket Policy",
"label.usersecretkey": "Secret Key",
"label.create.bucket": "Create Bucket",
+"label.create.instance.from.backup": "Create new instance from backup",
Review Comment:
why two different keys? `label.create.new.instance.from.backup` and
`label.create.instance.from.backup`
##########
ui/src/views/compute/DeployVMFromBackup.vue:
##########
@@ -0,0 +1,2211 @@
+// Licensed to the Apache Software Foundation (ASF) under one
Review Comment:
should this be moved to components?
##########
ui/src/views/compute/wizard/VolumeDiskOfferingMap.vue:
##########
@@ -0,0 +1,265 @@
+// Licensed to the Apache Software Foundation (ASF) under one
Review Comment:
VolumeDiskofferingSelectView?
##########
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")) {
Review Comment:
better to use - "0".equals(deviceIds[i])
##########
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]);
Review Comment:
edge case - what if the disk offering access for zone/domain is removed.
(Not sure of UI but can be done using API)
##########
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) {
Review Comment:
wrong check
##########
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");
Review Comment:
Better message can be used
##########
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")) ?
Review Comment:
```suggestion
Long minIops =
(Boolean.TRUE.equals(diskOffering.isCustomizedIops()) &&
!minIopsList[i].equals("null")) ?
```
##########
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.";
Review Comment:
not used
##########
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:
possible to avoid catch all?
--
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: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]