Skip to content

Commit 29888aa

Browse files
SadiJrSadiJr
authored andcommitted
Fix full backup VM restore (#5680)
Co-authored-by: SadiJr <sadi@scclouds.com.br>
1 parent f6bd780 commit 29888aa

4 files changed

Lines changed: 80 additions & 8 deletions

File tree

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
4343
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
4444
import org.apache.cloudstack.storage.to.VolumeObjectTO;
45+
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
4546
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
4647
import org.apache.commons.collections.CollectionUtils;
4748
import org.apache.commons.lang.BooleanUtils;
@@ -500,7 +501,9 @@ private boolean isRootDisk(VirtualDisk disk, Map<VirtualDisk, VolumeVO> disksMap
500501
*/
501502
private void checkBackingInfo(VirtualDeviceBackingInfo backingInfo) {
502503
if (!(backingInfo instanceof VirtualDiskFlatVer2BackingInfo)) {
503-
throw new CloudRuntimeException("Unsopported backing, expected " + VirtualDiskFlatVer2BackingInfo.class.getSimpleName());
504+
String errorMessage = String.format("Unsupported backing info. Expected: [%s], but received: [%s].", VirtualDiskFlatVer2BackingInfo.class.getSimpleName(), backingInfo.getClass().getSimpleName());
505+
s_logger.error(errorMessage);
506+
throw new CloudRuntimeException(errorMessage);
504507
}
505508
}
506509

@@ -642,8 +645,11 @@ private Long getImportingVMTemplate(List<VirtualDisk> virtualDisks, DatacenterMO
642645
* If VM exists: update VM
643646
*/
644647
private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsId, long serviceOfferingId, long zoneId, long accountId, long userId, long domainId) {
648+
s_logger.debug(String.format("Trying to get VM with specs: [vmInternalName: %s, templateId: %s, guestOsId: %s, serviceOfferingId: %s].", vmInternalName,
649+
templateId, guestOsId, serviceOfferingId));
645650
VMInstanceVO vm = _vmDao.findVMByInstanceNameIncludingRemoved(vmInternalName);
646651
if (vm != null) {
652+
s_logger.debug(String.format("Found an existing VM [id: %s, removed: %s] with internalName: [%s].", vm.getUuid(), vm.getRemoved() != null ? "yes" : "no", vmInternalName));
647653
vm.setState(VirtualMachine.State.Stopped);
648654
vm.setPowerState(VirtualMachine.PowerState.PowerOff);
649655
_vmDao.update(vm.getId(), vm);
@@ -655,6 +661,9 @@ private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsI
655661
return _vmDao.findById(vm.getId());
656662
} else {
657663
long id = userVmDao.getNextInSequence(Long.class, "id");
664+
s_logger.debug(String.format("Can't find an existing VM with internalName: [%s]. Creating a new VM with: [id: %s, name: %s, templateId: %s, guestOsId: %s, serviceOfferingId: %s].",
665+
vmInternalName, id, vmInternalName, templateId, guestOsId, serviceOfferingId));
666+
658667
UserVmVO vmInstanceVO = new UserVmVO(id, vmInternalName, vmInternalName, templateId, HypervisorType.VMware, guestOsId, false, false, domainId, accountId, userId,
659668
serviceOfferingId, null, vmInternalName, null);
660669
vmInstanceVO.setDataCenterId(zoneId);
@@ -743,15 +752,19 @@ private void syncVMVolumes(VMInstanceVO vmInstanceVO, List<VirtualDisk> virtualD
743752
long templateId = vmInstanceVO.getTemplateId();
744753
long instanceId = vmInstanceVO.getId();
745754

755+
String operation = "";
746756
for (VirtualDisk disk : virtualDisks) {
747757
Long poolId = getPoolId(disk);
748758
Volume volume = null;
749759
if (disksMapping.containsKey(disk) && disksMapping.get(disk) != null) {
750760
volume = updateVolume(disk, disksMapping, vmToImport, poolId, vmInstanceVO);
761+
operation = "updated";
751762
} else {
752763
volume = createVolume(disk, vmToImport, domainId, zoneId, accountId, instanceId, poolId, templateId, backup, true);
764+
operation = "created";
753765
}
754-
s_logger.debug("VM backup restored (updated/created) volume id:" + volume.getId() + " for VM id:" + instanceId);
766+
s_logger.debug(String.format("VM [id: %s, instanceName: %s] backup restore operation %s volume [id: %s].", instanceId, vmInstanceVO.getInstanceName(),
767+
operation, volume.getUuid()));
755768
}
756769
}
757770

@@ -968,7 +981,10 @@ private ManagedObjectReference getDestStoreMor(VirtualMachineMO vmMo) throws Exc
968981
return info.getDatastore();
969982
}
970983

971-
@Override public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup) throws Exception {
984+
@Override
985+
public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup) throws Exception {
986+
s_logger.debug(String.format("Trying to import VM [vmInternalName: %s] from Backup [%s].", vmInternalName,
987+
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "id", "uuid", "vmId", "externalId", "backupType")));
972988
DatacenterMO dcMo = getDatacenterMO(zoneId);
973989
VirtualMachineMO vmToImport = dcMo.findVm(vmInternalName);
974990
if (vmToImport == null) {

server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
2828
import org.apache.cloudstack.framework.config.ConfigKey;
2929
import org.apache.cloudstack.framework.config.Configurable;
30+
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
3031
import org.apache.commons.collections.CollectionUtils;
3132
import org.apache.commons.collections.MapUtils;
3233
import org.apache.commons.lang3.StringUtils;
@@ -199,13 +200,13 @@ protected void addServiceOfferingExtraConfiguration(ServiceOffering offering, Vi
199200
protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) {
200201
ServiceOffering offering = _serviceOfferingDao.findById(vmProfile.getId(), vmProfile.getServiceOfferingId());
201202
VirtualMachine vm = vmProfile.getVirtualMachine();
202-
HostVO host = hostDao.findById(vm.getHostId());
203+
Long clusterId = findClusterOfVm(vm);
203204
boolean divideMemoryByOverprovisioning = true;
204205
boolean divideCpuByOverprovisioning = true;
205206

206-
if (host != null) {
207-
divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(host.getClusterId());
208-
divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(host.getClusterId());
207+
if (clusterId != null) {
208+
divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(clusterId);
209+
divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(clusterId);
209210
}
210211

211212
Long minMemory = (long)(offering.getRamSize() / (divideMemoryByOverprovisioning ? vmProfile.getMemoryOvercommitRatio() : 1));
@@ -280,6 +281,22 @@ protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) {
280281
return to;
281282
}
282283

284+
protected Long findClusterOfVm(VirtualMachine vm) {
285+
HostVO host = hostDao.findById(vm.getHostId());
286+
if (host != null) {
287+
return host.getClusterId();
288+
}
289+
290+
s_logger.debug(String.format("VM [%s] does not have a host id. Trying the last host.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "instanceName", "id", "uuid")));
291+
host = hostDao.findById(vm.getLastHostId());
292+
if (host != null) {
293+
return host.getClusterId();
294+
}
295+
296+
s_logger.debug(String.format("VM [%s] does not have a last host id.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "instanceName", "id", "uuid")));
297+
return null;
298+
}
299+
283300
@Override
284301
/**
285302
* The basic implementation assumes that the initial "host" defined to execute the command is the host that is in fact going to execute it.

server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,8 @@ public boolean importRestoredVM(long zoneId, long domainId, long accountId, long
533533
try {
534534
vm = guru.importVirtualMachineFromBackup(zoneId, domainId, accountId, userId, vmInternalName, backup);
535535
} catch (final Exception e) {
536-
LOG.error("Failed to import VM from backup restoration", e);
536+
LOG.error(String.format("Failed to import VM [vmInternalName: %s] from backup restoration [%s] with hypervisor [type: %s] due to: [%s].", vmInternalName,
537+
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "id", "uuid", "vmId", "externalId", "backupType"), hypervisorType, e.getMessage()), e);
537538
throw new CloudRuntimeException("Error during vm backup restoration and import: " + e.getMessage());
538539
}
539540
if (vm == null) {

server/src/test/java/com/cloud/hypervisor/KVMGuruTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,42 @@ public void validateConfigureVmOsDescriptionHostNullAndGuestOsMappingNullAndGues
452452
Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator());
453453
}
454454

455+
@Test
456+
public void testGetClusterIdFromVMHost() {
457+
Mockito.when(vm.getHostId()).thenReturn(123l);
458+
HostVO vo = new HostVO("");
459+
Long expected = 5l;
460+
vo.setClusterId(expected);
461+
462+
Mockito.when(hostDao.findById(123l)).thenReturn(vo);
463+
464+
Long clusterId = guru.findClusterOfVm(vm);
465+
466+
Assert.assertEquals(expected, clusterId);
467+
}
468+
469+
@Test
470+
public void testGetClusterIdFromLastVMHost() {
471+
Mockito.when(vm.getHostId()).thenReturn(null);
472+
Mockito.when(vm.getLastHostId()).thenReturn(321l);
473+
HostVO vo = new HostVO("");
474+
Long expected = 7l;
475+
vo.setClusterId(expected);
476+
477+
Mockito.when(hostDao.findById(321l)).thenReturn(vo);
478+
479+
Long clusterId = guru.findClusterOfVm(vm);
480+
481+
Assert.assertEquals(expected, clusterId);
482+
}
483+
484+
@Test
485+
public void testGetNullWhenVMThereIsNoInformationOfUsedHosts() {
486+
Mockito.when(vm.getHostId()).thenReturn(null);
487+
Mockito.when(vm.getLastHostId()).thenReturn(null);
488+
489+
Long clusterId = guru.findClusterOfVm(vm);
490+
491+
Assert.assertNull(clusterId);
492+
}
455493
}

0 commit comments

Comments
 (0)