From f66d574541406753cdda83f045f8fe6d3fb2896a Mon Sep 17 00:00:00 2001 From: Matthias Bolte Date: Sun, 15 Nov 2009 22:22:47 +0100 Subject: [PATCH] esx: Add automatic question handling 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 0000000000..36190547c7 --- /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 c7b9e06f1a..9ee18de8e2 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 #include @@ -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}://[@][:][?transport={http|https}][&vcenter=][&no_verify={0|1}] + * URI format: {esx|gsx}://[@][:][?transport={http|https}][&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 35a48e0898..2e24386561 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 c466b443e4..3987f3e6a7 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 1138e8c14b..0b9f26d6a1 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) @@ -1478,6 +1479,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, @@ -1826,6 +1854,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, @@ -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, @@ -2133,9 +2373,110 @@ 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 4b3005e992..a10d8747b1 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 06b5fd4e60..d18e56b09f 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -576,6 +576,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, ""); + + if (esxVI_ManagedObjectReference_Serialize(conn, task, "_this", &buffer, + esxVI_Boolean_True) < 0) { + goto failure; + } + + virBufferAddLit(&buffer, ""); + 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) @@ -625,6 +680,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, ""); + + 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, ""); + 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, diff --git a/src/esx/esx_vi_methods.h b/src/esx/esx_vi_methods.h index 5f3caff9c8..03e4fdf3e5 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 9af9f7399d..aa2f968937 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, @@ -1339,6 +1345,76 @@ esxVI_ManagedObjectReference_CastFromAnyType expectedType); } +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, @@ -2426,6 +2502,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 * @@ -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, { @@ -2462,6 +2576,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 32ccda614e..418332456f 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, @@ -1064,6 +1077,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 * @@ -1087,12 +1126,40 @@ 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); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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__ */ -- GitLab