[libvirt] [PATCH 01/13] esx: Add automatic question handling

Matthias Bolte matthias.bolte at googlemail.com
Sat Dec 12 23:20:38 UTC 2009


Questions can block tasks, to handle them automatically the driver can answers
them with the default answer. The auto_answer query parameter allows to enable
this automatic question handling.

* src/esx/README: add a detailed explanation for automatic question handling
* src/esx/esx_driver.c: add automatic question handling for all task related
  driver functions
* src/esx/esx_util.[ch]: add handling for the auto_answer query parameter
* src/esx/esx_vi.[ch], src/esx/esx_vi_methods.[ch], src/esx/esx_vi_types.[ch]:
  add new VI API methods and types and additional helper functions for
  automatic question handling
---
 src/esx/README           |   75 +++++++++
 src/esx/esx_driver.c     |  107 +++++++-------
 src/esx/esx_util.c       |   22 +++-
 src/esx/esx_util.h       |    2 +-
 src/esx/esx_vi.c         |  374 +++++++++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.h         |   31 ++++
 src/esx/esx_vi_methods.c |  111 ++++++++++++++
 src/esx/esx_vi_methods.h |    7 +
 src/esx/esx_vi_types.c   |  218 +++++++++++++++++++++++++++
 src/esx/esx_vi_types.h   |  106 +++++++++++++
 10 files changed, 997 insertions(+), 56 deletions(-)
 create mode 100644 src/esx/README

diff --git a/src/esx/README b/src/esx/README
new file mode 100644
index 0000000..3619054
--- /dev/null
+++ b/src/esx/README
@@ -0,0 +1,75 @@
+
+Some links to relevant documentation
+====================================
+
+
+VI API reference: http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/
+VMX config:       http://www.sanbarrow.com/vmx.html
+CPUID:            http://www.sandpile.org/ia32/cpuid.htm
+Memory model:     http://www.vmware.com/pdf/esx3_memory.pdf
+
+
+
+
+Automatic question handling
+===========================
+
+
+What is a question in the ESX context?
+--------------------------------------
+
+The VI API contains calls that start tasks, for example PowerOnVM_Task(). Such
+tasks may be blocked by a question if the ESX host detects an issue with the
+virtual machine that requires user interaction.
+
+An example: If a virtual machine has a serial port that is realized via a file,
+the ESX host will ask a question on power-on of this virtual machine whether
+new content should be appended to this file or the file should be replaced.
+Until this question is answered the power-on task is blocked and the virtual
+machine won't get powered on.
+
+The ESX driver cannot prompt the user to answer a question, libvirt doesn't
+have an API for something like this. The VI API provides a AnswerVM() method to
+programmatically answer such questions. A question comes together with a list
+of possible answers. One of this answers is marked as the default one. For all
+questions I've seen so far the default answer is always a non-destructive one.
+
+There are two options how to handle a question that is blocking a task: either
+answer it automatically or report it as error and try to cancel the blocked
+task.
+
+The auto_answer query parameter defines how the driver should handle questions.
+Possible values are 0 for the report-error-and-try-to-cancel option and 1 for
+the automatic-answer option.
+
+
+How is automatic question handling implemented?
+-----------------------------------------------
+
+Before any new task is started the driver checks if there is a pending task
+blocked by a question. If automatic question handling is disabled the driver
+reports an error that includes the question and returns from the driver
+function. If automatic question handling is enabled the driver answers the
+question with the default answer and returns from the driver function.
+
+In both cases the actual desired task is not started. If the question was not
+answered the blocked task is still blocked and because task can't be executed
+in parallel in general it's of no use to start yet another task. If the
+question was answered the blocked task may already perform the desired action
+and one must wait for its completion, so it's of no use to start yet another
+task.
+
+If there is no question blocking a task or another pending task that had not
+finished yet the driver starts the desired task and waits for its completion.
+While polling for status updates of the task it also checks for question that
+may have been triggered by the current task and handles them according to the
+value of the auto_answer query parameter. If automatic question handling is
+enabled the driver answers the question with the default answer and continues
+polling for status updates. If automatic question handling is disabled the
+driver reports an error that includes the question, tries to cancel the blocked
+task and returns from the driver function.
+
+It tries to cancel the blocked task, but this may not be possible, because
+there are task like the power-on task that is marked as non-cancelable. So the
+driver may leave blocked tasks behind if automatic question handling is
+disabled.
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index ea464a3..45da694 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -21,15 +21,6 @@
  *
  */
 
-/*
- * Some links to relevant documentation:
- *
- * - Memory model:        http://www.vmware.com/pdf/esx3_memory.pdf
- * - VI API reference:    http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/
- * - VMX-file parameters: http://www.sanbarrow.com/vmx.html
- * - CPUID:               http://www.sandpile.org/ia32/cpuid.htm
- */
-
 #include <config.h>
 
 #include <netdb.h>
@@ -63,6 +54,7 @@ typedef struct _esxPrivate {
     int32_t maxVcpus;
     esxVI_Boolean supportsVMotion;
     esxVI_Boolean supportsLongMode; /* aka x86_64 */
+    esxVI_Boolean autoAnswer;
     int32_t usedCpuTimeCounterId;
 } esxPrivate;
 
@@ -242,7 +234,7 @@ esxCapsInit(virConnectPtr conn)
 
 
 /*
- * URI format: {esx|gsx}://[<user>@]<server>[:<port>][?transport={http|https}][&vcenter=<vcenter>][&no_verify={0|1}]
+ * URI format: {esx|gsx}://[<user>@]<server>[:<port>][?transport={http|https}][&vcenter=<vcenter>][&no_verify={0|1}][&auto_answer={0|1}]
  *
  * If no port is specified the default port is set dependent on the scheme and
  * transport parameter:
@@ -258,6 +250,10 @@ esxCapsInit(virConnectPtr conn)
  *
  * If the no_verify parameter is set to 1, this disables libcurl client checks
  * of the server's certificate. The default value it 0.
+ *
+ * If the auto_answer parameter is set to 1, the driver will respond to all
+ * virtual machine questions with the default answer, otherwise virtual machine
+ * questions will be reported as errors. The default value it 0.
  */
 static virDrvOpenStatus
 esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
@@ -268,6 +264,7 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
     char *url = NULL;
     char *vCenter = NULL;
     int noVerify = 0; // boolean
+    int autoAnswer = 0; // boolean
     char *username = NULL;
     char *password = NULL;
 
@@ -296,13 +293,19 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
     priv->maxVcpus = -1;
     priv->supportsVMotion = esxVI_Boolean_Undefined;
     priv->supportsLongMode = esxVI_Boolean_Undefined;
+    priv->autoAnswer = esxVI_Boolean_False;
     priv->usedCpuTimeCounterId = -1;
 
