Updated Branches: refs/heads/4.2 6a92f7546 -> 8f53bb273
CLOUDSTACK-4993 [VMware] When issuing detach ISO to Vcenter, MS should prevent Vcenter from posting Virtual Machine question dialog waiting for user response During ISO detach operation, answer question from vCenter by pragrmatically answering for VM question in detaching process. Signed-off-by: Sateesh Chodapuneedi <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/8f53bb27 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/8f53bb27 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/8f53bb27 Branch: refs/heads/4.2 Commit: 8f53bb2731c04487a6c0c0cd5062eb957f0636f4 Parents: 6a92f75 Author: Sateesh Chodapuneedi <[email protected]> Authored: Mon Nov 11 08:48:12 2013 +0530 Committer: Sateesh Chodapuneedi <[email protected]> Committed: Mon Nov 11 08:48:12 2013 +0530 ---------------------------------------------------------------------- .../hypervisor/vmware/mo/VirtualMachineMO.java | 194 +++++++++++++++++-- 1 file changed, 179 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f53bb27/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 55cc8de..126b67d 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -29,14 +29,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.apache.log4j.Logger; import com.google.gson.Gson; import com.vmware.vim25.ArrayOfManagedObjectReference; +import com.vmware.vim25.ChoiceOption; import com.vmware.vim25.CustomFieldStringValue; import com.vmware.vim25.DistributedVirtualSwitchPortConnection; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.ElementDescription; import com.vmware.vim25.GuestInfo; import com.vmware.vim25.GuestOsDescriptor; import com.vmware.vim25.HttpNfcLeaseDeviceUrl; @@ -80,8 +85,10 @@ import com.vmware.vim25.VirtualMachineConfigOption; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineConfigSummary; import com.vmware.vim25.VirtualMachineFileInfo; +import com.vmware.vim25.VirtualMachineMessage; import com.vmware.vim25.VirtualMachineMovePriority; import com.vmware.vim25.VirtualMachinePowerState; +import com.vmware.vim25.VirtualMachineQuestionInfo; import com.vmware.vim25.VirtualMachineRelocateDiskMoveOptions; import com.vmware.vim25.VirtualMachineRelocateSpec; import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; @@ -98,12 +105,14 @@ import com.cloud.hypervisor.vmware.util.VmwareHelper; import com.cloud.utils.ActionDelegate; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.script.Script; import edu.emory.mathcs.backport.java.util.Arrays; public class VirtualMachineMO extends BaseMO { private static final Logger s_logger = Logger.getLogger(VirtualMachineMO.class); + private static final ExecutorService _monitorServiceExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("VM-Question-Monitor")); private ManagedObjectReference _vmEnvironmentBrowser = null; public VirtualMachineMO(VmwareContext context, ManagedObjectReference morVm) { @@ -170,6 +179,10 @@ public class VirtualMachineMO extends BaseMO { return (GuestInfo)getContext().getVimClient().getDynamicProperty(_mor, "guest"); } + public void answerVM(String questionId, String choice) throws Exception { + getContext().getService().answerVM(_mor, questionId, choice); + } + public boolean isVMwareToolsRunning() throws Exception { GuestInfo guestInfo = getVmGuestInfo(); if(guestInfo != null) { @@ -1157,7 +1170,7 @@ public class VirtualMachineMO extends BaseMO { boolean connect, boolean connectAtBoot) throws Exception { if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: " + isoDatastorePath + ", datastore: " + morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot); assert(isoDatastorePath != null); @@ -1240,18 +1253,90 @@ public class VirtualMachineMO extends BaseMO { //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); - ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); - boolean result = _context.getVimClient().waitForTask(morTask); + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); + + // 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(), "1"); + 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(), "1"); + } + } - if(!result) { - if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso() done(failed)"); - throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + 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.info("VM Question monitor stopped"); + } + }); + try { + boolean result = _context.getVimClient().waitForTask(morTask); + if (!result) { + if(s_logger.isDebugEnabled()) + s_logger.trace("vCenter API trace - detachIso() done(failed)"); + throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + _context.waitForTaskProgressDone(morTask); + s_logger.trace("vCenter API trace - detachIso() done(successfully)"); + } finally { + flags[0] = true; + future.cancel(true); } - _context.waitForTaskProgressDone(morTask); - - if(s_logger.isTraceEnabled()) - s_logger.trace("vCenter API trace - detachIso() done(successfully)"); } public Pair<VmdkFileDescriptor, byte[]> getVmdkFileInfo(String vmdkDatastorePath) throws Exception { @@ -2027,7 +2112,7 @@ public class VirtualMachineMO extends BaseMO { } } - return detachedDiskFiles; + return detachedDiskFiles; } public List<VirtualDevice> getAllDeviceList() throws Exception { @@ -2052,7 +2137,7 @@ public class VirtualMachineMO extends BaseMO { for(VirtualDevice device : allDevices ) { if(device instanceof VirtualDisk) { VirtualDisk disk = (VirtualDisk)device; - String diskBusName = getDeviceBusName(allDevices, (VirtualDevice)disk); + String diskBusName = getDeviceBusName(allDevices, disk); if(busName.equalsIgnoreCase(diskBusName)) return disk; } @@ -2280,8 +2365,87 @@ public class VirtualMachineMO extends BaseMO { } public void unmountToolsInstaller() throws Exception { - _context.getService().unmountToolsInstaller(_mor); - } + int i = 1; + // 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(), "1"); + 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(), "1"); + } + } + + 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.info("VM Question monitor stopped"); + } + }); + + try { + _context.getService().unmountToolsInstaller(_mor); + } finally { + flags[0] = true; + future.cancel(true); + } + } public void redoRegistration(ManagedObjectReference morHost) throws Exception { String vmName = getVmName();
