[libvirt] [PATCH 09/13] esx: Use occurrence enum to specify expected result of a SOAP call

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


Also move XPath expression composition into esxVI_Context_Execute().
---
 src/esx/esx_vi.c         |  155 +++++++++++++++++++++++++++++-----------------
 src/esx/esx_vi.h         |    8 +-
 src/esx/esx_vi_methods.c |   80 ++++++++++--------------
 3 files changed, 133 insertions(+), 110 deletions(-)

diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index e039a5d..64bf649 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 c2054c8..840a3c3 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 6f9f3a8..be21112 100644
--- a/src/esx/esx_vi_methods.c
+++ b/src/esx/esx_vi_methods.c
@@ -49,9 +49,6 @@
     "</soapenv:Body>"                                                         \
     "</soapenv:Envelope>"
 
-#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;
-- 
1.6.0.4




More information about the libvir-list mailing list