Fix full backup VM restore (#5680)

Co-authored-by: SadiJr <sadi@scclouds.com.br>
This commit is contained in:
SadiJr 2021-12-10 03:16:42 -03:00 committed by GitHub
parent 28385be609
commit 9363f6490b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 8 deletions

View File

@ -42,6 +42,7 @@ import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.BooleanUtils;
@ -500,7 +501,9 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
*/
private void checkBackingInfo(VirtualDeviceBackingInfo backingInfo) {
if (!(backingInfo instanceof VirtualDiskFlatVer2BackingInfo)) {
throw new CloudRuntimeException("Unsopported backing, expected " + VirtualDiskFlatVer2BackingInfo.class.getSimpleName());
String errorMessage = String.format("Unsupported backing info. Expected: [%s], but received: [%s].", VirtualDiskFlatVer2BackingInfo.class.getSimpleName(), backingInfo.getClass().getSimpleName());
s_logger.error(errorMessage);
throw new CloudRuntimeException(errorMessage);
}
}
@ -642,8 +645,11 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
* If VM exists: update VM
*/
private VMInstanceVO getVM(String vmInternalName, long templateId, long guestOsId, long serviceOfferingId, long zoneId, long accountId, long userId, long domainId) {
s_logger.debug(String.format("Trying to get VM with specs: [vmInternalName: %s, templateId: %s, guestOsId: %s, serviceOfferingId: %s].", vmInternalName,
templateId, guestOsId, serviceOfferingId));
VMInstanceVO vm = _vmDao.findVMByInstanceNameIncludingRemoved(vmInternalName);
if (vm != null) {
s_logger.debug(String.format("Found an existing VM [id: %s, removed: %s] with internalName: [%s].", vm.getUuid(), vm.getRemoved() != null ? "yes" : "no", vmInternalName));
vm.setState(VirtualMachine.State.Stopped);
vm.setPowerState(VirtualMachine.PowerState.PowerOff);
_vmDao.update(vm.getId(), vm);
@ -655,6 +661,9 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
return _vmDao.findById(vm.getId());
} else {
long id = userVmDao.getNextInSequence(Long.class, "id");
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].",
vmInternalName, id, vmInternalName, templateId, guestOsId, serviceOfferingId));
UserVmVO vmInstanceVO = new UserVmVO(id, vmInternalName, vmInternalName, templateId, HypervisorType.VMware, guestOsId, false, false, domainId, accountId, userId,
serviceOfferingId, null, vmInternalName, null);
vmInstanceVO.setDataCenterId(zoneId);
@ -743,15 +752,19 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
long templateId = vmInstanceVO.getTemplateId();
long instanceId = vmInstanceVO.getId();
String operation = "";
for (VirtualDisk disk : virtualDisks) {
Long poolId = getPoolId(disk);
Volume volume = null;
if (disksMapping.containsKey(disk) && disksMapping.get(disk) != null) {
volume = updateVolume(disk, disksMapping, vmToImport, poolId, vmInstanceVO);
operation = "updated";
} else {
volume = createVolume(disk, vmToImport, domainId, zoneId, accountId, instanceId, poolId, templateId, backup, true);
operation = "created";
}
s_logger.debug("VM backup restored (updated/created) volume id:" + volume.getId() + " for VM id:" + instanceId);
s_logger.debug(String.format("VM [id: %s, instanceName: %s] backup restore operation %s volume [id: %s].", instanceId, vmInstanceVO.getInstanceName(),
operation, volume.getUuid()));
}
}
@ -968,7 +981,10 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
return info.getDatastore();
}
@Override public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup) throws Exception {
@Override
public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId, String vmInternalName, Backup backup) throws Exception {
s_logger.debug(String.format("Trying to import VM [vmInternalName: %s] from Backup [%s].", vmInternalName,
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "id", "uuid", "vmId", "externalId", "backupType")));
DatacenterMO dcMo = getDatacenterMO(zoneId);
VirtualMachineMO vmToImport = dcMo.findVm(vmInternalName);
if (vmToImport == null) {

View File

@ -27,6 +27,7 @@ import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
@ -199,13 +200,13 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
protected VirtualMachineTO toVirtualMachineTO(VirtualMachineProfile vmProfile) {
ServiceOffering offering = _serviceOfferingDao.findById(vmProfile.getId(), vmProfile.getServiceOfferingId());
VirtualMachine vm = vmProfile.getVirtualMachine();
HostVO host = hostDao.findById(vm.getHostId());
Long clusterId = findClusterOfVm(vm);
boolean divideMemoryByOverprovisioning = true;
boolean divideCpuByOverprovisioning = true;
if (host != null) {
divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(host.getClusterId());
divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(host.getClusterId());
if (clusterId != null) {
divideMemoryByOverprovisioning = VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor.valueIn(clusterId);
divideCpuByOverprovisioning = VmMinCpuSpeedEqualsCpuSpeedDividedByCpuOverprovisioningFactor.valueIn(clusterId);
}
Long minMemory = (long)(offering.getRamSize() / (divideMemoryByOverprovisioning ? vmProfile.getMemoryOvercommitRatio() : 1));
@ -280,6 +281,22 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
return to;
}
protected Long findClusterOfVm(VirtualMachine vm) {
HostVO host = hostDao.findById(vm.getHostId());
if (host != null) {
return host.getClusterId();
}
s_logger.debug(String.format("VM [%s] does not have a host id. Trying the last host.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "instanceName", "id", "uuid")));
host = hostDao.findById(vm.getLastHostId());
if (host != null) {
return host.getClusterId();
}
s_logger.debug(String.format("VM [%s] does not have a last host id.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(vm, "instanceName", "id", "uuid")));
return null;
}
@Override
/**
* The basic implementation assumes that the initial "host" defined to execute the command is the host that is in fact going to execute it.

View File

@ -533,7 +533,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
try {
vm = guru.importVirtualMachineFromBackup(zoneId, domainId, accountId, userId, vmInternalName, backup);
} catch (final Exception e) {
LOG.error("Failed to import VM from backup restoration", e);
LOG.error(String.format("Failed to import VM [vmInternalName: %s] from backup restoration [%s] with hypervisor [type: %s] due to: [%s].", vmInternalName,
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "id", "uuid", "vmId", "externalId", "backupType"), hypervisorType, e.getMessage()), e);
throw new CloudRuntimeException("Error during vm backup restoration and import: " + e.getMessage());
}
if (vm == null) {

View File

@ -452,4 +452,42 @@ public class KVMGuruTest {
Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator());
}
@Test
public void testGetClusterIdFromVMHost() {
Mockito.when(vm.getHostId()).thenReturn(123l);
HostVO vo = new HostVO("");
Long expected = 5l;
vo.setClusterId(expected);
Mockito.when(hostDao.findById(123l)).thenReturn(vo);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertEquals(expected, clusterId);
}
@Test
public void testGetClusterIdFromLastVMHost() {
Mockito.when(vm.getHostId()).thenReturn(null);
Mockito.when(vm.getLastHostId()).thenReturn(321l);
HostVO vo = new HostVO("");
Long expected = 7l;
vo.setClusterId(expected);
Mockito.when(hostDao.findById(321l)).thenReturn(vo);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertEquals(expected, clusterId);
}
@Test
public void testGetNullWhenVMThereIsNoInformationOfUsedHosts() {
Mockito.when(vm.getHostId()).thenReturn(null);
Mockito.when(vm.getLastHostId()).thenReturn(null);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertNull(clusterId);
}
}