This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.15
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.15 by this push:
     new 98e2ed3  vmware: Add force parameter to iso attach/detach operations 
(#4907)
98e2ed3 is described below

commit 98e2ed3c4fbfb6ec731fb91b6e00a98c5ecf7253
Author: Pearl Dsilva <[email protected]>
AuthorDate: Wed Apr 28 13:46:03 2021 +0530

    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 <[email protected]>
---
 .../com/cloud/template/TemplateApiService.java     |   4 +-
 .../api/command/user/iso/AttachIsoCmd.java         |  10 +-
 .../api/command/user/iso/DetachIsoCmd.java         |  14 +-
 .../cloudstack/storage/command/AttachCommand.java  |   9 ++
 .../cloudstack/storage/command/DettachCommand.java |   9 ++
 .../hypervisor/vmware/resource/VmwareResource.java |  82 ++++++----
 .../storage/resource/VmwareStorageProcessor.java   |  12 +-
 .../KubernetesClusterActionWorker.java             |   4 +-
 .../com/cloud/template/TemplateManagerImpl.java    |  20 +--
 .../main/java/com/cloud/vm/UserVmManagerImpl.java  |   2 +-
 ui/src/config/section/compute.js                   |   8 +-
 ui/src/views/compute/AttachIso.vue                 |   8 +
 .../hypervisor/vmware/mo/VirtualMachineMO.java     | 171 +++++++++++----------
 13 files changed, 215 insertions(+), 138 deletions(-)

diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java 
b/api/src/main/java/com/cloud/template/TemplateApiService.java
index b626285..ea818a5 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 2458400..74a98be 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 ae86e2f..4f4a019 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 d15a4e4..ae6ea1f 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<String, String> 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 1d805b5..eeeadaa 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<String, String> 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 97a10e5..3136608 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<String, ManagedObjectReference> 
isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath);
-                                assert (isoDatastoreInfo != null);
-                                assert (isoDatastoreInfo.second() != null);
-
-                                deviceConfigSpecArray[i] = new 
VirtualDeviceConfigSpec();
-                                Pair<VirtualDevice, Boolean> 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<String, ManagedObjectReference> isoDatastoreInfo = 
getIsoDatastoreInfo(hyperHost, isoPath);
+            assert (isoDatastoreInfo != null);
+            assert (isoDatastoreInfo.second() != null);
+
+            deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
+            Pair<VirtualDevice, Boolean> 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 a2aee6b..b06c1be 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 e5c8118..1ca58a0 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 deb5feb..956c456 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 53647ea..04de128 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 69a7018..9428725 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 efb591f..bc12c26 100644
--- a/ui/src/views/compute/AttachIso.vue
+++ b/ui/src/views/compute/AttachIso.vue
@@ -33,6 +33,9 @@
             </a-select-option>
           </a-select>
         </a-form-item>
+        <a-form-item :label="$t('label.forced')" v-if="resource && 
resource.hypervisor === 'VMware'">
+          <a-switch v-decorator="['forced']" :auto-focus="true" />
+        </a-form-item>
       </a-form>
       <div :span="24" class="action-button">
         <a-button @click="closeAction">{{ this.$t('label.cancel') }}</a-button>
@@ -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 e1ba6b0..0d01931 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,14 +1498,82 @@ public class VirtualMachineMO extends BaseMO {
             s_logger.trace("vCenter API trace - detachAllDisk() 
done(successfully)");
     }
 
+    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();
+                        VirtualMachineQuestionInfo question = 
runtimeInfo.getQuestion();
+                        if (question != null) {
+                            if (s_logger.isTraceEnabled()) {
+                                s_logger.trace("Question id: " + 
question.getId());
+                                s_logger.trace("Question text: " + 
question.getText());
+                            }
+                            if (question.getMessage() != null) {
+                                for (VirtualMachineMessage msg : 
question.getMessage()) {
+                                    if (s_logger.isTraceEnabled()) {
+                                        s_logger.trace("msg id: " + 
msg.getId());
+                                        s_logger.trace("msg text: " + 
msg.getText());
+                                    }
+                                    if 
("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
+                                        s_logger.info("Found that VM has a 
pending question that we need to answer programmatically, question id: " + 
msg.getId() +
+                                                ", for safe operation we will 
automatically decline it");
+                                        vmMo.answerVM(question.getId(), force 
? ANSWER_YES : ANSWER_NO);
+                                        break;
+                                    }
+                                }
+                            } else if (question.getText() != null) {
+                                String text = question.getText();
+                                String msgId;
+                                String msgText;
+                                if (s_logger.isDebugEnabled()) {
+                                    s_logger.debug("question text : " + text);
+                                }
+                                String[] tokens = text.split(":");
+                                msgId = tokens[0];
+                                msgText = tokens[1];
+                                if 
("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
+                                    s_logger.info("Found that VM has a pending 
question that we need to answer programmatically, question id: " + 
question.getId() +
+                                            ". Message id : " + msgId + ". 
Message text : " + msgText + ", for safe operation we will automatically 
decline it.");
+                                    vmMo.answerVM(question.getId(), force ? 
ANSWER_YES : ANSWER_NO);
+                                }
+                            }
+
+                            ChoiceOption choice = question.getChoice();
+                            if (choice != null) {
+                                for (ElementDescription info : 
choice.getChoiceInfo()) {
+                                    if (s_logger.isTraceEnabled()) {
+                                        s_logger.trace("Choice option key: " + 
info.getKey());
+                                        s_logger.trace("Choice option label: " 
+ info.getLabel());
+                                    }
+                                }
+                            }
+                        }
+                    } catch (Throwable e) {
+                        s_logger.error("Unexpected exception: ", e);
+                    }
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        s_logger.debug("[ignored] interupted while handling vm 
question about iso detach.");
+                    }
+                }
+                s_logger.info("VM Question monitor stopped");
+            }
+        });
+        return future;
+    }
     // isoDatastorePath: [datastore name] isoFilePath
