mirror of https://github.com/apache/cloudstack.git
Fix restore VM workflow - clone and replace existing VM instead of cloning and moving disks
This commit is contained in:
parent
67794aba23
commit
f1f490b151
|
|
@ -26,42 +26,23 @@ import java.util.Map;
|
|||
*/
|
||||
public class DeployAsIsInfoTO {
|
||||
|
||||
private String templatePath;
|
||||
private String destStoragePool;
|
||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||
private Map<String, String> properties = new HashMap<>();
|
||||
private Map<Integer, String> nicAdapterMap = new HashMap();
|
||||
private boolean replaceVm;
|
||||
|
||||
public DeployAsIsInfoTO() {
|
||||
}
|
||||
|
||||
public DeployAsIsInfoTO(String templatePath, String destStoragePool, Map<String, String> properties,
|
||||
Map<Integer, String> nicAdapterMap, boolean replaceVm) {
|
||||
this.templatePath = templatePath;
|
||||
this.destStoragePool = destStoragePool;
|
||||
public DeployAsIsInfoTO(Map<String, String> properties, Map<Integer, String> nicAdapterMap) {
|
||||
this.properties = properties;
|
||||
this.nicAdapterMap = nicAdapterMap;
|
||||
this.replaceVm = replaceVm;
|
||||
}
|
||||
|
||||
public String getTemplatePath() {
|
||||
return templatePath;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public String getDestStoragePool() {
|
||||
return destStoragePool;
|
||||
}
|
||||
|
||||
public Map<Integer, String> getNicAdapterMap() {
|
||||
return nicAdapterMap;
|
||||
}
|
||||
|
||||
public boolean isReplaceVm() {
|
||||
return replaceVm;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ public interface VirtualMachineProfile {
|
|||
public static final Param BootType = new Param("BootType");
|
||||
public static final Param BootIntoSetup = new Param("enterHardwareSetup");
|
||||
public static final Param PreserveNics = new Param("PreserveNics");
|
||||
public static final Param ReplaceDeployAsIs = new Param("ReplaceDeployAsIs");
|
||||
|
||||
private String name;
|
||||
|
||||
|
|
|
|||
|
|
@ -186,17 +186,9 @@ class VmwareVmImplementer {
|
|||
* Set the information relevant for deploy-as-is VMs on the VM TO
|
||||
*/
|
||||
private void setDeployAsIsInfoTO(VirtualMachineProfile vm, VirtualMachineTO to, Map<String, String> details) {
|
||||
String configuration = details.getOrDefault(VmDetailConstants.DEPLOY_AS_IS_CONFIGURATION, null);
|
||||
Map<String, String> properties = deployAsIsHelper.getVirtualMachineDeployAsIsProperties(vm);
|
||||
String templatePath = null;
|
||||
String destStoragePool = null;
|
||||
if (vm.getVirtualMachine().getState() == VirtualMachine.State.Starting) {
|
||||
destStoragePool = deployAsIsHelper.getAllocatedVirtualMachineDestinationStoragePool(vm);
|
||||
templatePath = deployAsIsHelper.getAllocatedVirtualMachineTemplatePath(vm, configuration, destStoragePool);
|
||||
}
|
||||
Map<Integer, String> nicsAdapterMapping = deployAsIsHelper.getAllocatedVirtualMachineNicsAdapterMapping(vm, to.getNics());
|
||||
boolean replaceVm = vm.getParameter(VirtualMachineProfile.Param.ReplaceDeployAsIs) != null ? (Boolean) vm.getParameter(VirtualMachineProfile.Param.ReplaceDeployAsIs) : false;
|
||||
DeployAsIsInfoTO info = new DeployAsIsInfoTO(templatePath, destStoragePool, properties, nicsAdapterMapping, replaceVm);
|
||||
DeployAsIsInfoTO info = new DeployAsIsInfoTO(properties, nicsAdapterMapping);
|
||||
to.setDeployAsIsInfo(info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import javax.xml.datatype.XMLGregorianCalendar;
|
|||
import com.cloud.agent.api.to.DataTO;
|
||||
import com.cloud.agent.api.to.DeployAsIsInfoTO;
|
||||
import com.cloud.agent.api.ValidateVcenterDetailsCommand;
|
||||
import com.cloud.storage.resource.VmwareStorageLayoutType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
|
||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||
|
|
@ -1739,57 +1738,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
}
|
||||
|
||||
private void restoreVirtualMachineVolumesFromTemplate(String vmInternalCSName, VirtualMachineTO vmSpec,
|
||||
VmwareHypervisorHost host, VirtualMachineMO virtualMachineMO,
|
||||
VmwareContext context, DatacenterMO dcMo) throws Exception {
|
||||
DeployAsIsInfoTO deployAsIsInfo = vmSpec.getDeployAsIsInfo();
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Restoring VM " + vmInternalCSName + " volumes from template as-is");
|
||||
}
|
||||
String deployAsIsTemplate = deployAsIsInfo.getTemplatePath();
|
||||
String destDatastore = deployAsIsInfo.getDestStoragePool();
|
||||
|
||||
String auxVMName = vmInternalCSName + "-aux";
|
||||
_storageProcessor.cloneVMFromTemplate(host, deployAsIsTemplate, auxVMName, destDatastore);
|
||||
VirtualMachineMO auxVM = host.findVmOnHyperHost(auxVMName);
|
||||
if (auxVM == null) {
|
||||
s_logger.info("Cloned deploy-as-is VM " + auxVMName + " is not in this host, relocating it");
|
||||
auxVM = takeVmFromOtherHyperHost(host, auxVMName);
|
||||
}
|
||||
ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(host, destDatastore);
|
||||
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
|
||||
List<String> vmdkFileBaseNames = auxVM.getVmdkFileBaseNames();
|
||||
for (String vmdkFileBaseName : vmdkFileBaseNames) {
|
||||
s_logger.info("Move volume out of volume-wrapper VM " + vmdkFileBaseName);
|
||||
String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, auxVMName, vmdkFileBaseName, VmwareStorageLayoutType.VMWARE, !_fullCloneFlag);
|
||||
String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, auxVMName, vmdkFileBaseName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, !_fullCloneFlag);
|
||||
for (int i=0; i<vmwareLayoutFilePair.length; i++) {
|
||||
dsMo.moveDatastoreFile(vmwareLayoutFilePair[i], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[i], dcMo.getMor(), true);
|
||||
}
|
||||
}
|
||||
auxVM.detachAllDisks();
|
||||
auxVM.destroy();
|
||||
String vmNameInVcenter = virtualMachineMO.getName();
|
||||
virtualMachineMO.tearDownDevices(new Class<?>[]{VirtualDisk.class});
|
||||
s_logger.info("Changing VM datastore to " + dsMo);
|
||||
virtualMachineMO.changeDatastore(morDatastore);
|
||||
for (String vmdkFileBaseName : vmdkFileBaseNames) {
|
||||
if (dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmNameInVcenter)) {
|
||||
String newPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmNameInVcenter, dsMo, vmdkFileBaseName, null);
|
||||
s_logger.info("Attaching disk to restored VM at: " + newPath + " on datastore: " + destDatastore);
|
||||
virtualMachineMO.attachDisk(new String[] {newPath}, morDatastore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRestoreParameterSet(VirtualMachineTO vmSpec) {
|
||||
DeployAsIsInfoTO deployAsIsInfo = vmSpec.getDeployAsIsInfo();
|
||||
if (deployAsIsInfo != null) {
|
||||
return deployAsIsInfo.isReplaceVm();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected StartAnswer execute(StartCommand cmd) {
|
||||
if (s_logger.isInfoEnabled()) {
|
||||
s_logger.info("Executing resource StartCommand: " + getHumanReadableBytesJson(_gson.toJson(cmd)));
|
||||
|
|
@ -1908,18 +1856,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
|
||||
if (deployAsIs) {
|
||||
if (s_logger.isTraceEnabled()) {
|
||||
s_logger.trace("Deploying OVA from template as-is");
|
||||
}
|
||||
String deployAsIsTemplate = deployAsIsInfo.getTemplatePath();
|
||||
String destDatastore = deployAsIsInfo.getDestStoragePool();
|
||||
_storageProcessor.cloneVMFromTemplate(hyperHost, deployAsIsTemplate, vmInternalCSName, destDatastore);
|
||||
vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName);
|
||||
if (vmMo == null) {
|
||||
s_logger.info("Cloned deploy-as-is VM " + vmInternalCSName + " is not in this host, relocating it");
|
||||
vmMo = takeVmFromOtherHyperHost(hyperHost, vmInternalCSName);
|
||||
}
|
||||
mapSpecDisksToClonedDisks(vmMo, vmInternalCSName, specDisks);
|
||||
} else {
|
||||
DiskTO rootDisk = null;
|
||||
for (DiskTO vol : disks) {
|
||||
|
|
@ -1970,10 +1911,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName);
|
||||
}
|
||||
}
|
||||
|
||||
if (deployAsIs && isRestoreParameterSet(vmSpec)) {
|
||||
restoreVirtualMachineVolumesFromTemplate(vmInternalCSName, vmSpec, hyperHost, vmMo, context, dcMo);
|
||||
mapSpecDisksToClonedDisks(vmMo, vmInternalCSName, specDisks);
|
||||
if (deployAsIs) {
|
||||
s_logger.info("Mapping VM disks to spec disks and tearing down datadisks (if any)");
|
||||
mapSpecDisksToClonedDisksAndTearDownDatadisks(vmMo, vmInternalCSName, specDisks);
|
||||
}
|
||||
|
||||
int disksChanges = getDisksChangesNumberFromDisksSpec(disks, deployAsIs);
|
||||
|
|
@ -2569,6 +2509,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
}
|
||||
|
||||
private void tearDownVMDisks(VirtualMachineMO vmMo, List<VirtualDisk> disks) throws Exception {
|
||||
for (VirtualDisk disk : disks) {
|
||||
vmMo.tearDownDevice(disk);
|
||||
}
|
||||
}
|
||||
|
||||
private String getGuestOsIdFromVmSpec(VirtualMachineTO vmSpec, boolean deployAsIs) {
|
||||
return translateGuestOsIdentifier(vmSpec.getArch(), vmSpec.getOs(), vmSpec.getPlatformEmulator()).value();
|
||||
}
|
||||
|
|
@ -2624,21 +2570,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
/**
|
||||
* Modify the specDisks information to match the cloned VM's disks (from vmMo VM)
|
||||
*/
|
||||
private void mapSpecDisksToClonedDisks(VirtualMachineMO vmMo, String vmInternalCSName, DiskTO[] specDisks) {
|
||||
private void mapSpecDisksToClonedDisksAndTearDownDatadisks(VirtualMachineMO vmMo, String vmInternalCSName, DiskTO[] specDisks) {
|
||||
try {
|
||||
s_logger.debug("Mapping spec disks information to cloned VM disks for VM " + vmInternalCSName);
|
||||
if (vmMo != null && ArrayUtils.isNotEmpty(specDisks)) {
|
||||
List<VirtualDisk> vmDisks = vmMo.getVirtualDisks();
|
||||
List<DiskTO> sortedDisks = Arrays.asList(sortVolumesByDeviceId(specDisks))
|
||||
List<VirtualDisk> rootDisks = new ArrayList<>();
|
||||
List<DiskTO> sortedRootDisksFromSpec = Arrays.asList(sortVolumesByDeviceId(specDisks))
|
||||
.stream()
|
||||
.filter(x -> x.getType() == Volume.Type.ROOT)
|
||||
.collect(Collectors.toList());
|
||||
if (sortedDisks.size() != vmDisks.size()) {
|
||||
s_logger.error("Different number of root disks spec vs cloned deploy-as-is VM disks: " + sortedDisks.size() + " - " + vmDisks.size());
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sortedDisks.size(); i++) {
|
||||
DiskTO specDisk = sortedDisks.get(i);
|
||||
for (int i = 0; i < sortedRootDisksFromSpec.size(); i++) {
|
||||
DiskTO specDisk = sortedRootDisksFromSpec.get(i);
|
||||
VirtualDisk vmDisk = vmDisks.get(i);
|
||||
DataTO dataVolume = specDisk.getData();
|
||||
if (dataVolume instanceof VolumeObjectTO) {
|
||||
|
|
@ -2662,6 +2605,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
volumeObjectTO.setPath(relativePath);
|
||||
specDisk.setPath(relativePath);
|
||||
rootDisks.add(vmDisk);
|
||||
} else {
|
||||
s_logger.error("Empty backing filename for volume " + volumeObjectTO.getName());
|
||||
}
|
||||
|
|
@ -2670,6 +2614,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
|
|||
}
|
||||
}
|
||||
}
|
||||
vmDisks.removeAll(rootDisks);
|
||||
if (CollectionUtils.isNotEmpty(vmDisks)) {
|
||||
s_logger.info("Tearing down datadisks for deploy-as-is VM");
|
||||
tearDownVMDisks(vmMo, vmDisks);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String msg = "Error mapping deploy-as-is VM disks from cloned VM " + vmInternalCSName;
|
||||
|
|
|
|||
|
|
@ -810,9 +810,21 @@ public class VmwareStorageProcessor implements StorageProcessor {
|
|||
DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
|
||||
|
||||
String vmdkName = volume.getName();
|
||||
String vmName = volume.getVmName();
|
||||
String vmdkFileBaseName = null;
|
||||
if (template.isDeployAsIs() && volume.getVolumeType() == Volume.Type.ROOT) {
|
||||
s_logger.info("ROOT Volume from deploy-as-is template, no need to create the volume at this point, will be cloned from template");
|
||||
VirtualMachineMO existingVm = dcMo.findVm(vmName);
|
||||
if (volume.getDeviceId().equals(0L)) {
|
||||
if (existingVm != null) {
|
||||
s_logger.info("Found existing VM " + vmName + " before cloning from template, destroying it");
|
||||
existingVm.detachAllDisks();
|
||||
existingVm.destroy();
|
||||
}
|
||||
s_logger.info("ROOT Volume from deploy-as-is template, cloning template");
|
||||
cloneVMFromTemplate(hyperHost, template.getPath(), vmName, primaryStore.getUuid());
|
||||
} else {
|
||||
s_logger.info("ROOT Volume from deploy-as-is template, volume already created at this point");
|
||||
}
|
||||
} else {
|
||||
if (srcStore == null) {
|
||||
// create a root volume for blank VM (created from ISO)
|
||||
|
|
|
|||
|
|
@ -6724,6 +6724,47 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
return _itMgr.restoreVirtualMachine(vm.getId(), newTemplateId);
|
||||
}
|
||||
|
||||
private VMTemplateVO getRestoreVirtualMachineTemplate(Account caller, Long newTemplateId, List<VolumeVO> rootVols, UserVmVO vm) {
|
||||
VMTemplateVO template = null;
|
||||
if (CollectionUtils.isNotEmpty(rootVols)) {
|
||||
VolumeVO root = rootVols.get(0);
|
||||
Long templateId = root.getTemplateId();
|
||||
boolean isISO = false;
|
||||
if (templateId == null) {
|
||||
// Assuming that for a vm deployed using ISO, template ID is set to NULL
|
||||
isISO = true;
|
||||
templateId = vm.getIsoId();
|
||||
}
|
||||
//newTemplateId can be either template or ISO id. In the following snippet based on the vm deployment (from template or ISO) it is handled accordingly
|
||||
if (newTemplateId != null) {
|
||||
template = _templateDao.findById(newTemplateId);
|
||||
_accountMgr.checkAccess(caller, null, true, template);
|
||||
if (isISO) {
|
||||
if (!template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid ISO id provided to restore the VM ");
|
||||
}
|
||||
} else {
|
||||
if (template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid template id provided to restore the VM ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isISO && templateId == null) {
|
||||
throw new CloudRuntimeException("Cannot restore the VM since there is no ISO attached to VM");
|
||||
}
|
||||
template = _templateDao.findById(templateId);
|
||||
if (template == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find template/ISO for specified volumeid and vmId");
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
ex.addProxyObject(root.getUuid(), "volumeId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserVm restoreVirtualMachine(final Account caller, final long vmId, final Long newTemplateId) throws InsufficientCapacityException, ResourceUnavailableException {
|
||||
Long userId = caller.getId();
|
||||
|
|
@ -6761,163 +6802,137 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
VolumeVO root = rootVols.get(0);
|
||||
if ( !Volume.State.Allocated.equals(root.getState()) || newTemplateId != null ){
|
||||
Long templateId = root.getTemplateId();
|
||||
boolean isISO = false;
|
||||
if (templateId == null) {
|
||||
// Assuming that for a vm deployed using ISO, template ID is set to NULL
|
||||
isISO = true;
|
||||
templateId = vm.getIsoId();
|
||||
}
|
||||
|
||||
// If target VM has associated VM snapshots then don't allow restore of VM
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (vmSnapshots.size() > 0) {
|
||||
throw new InvalidParameterValueException("Unable to restore VM, please remove VM snapshots before restoring VM");
|
||||
}
|
||||
// If target VM has associated VM snapshots then don't allow restore of VM
|
||||
List<VMSnapshotVO> vmSnapshots = _vmSnapshotDao.findByVm(vmId);
|
||||
if (vmSnapshots.size() > 0) {
|
||||
throw new InvalidParameterValueException("Unable to restore VM, please remove VM snapshots before restoring VM");
|
||||
}
|
||||
|
||||
VMTemplateVO template = null;
|
||||
//newTemplateId can be either template or ISO id. In the following snippet based on the vm deployment (from template or ISO) it is handled accordingly
|
||||
if (newTemplateId != null) {
|
||||
template = _templateDao.findById(newTemplateId);
|
||||
_accountMgr.checkAccess(caller, null, true, template);
|
||||
if (isISO) {
|
||||
if (!template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid ISO id provided to restore the VM ");
|
||||
VMTemplateVO template = getRestoreVirtualMachineTemplate(caller, newTemplateId, rootVols, vm);
|
||||
checkRestoreVmFromTemplate(vm, template);
|
||||
|
||||
if (needRestart) {
|
||||
try {
|
||||
_itMgr.stop(vm.getUuid());
|
||||
} catch (ResourceUnavailableException e) {
|
||||
s_logger.debug("Stop vm " + vm.getUuid() + " failed", e);
|
||||
CloudRuntimeException ex = new CloudRuntimeException("Stop vm failed for specified vmId");
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
List<Volume> newVols = new ArrayList<>();
|
||||
for (VolumeVO root : rootVols) {
|
||||
if ( !Volume.State.Allocated.equals(root.getState()) || newTemplateId != null ){
|
||||
Long templateId = root.getTemplateId();
|
||||
boolean isISO = false;
|
||||
if (templateId == null) {
|
||||
// Assuming that for a vm deployed using ISO, template ID is set to NULL
|
||||
isISO = true;
|
||||
templateId = vm.getIsoId();
|
||||
}
|
||||
|
||||
/* If new template/ISO is provided allocate a new volume from new template/ISO otherwise allocate new volume from original template/ISO */
|
||||
Volume newVol = null;
|
||||
if (newTemplateId != null) {
|
||||
if (isISO) {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
vm.setIsoId(newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
}
|
||||
} else {
|
||||
if (template.getFormat().equals(ImageFormat.ISO)) {
|
||||
throw new InvalidParameterValueException("Invalid template id provided to restore the VM ");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isISO && templateId == null) {
|
||||
throw new CloudRuntimeException("Cannot restore the VM since there is no ISO attached to VM");
|
||||
}
|
||||
template = _templateDao.findById(templateId);
|
||||
if (template == null) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Cannot find template/ISO for specified volumeid and vmId");
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
ex.addProxyObject(root.getUuid(), "volumeId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
checkRestoreVmFromTemplate(vm, template);
|
||||
|
||||
if (needRestart) {
|
||||
try {
|
||||
_itMgr.stop(vm.getUuid());
|
||||
} catch (ResourceUnavailableException e) {
|
||||
s_logger.debug("Stop vm " + vm.getUuid() + " failed", e);
|
||||
CloudRuntimeException ex = new CloudRuntimeException("Stop vm failed for specified vmId");
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/* If new template/ISO is provided allocate a new volume from new template/ISO otherwise allocate new volume from original template/ISO */
|
||||
Volume newVol = null;
|
||||
if (newTemplateId != null) {
|
||||
if (isISO) {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
vm.setIsoId(newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId);
|
||||
vm.setGuestOSId(template.getGuestOSId());
|
||||
vm.setTemplateId(newTemplateId);
|
||||
_vmDao.update(vmId, vm);
|
||||
}
|
||||
} else {
|
||||
newVol = volumeMgr.allocateDuplicateVolume(root, null);
|
||||
}
|
||||
newVols.add(newVol);
|
||||
|
||||
// 1. Save usage event and update resource count for user vm volumes
|
||||
_resourceLimitMgr.incrementResourceCount(newVol.getAccountId(), ResourceType.volume, newVol.isDisplay());
|
||||
_resourceLimitMgr.incrementResourceCount(newVol.getAccountId(), ResourceType.primary_storage, newVol.isDisplay(), new Long(newVol.getSize()));
|
||||
// 2. Create Usage event for the newly created volume
|
||||
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, newVol.getAccountId(), newVol.getDataCenterId(), newVol.getId(), newVol.getName(), newVol.getDiskOfferingId(), template.getId(), newVol.getSize());
|
||||
_usageEventDao.persist(usageEvent);
|
||||
// 1. Save usage event and update resource count for user vm volumes
|
||||
_resourceLimitMgr.incrementResourceCount(newVol.getAccountId(), ResourceType.volume, newVol.isDisplay());
|
||||
_resourceLimitMgr.incrementResourceCount(newVol.getAccountId(), ResourceType.primary_storage, newVol.isDisplay(), new Long(newVol.getSize()));
|
||||
// 2. Create Usage event for the newly created volume
|
||||
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, newVol.getAccountId(), newVol.getDataCenterId(), newVol.getId(), newVol.getName(), newVol.getDiskOfferingId(), template.getId(), newVol.getSize());
|
||||
_usageEventDao.persist(usageEvent);
|
||||
|
||||
handleManagedStorage(vm, root);
|
||||
handleManagedStorage(vm, root);
|
||||
|
||||
_volsDao.attachVolume(newVol.getId(), vmId, newVol.getDeviceId());
|
||||
_volsDao.attachVolume(newVol.getId(), vmId, newVol.getDeviceId());
|
||||
|
||||
// Detach, destroy and create the usage event for the old root volume.
|
||||
_volsDao.detachVolume(root.getId());
|
||||
volumeMgr.destroyVolume(root);
|
||||
// Detach, destroy and create the usage event for the old root volume.
|
||||
_volsDao.detachVolume(root.getId());
|
||||
volumeMgr.destroyVolume(root);
|
||||
|
||||
// For VMware hypervisor since the old root volume is replaced by the new root volume, force expunge old root volume if it has been created in storage
|
||||
if (vm.getHypervisorType() == HypervisorType.VMware) {
|
||||
VolumeInfo volumeInStorage = volFactory.getVolume(root.getId());
|
||||
if (volumeInStorage != null) {
|
||||
s_logger.info("Expunging volume " + root.getId() + " from primary data store");
|
||||
AsyncCallFuture<VolumeApiResult> future = _volService.expungeVolumeAsync(volFactory.getVolume(root.getId()));
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to expunge volume:" + root.getId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<VirtualMachineProfile.Param, Object> params = null;
|
||||
String password = null;
|
||||
|
||||
if (template.isEnablePassword()) {
|
||||
password = _mgr.generateRandomPassword();
|
||||
boolean result = resetVMPasswordInternal(vmId, password);
|
||||
if (!result) {
|
||||
throw new CloudRuntimeException("VM reset is completed but failed to reset password for the virtual machine ");
|
||||
}
|
||||
vm.setPassword(password);
|
||||
}
|
||||
|
||||
if (needRestart) {
|
||||
try {
|
||||
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
|
||||
params = new HashMap<>();
|
||||
params.put(VirtualMachineProfile.Param.VmPassword, password);
|
||||
}
|
||||
if (template.isDeployAsIs()) {
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
}
|
||||
params.put(VirtualMachineProfile.Param.ReplaceDeployAsIs, true);
|
||||
}
|
||||
_itMgr.start(vm.getUuid(), params);
|
||||
vm = _vmDao.findById(vmId);
|
||||
if (template.isEnablePassword()) {
|
||||
// this value is not being sent to the backend; need only for api
|
||||
// display purposes
|
||||
vm.setPassword(password);
|
||||
if (vm.isUpdateParameters()) {
|
||||
vm.setUpdateParameters(false);
|
||||
_vmDao.loadDetails(vm);
|
||||
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
|
||||
userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD);
|
||||
}
|
||||
_vmDao.update(vm.getId(), vm);
|
||||
// For VMware hypervisor since the old root volume is replaced by the new root volume, force expunge old root volume if it has been created in storage
|
||||
if (vm.getHypervisorType() == HypervisorType.VMware) {
|
||||
VolumeInfo volumeInStorage = volFactory.getVolume(root.getId());
|
||||
if (volumeInStorage != null) {
|
||||
s_logger.info("Expunging volume " + root.getId() + " from primary data store");
|
||||
AsyncCallFuture<VolumeApiResult> future = _volService.expungeVolumeAsync(volFactory.getVolume(root.getId()));
|
||||
try {
|
||||
future.get();
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Failed to expunge volume:" + root.getId(), e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Unable to start VM " + vm.getUuid(), e);
|
||||
CloudRuntimeException ex = new CloudRuntimeException("Unable to start VM with specified id" + e.getMessage());
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<VirtualMachineProfile.Param, Object> params = null;
|
||||
String password = null;
|
||||
|
||||
if (template.isEnablePassword()) {
|
||||
password = _mgr.generateRandomPassword();
|
||||
boolean result = resetVMPasswordInternal(vmId, password);
|
||||
if (!result) {
|
||||
throw new CloudRuntimeException("VM reset is completed but failed to reset password for the virtual machine ");
|
||||
}
|
||||
vm.setPassword(password);
|
||||
}
|
||||
if (needRestart) {
|
||||
try {
|
||||
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
|
||||
params = new HashMap<>();
|
||||
params.put(VirtualMachineProfile.Param.VmPassword, password);
|
||||
}
|
||||
_itMgr.start(vm.getUuid(), params);
|
||||
vm = _vmDao.findById(vmId);
|
||||
if (template.isEnablePassword()) {
|
||||
// this value is not being sent to the backend; need only for api
|
||||
// display purposes
|
||||
vm.setPassword(password);
|
||||
if (vm.isUpdateParameters()) {
|
||||
vm.setUpdateParameters(false);
|
||||
_vmDao.loadDetails(vm);
|
||||
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
|
||||
userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD);
|
||||
}
|
||||
_vmDao.update(vm.getId(), vm);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.debug("Unable to start VM " + vm.getUuid(), e);
|
||||
CloudRuntimeException ex = new CloudRuntimeException("Unable to start VM with specified id" + e.getMessage());
|
||||
ex.addProxyObject(vm.getUuid(), "vmId");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
s_logger.debug("Restore VM " + vmId + " done successfully");
|
||||
return vm;
|
||||
|
||||
}
|
||||
|
||||
private void recreateDeployAsIsVirtualMachine(UserVmVO vm, List<Volume> newVols) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform basic checkings to make sure restore is possible. If not, #InvalidParameterValueException is thrown.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue