From 98e2ed3c4fbfb6ec731fb91b6e00a98c5ecf7253 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Wed, 28 Apr 2021 13:46:03 +0530 Subject: [PATCH] vmware: Add force parameter to iso attach/detach operations (#4907) Fixes: #4808, #4941 This PR adds a force flag to the attachIso / detachIso commands, especially for VMware where it is noticed that when trying to either detach an iso or attach an iso when there already exists another present it fails to do the necessary operation as from ACS end we either answer the question returned by Esxi for CDRom disconnect operation as No (for detach operation) or do not answer the question at all (for Attach operation). Co-authored-by: Pearl Dsilva --- .../cloud/template/TemplateApiService.java | 4 +- .../api/command/user/iso/AttachIsoCmd.java | 10 +- .../api/command/user/iso/DetachIsoCmd.java | 14 +- .../storage/command/AttachCommand.java | 9 + .../storage/command/DettachCommand.java | 9 + .../vmware/resource/VmwareResource.java | 82 ++++--- .../resource/VmwareStorageProcessor.java | 12 +- .../KubernetesClusterActionWorker.java | 4 +- .../cloud/template/TemplateManagerImpl.java | 20 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 2 +- ui/src/config/section/compute.js | 8 +- ui/src/views/compute/AttachIso.vue | 8 + .../vmware/mo/VirtualMachineMO.java | 221 +++++++++--------- 13 files changed, 240 insertions(+), 163 deletions(-) diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index b62628560ae..ea818a55a0c 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -56,9 +56,9 @@ public interface TemplateApiService { VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId); - boolean detachIso(long vmId); + boolean detachIso(long vmId, boolean forced); - boolean attachIso(long isoId, long vmId); + boolean attachIso(long isoId, long vmId, boolean forced); /** * Deletes a template diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/AttachIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/AttachIsoCmd.java index 245840004fe..74a98beef9d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/AttachIsoCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/AttachIsoCmd.java @@ -54,6 +54,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd { required = true, description = "the ID of the virtual machine") protected Long virtualMachineId; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, + description = "If true, ejects existing ISO before attaching on VMware. Default: false", since = "4.15.1") + protected Boolean forced; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -66,6 +70,10 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd { return virtualMachineId; } + public Boolean isForced() { + return forced != null; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -98,7 +106,7 @@ public class AttachIsoCmd extends BaseAsyncCmd implements UserCmd { @Override public void execute() { CallContext.current().setEventDetails("Vm Id: " + getVirtualMachineId() + " ISO ID: " + getId()); - boolean result = _templateService.attachIso(id, virtualMachineId); + boolean result = _templateService.attachIso(id, virtualMachineId, isForced()); if (result) { UserVm userVm = _responseGenerator.findUserVmById(virtualMachineId); if (userVm != null) { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/DetachIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/DetachIsoCmd.java index ae86e2fdd7f..4f4a0197ac7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/DetachIsoCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/DetachIsoCmd.java @@ -44,10 +44,14 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class, - required=true, description="The ID of the virtual machine") + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = UserVmResponse.class, + required = true, description = "The ID of the virtual machine") protected Long virtualMachineId; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, + description = "If true, ejects the ISO before detaching on VMware. Default: false", since = "4.15.1") + protected Boolean forced; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -56,6 +60,10 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd { return virtualMachineId; } + public Boolean isForced() { + return forced != null; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -87,7 +95,7 @@ public class DetachIsoCmd extends BaseAsyncCmd implements UserCmd { @Override public void execute() { - boolean result = _templateService.detachIso(virtualMachineId); + boolean result = _templateService.detachIso(virtualMachineId, isForced()); if (result) { UserVm userVm = _entityMgr.findById(UserVm.class, virtualMachineId); UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0); diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/AttachCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/AttachCommand.java index d15a4e42da3..ae6ea1fa649 100644 --- a/core/src/main/java/org/apache/cloudstack/storage/command/AttachCommand.java +++ b/core/src/main/java/org/apache/cloudstack/storage/command/AttachCommand.java @@ -27,6 +27,7 @@ public final class AttachCommand extends StorageSubSystemCommand { private DiskTO disk; private String vmName; private boolean inSeq = false; + private boolean forced = false; private Map controllerInfo; public AttachCommand(final DiskTO disk, final String vmName) { @@ -69,6 +70,14 @@ public final class AttachCommand extends StorageSubSystemCommand { this.vmName = vmName; } + public boolean isForced() { + return forced; + } + + public void setForced(boolean forced) { + this.forced = forced; + } + @Override public void setExecuteInSequence(final boolean inSeq) { this.inSeq = inSeq; diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java index 1d805b582e9..eeeadaac42b 100644 --- a/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java +++ b/core/src/main/java/org/apache/cloudstack/storage/command/DettachCommand.java @@ -31,6 +31,7 @@ public class DettachCommand extends StorageSubSystemCommand { private String _storageHost; private int _storagePort; private Map params; + private boolean forced; public DettachCommand(final DiskTO disk, final String vmName) { super(); @@ -106,6 +107,14 @@ public class DettachCommand extends StorageSubSystemCommand { this.params = params; } + public boolean isForced() { + return forced; + } + + public void setForced(boolean forced) { + this.forced = forced; + } + @Override public void setExecuteInSequence(final boolean inSeq) { diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 97a10e51f56..313660831dd 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2019,35 +2019,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (volIso != null) { for (DiskTO vol : disks) { if (vol.getType() == Volume.Type.ISO) { - - TemplateObjectTO iso = (TemplateObjectTO) vol.getData(); - - if (iso.getPath() != null && !iso.getPath().isEmpty()) { - DataStoreTO imageStore = iso.getDataStore(); - if (!(imageStore instanceof NfsTO)) { - s_logger.debug("unsupported protocol"); - throw new Exception("unsupported protocol"); - } - NfsTO nfsImageStore = (NfsTO) imageStore; - String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath(); - Pair isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath); - assert (isoDatastoreInfo != null); - assert (isoDatastoreInfo.second() != null); - - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - Pair isoInfo = - VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber++, i + 1); - deviceConfigSpecArray[i].setDevice(isoInfo.first()); - if (isoInfo.second()) { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - if (s_logger.isDebugEnabled()) - s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - } + configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i); i++; } } @@ -2075,8 +2047,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // // Setup ROOT/DATA disk devices // + if (multipleIsosAtached(sortedDisks) && deployAsIs) { + sortedDisks = getDisks(sortedDisks); + } + for (DiskTO vol : sortedDisks) { if (vol.getType() == Volume.Type.ISO) { + if (deployAsIs) { + configureIso(hyperHost, vmMo, vol, deviceConfigSpecArray, ideUnitNumber++, i); + i++; + } continue; } @@ -2457,6 +2437,46 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa } } + private boolean multipleIsosAtached(DiskTO[] sortedDisks) { + return Arrays.stream(sortedDisks).filter(disk -> disk.getType() == Volume.Type.ISO).count() > 1; + } + + private DiskTO[] getDisks(DiskTO[] sortedDisks) { + return Arrays.stream(sortedDisks).filter(vol -> ((vol.getPath() != null && + vol.getPath().contains("configdrive"))) || (vol.getType() != Volume.Type.ISO)).toArray(DiskTO[]::new); + } + private void configureIso(VmwareHypervisorHost hyperHost, VirtualMachineMO vmMo, DiskTO vol, + VirtualDeviceConfigSpec[] deviceConfigSpecArray, int ideUnitNumber, int i) throws Exception { + TemplateObjectTO iso = (TemplateObjectTO) vol.getData(); + + if (iso.getPath() != null && !iso.getPath().isEmpty()) { + DataStoreTO imageStore = iso.getDataStore(); + if (!(imageStore instanceof NfsTO)) { + s_logger.debug("unsupported protocol"); + throw new Exception("unsupported protocol"); + } + NfsTO nfsImageStore = (NfsTO) imageStore; + String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath(); + Pair isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath); + assert (isoDatastoreInfo != null); + assert (isoDatastoreInfo.second() != null); + + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + Pair isoInfo = + VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, ideUnitNumber, i + 1); + deviceConfigSpecArray[i].setDevice(isoInfo.first()); + if (isoInfo.second()) { + if (s_logger.isDebugEnabled()) + s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + if (s_logger.isDebugEnabled()) + s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first())); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + } + } + private String mapAdapterType(String adapterStringFromOVF) { if (StringUtils.isBlank(adapterStringFromOVF) || adapterStringFromOVF.equalsIgnoreCase(VirtualEthernetCardType.E1000.toString())) { return VirtualEthernetCardType.E1000.toString(); @@ -5382,7 +5402,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa "Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try."); } } catch (Throwable e) { - vmMo.detachIso(null); + vmMo.detachIso(null, cmd.isForce()); } } @@ -5411,7 +5431,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName); if (cmd.isAttach()) { - vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, cmd.getDeviceKey()); + vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, cmd.getDeviceKey(), cmd.isForce()); return new AttachIsoAnswer(cmd); } else { int key = vmMo.detachIso(isoDatastorePath, cmd.isForce()); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index a2aee6b53e1..b06c1bef69c 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -2045,7 +2045,7 @@ public class VmwareStorageProcessor implements StorageProcessor { @Override public Answer attachIso(AttachCommand cmd) { - return this.attachIso(cmd.getDisk(), true, cmd.getVmName()); + return this.attachIso(cmd.getDisk(), true, cmd.getVmName(), cmd.isForced()); } @Override @@ -2411,7 +2411,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return morDatastore; } - private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) { + private Answer attachIso(DiskTO disk, boolean isAttach, String vmName, boolean force) { try { VmwareContext context = hostService.getServiceContext(null); VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null); @@ -2441,7 +2441,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return new AttachAnswer("Failed to unmount vmware-tools installer ISO as the corresponding CDROM device is locked by VM. Please unmount the CDROM device inside the VM and ret-try."); } } catch(Throwable e){ - vmMo.detachIso(null); + vmMo.detachIso(null, force); } } @@ -2469,9 +2469,9 @@ public class VmwareStorageProcessor implements StorageProcessor { String isoDatastorePath = String.format("[%s] %s/%s", storeName, isoStorePathFromRoot, isoFileName); if (isAttach) { - vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false); + vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false, force); } else { - vmMo.detachIso(isoDatastorePath); + vmMo.detachIso(isoDatastorePath, force); } return new AttachAnswer(disk); @@ -2497,7 +2497,7 @@ public class VmwareStorageProcessor implements StorageProcessor { @Override public Answer dettachIso(DettachCommand cmd) { - return this.attachIso(cmd.getDisk(), false, cmd.getVmName()); + return this.attachIso(cmd.getDisk(), false, cmd.getVmName(), cmd.isForced()); } @Override diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java index e5c811878ce..1ca58a0dfa6 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterActionWorker.java @@ -319,7 +319,7 @@ public class KubernetesClusterActionWorker { } for (UserVm vm : clusterVMs) { try { - templateService.attachIso(iso.getId(), vm.getId()); + templateService.attachIso(iso.getId(), vm.getId(), true); if (LOGGER.isInfoEnabled()) { LOGGER.info(String.format("Attached binaries ISO for VM : %s in cluster: %s", vm.getDisplayName(), kubernetesCluster.getName())); } @@ -337,7 +337,7 @@ public class KubernetesClusterActionWorker { for (UserVm vm : clusterVMs) { boolean result = false; try { - result = templateService.detachIso(vm.getId()); + result = templateService.detachIso(vm.getId(), true); } catch (CloudRuntimeException ex) { LOGGER.warn(String.format("Failed to detach binaries ISO from VM : %s in the Kubernetes cluster : %s ", vm.getDisplayName(), kubernetesCluster.getName()), ex); } diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index deb5feb2e81..956c456c2ff 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1150,7 +1150,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Override @ActionEvent(eventType = EventTypes.EVENT_ISO_DETACH, eventDescription = "detaching ISO", async = true) - public boolean detachIso(long vmId) { + public boolean detachIso(long vmId, boolean forced) { Account caller = CallContext.current().getCallingAccount(); Long userId = CallContext.current().getCallingUserId(); @@ -1178,7 +1178,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new InvalidParameterValueException("Please specify a VM that is either Stopped or Running."); } - boolean result = attachISOToVM(vmId, userId, isoId, false); // attach=false + boolean result = attachISOToVM(vmId, userId, isoId, false, forced); // attach=false // => detach if (result) { return result; @@ -1189,7 +1189,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Override @ActionEvent(eventType = EventTypes.EVENT_ISO_ATTACH, eventDescription = "attaching ISO", async = true) - public boolean attachIso(long isoId, long vmId) { + public boolean attachIso(long isoId, long vmId, boolean forced) { Account caller = CallContext.current().getCallingAccount(); Long userId = CallContext.current().getCallingUserId(); @@ -1231,7 +1231,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if ("vmware-tools.iso".equals(iso.getName()) && vm.getHypervisorType() != Hypervisor.HypervisorType.VMware) { throw new InvalidParameterValueException("Cannot attach VMware tools drivers to incompatible hypervisor " + vm.getHypervisorType()); } - boolean result = attachISOToVM(vmId, userId, isoId, true); + boolean result = attachISOToVM(vmId, userId, isoId, true, forced); if (result) { return result; } else { @@ -1270,7 +1270,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } } - private boolean attachISOToVM(long vmId, long isoId, boolean attach) { + private boolean attachISOToVM(long vmId, long isoId, boolean attach, boolean forced) { UserVmVO vm = _userVmDao.findById(vmId); if (vm == null) { @@ -1302,19 +1302,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, Command cmd = null; if (attach) { - cmd = new AttachCommand(disk, vmName, vmTO.getDetails()); + cmd = new AttachCommand(disk, vmName); + ((AttachCommand)cmd).setForced(forced); } else { - cmd = new DettachCommand(disk, vmName, vmTO.getDetails()); + cmd = new DettachCommand(disk, vmName); + ((DettachCommand)cmd).setForced(forced); } Answer a = _agentMgr.easySend(vm.getHostId(), cmd); return (a != null && a.getResult()); } - private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach) { + private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach, boolean forced) { UserVmVO vm = _userVmDao.findById(vmId); VMTemplateVO iso = _tmpltDao.findById(isoId); - boolean success = attachISOToVM(vmId, isoId, attach); + boolean success = attachISOToVM(vmId, isoId, attach, forced); if (success && attach) { vm.setIsoId(iso.getId()); _userVmDao.update(vmId, vm); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 53647ea74e6..04de128ac2b 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5350,7 +5350,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir for (VMTemplateVO tmpl: child_templates){ if (tmpl.getFormat() == Storage.ImageFormat.ISO){ s_logger.info("MDOV trying to attach disk to the VM " + tmpl.getId() + " vmid=" + vm.getId()); - _tmplService.attachIso(tmpl.getId(), vm.getId()); + _tmplService.attachIso(tmpl.getId(), vm.getId(), true); } } diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index 69a70182218..9428725302b 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -253,7 +253,13 @@ export default { label: 'label.action.detach.iso', message: 'message.detach.iso.confirm', dataView: true, - args: ['virtualmachineid'], + args: (record, store) => { + var args = ['virtualmachineid'] + if (record && record.hypervisor && record.hypervisor === 'VMware') { + args.push('forced') + } + return args + }, show: (record) => { return ['Running', 'Stopped'].includes(record.state) && 'isoid' in record && record.isoid }, mapping: { virtualmachineid: { diff --git a/ui/src/views/compute/AttachIso.vue b/ui/src/views/compute/AttachIso.vue index efb591f341a..bc12c264f8c 100644 --- a/ui/src/views/compute/AttachIso.vue +++ b/ui/src/views/compute/AttachIso.vue @@ -33,6 +33,9 @@ + + +
{{ this.$t('label.cancel') }} @@ -116,6 +119,11 @@ export default { id: values.id, virtualmachineid: this.resource.id } + + if (values.forced) { + params.forced = values.forced + } + this.loading = true const title = this.$t('label.action.attach.iso') api('attachIso', params).then(json => { diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index e1ba6b0b87f..0d01931989b 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -1498,117 +1498,11 @@ public class VirtualMachineMO extends BaseMO { s_logger.trace("vCenter API trace - detachAllDisk() done(successfully)"); } - // isoDatastorePath: [datastore name] isoFilePath - public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot) throws Exception { - attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null); - } - - // isoDatastorePath: [datastore name] isoFilePath - public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, - boolean connect, boolean connectAtBoot, Integer key) throws Exception { - - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " + - morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot); - - assert (isoDatastorePath != null); - assert (morDs != null); - - boolean newCdRom = false; - VirtualCdrom cdRom; - if (key == null) { - cdRom = (VirtualCdrom) getIsoDevice(); - } else { - cdRom = (VirtualCdrom) getIsoDevice(key); - } - if (cdRom == null) { - newCdRom = true; - cdRom = new VirtualCdrom(); - cdRom.setControllerKey(getIDEDeviceControllerKey()); - - int deviceNumber = getNextIDEDeviceNumber(); - cdRom.setUnitNumber(deviceNumber); - cdRom.setKey(-deviceNumber); - } - - VirtualDeviceConnectInfo cInfo = new VirtualDeviceConnectInfo(); - cInfo.setConnected(connect); - cInfo.setStartConnected(connectAtBoot); - cdRom.setConnectable(cInfo); - - VirtualCdromIsoBackingInfo backingInfo = new VirtualCdromIsoBackingInfo(); - backingInfo.setFileName(isoDatastorePath); - backingInfo.setDatastore(morDs); - cdRom.setBacking(backingInfo); - - VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; - VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); - - deviceConfigSpec.setDevice(cdRom); - if (newCdRom) { - deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - } else { - deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - } - - //deviceConfigSpecArray[0] = deviceConfigSpec; - reConfigSpec.getDeviceChange().add(deviceConfigSpec); - - ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); - boolean result = _context.getVimClient().waitForTask(morTask); - - if (!result) { - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - attachIso() done(failed)"); - throw new Exception("Failed to attach ISO due to " + TaskMO.getTaskFailureInfo(_context, morTask)); - } - - _context.waitForTaskProgressDone(morTask); - - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - attachIso() done(successfully)"); - } - - public int detachIso(String isoDatastorePath) throws Exception { - return detachIso(isoDatastorePath, false); - } - - public int detachIso(String isoDatastorePath, final boolean force) throws Exception { - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath); - - VirtualDevice device = getIsoDevice(isoDatastorePath); - if (device == null) { - if (s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso() done(failed)"); - throw new Exception("Unable to find a CDROM device"); - } - - VirtualCdromRemotePassthroughBackingInfo backingInfo = new VirtualCdromRemotePassthroughBackingInfo(); - backingInfo.setDeviceName(""); - device.setBacking(backingInfo); - - VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; - VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); - - deviceConfigSpec.setDevice(device); - deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); - - //deviceConfigSpecArray[0] = deviceConfigSpec; - reConfigSpec.getDeviceChange().add(deviceConfigSpec); - - ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); - - // Monitor VM questions - final Boolean[] flags = {false}; - final VirtualMachineMO vmMo = this; + private Future answerVmwareQuestion(Boolean[] flags, VirtualMachineMO vmMo, boolean force) { Future future = MonitorServiceExecutor.submit(new Runnable() { @Override public void run() { s_logger.info("VM Question monitor started..."); - while (!flags[0]) { try { VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo(); @@ -1670,6 +1564,119 @@ public class VirtualMachineMO extends BaseMO { s_logger.info("VM Question monitor stopped"); } }); + return future; + } + // isoDatastorePath: [datastore name] isoFilePath + public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, boolean connect, boolean connectAtBoot, boolean forced) throws Exception { + attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null, forced); + } + + // isoDatastorePath: [datastore name] isoFilePath + public void attachIso(String isoDatastorePath, ManagedObjectReference morDs, + boolean connect, boolean connectAtBoot, Integer key, boolean force) throws Exception { + + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " + + morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot); + + assert (isoDatastorePath != null); + assert (morDs != null); + + boolean newCdRom = false; + VirtualCdrom cdRom; + if (key == null) { + cdRom = (VirtualCdrom) getIsoDevice(); + } else { + cdRom = (VirtualCdrom) getIsoDevice(key); + } + if (cdRom == null) { + newCdRom = true; + cdRom = new VirtualCdrom(); + cdRom.setControllerKey(getIDEDeviceControllerKey()); + + int deviceNumber = getNextIDEDeviceNumber(); + cdRom.setUnitNumber(deviceNumber); + cdRom.setKey(-deviceNumber); + } + + VirtualDeviceConnectInfo cInfo = new VirtualDeviceConnectInfo(); + cInfo.setConnected(connect); + cInfo.setStartConnected(connectAtBoot); + cdRom.setConnectable(cInfo); + + VirtualCdromIsoBackingInfo backingInfo = new VirtualCdromIsoBackingInfo(); + backingInfo.setFileName(isoDatastorePath); + backingInfo.setDatastore(morDs); + cdRom.setBacking(backingInfo); + + VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); + //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + deviceConfigSpec.setDevice(cdRom); + if (newCdRom) { + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + } else { + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + } + + //deviceConfigSpecArray[0] = deviceConfigSpec; + reConfigSpec.getDeviceChange().add(deviceConfigSpec); + + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); + + final Boolean[] flags = {false}; + final VirtualMachineMO vmMo = this; + Future future = answerVmwareQuestion(flags, vmMo, force); + try { + boolean result = _context.getVimClient().waitForTask(morTask); + + if (!result) { + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachIso() done(failed)"); + throw new Exception("Failed to attach ISO due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + _context.waitForTaskProgressDone(morTask); + + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachIso() done(successfully)"); + } finally { + flags[0] = true; + future.cancel(true); + } + } + + public int detachIso(String isoDatastorePath, final boolean force) throws Exception { + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath); + + VirtualDevice device = getIsoDevice(isoDatastorePath); + if (device == null) { + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - detachIso() done(failed)"); + throw new Exception("Unable to find a CDROM device"); + } + + VirtualCdromRemotePassthroughBackingInfo backingInfo = new VirtualCdromRemotePassthroughBackingInfo(); + backingInfo.setDeviceName(""); + device.setBacking(backingInfo); + + VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); + //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + deviceConfigSpec.setDevice(device); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + + //deviceConfigSpecArray[0] = deviceConfigSpec; + reConfigSpec.getDeviceChange().add(deviceConfigSpec); + + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); + + // Monitor VM questions + final Boolean[] flags = {false}; + final VirtualMachineMO vmMo = this; + Future future = answerVmwareQuestion(flags, vmMo, force); try { boolean result = _context.getVimClient().waitForTask(morTask); if (!result) {