-    /* Request credentials and login to host/vCenter */
-    if (esxUtil_ParseQuery(conn, &priv->transport, &vCenter, &noVerify) < 0) {
+    if (esxUtil_ParseQuery(conn, &priv->transport, &vCenter, &noVerify,
+                           &autoAnswer) < 0) {
         goto failure;
     }
 
+    if (autoAnswer) {
+        priv->autoAnswer = esxVI_Boolean_True;
+    }
+
+    /* Request credentials and login to host/vCenter */
     if (esxUtil_ResolveHostname(conn, conn->uri->server, hostIpAddress,
                                 NI_MAXHOST) < 0) {
         goto failure;
@@ -1360,10 +1363,9 @@ esxDomainSuspend(virDomainPtr domain)
 
     if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "runtime.powerState") < 0 ||
-        esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, propertyNameList,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, propertyNameList,
+           &virtualMachine, priv->autoAnswer) < 0 ||
         esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
                                           &powerState) < 0) {
         goto failure;
@@ -1378,6 +1380,7 @@ esxDomainSuspend(virDomainPtr domain)
     if (esxVI_SuspendVM_Task(domain->conn, priv->host, virtualMachine->obj,
                              &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -1420,10 +1423,9 @@ esxDomainResume(virDomainPtr domain)
 
     if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "runtime.powerState") < 0 ||
-        esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, propertyNameList,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, propertyNameList,
+           &virtualMachine, priv->autoAnswer) < 0 ||
         esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
                                           &powerState) < 0) {
         goto failure;
@@ -1438,6 +1440,7 @@ esxDomainResume(virDomainPtr domain)
     if (esxVI_PowerOnVM_Task(domain->conn, priv->host, virtualMachine->obj,
                              &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -1577,10 +1580,9 @@ esxDomainDestroy(virDomainPtr domain)
 
     if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "runtime.powerState") < 0 ||
-        esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, propertyNameList,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, propertyNameList,
+           &virtualMachine, priv->autoAnswer) < 0 ||
         esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
                                           &powerState) < 0) {
         goto failure;
@@ -1595,6 +1597,7 @@ esxDomainDestroy(virDomainPtr domain)
     if (esxVI_PowerOffVM_Task(domain->conn, priv->host, virtualMachine->obj,
                               &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -1707,10 +1710,9 @@ esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
         goto failure;
     }
 
-    if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, NULL,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, NULL, &virtualMachine,
+           priv->autoAnswer) < 0 ||
         esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 ||
         esxVI_Long_Alloc(domain->conn, &spec->memoryMB) < 0) {
         goto failure;
@@ -1722,6 +1724,7 @@ esxDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
     if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj,
                               spec, &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -1761,10 +1764,9 @@ esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
         goto failure;
     }
 
-    if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, NULL,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, NULL, &virtualMachine,
+           priv->autoAnswer) < 0 ||
         esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 ||
         esxVI_ResourceAllocationInfo_Alloc(domain->conn,
                                            &spec->memoryAllocation) < 0 ||
@@ -1778,6 +1780,7 @@ esxDomainSetMemory(virDomainPtr domain, unsigned long memory)
     if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj,
                               spec, &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -2100,10 +2103,9 @@ esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
         goto failure;
     }
 
-    if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, NULL,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, NULL, &virtualMachine,
+           priv->autoAnswer) < 0 ||
         esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 ||
         esxVI_Int_Alloc(domain->conn, &spec->numCPUs) < 0) {
         goto failure;
@@ -2114,6 +2116,7 @@ esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
     if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj,
                               spec, &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -2483,10 +2486,9 @@ esxDomainCreate(virDomainPtr domain)
 
     if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "runtime.powerState") < 0 ||