-    public void attachIso(String isoDatastorePath, ManagedObjectReference 
morDs, boolean connect, boolean connectAtBoot) throws Exception {
-        attachIso(isoDatastorePath, morDs, connect, connectAtBoot, null);
+    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) throws Exception {
+    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: " +
@@ -1556,22 +1624,26 @@ public class VirtualMachineMO extends BaseMO {
         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);
+        final Boolean[] flags = {false};
+        final VirtualMachineMO vmMo = this;
+        Future<?> future = answerVmwareQuestion(flags, vmMo, force);
+        try {
+            boolean result = _context.getVimClient().waitForTask(morTask);
 
-        if (s_logger.isTraceEnabled())
-            s_logger.trace("vCenter API trace - attachIso() 
done(successfully)");
-    }
+            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);
 
-    public int detachIso(String isoDatastorePath) throws Exception {
-        return detachIso(isoDatastorePath, false);
+            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 {
@@ -1604,72 +1676,7 @@ public class VirtualMachineMO extends BaseMO {
         // Monitor VM questions
         final Boolean[] flags = {false};
         final VirtualMachineMO vmMo = this;
-        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();
-                        VirtualMachineQuestionInfo question = 
runtimeInfo.getQuestion();
-                        if (question != null) {
-                            if (s_logger.isTraceEnabled()) {
-                                s_logger.trace("Question id: " + 
question.getId());
-                                s_logger.trace("Question text: " + 
question.getText());
-                            }
-                            if (question.getMessage() != null) {
-                                for (VirtualMachineMessage msg : 
question.getMessage()) {
-                                    if (s_logger.isTraceEnabled()) {
-                                        s_logger.trace("msg id: " + 
msg.getId());
-                                        s_logger.trace("msg text: " + 
msg.getText());
-                                    }
-                                    if 
("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
-                                        s_logger.info("Found that VM has a 
pending question that we need to answer programmatically, question id: " + 
msg.getId() +
-                                                ", for safe operation we will 
automatically decline it");
-                                        vmMo.answerVM(question.getId(), force 
? ANSWER_YES : ANSWER_NO);
-                                        break;
-                                    }
-                                }
-                            } else if (question.getText() != null) {
-                                String text = question.getText();
-                                String msgId;
-                                String msgText;
-                                if (s_logger.isDebugEnabled()) {
-                                    s_logger.debug("question text : " + text);
-                                }
-                                String[] tokens = text.split(":");
-                                msgId = tokens[0];
-                                msgText = tokens[1];
-                                if 
("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
-                                    s_logger.info("Found that VM has a pending 
question that we need to answer programmatically, question id: " + 
question.getId() +
-                                            ". Message id : " + msgId + ". 
Message text : " + msgText + ", for safe operation we will automatically 
decline it.");
-                                    vmMo.answerVM(question.getId(), force ? 
ANSWER_YES : ANSWER_NO);
-                                }
-                            }
-
-                            ChoiceOption choice = question.getChoice();
-                            if (choice != null) {
-                                for (ElementDescription info : 
choice.getChoiceInfo()) {
-                                    if (s_logger.isTraceEnabled()) {
-                                        s_logger.trace("Choice option key: " + 
info.getKey());
-                                        s_logger.trace("Choice option label: " 
+ info.getLabel());
-                                    }
-                                }
-                            }
-                        }
-                    } catch (Throwable e) {
-                        s_logger.error("Unexpected exception: ", e);
-                    }
-                    try {
-                        Thread.sleep(1000);
-                    } catch (InterruptedException e) {
-                        s_logger.debug("[ignored] interupted while handling vm 
question about iso detach.");
-                    }
-                }
-                s_logger.info("VM Question monitor stopped");
-            }
-        });
+        Future<?> future = answerVmwareQuestion(flags, vmMo, force);
         try {
             boolean result = _context.getVimClient().waitForTask(morTask);
             if (!result) {

Reply via email to