[libvirt] [PATCH 07/16] hyperv: implement ability to send xml soap requests

Jason Miesionczek jmiesionczek at datto.com
Tue Aug 9 12:39:15 UTC 2016


also added ability to get/set auto start
---
 src/hyperv/hyperv_driver.c | 101 +++++++
 src/hyperv/hyperv_wmi.c    | 670 ++++++++++++++++++++++++++++++++++++++++++++-
 src/hyperv/hyperv_wmi.h    |  58 ++++
 src/hyperv/openwsman.h     |   4 +
 4 files changed, 827 insertions(+), 6 deletions(-)

diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index 861d5ab..aea7837 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -1604,6 +1604,105 @@ hypervNodeGetFreeMemory(virConnectPtr conn)
     return res;
 }
 
+static int
+hypervDomainSetAutostart(virDomainPtr domain, int autostart)
+{
+    int result = -1;
+    invokeXmlParam *params = NULL;
+    hypervPrivate *priv = domain->conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    virBuffer queryVssd = VIR_BUFFER_INITIALIZER;
+    Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL;
+    properties_t *tab_props = NULL;
+    eprParam eprparam;
+    embeddedParam embeddedparam;
+    int nb_params;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService";
+
+    virUUIDFormat(domain->uuid, uuid_string);
+
+    /* Prepare EPR param */
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string);
+    eprparam.query = &query;
+    eprparam.wmiProviderURI = ROOT_VIRTUALIZATION;
+
+    /* Prepare EMBEDDED param */
+    virBufferAsprintf(&queryVssd,
+                      "associators of "
+                      "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+                      "Name=\"%s\"} "
+                      "where AssocClass = Msvm_SettingsDefineState "
+                      "ResultClass = Msvm_VirtualSystemSettingData",
+                      uuid_string);
+
+    if (hypervGetMsvmVirtualSystemSettingDataList(priv, &queryVssd, &virtualSystemSettingData) < 0)
+        goto cleanup;
+
+    embeddedparam.nbProps = 2;
+    if (VIR_ALLOC_N(tab_props, embeddedparam.nbProps) < 0)
+        goto cleanup;
+    (*tab_props).name = "AutomaticStartupAction";
+    (*tab_props).val = autostart ? "2" : "0";
+    (*(tab_props+1)).name = "InstanceID";
+    (*(tab_props+1)).val = virtualSystemSettingData->data->InstanceID;
+
+    embeddedparam.instanceName =  "Msvm_VirtualSystemGlobalSettingData";
+    embeddedparam.prop_t = tab_props;
+
+    /* Create invokeXmlParam tab */
+    nb_params = 2;
+    if (VIR_ALLOC_N(params, nb_params) < 0)
+        goto cleanup;
+    (*params).name = "ComputerSystem";
+    (*params).type = EPR_PARAM;
+    (*params).param = &eprparam;
+    (*(params+1)).name = "SystemSettingData";
+    (*(params+1)).type = EMBEDDED_PARAM;
+    (*(params+1)).param = &embeddedparam;
+
+    result = hypervInvokeMethod(priv, params, nb_params, "ModifyVirtualSystem",
+                             MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector);
+
+ cleanup:
+    hypervFreeObject(priv, (hypervObject *) virtualSystemSettingData);
+    VIR_FREE(tab_props);
+    VIR_FREE(params);
+    virBufferFreeAndReset(&query);
+    virBufferFreeAndReset(&queryVssd);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainGetAutostart(virDomainPtr domain, int *autostart)
+{
+    int result = -1;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    hypervPrivate *priv = domain->conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_VirtualSystemGlobalSettingData *vsgsd = NULL;
+
+    virUUIDFormat(domain->uuid, uuid_string);
+    virBufferAddLit(&query, MSVM_VIRTUALSYSTEMGLOBALSETTINGDATA_WQL_SELECT);
+    virBufferAsprintf(&query, "where SystemName = \"%s\"", uuid_string);
+
+    if (hypervGetMsvmVirtualSystemGlobalSettingDataList(priv, &query, &vsgsd) < 0)
+        goto cleanup;
+
+    *autostart = vsgsd->data->AutomaticStartupAction;
+    result = 0;
+
+ cleanup:
+    hypervFreeObject(priv, (hypervObject *) vsgsd);
+    virBufferFreeAndReset(&query);
+
+    return result;
+}
+
 static virHypervisorDriver hypervHypervisorDriver = {
     .name = "Hyper-V",
     .connectOpen = hypervConnectOpen, /* 0.9.5 */
@@ -1645,6 +1744,8 @@ static virHypervisorDriver hypervHypervisorDriver = {
     .domainGetMaxVcpus = hypervDomainGetMaxVcpus, /* 1.2.10 */
     .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 1.2.10 */
     .domainGetVcpus = hypervDomainGetVcpus, /* 1.2.10 */
+    .domainSetAutostart = hypervDomainSetAutostart, /* 1.2.10 */
+    .domainGetAutostart = hypervDomainGetAutostart, /* 1.2.10 */
 };
 
 /* Retrieves host system UUID  */
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
index 13acd09..51d9b43 100644
--- a/src/hyperv/hyperv_wmi.c
+++ b/src/hyperv/hyperv_wmi.c
@@ -23,6 +23,7 @@
  */
 
 #include <config.h>
+#include <wsman-soap.h>  /* Where struct _WsXmlDoc is defined (necessary to dereference WsXmlDocH type) */
 
 #include "internal.h"
 #include "virerror.h"
@@ -33,15 +34,10 @@
 #include "hyperv_private.h"
 #include "hyperv_wmi.h"
 #include "virstring.h"
+#include "hyperv_wmi_cimtypes.generated.h"
 
 #define WS_SERIALIZER_FREE_MEM_WORKS 0
 
-#define ROOT_CIMV2 \
-    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*"
-
-#define ROOT_VIRTUALIZATION \
-    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*"
-
 #define VIR_FROM_THIS VIR_FROM_HYPERV
 
 
@@ -667,6 +663,668 @@ hypervMsvmComputerSystemFromDomain(virDomainPtr domain,
     return 0;
 }
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * hypervInvokeMethod
+ *   Function to invoke WSMAN request with simple, EPR or embedded parameters
+ */
+
+/* Create XML structure */
+static int
+hypervCreateXmlStruct(const char *methodName, const char *classURI,
+                      WsXmlDocH *xmlDocRoot, WsXmlNodeH *xmlNodeMethod)
+{
+    virBuffer method_buff = VIR_BUFFER_INITIALIZER;
+    char *methodNameInput = NULL;
+
+    virBufferAsprintf(&method_buff, "%s_INPUT", methodName);
+    methodNameInput = virBufferContentAndReset(&method_buff);
+
+    if (methodNameInput == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not create Xml Doc"));
+        goto cleanup;
+    }
+
+    *xmlDocRoot = ws_xml_create_doc(NULL, methodNameInput);
+    if (*xmlDocRoot == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not create Xml Doc with given parameter xmlDocRoot"));
+        goto cleanup;
+    }
+
+    *xmlNodeMethod = xml_parser_get_root(*xmlDocRoot);
+    if (*xmlNodeMethod == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not get xmlDocRoot root node"));
+        goto cleanup;
+    }
+
+    /* Add namespace to xmlNodeMethode */
+    ws_xml_set_ns(*xmlNodeMethod, classURI, "p");
+
+    VIR_FREE(methodNameInput);
+    return 0;
+
+ cleanup:
+
+    virBufferFreeAndReset(&method_buff);
+    VIR_FREE(methodNameInput);
+    if (*xmlDocRoot != NULL) {
+        ws_xml_destroy_doc(*xmlDocRoot);
+        *xmlDocRoot = NULL;
+    }
+
+    return -1;
+}
+
+
+/* Look for the type of a given property class and specifies if it is an array */
+static int
+hypervGetPropType(const char *className, const char *propName, const char **propType, bool *isArray)
+{
+    int i, y;
+
+    i = 0;
+    while (cimClasses[i].name[0] != '\0') {
+        if (STREQ(cimClasses[i].name, className)){
+            y = 0;
+            while (cimClasses[i].cimTypesPtr[y].name[0] != '\0') {
+                if (STREQ(cimClasses[i].cimTypesPtr[y].name, propName)){
+                    *propType = cimClasses[i].cimTypesPtr[y].type;
+                    *isArray = cimClasses[i].cimTypesPtr[y].isArray;
+                    return 0;
+                }
+                y++;
+            }
+            break;
+        }
+        i++;
+    }
+
+    return -1;
+}
+
+
+/* Adding an Simple param node to a parent node given in parameter */
+static int
+hypervAddSimpleParam(const char *paramName, const char* value,
+                     const char *classURI, WsXmlNodeH *parentNode)
+{
+    int result = -1;
+    WsXmlNodeH xmlNodeParam = NULL;
+
+    xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, value);
+    if (xmlNodeParam == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not create simple param"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    return result;
+}
+
+
+/* Adding EPR param node to a parent node given in parameter */
+static int
+hypervAddEprParam(const char *paramName, virBufferPtr query, const char *root,
+                  const char *classURI, WsXmlNodeH *parentNode, WsXmlDocH doc, hypervPrivate *priv)
+{
+
+    int result = -1;
+    WsXmlNodeH xmlNodeParam = NULL;
+    WsXmlNodeH xmlNodTemp = NULL;
+    WsXmlNodeH xmlNodeAdr = NULL;
+    WsXmlNodeH xmlNodeRef = NULL;
+    xmlNodePtr xmlNodeAdrPtr = NULL;
+    xmlNodePtr xmlNodeRefPtr = NULL;
+    WsXmlDocH xmlDocResponse = NULL;
+    xmlDocPtr docPtr = (xmlDocPtr) doc->parserDoc;
+    WsXmlNsH ns = NULL;
+    client_opt_t *options = NULL;
+    filter_t *filter = NULL;
+    char *enumContext = NULL;
+    char *query_string = NULL;
+
+    /* Request options and filter */
+    options = wsmc_options_init();
+
+    if (options == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not initialize options"));
+        goto cleanup;
+    }
+
+    wsmc_set_action_option(options, FLAG_ENUMERATION_ENUM_EPR);
+
+    query_string = virBufferContentAndReset(query);
+    filter = filter_create_simple(WSM_WQL_FILTER_DIALECT, query_string);
+    if (filter == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not create filter"));
+        goto cleanup;
+    }
+
+    /* Invoke enumerate action*/
+    xmlDocResponse = wsmc_action_enumerate(priv->client,root, options, filter);
+
+    /* Check return value */
+    if (hyperyVerifyResponse(priv->client, xmlDocResponse, "enumeration") < 0) {
+        goto cleanup;
+    }
+
+    /* Get enumerate conext*/
+    enumContext = wsmc_get_enum_context(xmlDocResponse);
+
+    ws_xml_destroy_doc(xmlDocResponse);
+
+
+    /* Invoke pull action*/
+    xmlDocResponse = wsmc_action_pull(priv->client, classURI, options, filter, enumContext);
+
+    /* Check return value */
+    if (hyperyVerifyResponse(priv->client, xmlDocResponse, "pull") < 0) {
+        goto cleanup;
+    }
+
+    /* Extract EPR nodes childs */
+    xmlNodTemp = ws_xml_get_soap_body(xmlDocResponse);
+    if (xmlNodTemp == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup SOAP body"));
+        goto cleanup;
+    }
+
+    xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP);
+    if (xmlNodTemp == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup pull response"));
+        goto cleanup;
+    }
+
+    xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ENUMERATION, WSENUM_ITEMS);
+    if (xmlNodTemp == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup pull response items"));
+        goto cleanup;
+    }
+
+    xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_EPR);
+    if (xmlNodTemp == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup pull response item EPR"));
+        goto cleanup;
+    }
+
+    xmlNodeAdr = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_ADDRESS);
+    if (xmlNodeAdr == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup pull response item ADDRESS"));
+        goto cleanup;
+    }
+    xmlNodeAdrPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeAdr, docPtr, 1);
+    if (xmlNodeAdrPtr == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not copy item ADDRESS"));
+        goto cleanup;
+    }
+
+    xmlNodeRef = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS);
+    if (xmlNodeRef == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not lookup pull response item REFERENCE PARAMETERS"));
+        goto cleanup;
+    }
+    xmlNodeRefPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeRef, docPtr, 1);
+    if (xmlNodeRefPtr == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not copy item REFERENCE PARAMETERS"));
+        goto cleanup;
+    }
+
+    /* Build XmlDoc with adding previous EPR nodes childs */
+    xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, NULL);
+    if (xmlNodeParam == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not add child node to xmlNodeParam"));
+        goto cleanup;
+    }
+
+/*
+  The folowing line has been commented because of a memory corruption issue reported in the openwsman library
+  [ issue #43 - xml_parser_ns_add: alloc item size, not pointer size ]
+  xmlNodeSetLang((xmlNodePtr) xmlNodeParam, BAD_CAST "en-US");
+*/
+    ns = ws_xml_ns_add(xmlNodeParam, "http://schemas.xmlsoap.org/ws/2004/08/addressing", "a");
+    if (ns == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not set namespace adressing to xmlNodeParam"));
+        goto cleanup;
+    }
+
+    ns = NULL;
+    ns = ws_xml_ns_add(xmlNodeParam, "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", "w");
+    if (ns == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not set namespace wsman to xmlNodeParam"));
+        goto cleanup;
+    }
+
+    if (xmlAddChild((xmlNodePtr) *parentNode,(xmlNodePtr) xmlNodeParam) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not add child to xml parent node"));
+        goto cleanup;
+    }
+
+    if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeAdrPtr) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not add child to xml parent node"));
+        goto cleanup;
+    }
+
+    if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeRefPtr) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not add child to xml parent node"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    if (options != NULL) {
+        wsmc_options_destroy(options);
+    }
+    if (filter != NULL) {
+        filter_destroy(filter);
+    }
+    ws_xml_destroy_doc(xmlDocResponse);
+    VIR_FREE(enumContext);
+    VIR_FREE(query_string);
+
+    return result;
+}
+
+
+/* Adding an Embedded Instance node to a parent node given in parameter */
+static int
+hypervAddEmbeddedParam(properties_t *prop_t, int nbProps, const char *paramName,
+                       const char *instanceName, const char *classURI, WsXmlNodeH *parentNode)
+{
+
+    int result = -1;
+    WsXmlNodeH xmlNodeInstance = NULL;
+    WsXmlNodeH xmlNodeProperty = NULL;
+    WsXmlNodeH xmlNodeParam = NULL;
+    WsXmlNodeH xmlNodeArray = NULL;
+    WsXmlDocH xmlDocTemp = NULL;
+    WsXmlDocH xmlDocCdata = NULL;
+    xmlBufferPtr xmlBufferNode = NULL;
+    const xmlChar *xmlCharCdataContent = NULL;
+    xmlNodePtr xmlNodeCdata = NULL;
+    const char *type = NULL;
+    bool isArray = false;
+    int len = 0;
+    int	i = 0;
+
+    /* Add child to given parent node*/
+    xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, NULL);
+    if (xmlNodeParam == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not add child node to xmlNodeParam"));
+        goto cleanup;
+    }
+
+    /* Create temp Xml doc */
+    /* INSTANCE node */
+    xmlDocTemp = ws_xml_create_doc(NULL, "INSTANCE");
+    if (xmlDocTemp == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not create temporary Xml doc"));
+        goto cleanup;
+    }
+
+    xmlNodeInstance = xml_parser_get_root(xmlDocTemp);
+    if (xmlNodeInstance == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not get root of temporary Xml doc"));
+        goto cleanup;
+    }
+
+    /* Add CLASSNAME node to INSTANCE node */
+    if (ws_xml_add_node_attr(xmlNodeInstance, NULL, "CLASSNAME", instanceName) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not add attribute to node "));
+        goto cleanup;
+    }
+
+    /* Property nodes */
+    while (i < nbProps) {
+
+        if (prop_t[i].name == NULL && prop_t[i].val == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not get properties from array"));
+            goto cleanup;
+        }
+
+        if (hypervGetPropType(instanceName, prop_t[i].name, &type, &isArray) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not get properties from array"));
+            goto cleanup;
+        }
+
+        xmlNodeProperty = ws_xml_add_child(xmlNodeInstance, NULL,
+                                           isArray ? "PROPERTY.ARRAY" : "PROPERTY", NULL);
+        if (xmlNodeProperty == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not add child to node"));
+            goto cleanup;
+        }
+
+        if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "NAME", prop_t[i].name) == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not add attribute to node"));
+            goto cleanup;
+        }
+
+        if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "TYPE", type) == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not add attribute to node"));
+            goto cleanup;
+        }
+
+        /* Add the node VALUE.ARRAY if the attribute is an array */
+        if (isArray) {
+            xmlNodeArray = ws_xml_add_child(xmlNodeProperty, NULL, "VALUE.ARRAY", NULL);
+            if (xmlNodeArray == NULL) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("Could not add child to node"));
+                goto cleanup;
+            }
+        }
+
+        if (ws_xml_add_child(isArray ? xmlNodeArray : xmlNodeProperty, NULL, "VALUE", prop_t[i].val) == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           "%s",
+                           _("Could not add child to node"));
+            goto cleanup;
+        }
+
+        xmlNodeArray = NULL;
+        xmlNodeProperty = NULL;
+        i++;
+    }
+
+    /* Create CDATA node */
+    xmlBufferNode = xmlBufferCreate();
+    if (xmlNodeDump(xmlBufferNode, (xmlDocPtr) xmlDocTemp->parserDoc, (xmlNodePtr) xmlNodeInstance, 0, 0) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not get root of temporary Xml doc"));
+        goto cleanup;
+    }
+
+    len = xmlBufferLength(xmlBufferNode);
+    xmlCharCdataContent = xmlBufferContent(xmlBufferNode);
+    xmlNodeCdata = xmlNewCDataBlock((xmlDocPtr) xmlDocCdata, xmlCharCdataContent, len);
+    if (xmlNodeCdata == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not get root of temporary Xml doc"));
+        goto cleanup;
+    }
+    /* Add CDATA node child to the root node of the main doc given */
+    if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeCdata) == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not get root of temporary Xml doc"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    ws_xml_destroy_doc(xmlDocCdata);
+    ws_xml_destroy_doc(xmlDocTemp);
+    if (xmlBufferNode != NULL)
+        xmlBufferFree(xmlBufferNode);
+
+    return result;
+}
+
+
+/* Call wsmc_action_invoke() function of OpenWsman API with XML tree given in parameters*/
+static int
+hypervInvokeMethodXml(hypervPrivate *priv, WsXmlDocH xmlDocRoot,
+                      const char *methodName, const char *ressourceURI, const char *selector)
+{
+    int result = -1;
+    int returnCode;
+    char *instanceID = NULL;
+    char *xpath_expr_string = NULL;
+    char *returnValue = NULL;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    virBuffer xpath_expr_buff = VIR_BUFFER_INITIALIZER;
+    client_opt_t *options = NULL;
+    WsXmlDocH response = NULL;
+    Msvm_ConcreteJob *concreteJob = NULL;
+    bool completed = false;
+
+    options = wsmc_options_init();
+
+    if (options == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not initialize options"));
+        goto cleanup;
+    }
+
+    wsmc_add_selectors_from_str(options, selector);
+
+    /* Invoke action */
+    response = wsmc_action_invoke(priv->client, ressourceURI, options, methodName, xmlDocRoot);
+
+    virBufferAsprintf(&xpath_expr_buff, "/s:Envelope/s:Body/p:%s_OUTPUT/p:ReturnValue", methodName);
+    xpath_expr_string = virBufferContentAndReset(&xpath_expr_buff);
+
+    if (xpath_expr_string == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not lookup %s for %s invocation"),
+                       "ReturnValue", "RequestStateChange");
+        goto cleanup;
+    }
+
+    /* Check return value */
+    returnValue = ws_xml_get_xpath_value(response, xpath_expr_string);
+
+    VIR_FREE(xpath_expr_string);
+    xpath_expr_string = NULL;
+
+    if (returnValue == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not lookup %s for %s invocation"),
+                       "ReturnValue", "RequestStateChange");
+        goto cleanup;
+    }
+
+    if (virStrToLong_i(returnValue, NULL, 10, &returnCode) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Could not parse return code from '%s'"), returnValue);
+        goto cleanup;
+    }
+
+    if (returnCode == CIM_RETURNCODE_TRANSITION_STARTED) {
+        virBufferAsprintf(&xpath_expr_buff, "/s:Envelope/s:Body/p:%s_OUTPUT/p:Job/a:ReferenceParameters/w:SelectorSet/w:Selector[ Name='InstanceID']", methodName);
+        xpath_expr_string = virBufferContentAndReset(&xpath_expr_buff);
+        if (xpath_expr_string == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Could not lookup %s for %s invocation"),
+                           "InstanceID", "RequestStateChange");
+            goto cleanup;
+        }
+
+        /* Get concrete job object */
+        instanceID = ws_xml_get_xpath_value(response, xpath_expr_string);
+        if (instanceID == NULL) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Could not lookup %s for %s invocation"),
+                           "InstanceID", "RequestStateChange");
+            goto cleanup;
+        }
+
+        /* FIXME: Poll every 100ms until the job completes or fails.
+         *        There seems to be no other way than polling. */
+        while (!completed) {
+            virBufferAddLit(&query, MSVM_CONCRETEJOB_WQL_SELECT);
+            virBufferAsprintf(&query, "where InstanceID = \"%s\"", instanceID);
+
+            if (hypervGetMsvmConcreteJobList(priv, &query, &concreteJob) < 0) {
+                goto cleanup;
+            }
+            if (concreteJob == NULL) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Could not lookup %s for %s invocation"),
+                               "Msvm_ConcreteJob", "RequestStateChange");
+                goto cleanup;
+            }
+
+            switch (concreteJob->data->JobState) {
+                case MSVM_CONCRETEJOB_JOBSTATE_NEW:
+                case MSVM_CONCRETEJOB_JOBSTATE_STARTING:
+                case MSVM_CONCRETEJOB_JOBSTATE_RUNNING:
+                case MSVM_CONCRETEJOB_JOBSTATE_SHUTTING_DOWN:
+                    hypervFreeObject(priv, (hypervObject *) concreteJob);
+                    concreteJob = NULL;
+                    usleep(100 * 1000);  /* Wait 100 ms */
+                    continue;
+
+                case MSVM_CONCRETEJOB_JOBSTATE_COMPLETED:
+                    completed = true;
+                    break;
+
+                case MSVM_CONCRETEJOB_JOBSTATE_TERMINATED:
+                case MSVM_CONCRETEJOB_JOBSTATE_KILLED:
+                case MSVM_CONCRETEJOB_JOBSTATE_EXCEPTION:
+                case MSVM_CONCRETEJOB_JOBSTATE_SERVICE:
+                    goto cleanup;
+
+                default:
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("Concrete job for %s invocation is in unknown state"),
+                                   "RequestStateChange");
+                    goto cleanup;
+            }
+        }
+    }
+    else if (returnCode != CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Invocation of %s returned an error: %s (%d)"),
+                       "RequestStateChange", hypervReturnCodeToString(returnCode),
+                       returnCode);
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    if (options != NULL)
+        wsmc_options_destroy(options);
+    if (response != NULL)
+        ws_xml_destroy_doc(response);
+    VIR_FREE(returnValue);
+    VIR_FREE(instanceID);
+    VIR_FREE(xpath_expr_string);
+    hypervFreeObject(priv, (hypervObject *) concreteJob);
+    virBufferFreeAndReset(&query);
+    virBufferFreeAndReset(&xpath_expr_buff);
+
+    return result;
+}
+
+
+/* Calls the invoke method by passing provided parameters as an XML tree */
+int
+hypervInvokeMethod(hypervPrivate *priv, invokeXmlParam *param_t, int nbParameters,
+                   const char* methodName, const char* providerURI, const char *selector)
+{
+    int result = -1;
+    WsXmlDocH doc = NULL;
+    WsXmlNodeH methodNode = NULL;
+    simpleParam *simple;
+    eprParam *epr;
+    embeddedParam *embedded;
+    int i =0;
+
+    if (hypervCreateXmlStruct(methodName,providerURI,&doc,&methodNode) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Could not create xml base structure"));
+        goto cleanup;
+    }
+
+    /* Process parameters among the three allowed types */
+    while ( i < nbParameters) {
+        switch (param_t[i].type) {
+            case SIMPLE_PARAM:
+                simple = (simpleParam *) param_t[i].param;
+                if (hypervAddSimpleParam(param_t[i].name,simple->value, providerURI, &methodNode) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   "%s",
+                                   _("Could not add embedded instance param to xml base structure"));
+                    goto cleanup;
+                }
+                break;
+            case EPR_PARAM:
+                epr = (eprParam *) param_t[i].param;
+                if (hypervAddEprParam(param_t[i].name, epr->query, epr->wmiProviderURI, providerURI, &methodNode, doc, priv) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   "%s",
+                                   _("Could not add EPR param to xml base structure"));
+                    goto cleanup;
+                }
+                break;
+            case EMBEDDED_PARAM:
+                embedded = (embeddedParam *) param_t[i].param;
+                if (hypervAddEmbeddedParam(embedded->prop_t, embedded->nbProps, param_t[i].name, embedded->instanceName, providerURI, &methodNode) < 0) {
+                    virReportError(VIR_ERR_INTERNAL_ERROR,
+                                   "%s",
+                                   _("Could not add embedded instance param to xml base structure"));
+                    goto cleanup;
+                }
+                break;
+        }
+        i++;
+    }
+
+    /* Call the invoke method */
+    if (hypervInvokeMethodXml(priv, doc, methodName, providerURI, selector) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Error during invocation action"));
+        goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    if (doc != NULL)
+        ws_xml_destroy_doc(doc);
+
+    return result;
+}
+
 
 
 #include "hyperv_wmi.generated.c"
diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
index 5fbbbac..c14d229 100644
--- a/src/hyperv/hyperv_wmi.h
+++ b/src/hyperv/hyperv_wmi.h
@@ -29,7 +29,11 @@
 # include "hyperv_wmi_classes.h"
 # include "openwsman.h"
 
+#define ROOT_CIMV2 \
+    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*"
 
+#define ROOT_VIRTUALIZATION \
+    "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*"
 
 typedef struct _hypervObject hypervObject;
 
@@ -38,6 +42,8 @@ int hyperyVerifyResponse(WsManClient *client, WsXmlDocH response,
 
 
 
+
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * Object
  */
@@ -91,6 +97,58 @@ enum _Msvm_ReturnCode {
 
 const char *hypervReturnCodeToString(int returnCode);
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * hypervInvokeMethod
+ *   Function to invoke WSMAN request with simple, EPR or embedded parameters
+ */
+
+enum _PARAM_Type {
+    SIMPLE_PARAM = 0,
+    EPR_PARAM = 1,
+    EMBEDDED_PARAM = 2,
+};
+
+typedef struct _invokeXmlParam invokeXmlParam;
+struct _invokeXmlParam{
+        const char *name;
+        int type;
+	void *param;
+};
+
+typedef struct _eprParam eprParam;
+struct _eprParam{
+        virBufferPtr query;
+	const char *wmiProviderURI;
+};
+
+typedef struct _simpleParam simpleParam;
+struct _simpleParam{
+	const char *value;
+};
+
+typedef struct _properties_t properties_t;
+struct _properties_t{
+        const char *name;
+        const char *val;
+};
+
+typedef struct _embeddedParam embeddedParam;
+struct _embeddedParam{
+	const char *instanceName;
+	properties_t *prop_t;
+	int nbProps;
+};
+
+
+int
+hypervInvokeMethod(hypervPrivate *priv,
+                   invokeXmlParam *parameters,
+                   int nbParameters,
+                   const char* methodName,
+                   const char* providerURI,
+                   const char *selector);
+
+
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
diff --git a/src/hyperv/openwsman.h b/src/hyperv/openwsman.h
index f66ed86..27029e7 100644
--- a/src/hyperv/openwsman.h
+++ b/src/hyperv/openwsman.h
@@ -43,4 +43,8 @@
 #  define SER_NS_INT64(ns, n, x) SER_NS_INT64_FLAGS(ns, n, x, 0)
 # endif
 
+/* wsman-xml.h */
+WsXmlDocH ws_xml_create_doc( const char *rootNsUri, const char *rootName);
+WsXmlNodeH xml_parser_get_root(WsXmlDocH doc);
+
 #endif /* __OPENWSMAN_H__ */
-- 
2.7.4




More information about the libvir-list mailing list