-        esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, propertyNameList,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, propertyNameList,
+           &virtualMachine, priv->autoAnswer) < 0 ||
         esxVI_GetVirtualMachinePowerState(domain->conn, virtualMachine,
                                           &powerState) < 0) {
         goto failure;
@@ -2501,6 +2503,7 @@ esxDomainCreate(virDomainPtr domain)
     if (esxVI_PowerOnVM_Task(domain->conn, priv->host, virtualMachine->obj,
                              &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -2690,6 +2693,7 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml ATTRIBUTE_UNUSED)
                               datastoreRelatedPath, NULL, esxVI_Boolean_False,
                               resourcePool, hostSystem->obj, &task) < 0 ||
         esxVI_WaitForTaskCompletion(conn, priv->host, task,
+                                    def->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -2977,10 +2981,9 @@ esxDomainSetSchedulerParameters(virDomainPtr domain,
         goto failure;
     }
 
-    if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->host,
-                                         domain->uuid, NULL,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0 ||
+    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->host, domain->uuid, NULL, &virtualMachine,
+           priv->autoAnswer) < 0 ||
         esxVI_VirtualMachineConfigSpec_Alloc(domain->conn, &spec) < 0 ||
         esxVI_ResourceAllocationInfo_Alloc(domain->conn,
                                            &spec->cpuAllocation) < 0) {
@@ -3068,6 +3071,7 @@ esxDomainSetSchedulerParameters(virDomainPtr domain,
     if (esxVI_ReconfigVM_Task(domain->conn, priv->host, virtualMachine->obj,
                               spec, &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->host, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
@@ -3106,7 +3110,7 @@ esxDomainMigratePrepare(virConnectPtr dconn,
     char *transport = NULL;
 
     if (uri_in == NULL) {
-        if (esxUtil_ParseQuery(dconn, &transport, NULL, NULL) < 0) {
+        if (esxUtil_ParseQuery(dconn, &transport, NULL, NULL, NULL) < 0) {
             return -1;
         }
 
@@ -3181,14 +3185,10 @@ esxDomainMigratePerform(virDomainPtr domain,
     }
 
     /* Lookup VirtualMachine, HostSystem and ResourcePool */
-    if (esxVI_LookupVirtualMachineByUuid(domain->conn, priv->vCenter,
-                                         domain->uuid, NULL,
-                                         &virtualMachine,
-                                         esxVI_Occurence_RequiredItem) < 0) {
-        goto failure;
-    }
-
-    if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
+    if (esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+          (domain->conn, priv->vCenter, domain->uuid, NULL, &virtualMachine,
+           priv->autoAnswer) < 0 ||
+        esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "parent") < 0 ||
         esxVI_LookupHostSystemByIp(domain->conn, priv->vCenter, hostIpAddress,
                                    propertyNameList, &hostSystem) < 0) {
@@ -3231,6 +3231,7 @@ esxDomainMigratePerform(virDomainPtr domain,
     if (esxVI_MigrateVM_Task(domain->conn, priv->vCenter, virtualMachine->obj,
                              resourcePool, hostSystem->obj, &task) < 0 ||
         esxVI_WaitForTaskCompletion(domain->conn, priv->vCenter, task,
+                                    domain->uuid, priv->autoAnswer,
                                     &taskInfoState) < 0) {
         goto failure;
     }
diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c
index 3e53921..33babce 100644
--- a/src/esx/esx_util.c
+++ b/src/esx/esx_util.c
@@ -133,7 +133,7 @@ esxUtil_RequestPassword(virConnectAuthPtr auth, const char *username,
 
 int
 esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vCenter,
-                   int *noVerify)
+                   int *noVerify, int *autoAnswer)
 {
     int result = 0;
     int i;
@@ -148,6 +148,14 @@ esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vCenter,
         *vCenter = NULL;
     }
 
+    if (noVerify != NULL) {
+        *noVerify = 0;
+    }
+
+    if (autoAnswer != NULL) {
+        *autoAnswer = 0;
+    }
+
 #ifdef HAVE_XMLURI_QUERY_RAW
     queryParamSet = qparam_query_parse(conn->uri->query_raw);
 #else
@@ -202,6 +210,18 @@ esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vCenter,
                           "'%s' (should be 0 or 1)", queryParam->value);
                 goto failure;
             }
+        } else if (STRCASEEQ(queryParam->name, "auto_answer")) {
+            if (autoAnswer == NULL) {
+                continue;
+            }
+
+            if (virStrToLong_i(queryParam->value, NULL, 10, autoAnswer) < 0 ||
+                (*autoAnswer != 0 && *autoAnswer != 1)) {
+                ESX_ERROR(conn, VIR_ERR_INVALID_ARG,
+                          "Query parameter 'auto_answer' has unexpected value "
+                          "'%s' (should be 0 or 1)", queryParam->value);
+                goto failure;
+            }
         } else {
             VIR_WARN("Ignoring unexpected query parameter '%s'",
                      queryParam->name);
diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h
index c466b44..3987f3e 100644
--- a/src/esx/esx_util.h
+++ b/src/esx/esx_util.h
@@ -36,7 +36,7 @@ char *esxUtil_RequestPassword(virConnectAuthPtr auth, const char *username,
                               const char *hostname);
 
 int esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vCenter,
-                       int *noVerify);
+                       int *noVerify, int *autoAnswer);
 
 int esxUtil_ParseVirtualMachineIDString(const char *id_string, int *id);
 
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 5725b2f..e934bd4 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -982,7 +982,6 @@ esxVI_List_CastFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
     goto cleanup;
 }
 
-
 int
 esxVI_List_Serialize(virConnectPtr conn, esxVI_List *list, const char *element,
                      virBufferPtr output, esxVI_Boolean required,
@@ -1076,6 +1075,8 @@ esxVI_Alloc(virConnectPtr conn, void **ptrptr, size_t size)
     return 0;
 }
 
+
+
 int
 esxVI_CheckSerializationNecessity(virConnectPtr conn, const char *element,
                                   esxVI_Boolean required)
@@ -1479,6 +1480,33 @@ esxVI_GetVirtualMachinePowerState(virConnectPtr conn,
 
 
 int
+esxVI_GetVirtualMachineQuestionInfo
+  (virConnectPtr conn, esxVI_ObjectContent *virtualMachine,
+   esxVI_VirtualMachineQuestionInfo **questionInfo)
+{
+    esxVI_DynamicProperty *dynamicProperty;
+
+    if (questionInfo == NULL || *questionInfo != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "runtime.question")) {
+            if (esxVI_VirtualMachineQuestionInfo_CastFromAnyType
+                  (conn, dynamicProperty->val, questionInfo) < 0) {
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+
+int
 esxVI_LookupNumberOfDomainsByPowerState(virConnectPtr conn, esxVI_Context *ctx,
                                         esxVI_VirtualMachinePowerState powerState,
                                         esxVI_Boolean inverse)
@@ -1827,6 +1855,60 @@ esxVI_LookupVirtualMachineByUuid(virConnectPtr conn, esxVI_Context *ctx,
 
 
 int
+esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+  (virConnectPtr conn, esxVI_Context *ctx, const unsigned char *uuid,
+   esxVI_String *propertyNameList, esxVI_ObjectContent **virtualMachine,
+   esxVI_Boolean autoAnswer)
+{
+    int result = 0;
+    esxVI_String *completePropertyNameList = NULL;
+    esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
+    esxVI_TaskInfo *pendingTaskInfoList = NULL;
+
+    if (esxVI_String_DeepCopyList(conn, &completePropertyNameList,
+                                  propertyNameList) < 0 ||
+        esxVI_String_AppendValueListToList(conn, &completePropertyNameList,
+                                           "runtime.question\0"
+                                           "recentTask\0") < 0 ||
+        esxVI_LookupVirtualMachineByUuid(conn, ctx, uuid,
+                                         completePropertyNameList,
+                                         virtualMachine,
+                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_GetVirtualMachineQuestionInfo(conn, *virtualMachine,
+                                            &questionInfo) < 0 ||
+        esxVI_LookupPendingTaskInfoListByVirtualMachine
+           (conn, ctx, *virtualMachine, &pendingTaskInfoList) < 0) {
+        goto failure;
+    }
+
+    if (questionInfo != NULL &&
+        esxVI_HandleVirtualMachineQuestion(conn, ctx, (*virtualMachine)->obj,
+                                           questionInfo, autoAnswer) < 0) {
+        goto failure;
+    }
+
+    if (pendingTaskInfoList != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_OPERATION_INVALID,
+                     "Other tasks are pending for this domain");
+        goto failure;
+    }
+
+  cleanup:
+    esxVI_String_Free(&completePropertyNameList);
+    esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
+    esxVI_TaskInfo_Free(&pendingTaskInfoList);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
 esxVI_LookupDatastoreByName(virConnectPtr conn, esxVI_Context *ctx,
                             const char *name, esxVI_String *propertyNameList,
                             esxVI_ObjectContent **datastore,
@@ -1986,6 +2068,164 @@ esxVI_LookupDatastoreByName(virConnectPtr conn, esxVI_Context *ctx,
 
 
 
+int esxVI_LookupTaskInfoByTask(virConnectPtr conn, esxVI_Context *ctx,
+                               esxVI_ManagedObjectReference *task,
+                               esxVI_TaskInfo **taskInfo)
+{
+    int result = 0;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *objectContent = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+
+    if (taskInfo == NULL || *taskInfo != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    if (esxVI_String_AppendValueToList(conn, &propertyNameList, "info") < 0 ||
+        esxVI_LookupObjectContentByType(conn, ctx, task, "Task",
+                                        propertyNameList, esxVI_Boolean_False,
+                                        &objectContent) < 0) {
+        goto failure;
+    }
+
+    for (dynamicProperty = objectContent->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "info")) {
+            if (esxVI_TaskInfo_CastFromAnyType(conn, dynamicProperty->val,
+                                               taskInfo) < 0) {
+                goto failure;
+            }
+
+            break;
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&objectContent);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
+esxVI_LookupPendingTaskInfoListByVirtualMachine
+  (virConnectPtr conn, esxVI_Context *ctx, esxVI_ObjectContent *virtualMachine,
+   esxVI_TaskInfo **pendingTaskInfoList)
+{
+    int result = 0;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ManagedObjectReference *recentTaskList = NULL;
+    esxVI_ManagedObjectReference *recentTask = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_TaskInfo *taskInfo = NULL;
+
+    if (pendingTaskInfoList == NULL || *pendingTaskInfoList != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    /* Get list of recent tasks */
+    for (dynamicProperty = virtualMachine->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "recentTask")) {
+            if (esxVI_ManagedObjectReference_CastListFromAnyType
+                  (conn, dynamicProperty->val, &recentTaskList, "Task") < 0) {
+                goto failure;
+            }
+
+            break;
+        }
+    }
+
+    /* Lookup task info for each task */
+    for (recentTask = recentTaskList; recentTask != NULL;
+         recentTask = recentTask->_next) {
+        if (esxVI_LookupTaskInfoByTask(conn, ctx, recentTask, &taskInfo) < 0) {
+            goto failure;
+        }
+
+        if (taskInfo->state == esxVI_TaskInfoState_Queued ||
+            taskInfo->state == esxVI_TaskInfoState_Running) {
+            if (esxVI_TaskInfo_AppendToList(conn, pendingTaskInfoList,
+                                            taskInfo) < 0) {
+                goto failure;
+            }
+
+            taskInfo = NULL;
+        } else {
+            esxVI_TaskInfo_Free(&taskInfo);
+        }
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ManagedObjectReference_Free(&recentTaskList);
+    esxVI_TaskInfo_Free(&taskInfo);
+
+    return result;
+
+  failure:
+    esxVI_TaskInfo_Free(pendingTaskInfoList);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
+esxVI_LookupAndHandleVirtualMachineQuestion(virConnectPtr conn,
+                                            esxVI_Context *ctx,
+                                            const unsigned char *uuid,
+                                            esxVI_Boolean autoAnswer)
+{
+    int result = 0;
+    esxVI_ObjectContent *virtualMachine = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
+
+    if (esxVI_String_AppendValueToList(conn, &propertyNameList,
+                                       "runtime.question") < 0 ||
+        esxVI_LookupVirtualMachineByUuid(conn, ctx, uuid, propertyNameList,
+                                         &virtualMachine,
+                                         esxVI_Occurence_RequiredItem) < 0 ||
+        esxVI_GetVirtualMachineQuestionInfo(conn, virtualMachine,
+                                            &questionInfo) < 0) {
+        goto failure;
+    }
+
+    if (questionInfo != NULL &&
+        esxVI_HandleVirtualMachineQuestion(conn, ctx, virtualMachine->obj,
+                                           questionInfo, autoAnswer) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    esxVI_ObjectContent_Free(&virtualMachine);
+    esxVI_String_Free(&propertyNameList);
+    esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
 int
 esxVI_StartVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx,
                               const char *name, const char *request,
@@ -2134,8 +2374,109 @@ esxVI_SimpleVirtualMachineMethod(virConnectPtr conn, esxVI_Context *ctx,
 
 
 int
+esxVI_HandleVirtualMachineQuestion
+  (virConnectPtr conn, esxVI_Context *ctx,
+   esxVI_ManagedObjectReference *virtualMachine,
+   esxVI_VirtualMachineQuestionInfo *questionInfo,
+   esxVI_Boolean autoAnswer)
+{
+    int result = 0;
+    esxVI_ElementDescription *elementDescription = NULL;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    esxVI_ElementDescription *answerChoice = NULL;
+    int answerIndex = 0;
+    char *possibleAnswers = NULL;
+
+    if (questionInfo->choice->choiceInfo != NULL) {
+        for (elementDescription = questionInfo->choice->choiceInfo;
+             elementDescription != NULL;
+             elementDescription = elementDescription->_next) {
+            virBufferVSprintf(&buffer, "'%s'", elementDescription->label);
+
+            if (elementDescription->_next != NULL) {
+                virBufferAddLit(&buffer, ", ");
+            }
+
+            if (answerChoice == NULL &&
+                questionInfo->choice->defaultIndex != NULL &&
+                questionInfo->choice->defaultIndex->value == answerIndex) {
+                answerChoice = elementDescription;
+            }
+
+            ++answerIndex;
+        }
+
+        if (virBufferError(&buffer)) {
+            virReportOOMError(conn);
+            goto failure;
+        }
+
+        possibleAnswers = virBufferContentAndReset(&buffer);
+    }
+
+    if (autoAnswer == esxVI_Boolean_True) {
+        if (possibleAnswers == NULL) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Pending question blocks virtual machine execution, "
+                         "question is '%s', no possible answers",
+                         questionInfo->text);
+            goto failure;
+        } else if (answerChoice == NULL) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Pending question blocks virtual machine execution, "
+                         "question is '%s', possible answers are %s, but no "
+                         "default answer is specified", questionInfo->text,
+                         possibleAnswers);
+            goto failure;
+        }
+
+        VIR_INFO("Pending question blocks virtual machine execution, "
+                 "question is '%s', possible answers are %s, responding "
+                 "with default answer '%s'", questionInfo->text,
+                 possibleAnswers, answerChoice->label);
+
+        if (esxVI_AnswerVM(conn, ctx, virtualMachine, questionInfo->id,
+                           answerChoice->key) < 0) {
+            goto failure;
+        }
+    } else {
+        if (possibleAnswers != NULL) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Pending question blocks virtual machine execution, "
+                         "question is '%s', possible answers are %s",
+                         questionInfo->text, possibleAnswers);
+        } else {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Pending question blocks virtual machine execution, "
+                         "question is '%s', no possible answers",
+                         questionInfo->text);
+        }
+
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(possibleAnswers);
+
+    return result;
+
+  failure:
+    if (possibleAnswers == NULL) {
+        possibleAnswers = virBufferContentAndReset(&buffer);
+    }
+
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
 esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
                             esxVI_ManagedObjectReference *task,
+                            const unsigned char *virtualMachineUuid,
+                            esxVI_Boolean autoAnswer,
                             esxVI_TaskInfoState *finalState)
 {
     int result = 0;
@@ -2150,6 +2491,7 @@ esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
     esxVI_PropertyChange *propertyChange = NULL;
     esxVI_AnyType *propertyValue = NULL;
     esxVI_TaskInfoState state = esxVI_TaskInfoState_Undefined;
+    esxVI_TaskInfo *taskInfo = NULL;
 
     version = strdup("");
 
@@ -2187,6 +2529,35 @@ esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
            state != esxVI_TaskInfoState_Error) {
         esxVI_UpdateSet_Free(&updateSet);
 
+        if (virtualMachineUuid != NULL) {
+            if (esxVI_LookupAndHandleVirtualMachineQuestion
+                  (conn, ctx, virtualMachineUuid, autoAnswer) < 0) {
+                /*
+                 * FIXME: Disable error reporting here, so possible errors from
+                 *        esxVI_LookupTaskInfoByTask() and esxVI_CancelTask()
+                 *        don't overwrite the actual error
+                 */
+                if (esxVI_LookupTaskInfoByTask(conn, ctx, task, &taskInfo)) {
+                    goto failure;
+                }
+
+                if (taskInfo->cancelable == esxVI_Boolean_True) {
+                    if (esxVI_CancelTask(conn, ctx, task) < 0) {
+                        VIR_ERROR0("Cancelable task is blocked by an "
+                                   "unanswered question but cancelation "
+                                   "failed");
+                    }
+                } else {
+                    VIR_ERROR0("Non-cancelable task is blocked by an "
+                               "unanswered question");
+                }
+
+                /* FIXME: Enable error reporting here again */
+
+                goto failure;
+            }
+        }
+
         if (esxVI_WaitForUpdates(conn, ctx, version, &updateSet) < 0) {
             goto failure;
         }
@@ -2259,6 +2630,7 @@ esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
     esxVI_ManagedObjectReference_Free(&propertyFilter);
     VIR_FREE(version);
     esxVI_UpdateSet_Free(&updateSet);
+    esxVI_TaskInfo_Free(&taskInfo);
 
     return result;
 
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 4b3005e..a10d874 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -229,6 +229,10 @@ int esxVI_GetVirtualMachinePowerState
       (virConnectPtr conn, esxVI_ObjectContent *virtualMachine,
        esxVI_VirtualMachinePowerState *powerState);
 
+int esxVI_GetVirtualMachineQuestionInfo
+      (virConnectPtr conn, esxVI_ObjectContent *virtualMachine,
+       esxVI_VirtualMachineQuestionInfo **questionInfo);
+
 int esxVI_LookupNumberOfDomainsByPowerState
       (virConnectPtr conn, esxVI_Context *ctx,
        esxVI_VirtualMachinePowerState powerState, esxVI_Boolean inverse);
@@ -252,12 +256,31 @@ int esxVI_LookupVirtualMachineByUuid(virConnectPtr conn, esxVI_Context *ctx,
                                      esxVI_ObjectContent **virtualMachine,
                                      esxVI_Occurence occurence);
 
+int esxVI_LookupVirtualMachineByUuidAndPrepareForTask
+      (virConnectPtr conn, esxVI_Context *ctx, const unsigned char *uuid,
+       esxVI_String *propertyNameList, esxVI_ObjectContent **virtualMachine,
+       esxVI_Boolean autoAnswer);
+
 int esxVI_LookupDatastoreByName(virConnectPtr conn, esxVI_Context *ctx,
                                 const char *name,
                                 esxVI_String *propertyNameList,
                                 esxVI_ObjectContent **datastore,
                                 esxVI_Occurence occurence);
 
+int esxVI_LookupTaskInfoByTask(virConnectPtr conn, esxVI_Context *ctx,
+                               esxVI_ManagedObjectReference *task,
+                               esxVI_TaskInfo **taskInfo);
+
+int esxVI_LookupPendingTaskInfoListByVirtualMachine
+      (virConnectPtr conn, esxVI_Context *ctx,
+       esxVI_ObjectContent *virtualMachine,
+       esxVI_TaskInfo **pendingTaskInfoList);
+
+int esxVI_LookupAndHandleVirtualMachineQuestion(virConnectPtr conn,
+                                                esxVI_Context *ctx,
+                                                const unsigned char *uuid,
+                                                esxVI_Boolean autoAnswer);
+
 int esxVI_StartVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx,
                                   const char *name, const char *request,
                                   esxVI_ManagedObjectReference **task);
@@ -271,8 +294,16 @@ int esxVI_SimpleVirtualMachineMethod
       (virConnectPtr conn, esxVI_Context *ctx, const char *name,
        esxVI_ManagedObjectReference *virtualMachine);
 
+int esxVI_HandleVirtualMachineQuestion
+      (virConnectPtr conn, esxVI_Context *ctx,
+       esxVI_ManagedObjectReference *virtualMachine,
+       esxVI_VirtualMachineQuestionInfo *questionInfo,
+       esxVI_Boolean autoAnswer);
+
 int esxVI_WaitForTaskCompletion(virConnectPtr conn, esxVI_Context *ctx,
                                 esxVI_ManagedObjectReference *task,
+                                const unsigned char *virtualMachineUuid,
+                                esxVI_Boolean autoAnswer,
                                 esxVI_TaskInfoState *finalState);
 
 #endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c
index 06b5fd4..d18e56b 100644
--- a/src/esx/esx_vi_methods.c
+++ b/src/esx/esx_vi_methods.c
@@ -577,6 +577,61 @@ esxVI_RegisterVM_Task(virConnectPtr conn, esxVI_Context *ctx,
 
 
 int
+esxVI_CancelTask(virConnectPtr conn, esxVI_Context *ctx,
+                 esxVI_ManagedObjectReference *task)
+{
+    int result = 0;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    char *request = NULL;
+    esxVI_Response *response = NULL;
+
+    if (ctx->service == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid call");
+        return -1;
+    }
+
+    virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER);
+    virBufferAddLit(&buffer, "<CancelTask xmlns=\"urn:vim25\">");
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, task, "_this", &buffer,
+                                               esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    virBufferAddLit(&buffer, "</CancelTask>");
+    virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER);
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    request = virBufferContentAndReset(&buffer);
+
+    if (esxVI_Context_Execute(conn, ctx, request, NULL, &response,
+                              esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(request);
+    esxVI_Response_Free(&response);
+
+    return result;
+
+  failure:
+    if (request == NULL) {
+        request = virBufferContentAndReset(&buffer);
+    }
+
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
 esxVI_UnregisterVM(virConnectPtr conn, esxVI_Context *ctx,
                    esxVI_ManagedObjectReference *virtualMachine)
 {
@@ -626,6 +681,62 @@ esxVI_UnregisterVM(virConnectPtr conn, esxVI_Context *ctx,
 
 
 int
+esxVI_AnswerVM(virConnectPtr conn, esxVI_Context *ctx,
+               esxVI_ManagedObjectReference *virtualMachine,
+               const char *questionId, const char *answerChoice)
+{
+    int result = 0;
+    virBuffer buffer = VIR_BUFFER_INITIALIZER;
+    char *request = NULL;
+    esxVI_Response *response = NULL;
+
+    virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_HEADER);
+    virBufferAddLit(&buffer, "<AnswerVM xmlns=\"urn:vim25\">");
+
+    if (esxVI_ManagedObjectReference_Serialize(conn, virtualMachine, "_this",
+                                               &buffer,
+                                               esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, questionId, "questionId",
+                                    &buffer, esxVI_Boolean_True) < 0 ||
+        esxVI_String_SerializeValue(conn, answerChoice, "answerChoice",
+                                    &buffer, esxVI_Boolean_True) < 0) {
+        goto failure;
+    }
+
+    virBufferAddLit(&buffer, "</AnswerVM>");
+    virBufferAddLit(&buffer, ESX_VI__SOAP__REQUEST_FOOTER);
+
+    if (virBufferError(&buffer)) {
+        virReportOOMError(conn);
+        goto failure;
+    }
+
+    request = virBufferContentAndReset(&buffer);
+
+    if (esxVI_Context_Execute(conn, ctx, request, NULL, &response,
+                              esxVI_Boolean_False) < 0) {
+        goto failure;
+    }
+
+  cleanup:
+    VIR_FREE(request);
+    esxVI_Response_Free(&response);
+
+    return result;
+
+  failure:
+    if (request == NULL) {
+        request = virBufferContentAndReset(&buffer);
+    }
+
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
+int
 esxVI_CreateFilter(virConnectPtr conn, esxVI_Context *ctx,
                    esxVI_PropertyFilterSpec *propertyFilterSpec,
                    esxVI_Boolean partialUpdates,
diff --git a/src/esx/esx_vi_methods.h b/src/esx/esx_vi_methods.h
index 5f3caff..03e4fdf 100644
--- a/src/esx/esx_vi_methods.h
+++ b/src/esx/esx_vi_methods.h
@@ -80,9 +80,16 @@ int esxVI_RegisterVM_Task(virConnectPtr conn, esxVI_Context *ctx,
                           esxVI_ManagedObjectReference *hostSystem,
                           esxVI_ManagedObjectReference **task);
 
+int esxVI_CancelTask(virConnectPtr conn, esxVI_Context *ctx,
+                     esxVI_ManagedObjectReference *task);
+
 int esxVI_UnregisterVM(virConnectPtr conn, esxVI_Context *ctx,
                        esxVI_ManagedObjectReference *virtualMachine);
 
+int esxVI_AnswerVM(virConnectPtr conn, esxVI_Context *ctx,
+                   esxVI_ManagedObjectReference *virtualMachine,
+                   const char *questionId, const char *answerChoice);
+
 int esxVI_CreateFilter(virConnectPtr conn, esxVI_Context *ctx,
                        esxVI_PropertyFilterSpec *propertyFilterSpec,
                        esxVI_Boolean partialUpdates,
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index 9af9f73..aa2f968 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -1202,6 +1202,9 @@ static const esxVI_Enumeration _esxVI_TaskInfoState_Enumeration = {
 /* esxVI_TaskInfoState_CastFromAnyType */
 ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(TaskInfoState);
 
+/* esxVI_TaskInfoState_Deserialize */
+ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(TaskInfoState);
+
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -1315,6 +1318,9 @@ esxVI_ManagedObjectReference_DeepCopy(virConnectPtr conn,
     return -1;
 }
 
+/* esxVI_ManagedObjectReference_AppendToList */
+ESX_VI__TEMPLATE__LIST__APPEND(ManagedObjectReference);
+
 int
 esxVI_ManagedObjectReference_CastFromAnyType
   (virConnectPtr conn, esxVI_AnyType *anyType,
@@ -1340,6 +1346,76 @@ esxVI_ManagedObjectReference_CastFromAnyType
 }
 
 int
+esxVI_ManagedObjectReference_CastListFromAnyType
+  (virConnectPtr conn, esxVI_AnyType *anyType,
+   esxVI_ManagedObjectReference **managedObjectReferenceList,
+   const char *expectedType)
+{
+    int result = 0;
+    xmlNodePtr childNode = NULL;
+    esxVI_AnyType *childAnyType = NULL;
+    esxVI_ManagedObjectReference *managedObjectReference = NULL;
+
+    if (managedObjectReferenceList == NULL ||
+        *managedObjectReferenceList != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        goto failure;
+    }
+
+    if (anyType == NULL) {
+        return 0;
+    }
+
+    if (STRNEQ(anyType->other, "ArrayOfManagedObjectReference")) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Expecting type to be 'ArrayOfManagedObjectReference' "
+                     "but found '%s'", anyType->other);
+        goto failure;
+    }
+
+    for (childNode = anyType->_node->children; childNode != NULL;
+         childNode = childNode->next) {
+        if (childNode->type != XML_ELEMENT_NODE) {
+            ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                         "Wrong XML element type %d", childNode->type);
+            goto failure;
+        }
+
+        esxVI_AnyType_Free(&childAnyType);
+
+        if (esxVI_AnyType_Deserialize(conn, childNode, &childAnyType) < 0) {
+            goto failure;
+        }
+
+        managedObjectReference = NULL;
+
+        if (esxVI_ManagedObjectReference_CastFromAnyType
+              (conn, childAnyType, &managedObjectReference,
+               expectedType) < 0) {
+            goto failure;
+        }
+
+        if (esxVI_ManagedObjectReference_AppendToList
+              (conn, managedObjectReferenceList, managedObjectReference) < 0) {
+            goto failure;
+        }
+    }
+
+
+  cleanup:
+    esxVI_AnyType_Free(&childAnyType);
+
+    return result;
+
+  failure:
+    esxVI_ManagedObjectReference_Free(managedObjectReferenceList);
+
+    result = -1;
+
+    goto cleanup;
+}
+
+int
 esxVI_ManagedObjectReference_Serialize
   (virConnectPtr conn, esxVI_ManagedObjectReference *managedObjectReference,
    const char *element, virBufferPtr output, esxVI_Boolean required)
@@ -2427,6 +2503,41 @@ ESX_VI__TEMPLATE__DESERIALIZE(UserSession,
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: VirtualMachineQuestionInfo
+ */
+
+/* esxVI_VirtualMachineQuestionInfo_Alloc */
+ESX_VI__TEMPLATE__ALLOC(VirtualMachineQuestionInfo);
+
+/* esxVI_VirtualMachineQuestionInfo_Free */
+ESX_VI__TEMPLATE__FREE(VirtualMachineQuestionInfo,
+{
+    VIR_FREE(item->id);
+    VIR_FREE(item->text);
+    esxVI_ChoiceOption_Free(&item->choice);
+    /*esxVI_VirtualMachineMessage_Free(&item->message);*//* FIXME */
+});
+
+/* esxVI_VirtualMachineQuestionInfo_CastFromAnyType */
+ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(VirtualMachineQuestionInfo);
+
+/* esxVI_VirtualMachineQuestionInfo_Deserialize */
+ESX_VI__TEMPLATE__DESERIALIZE(VirtualMachineQuestionInfo,
+{
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, id);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, text);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(ChoiceOption, choice);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(message); /* FIXME */
+},
+{
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(id);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(text);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(choice);
+});
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: ElementDescription extends Description
  *
  *          In contrast to SelectionSpec and TraversalSpec just merge
@@ -2447,6 +2558,9 @@ ESX_VI__TEMPLATE__FREE(ElementDescription,
     VIR_FREE(item->key);
 });
 
+/* esxVI_ElementDescription_AppendToList */
+ESX_VI__TEMPLATE__LIST__APPEND(ElementDescription);
+
 /* esxVI_ElementDescription_Deserialize */
 ESX_VI__TEMPLATE__DESERIALIZE(ElementDescription,
 {
@@ -2463,6 +2577,37 @@ ESX_VI__TEMPLATE__DESERIALIZE(ElementDescription,
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: ChoiceOption extends OptionType
+ *
+ *          In contrast to SelectionSpec and TraversalSpec just merge
+ *          OptionType into ChoiceOption for simplicity, because
+ *          only ChoiceOption is used.
+ */
+
+/* esxVI_ChoiceOption_Alloc */
+ESX_VI__TEMPLATE__ALLOC(ChoiceOption);
+
+/* esxVI_ChoiceOption_Free */
+ESX_VI__TEMPLATE__FREE(ChoiceOption,
+{
+    esxVI_ElementDescription_Free(&item->choiceInfo);
+    esxVI_Int_Free(&item->defaultIndex);
+});
+
+/* esxVI_ChoiceOption_Deserialize */
+ESX_VI__TEMPLATE__DESERIALIZE(ChoiceOption,
+{
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Boolean, valueIsReadonly);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(ElementDescription, choiceInfo);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, defaultIndex);
+},
+{
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(choiceInfo);
+});
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: PerfMetricId
  */
 
@@ -2699,3 +2844,76 @@ ESX_VI__TEMPLATE__DESERIALIZE(PerfEntityMetric,
 
 /* esxVI_PerfEntityMetric_DeserializeList */
 ESX_VI__TEMPLATE__LIST__DESERIALIZE(PerfEntityMetric);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: TaskInfo
+ */
+
+/* esxVI_TaskInfo_Alloc */
+ESX_VI__TEMPLATE__ALLOC(TaskInfo);
+
+/* esxVI_TaskInfo_Free */
+ESX_VI__TEMPLATE__FREE(TaskInfo,
+{
+    esxVI_TaskInfo_Free(&item->_next);
+
+    VIR_FREE(item->key);
+    esxVI_ManagedObjectReference_Free(&item->task);
+    VIR_FREE(item->name);
+    VIR_FREE(item->descriptionId);
+    esxVI_ManagedObjectReference_Free(&item->entity);
+    VIR_FREE(item->entityName);
+    /*esxVI_ManagedObjectReference_Free(&item->locked);*//* FIXME */
+    /*esxVI_MethodFault_Free(&item->error);*//* FIXME */
+    esxVI_AnyType_Free(&item->result);
+    esxVI_Int_Free(&item->progress);
+    /*esxVI_TaskReason_Free(&item->reason);*//* FIXME */
+    esxVI_DateTime_Free(&item->queueTime);
+    esxVI_DateTime_Free(&item->startTime);
+    esxVI_DateTime_Free(&item->completeTime);
+    esxVI_Int_Free(&item->eventChainId);
+});
+
+/* esxVI_TaskInfo_CastFromAnyType */
+ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(TaskInfo);
+
+/* esxVI_TaskInfo_AppendToList */
+ESX_VI__TEMPLATE__LIST__APPEND(TaskInfo);
+
+/* esxVI_TaskInfo_Deserialize */
+ESX_VI__TEMPLATE__DESERIALIZE(TaskInfo,
+{
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, key);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference,
+                                                     "Task", task);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, name);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, descriptionId);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_EXPECTED(ManagedObjectReference,
+                                                     NULL, entity);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, entityName);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(locked); /* FIXME */
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(TaskInfoState, state);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Boolean, cancelled);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Boolean, cancelable);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(error); /* FIXME */
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(AnyType, result);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, progress);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_NOOP(reason); /* FIXME */
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, queueTime);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, startTime);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(DateTime, completeTime);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, eventChainId);
+},
+{
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(key);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(task);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(descriptionId);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(state);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(cancelled);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(cancelable);
+    /*ESX_VI__TEMPLATE__PROPERTY__REQUIRED(reason);*//* FIXME */
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(queueTime);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(eventChainId);
+});
diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h
index 32ccda6..4183324 100644
--- a/src/esx/esx_vi_types.h
+++ b/src/esx/esx_vi_types.h
@@ -90,13 +90,16 @@ typedef struct _esxVI_ResourcePoolResourceUsage esxVI_ResourcePoolResourceUsage;
 typedef struct _esxVI_VirtualMachineConfigSpec esxVI_VirtualMachineConfigSpec;
 typedef struct _esxVI_Event esxVI_Event;
 typedef struct _esxVI_UserSession esxVI_UserSession;
+typedef struct _esxVI_VirtualMachineQuestionInfo esxVI_VirtualMachineQuestionInfo;
 typedef struct _esxVI_ElementDescription esxVI_ElementDescription;
+typedef struct _esxVI_ChoiceOption esxVI_ChoiceOption;
 typedef struct _esxVI_PerfMetricId esxVI_PerfMetricId;
 typedef struct _esxVI_PerfCounterInfo esxVI_PerfCounterInfo;
 typedef struct _esxVI_PerfQuerySpec esxVI_PerfQuerySpec;
 typedef struct _esxVI_PerfSampleInfo esxVI_PerfSampleInfo;
 typedef struct _esxVI_PerfMetricIntSeries esxVI_PerfMetricIntSeries;
 typedef struct _esxVI_PerfEntityMetric esxVI_PerfEntityMetric;
+typedef struct _esxVI_TaskInfo esxVI_TaskInfo;
 
 
 
@@ -403,6 +406,8 @@ enum _esxVI_TaskInfoState {
 int esxVI_TaskInfoState_CastFromAnyType(virConnectPtr conn,
                                         esxVI_AnyType *anyType,
                                         esxVI_TaskInfoState *taskInfoState);
+int esxVI_TaskInfoState_Deserialize(virConnectPtr conn, xmlNodePtr node,
+                                    esxVI_TaskInfoState *taskInfoState);
 
 
 
@@ -480,11 +485,19 @@ void esxVI_ManagedObjectReference_Free
 int esxVI_ManagedObjectReference_DeepCopy(virConnectPtr conn,
                                           esxVI_ManagedObjectReference **dest,
                                           esxVI_ManagedObjectReference *src);
+int esxVI_ManagedObjectReference_AppendToList
+      (virConnectPtr conn,
+       esxVI_ManagedObjectReference **managedObjectReferenceList,
+       esxVI_ManagedObjectReference *managedObjectReference);
 int esxVI_ManagedObjectReference_CastFromAnyType(virConnectPtr conn,
                                                  esxVI_AnyType *anyType,
                                                  esxVI_ManagedObjectReference
                                                  **managedObjectReference,
                                                  const char *expectedType);
+int esxVI_ManagedObjectReference_CastListFromAnyType
+      (virConnectPtr conn, esxVI_AnyType *anyType,
+       esxVI_ManagedObjectReference **managedObjectReferenceList,
+       const char *expectedType);
 int esxVI_ManagedObjectReference_Serialize
       (virConnectPtr conn,
        esxVI_ManagedObjectReference *managedObjectReference,
@@ -1065,6 +1078,32 @@ int esxVI_UserSession_Deserialize(virConnectPtr conn, xmlNodePtr node,
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: VirtualMachineQuestionInfo
+ */
+
+/* FIXME: implement the rest */
+struct _esxVI_VirtualMachineQuestionInfo {
+    char *id;                                              /* required */
+    char *text;                                            /* required */
+    esxVI_ChoiceOption *choice;                            /* required */
+    /*esxVI_VirtualMachineMessage *message;*/              /* optional, list */
+};
+
+int esxVI_VirtualMachineQuestionInfo_Alloc
+      (virConnectPtr conn,
+       esxVI_VirtualMachineQuestionInfo **virtualMachineQuestionInfo);
+void esxVI_VirtualMachineQuestionInfo_Free
+       (esxVI_VirtualMachineQuestionInfo **virtualMachineQuestionInfo);
+int esxVI_VirtualMachineQuestionInfo_CastFromAnyType
+      (virConnectPtr conn, esxVI_AnyType *anyType,
+       esxVI_VirtualMachineQuestionInfo **virtualMachineQuestionInfo);
+int esxVI_VirtualMachineQuestionInfo_Deserialize
+      (virConnectPtr conn, xmlNodePtr node,
+       esxVI_VirtualMachineQuestionInfo **virtualMachineQuestionInfo);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: ElementDescription extends Description
  *
  *          In contrast to SelectionSpec and TraversalSpec just merge
@@ -1087,6 +1126,9 @@ int esxVI_ElementDescription_Alloc
       (virConnectPtr conn, esxVI_ElementDescription **elementDescription);
 void esxVI_ElementDescription_Free
        (esxVI_ElementDescription **elementDescription);
+int esxVI_ElementDescription_AppendToList
+      (virConnectPtr conn, esxVI_ElementDescription **elementDescriptionList,
+       esxVI_ElementDescription *elementDescription);
 int esxVI_ElementDescription_Deserialize
       (virConnectPtr conn, xmlNodePtr node,
        esxVI_ElementDescription **elementDescription);
@@ -1094,6 +1136,31 @@ int esxVI_ElementDescription_Deserialize
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: ChoiceOption extends OptionType
+ *
+ *          In contrast to SelectionSpec and TraversalSpec just merge
+ *          OptionType into ChoiceOption for simplicity, because
+ *          only ChoiceOption is used.
+ */
+
+struct _esxVI_ChoiceOption {
+    /* OptionType */
+    esxVI_Boolean valueIsReadonly;                         /* optional */
+
+    /* ChoiceOption */
+    esxVI_ElementDescription *choiceInfo;                  /* required, list */
+    esxVI_Int *defaultIndex;                               /* optional */
+};
+
+int esxVI_ChoiceOption_Alloc(virConnectPtr conn,
+                             esxVI_ChoiceOption **choiceOption);
+void esxVI_ChoiceOption_Free(esxVI_ChoiceOption **choiceOption);
+int esxVI_ChoiceOption_Deserialize(virConnectPtr conn, xmlNodePtr node,
+                                   esxVI_ChoiceOption **choiceOption);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: PerfMetricId
  */
 
@@ -1272,4 +1339,43 @@ int esxVI_PerfEntityMetric_DeserializeList
       (virConnectPtr conn, xmlNodePtr node,
        esxVI_PerfEntityMetric **perfEntityMetricList);
 
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: TaskInfo
+ */
+
+struct _esxVI_TaskInfo {
+    esxVI_TaskInfo *_next;                                 /* optional */
+
+    char *key;                                             /* required */
+    esxVI_ManagedObjectReference *task;                    /* required */
+    char *name;                                            /* optional */
+    char *descriptionId;                                   /* required */
+    esxVI_ManagedObjectReference *entity;                  /* optional */
+    char *entityName;                                      /* optional */
+    /*esxVI_ManagedObjectReference *locked;*/                  /* optional, list *//* FIXME */
+    esxVI_TaskInfoState state;                             /* required */
+    esxVI_Boolean cancelled;                               /* required */
+    esxVI_Boolean cancelable;                              /* required */
+    /*esxVI_MethodFault *error;*/                              /* optional *//* FIXME */
+    esxVI_AnyType *result;                                 /* optional */
+    esxVI_Int *progress;                                   /* optional */
+    /*esxVI_TaskReason *reason;*/                              /* required *//* FIXME */
+    esxVI_DateTime *queueTime;                             /* required */
+    esxVI_DateTime *startTime;                             /* optional */
+    esxVI_DateTime *completeTime;                          /* optional */
+    esxVI_Int *eventChainId;                               /* required */
+};
+
+int esxVI_TaskInfo_Alloc(virConnectPtr conn, esxVI_TaskInfo **taskInfo);
+void esxVI_TaskInfo_Free(esxVI_TaskInfo **taskInfoList);
+int esxVI_TaskInfo_CastFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType,
+                                   esxVI_TaskInfo **taskInfo);
+int esxVI_TaskInfo_AppendToList(virConnectPtr conn,
+                                esxVI_TaskInfo **taskInfoList,
+                                esxVI_TaskInfo *taskInfo);
+int esxVI_TaskInfo_Deserialize(virConnectPtr conn, xmlNodePtr node,
+                               esxVI_TaskInfo **taskInfo);
+
 #endif /* __ESX_VI_TYPES_H__ */
-- 
1.6.0.4




More information about the libvir-list mailing list