diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index b7ff83bae9e5577c56dc9c2776229a7e41bf55c4..a7498f0a2bd88135eba9d98ed84bd5089f2413b4 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -514,7 +514,7 @@ esxVI_Context_DownloadFile(virConnectPtr conn, esxVI_Context *ctx, goto failure; } else if (responseCode != 200) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d while trying to download '%s'", + "HTTP response code %d for download from '%s'", responseCode, url); goto failure; } @@ -560,7 +560,7 @@ esxVI_Context_UploadFile(virConnectPtr conn, esxVI_Context *ctx, return -1; } else if (responseCode != 200 && responseCode != 201) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d while trying to upload to '%s'", + "HTTP response code %d for upload to '%s'", responseCode, url); return -1; } @@ -570,11 +570,15 @@ esxVI_Context_UploadFile(virConnectPtr conn, esxVI_Context *ctx, int esxVI_Context_Execute(virConnectPtr conn, esxVI_Context *ctx, - const char *request, const char *xpathExpression, - esxVI_Response **response, esxVI_Boolean expectList) + const char *methodName, const char *request, + esxVI_Response **response, esxVI_Occurrence occurrence) { + int result = 0; virBuffer buffer = VIR_BUFFER_INITIALIZER; esxVI_Fault *fault = NULL; + char *xpathExpression = NULL; + xmlXPathContextPtr xpathContext = NULL; + xmlNodePtr responseNode = NULL; if (request == NULL || response == NULL || *response != NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); @@ -608,108 +612,146 @@ esxVI_Context_Execute(virConnectPtr conn, esxVI_Context *ctx, (*response)->content = virBufferContentAndReset(&buffer); - if ((*response)->responseCode == 500 || - (xpathExpression != NULL && (*response)->responseCode == 200)) { + if ((*response)->responseCode == 500 || (*response)->responseCode == 200) { (*response)->document = xmlReadDoc(BAD_CAST (*response)->content, "", NULL, XML_PARSE_NONET); if ((*response)->document == NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "Could not parse XML response"); + "Response for call to '%s' could not be parsed", + methodName); goto failure; } if (xmlDocGetRootElement((*response)->document) == NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "XML response is an empty document"); + "Response for call to '%s' is an empty XML document", + methodName); goto failure; } - (*response)->xpathContext = xmlXPathNewContext((*response)->document); + xpathContext = xmlXPathNewContext((*response)->document); - if ((*response)->xpathContext == NULL) { + if (xpathContext == NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Could not create XPath context"); goto failure; } - xmlXPathRegisterNs((*response)->xpathContext, BAD_CAST "soapenv", + xmlXPathRegisterNs(xpathContext, BAD_CAST "soapenv", BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/"); - xmlXPathRegisterNs((*response)->xpathContext, BAD_CAST "vim", - BAD_CAST "urn:vim25"); + xmlXPathRegisterNs(xpathContext, BAD_CAST "vim", BAD_CAST "urn:vim25"); if ((*response)->responseCode == 500) { (*response)->node = virXPathNode(conn, "/soapenv:Envelope/soapenv:Body/soapenv:Fault", - (*response)->xpathContext); + xpathContext); if ((*response)->node == NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d. VI Fault is unknown, " - "XPath evaluation failed", - (int)(*response)->responseCode); + "HTTP response code %d for call to '%s'. " + "Fault is unknown, XPath evaluation failed", + (*response)->responseCode, methodName); goto failure; } if (esxVI_Fault_Deserialize(conn, (*response)->node, &fault) < 0) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d. VI Fault is unknown, " - "deserialization failed", - (int)(*response)->responseCode); + "HTTP response code %d for call to '%s'. " + "Fault is unknown, deserialization failed", + (*response)->responseCode, methodName); goto failure; } ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d. VI Fault: %s - %s", - (int)(*response)->responseCode, - fault->faultcode, fault->faultstring); - + "HTTP response code %d for call to '%s'. " + "Fault: %s - %s", (*response)->responseCode, + methodName, fault->faultcode, fault->faultstring); goto failure; - } else if (expectList == esxVI_Boolean_True) { - xmlNodePtr *nodeSet = NULL; - int nodeSet_size; + } else { + if (virAsprintf(&xpathExpression, + "/soapenv:Envelope/soapenv:Body/vim:%sResponse", + methodName) < 0) { + virReportOOMError(conn); + goto failure; + } - nodeSet_size = virXPathNodeSet(conn, xpathExpression, - (*response)->xpathContext, - &nodeSet); + responseNode = virXPathNode(conn, xpathExpression, xpathContext); - if (nodeSet_size < 0) { + if (responseNode == NULL) { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "XPath evaluation of '%s' failed", - xpathExpression); + "XPath evaluation of response for call to '%s' " + "failed", methodName); goto failure; - } else if (nodeSet_size == 0) { - (*response)->node = NULL; - } else { - (*response)->node = nodeSet[0]; } - VIR_FREE(nodeSet); - } else { - (*response)->node = virXPathNode(conn, xpathExpression, - (*response)->xpathContext); + xpathContext->node = responseNode; + (*response)->node = virXPathNode(conn, "./vim:returnval", + xpathContext); - if ((*response)->node == NULL) { + switch (occurrence) { + case esxVI_Occurrence_RequiredItem: + if ((*response)->node == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Call to '%s' returned an empty result, " + "expecting a non-empty result", methodName); + goto failure; + } + + break; + + case esxVI_Occurrence_OptionalItem: + if ((*response)->node != NULL && + (*response)->node->next != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Call to '%s' returned a list, expecting " + "exactly one item", methodName); + goto failure; + } + + break; + + case esxVI_Occurrence_List: + /* Any amount of items is valid */ + break; + + case esxVI_Occurrence_None: + if ((*response)->node != NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Call to '%s' returned something, expecting " + "an empty result", methodName); + goto failure; + } + + break; + + default: ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "XPath evaluation of '%s' failed", - xpathExpression); + "Invalid argument (occurrence)"); goto failure; } } - } else if ((*response)->responseCode != 200) { + } else { ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, - "HTTP response code %d", (*response)->responseCode); + "HTTP response code %d for call to '%s'", + (*response)->responseCode, methodName); goto failure; } - return 0; + cleanup: + VIR_FREE(xpathExpression); + xmlXPathFreeContext(xpathContext); + + return result; failure: virBufferFreeAndReset(&buffer); esxVI_Response_Free(response); esxVI_Fault_Free(&fault); - return -1; + result = -1; + + goto cleanup; } @@ -726,8 +768,6 @@ ESX_VI__TEMPLATE__FREE(Response, { VIR_FREE(item->content); - xmlXPathFreeContext(item->xpathContext); - if (item->document != NULL) { xmlFreeDoc(item->document); } @@ -2229,24 +2269,23 @@ esxVI_StartVirtualMachineTask(virConnectPtr conn, esxVI_Context *ctx, esxVI_ManagedObjectReference **task) { int result = 0; - char *xpathExpression = NULL; + char *methodName = NULL; esxVI_Response *response = NULL; - if (virAsprintf(&xpathExpression, - ESX_VI__SOAP__RESPONSE_XPATH("%s_Task"), name) < 0) { + if (virAsprintf(&methodName, "%s_Task", name) < 0) { virReportOOMError(conn); goto failure; } - if (esxVI_Context_Execute(conn, ctx, request, xpathExpression, &response, - esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, methodName, request, &response, + esxVI_Occurrence_RequiredItem) < 0 || esxVI_ManagedObjectReference_Deserialize(conn, response->node, task, "Task") < 0) { goto failure; } cleanup: - VIR_FREE(xpathExpression); + VIR_FREE(methodName); esxVI_Response_Free(&response); return result; @@ -2349,8 +2388,8 @@ esxVI_SimpleVirtualMachineMethod(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, NULL, &response, - esxVI_Boolean_False) < 0) { + if (esxVI_Context_Execute(conn, ctx, name, request, &response, + esxVI_Occurrence_None) < 0) { goto failure; } diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index c2054c8090e6f5a9d64770114b3c8f91278c2360..840a3c3e0c13d6a42961454426bcc80634341ebf 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -62,7 +62,8 @@ enum _esxVI_Occurrence { esxVI_Occurrence_Undefined = 0, esxVI_Occurrence_RequiredItem, esxVI_Occurrence_OptionalItem, - esxVI_Occurrence_List + esxVI_Occurrence_List, + esxVI_Occurrence_None }; @@ -100,8 +101,8 @@ int esxVI_Context_DownloadFile(virConnectPtr conn, esxVI_Context *ctx, int esxVI_Context_UploadFile(virConnectPtr conn, esxVI_Context *ctx, const char *url, const char *content); int esxVI_Context_Execute(virConnectPtr conn, esxVI_Context *ctx, - const char *request, const char *xpathExpression, - esxVI_Response **response, esxVI_Boolean expectList); + const char *methodName, const char *request, + esxVI_Response **response, esxVI_Occurrence occurrence); @@ -113,7 +114,6 @@ struct _esxVI_Response { int responseCode; /* required */ char *content; /* required */ xmlDocPtr document; /* optional */ - xmlXPathContextPtr xpathContext; /* optional */ xmlNodePtr node; /* optional, list */ }; diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index 6f9f3a88a309d240afd731853c9aeea12f07a650..be21112c827c9b3a876ef493a1d2d57f9f8e2882 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -49,9 +49,6 @@ "" \ "" -#define ESX_VI__SOAP__RESPONSE_XPATH(_type) \ - "/soapenv:Envelope/soapenv:Body/vim:"_type"Response/vim:returnval" - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -79,9 +76,8 @@ esxVI_RetrieveServiceContent(virConnectPtr conn, esxVI_Context *ctx, return -1; } - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("RetrieveServiceContent"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "RetrieveServiceContent", request, + &response, esxVI_Occurrence_RequiredItem) < 0 || esxVI_ServiceContent_Deserialize(conn, response->node, serviceContent) < 0) { goto failure; @@ -144,9 +140,8 @@ esxVI_Login(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("Login"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "Login", request, &response, + esxVI_Occurrence_RequiredItem) < 0 || esxVI_UserSession_Deserialize(conn, response->node, userSession) < 0) { goto failure; } @@ -200,8 +195,8 @@ esxVI_Logout(virConnectPtr conn, esxVI_Context *ctx) request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, NULL, &response, - esxVI_Boolean_False) < 0) { + if (esxVI_Context_Execute(conn, ctx, "Logout", request, &response, + esxVI_Occurrence_None) < 0) { goto failure; } @@ -265,9 +260,8 @@ esxVI_SessionIsActive(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("SessionIsActive"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "SessionIsActive", request, + &response, esxVI_Occurrence_RequiredItem) < 0 || esxVI_Boolean_Deserialize(conn, response->node, active) < 0) { goto failure; } @@ -331,9 +325,8 @@ esxVI_RetrieveProperties(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("RetrieveProperties"), - &response, esxVI_Boolean_True) < 0 || + if (esxVI_Context_Execute(conn, ctx, "RetrieveProperties", request, + &response, esxVI_Occurrence_List) < 0 || esxVI_ObjectContent_DeserializeList(conn, response->node, objectContentList) < 0) { goto failure; @@ -608,8 +601,8 @@ esxVI_CancelTask(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, NULL, &response, - esxVI_Boolean_False) < 0) { + if (esxVI_Context_Execute(conn, ctx, "UnregisterVM", request, &response, + esxVI_Occurrence_None) < 0) { goto failure; } @@ -659,8 +652,8 @@ esxVI_UnregisterVM(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, NULL, &response, - esxVI_Boolean_False) < 0) { + if (esxVI_Context_Execute(conn, ctx, "AnswerVM", request, &response, + esxVI_Occurrence_None) < 0) { goto failure; } @@ -781,9 +774,8 @@ esxVI_CreateFilter(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("CreateFilter"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "CreateFilter", request, &response, + esxVI_Occurrence_RequiredItem) < 0 || esxVI_ManagedObjectReference_Deserialize(conn, response->node, propertyFilter, "PropertyFilter") < 0) { @@ -839,8 +831,8 @@ esxVI_DestroyPropertyFilter(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, NULL, &response, - esxVI_Boolean_False) < 0) { + if (esxVI_Context_Execute(conn, ctx, "DestroyPropertyFilter", request, + &response, esxVI_Occurrence_None) < 0) { goto failure; } @@ -901,9 +893,8 @@ esxVI_WaitForUpdates(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("WaitForUpdates"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "WaitForUpdates", request, + &response, esxVI_Occurrence_RequiredItem) < 0 || esxVI_UpdateSet_Deserialize(conn, response->node, updateSet) < 0) { goto failure; } @@ -1003,9 +994,8 @@ esxVI_ValidateMigration(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("ValidateMigration"), - &response, esxVI_Boolean_True) < 0 || + if (esxVI_Context_Execute(conn, ctx, "ValidateMigration", request, + &response, esxVI_Occurrence_List) < 0 || esxVI_Event_DeserializeList(conn, response->node, eventList) < 0) { goto failure; } @@ -1073,9 +1063,8 @@ esxVI_FindByIp(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("FindByIp"), - &response, esxVI_Boolean_False) < 0 || + if (esxVI_Context_Execute(conn, ctx, "FindByIp", request, &response, + esxVI_Occurrence_OptionalItem) < 0 || esxVI_ManagedObjectReference_Deserialize (conn, response->node, managedObjectReference, vmSearch == esxVI_Boolean_True ? "VirtualMachine" @@ -1149,10 +1138,8 @@ esxVI_FindByUuid(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - /* FIXME: Use esxVI_Occurrence instead of expectList */ - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("FindByUuid"), - &response, esxVI_Boolean_True) < 0) { + if (esxVI_Context_Execute(conn, ctx, "FindByUuid", request, &response, + esxVI_Occurrence_OptionalItem) < 0) { goto failure; } @@ -1233,9 +1220,8 @@ esxVI_QueryAvailablePerfMetric(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("QueryAvailablePerfMetric"), - &response, esxVI_Boolean_True) < 0 || + if (esxVI_Context_Execute(conn, ctx, "QueryAvailablePerfMetric", request, + &response, esxVI_Occurrence_List) < 0 || esxVI_PerfMetricId_DeserializeList(conn, response->node, perfMetricIdList) < 0) { goto failure; @@ -1298,9 +1284,8 @@ esxVI_QueryPerfCounter(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("QueryPerfCounter"), - &response, esxVI_Boolean_True) < 0 || + if (esxVI_Context_Execute(conn, ctx, "QueryPerfCounter", request, + &response, esxVI_Occurrence_List) < 0 || esxVI_PerfCounterInfo_DeserializeList(conn, response->node, perfCounterInfoList) < 0) { goto failure; @@ -1363,9 +1348,8 @@ esxVI_QueryPerf(virConnectPtr conn, esxVI_Context *ctx, request = virBufferContentAndReset(&buffer); - if (esxVI_Context_Execute(conn, ctx, request, - ESX_VI__SOAP__RESPONSE_XPATH("QueryPerf"), - &response, esxVI_Boolean_True) < 0 || + if (esxVI_Context_Execute(conn, ctx, "QueryPerf", request, &response, + esxVI_Occurrence_List) < 0 || esxVI_PerfEntityMetric_DeserializeList(conn, response->node, perfEntityMetricList) < 0) { goto failure;