Skip to content

Commit ad5d607

Browse files
author
Sateesh Chodapuneedi
committed
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 programmatically answering for VM question in detaching process. Signed-off-by: Sateesh Chodapuneedi <sateesh@apache.org>
1 parent 17bdbeb commit ad5d607

1 file changed

Lines changed: 179 additions & 15 deletions

File tree

vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java

Lines changed: 179 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,19 @@
2929
import java.util.Collections;
3030
import java.util.Comparator;
3131
import java.util.List;
32+
import java.util.concurrent.ExecutorService;
33+
import java.util.concurrent.Executors;
34+
import java.util.concurrent.Future;
3235

3336
import org.apache.log4j.Logger;
3437

3538
import com.google.gson.Gson;
3639
import com.vmware.vim25.ArrayOfManagedObjectReference;
40+
import com.vmware.vim25.ChoiceOption;
3741
import com.vmware.vim25.CustomFieldStringValue;
3842
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
3943
import com.vmware.vim25.DynamicProperty;
44+
import com.vmware.vim25.ElementDescription;
4045
import com.vmware.vim25.GuestInfo;
4146
import com.vmware.vim25.GuestOsDescriptor;
4247
import com.vmware.vim25.HttpNfcLeaseDeviceUrl;
@@ -80,8 +85,10 @@
8085
import com.vmware.vim25.VirtualMachineConfigSpec;
8186
import com.vmware.vim25.VirtualMachineConfigSummary;
8287
import com.vmware.vim25.VirtualMachineFileInfo;
88+
import com.vmware.vim25.VirtualMachineMessage;
8389
import com.vmware.vim25.VirtualMachineMovePriority;
8490
import com.vmware.vim25.VirtualMachinePowerState;
91+
import com.vmware.vim25.VirtualMachineQuestionInfo;
8592
import com.vmware.vim25.VirtualMachineRelocateDiskMoveOptions;
8693
import com.vmware.vim25.VirtualMachineRelocateSpec;
8794
import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
@@ -98,12 +105,14 @@
98105
import com.cloud.utils.ActionDelegate;
99106
import com.cloud.utils.Pair;
100107
import com.cloud.utils.Ternary;
108+
import com.cloud.utils.concurrency.NamedThreadFactory;
101109
import com.cloud.utils.script.Script;
102110

103111
import java.util.Arrays;
104112

105113
public class VirtualMachineMO extends BaseMO {
106114
private static final Logger s_logger = Logger.getLogger(VirtualMachineMO.class);
115+
private static final ExecutorService _monitorServiceExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("VM-Question-Monitor"));
107116
private ManagedObjectReference _vmEnvironmentBrowser = null;
108117

109118
public VirtualMachineMO(VmwareContext context, ManagedObjectReference morVm) {
@@ -170,6 +179,10 @@ public GuestInfo getVmGuestInfo() throws Exception {
170179
return (GuestInfo)getContext().getVimClient().getDynamicProperty(_mor, "guest");
171180
}
172181

182+
public void answerVM(String questionId, String choice) throws Exception {
183+
getContext().getService().answerVM(_mor, questionId, choice);
184+
}
185+
173186
public boolean isVMwareToolsRunning() throws Exception {
174187
GuestInfo guestInfo = getVmGuestInfo();
175188
if(guestInfo != null) {
@@ -1161,7 +1174,7 @@ public void attachIso(String isoDatastorePath, ManagedObjectReference morDs,
11611174
boolean connect, boolean connectAtBoot) throws Exception {
11621175

11631176
if(s_logger.isTraceEnabled())
1164-
s_logger.trace("vCenter API trace - detachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: "
1177+
s_logger.trace("vCenter API trace - attachIso(). target MOR: " + _mor.getValue() + ", isoDatastorePath: "
11651178
+ isoDatastorePath + ", datastore: " + morDs.getValue() + ", connect: " + connect + ", connectAtBoot: " + connectAtBoot);
11661179

11671180
assert(isoDatastorePath != null);
@@ -1244,18 +1257,90 @@ public void detachIso(String isoDatastorePath) throws Exception {
12441257
//deviceConfigSpecArray[0] = deviceConfigSpec;
12451258
reConfigSpec.getDeviceChange().add(deviceConfigSpec);
12461259

1247-
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
1248-
boolean result = _context.getVimClient().waitForTask(morTask);
1260+
ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec);
1261+
1262+
// Monitor VM questions
1263+
final Boolean[] flags = { false };
1264+
final VirtualMachineMO vmMo = this;
1265+
Future<?> future = _monitorServiceExecutor.submit(new Runnable() {
1266+
@Override
1267+
public void run() {
1268+
s_logger.info("VM Question monitor started...");
1269+
1270+
while(!flags[0]) {
1271+
try {
1272+
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
1273+
VirtualMachineQuestionInfo question = runtimeInfo.getQuestion();
1274+
if(question != null) {
1275+
if(s_logger.isTraceEnabled()) {
1276+
s_logger.trace("Question id: " + question.getId());
1277+
s_logger.trace("Question text: " + question.getText());
1278+
}
1279+
if(question.getMessage() != null) {
1280+
for(VirtualMachineMessage msg : question.getMessage()) {
1281+
if(s_logger.isTraceEnabled()) {
1282+
s_logger.trace("msg id: " + msg.getId());
1283+
s_logger.trace("msg text: " + msg.getText());
1284+
}
1285+
if("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
1286+
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId()
1287+
+ ", for safe operation we will automatically decline it");
1288+
vmMo.answerVM(question.getId(), "1");
1289+
break;
1290+
}
1291+
}
1292+
} else if (question.getText() != null) {
1293+
String text = question.getText();
1294+
String msgId;
1295+
String msgText;
1296+
if (s_logger.isDebugEnabled()) {
1297+
s_logger.debug("question text : " + text);
1298+
}
1299+
String[] tokens = text.split(":");
1300+
msgId = tokens[0];
1301+
msgText = tokens[1];
1302+
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
1303+
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId()
1304+
+ ". Message id : " + msgId + ". Message text : " + msgText
1305+
+ ", for safe operation we will automatically decline it.");
1306+
vmMo.answerVM(question.getId(), "1");
1307+
}
1308+
}
12491309

1250-
if(!result) {
1251-
if(s_logger.isTraceEnabled())
1252-
s_logger.trace("vCenter API trace - detachIso() done(failed)");
1253-
throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask));
1310+
ChoiceOption choice = question.getChoice();
1311+
if(choice != null) {
1312+
for(ElementDescription info : choice.getChoiceInfo()) {
1313+
if(s_logger.isTraceEnabled()) {
1314+
s_logger.trace("Choice option key: " + info.getKey());
1315+
s_logger.trace("Choice option label: " + info.getLabel());
1316+
}
1317+
}
1318+
}
1319+
}
1320+
} catch(Throwable e) {
1321+
s_logger.error("Unexpected exception: ", e);
1322+
}
1323+
try {
1324+
Thread.sleep(1000);
1325+
} catch (InterruptedException e) {
1326+
}
1327+
}
1328+
s_logger.info("VM Question monitor stopped");
1329+
}
1330+
});
1331+
try {
1332+
boolean result = _context.getVimClient().waitForTask(morTask);
1333+
if (!result) {
1334+
if(s_logger.isDebugEnabled())
1335+
s_logger.trace("vCenter API trace - detachIso() done(failed)");
1336+
throw new Exception("Failed to detachIso due to " + TaskMO.getTaskFailureInfo(_context, morTask));
1337+
}
1338+
_context.waitForTaskProgressDone(morTask);
1339+
s_logger.trace("vCenter API trace - detachIso() done(successfully)");
1340+
} finally {
1341+
flags[0] = true;
1342+
future.cancel(true);
12541343
}
1255-
_context.waitForTaskProgressDone(morTask);
1256-
1257-
if(s_logger.isTraceEnabled())
1258-
s_logger.trace("vCenter API trace - detachIso() done(successfully)");
12591344
}
12601345

12611346
public Pair<VmdkFileDescriptor, byte[]> getVmdkFileInfo(String vmdkDatastorePath) throws Exception {
@@ -2061,7 +2146,7 @@ public List<String> detachAllDisksExcept(String vmdkBaseName, String deviceBusNa
20612146
}
20622147
}
20632148

2064-
return detachedDiskFiles;
2149+
return detachedDiskFiles;
20652150
}
20662151

20672152
public List<VirtualDevice> getAllDeviceList() throws Exception {
@@ -2086,7 +2171,7 @@ public VirtualDisk getDiskDeviceByBusName(List<VirtualDevice> allDevices, String
20862171
for(VirtualDevice device : allDevices ) {
20872172
if(device instanceof VirtualDisk) {
20882173
VirtualDisk disk = (VirtualDisk)device;
2089-
String diskBusName = getDeviceBusName(allDevices, (VirtualDevice)disk);
2174+
String diskBusName = getDeviceBusName(allDevices, disk);
20902175
if(busName.equalsIgnoreCase(diskBusName))
20912176
return disk;
20922177
}
@@ -2314,8 +2399,87 @@ public void mountToolsInstaller() throws Exception {
23142399
}
23152400

23162401
public void unmountToolsInstaller() throws Exception {
2317-
_context.getService().unmountToolsInstaller(_mor);
2318-
}
2402+
int i = 1;
2403+
// Monitor VM questions
2404+
final Boolean[] flags = {false};
2405+
final VirtualMachineMO vmMo = this;
2406+
Future<?> future = _monitorServiceExecutor.submit(new Runnable() {
2407+
@Override
2408+
public void run() {
2409+
s_logger.info("VM Question monitor started...");
2410+
2411+
while (!flags[0]) {
2412+
try {
2413+
VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
2414+
VirtualMachineQuestionInfo question = runtimeInfo.getQuestion();
2415+
if (question != null) {
2416+
if (s_logger.isTraceEnabled()) {
2417+
s_logger.trace("Question id: " + question.getId());
2418+
s_logger.trace("Question text: " + question.getText());
2419+
}
2420+
2421+
if (question.getMessage() != null) {
2422+
for (VirtualMachineMessage msg : question.getMessage()) {
2423+
if (s_logger.isTraceEnabled()) {
2424+
s_logger.trace("msg id: " + msg.getId());
2425+
s_logger.trace("msg text: " + msg.getText());
2426+
}
2427+
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msg.getId())) {
2428+
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + msg.getId()
2429+
+ ", for safe operation we will automatically decline it");
2430+
vmMo.answerVM(question.getId(), "1");
2431+
break;
2432+
}
2433+
}
2434+
} else if (question.getText() != null) {
2435+
String text = question.getText();
2436+
String msgId;
2437+
String msgText;
2438+
if (s_logger.isDebugEnabled()) {
2439+
s_logger.debug("question text : " + text);
2440+
}
2441+
String[] tokens = text.split(":");
2442+
msgId = tokens[0];
2443+
msgText = tokens[1];
2444+
if ("msg.cdromdisconnect.locked".equalsIgnoreCase(msgId)) {
2445+
s_logger.info("Found that VM has a pending question that we need to answer programmatically, question id: " + question.getId()
2446+
+ ". Message id : " + msgId + ". Message text : " + msgText
2447+
+ ", for safe operation we will automatically decline it.");
2448+
vmMo.answerVM(question.getId(), "1");
2449+
}
2450+
}
2451+
2452+
ChoiceOption choice = question.getChoice();
2453+
if (choice != null) {
2454+
for (ElementDescription info : choice.getChoiceInfo()) {
2455+
if (s_logger.isTraceEnabled()) {
2456+
s_logger.trace("Choice option key: " + info.getKey());
2457+
s_logger.trace("Choice option label: " + info.getLabel());
2458+
}
2459+
}
2460+
}
2461+
}
2462+
} catch (Throwable e) {
2463+
s_logger.error("Unexpected exception: ", e);
2464+
}
2465+
2466+
try {
2467+
Thread.sleep(1000);
2468+
} catch (InterruptedException e) {
2469+
}
2470+
}
2471+
2472+
s_logger.info("VM Question monitor stopped");
2473+
}
2474+
});
2475+
2476+
try {
2477+
_context.getService().unmountToolsInstaller(_mor);
2478+
} finally {
2479+
flags[0] = true;
2480+
future.cancel(true);
2481+
}
2482+
}
23192483

23202484
public void redoRegistration(ManagedObjectReference morHost) throws Exception {
23212485
String vmName = getVmName();

0 commit comments

Comments
 (0)