[libvirt] [PATCH v4 3/5] hyperv: add hypervInvokeMethod

Matthias Bolte matthias.bolte at googlemail.com
Sun May 28 16:38:36 UTC 2017


2017-05-19 22:58 GMT+02:00 Sri Ramanujam <sramanujam at datto.com>:
> This commit adds support for invoking methods on remote objects
> via hypervInvokeMethod.
> ---
>  src/hyperv/hyperv_wmi.c | 584 ++++++++++++++++++++++++++++++++++++++++++++++++
>  src/hyperv/hyperv_wmi.h |   3 +
>  src/hyperv/openwsman.h  |   4 +
>  3 files changed, 591 insertions(+)
>
> diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
> index 217a3b2..b847d17 100644
> --- a/src/hyperv/hyperv_wmi.c
> +++ b/src/hyperv/hyperv_wmi.c
> @@ -24,6 +24,7 @@
>   */
>
>  #include <config.h>
> +#include <wsman-soap.h>
>
>  #include "internal.h"
>  #include "virerror.h"
> @@ -34,11 +35,16 @@
>  #include "hyperv_private.h"
>  #include "hyperv_wmi.h"
>  #include "virstring.h"
> +#include "openwsman.h"
> +#include "virlog.h"
>
>  #define WS_SERIALIZER_FREE_MEM_WORKS 0
>
>  #define VIR_FROM_THIS VIR_FROM_HYPERV
>
> +#define HYPERV_JOB_TIMEOUT_MS 5000
> +
> +VIR_LOG_INIT("hyperv.hyperv_wmi");
>
>  static int
>  hypervGetWmiClassInfo(hypervPrivate *priv, hypervWmiClassInfoListPtr list,
> @@ -394,6 +400,584 @@ hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate *priv,
>  }
>
>
> +/*
> + * Serializing parameters to XML and invoking methods
> + */
> +
> +static int
> +hypervGetCimTypeInfo(hypervCimTypePtr typemap, const char *name,
> +        hypervCimTypePtr *property)
> +{
> +    size_t i = 0;
> +    while (typemap[i].name[0] != '\0') {
> +        if (STREQ(typemap[i].name, name)) {
> +            *property = &typemap[i];
> +            return 0;
> +        }
> +        i++;
> +    }
> +
> +    return -1;
> +}
> +
> +
> +static int
> +hypervCreateInvokeXmlDoc(hypervInvokeParamsListPtr params, WsXmlDocH *docRoot)
> +{
> +    int result = -1;
> +    char *method = NULL;
> +    WsXmlNodeH xmlNodeMethod = NULL;
> +
> +    if (virAsprintf(&method, "%s_INPUT", params->method) < 0)
> +        goto cleanup;
> +
> +    *docRoot = ws_xml_create_doc(NULL, method);
> +    if (*docRoot == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not instantiate XML document"));
> +        goto cleanup;
> +    }
> +
> +    xmlNodeMethod = xml_parser_get_root(*docRoot);
> +    if (xmlNodeMethod == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not get root node of XML document"));
> +        goto cleanup;
> +    }
> +
> +    /* add resource URI as namespace */
> +    ws_xml_set_ns(xmlNodeMethod, params->resourceUri, "p");
> +
> +    result = 0;
> +    goto cleanup;

This goto is unnecessary, as the label is the next line anyway.

> + cleanup:
> +    if (result < 0 && *docRoot != NULL) {
> +        ws_xml_destroy_doc(*docRoot);
> +        *docRoot = NULL;
> +    }
> +    VIR_FREE(method);
> +    return result;
> +}
> +
> +static int
> +hypervSerializeSimpleParam(hypervParamPtr p, const char *resourceUri,
> +        WsXmlNodeH *methodNode)
> +{
> +    WsXmlNodeH xmlNodeParam = NULL;
> +
> +    xmlNodeParam = ws_xml_add_child(*methodNode, resourceUri,
> +            p->simple.name, p->simple.value);
> +    if (xmlNodeParam == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not create simple param"));
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int
> +hypervSerializeEprParam(hypervParamPtr p, hypervPrivate *priv,
> +        const char *resourceUri, WsXmlDocH doc, WsXmlNodeH *methodNode)
> +{
> +    int result = -1;
> +    WsXmlNodeH xmlNodeParam = NULL,
> +               xmlNodeTemp = NULL,
> +               xmlNodeAddr = NULL,
> +               xmlNodeRef = NULL;
> +    xmlNodePtr xmlNodeAddrPtr = NULL,
> +               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;
> +
> +    /* init and set up options */
> +    options = wsmc_options_init();
> +    if (!options) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not init options"));
> +        goto cleanup;
> +    }
> +    wsmc_set_action_option(options, FLAG_ENUMERATION_ENUM_EPR);
> +
> +    /* Get query and create filter based on it */
> +    query_string = virBufferContentAndReset(p->epr.query);
> +    filter = filter_create_simple(WSM_WQL_FILTER_DIALECT, query_string);
> +    if (!filter) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create WQL filter"));
> +        goto cleanup;
> +    }
> +
> +    /* enumerate based on the filter from this query */
> +    xmlDocResponse = wsmc_action_enumerate(priv->client, p->epr.info->rootUri,
> +            options, filter);
> +    if (hypervVerifyResponse(priv->client, xmlDocResponse, "enumeration") < 0)
> +        goto cleanup;
> +
> +    /* Get context */
> +    enumContext = wsmc_get_enum_context(xmlDocResponse);
> +    ws_xml_destroy_doc(xmlDocResponse);
> +
> +    /* Pull using filter and enum context */
> +    xmlDocResponse = wsmc_action_pull(priv->client, resourceUri, options,
> +            filter, enumContext);
> +
> +    if (hypervVerifyResponse(priv->client, xmlDocResponse, "pull") < 0)
> +        goto cleanup;
> +
> +    /* drill down and extract EPR node children */
> +    if (!(xmlNodeTemp = ws_xml_get_soap_body(xmlDocResponse))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get SOAP body"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeTemp = ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ENUMERATION,
> +            WSENUM_PULL_RESP))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get response"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeTemp = ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ENUMERATION, WSENUM_ITEMS))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get response items"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeTemp = ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSING, WSA_EPR))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get EPR items"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeAddr = ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSING,
> +                    WSA_ADDRESS))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get EPR address"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeAddrPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeAddr, docPtr, 1))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not copy EPR address"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeRef = ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSING,
> +            WSA_REFERENCE_PARAMETERS))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not lookup EPR item reference parameters"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeRefPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeRef, docPtr, 1))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not copy EPR item reference parameters"));
> +        goto cleanup;
> +    }
> +
> +    /* now build a new xml doc with the EPR node children */
> +    if (!(xmlNodeParam = ws_xml_add_child(*methodNode, resourceUri,
> +                    p->epr.name, NULL))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not add child node to xmlNodeParam"));
> +        goto cleanup;
> +    }
> +
> +    if (!(ns = ws_xml_ns_add(xmlNodeParam,
> +                    "http://schemas.xmlsoap.org/ws/2004/08/addressing", "a"))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not set namespace address for xmlNodeParam"));
> +        goto cleanup;
> +    }
> +
> +    ns = NULL;

Setting ns to NULL is unnecessary as it's set by the next line anyway.

> +    if (!(ns = ws_xml_ns_add(xmlNodeParam,
> +                    "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", "w"))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not set wsman namespace address for xmlNodeParam"));
> +        goto cleanup;
> +    }
> +
> +    if (xmlAddChild((xmlNodePtr) *methodNode, (xmlNodePtr) xmlNodeParam) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not add child to xml parent node"));
> +        goto cleanup;
> +    }
> +
> +    if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeAddrPtr) == 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;
> +    }
> +
> +    /* we did it! */
> +    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;
> +}
> +
> +static int
> +hypervSerializeEmbeddedParam(hypervParamPtr p, const char *resourceUri,
> +        WsXmlNodeH *methodNode)
> +{
> +    int result = -1;
> +    WsXmlNodeH xmlNodeInstance = NULL,
> +               xmlNodeProperty = NULL,
> +               xmlNodeParam = NULL,
> +               xmlNodeArray = NULL;
> +    WsXmlDocH xmlDocTemp = NULL,
> +              xmlDocCdata = NULL;
> +    xmlBufferPtr xmlBufferNode = NULL;
> +    const xmlChar *xmlCharCdataContent = NULL;
> +    xmlNodePtr xmlNodeCdata = NULL;
> +    hypervWmiClassInfoPtr classInfo = p->embedded.info;
> +    virHashKeyValuePairPtr items = NULL;
> +    hypervCimTypePtr property = NULL;
> +    int numKeys = -1;
> +    int len = 0, i = 0;
> +
> +    if (!(xmlNodeParam = ws_xml_add_child(*methodNode, resourceUri, p->embedded.name,
> +                    NULL))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not add child node %s"),
> +                p->embedded.name);
> +        goto cleanup;
> +    }
> +
> +    /* create the temp xml doc */
> +
> +    /* start with the INSTANCE node */
> +    if (!(xmlDocTemp = ws_xml_create_doc(NULL, "INSTANCE"))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not create temporary xml doc"));
> +        goto cleanup;
> +    }
> +
> +    if (!(xmlNodeInstance = xml_parser_get_root(xmlDocTemp))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not get temp xml doc root"));
> +        goto cleanup;
> +    }
> +
> +    /* add CLASSNAME node to INSTANCE node */
> +    if (ws_xml_add_node_attr(xmlNodeInstance, NULL, "CLASSNAME",
> +                classInfo->name) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not add attribute to node"));
> +        goto cleanup;
> +    }
> +
> +    /* retrieve parameters out of hash table */
> +    numKeys = virHashSize(p->embedded.table);
> +    items = virHashGetItems(p->embedded.table, NULL);
> +    if (!items) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not read embedded param hash table"));
> +        goto cleanup;
> +    }
> +
> +    /* Add the parameters */
> +    for (i = 0; i < numKeys; i++) {
> +        const char *name = items[i].key;
> +        const char *value = items[i].value;
> +
> +        if (value != NULL) {
> +            if (hypervGetCimTypeInfo(classInfo->propertyInfo, name,
> +                        &property) < 0) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Could not read type information"));
> +                goto cleanup;
> +            }
> +
> +            if (!(xmlNodeProperty = ws_xml_add_child(xmlNodeInstance, NULL,
> +                            property->isArray ? "PROPERTY.ARRAY" : "PROPERTY",
> +                            NULL))) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Could not add child to XML node"));
> +                goto cleanup;
> +            }
> +
> +            if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "NAME", name) == NULL) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Could not add attribute to XML node"));
> +                goto cleanup;
> +            }
> +
> +            if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "TYPE", property->type) == NULL) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Could not add attribute to XML node"));
> +                goto cleanup;
> +            }
> +
> +            /* If this attribute is an array, add VALUE.ARRAY node */
> +            if (property->isArray) {
> +                if (!(xmlNodeArray = ws_xml_add_child(xmlNodeProperty, NULL,
> +                                "VALUE.ARRAY", NULL))) {
> +                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                            _("Could not add child to XML node"));
> +                    goto cleanup;
> +                }
> +            }
> +
> +            /* add the child */
> +            if (ws_xml_add_child(property->isArray ? xmlNodeArray : xmlNodeProperty,
> +                        NULL, "VALUE", value) == NULL) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Could not add child to XML node"));
> +                goto cleanup;
> +            }
> +
> +            xmlNodeArray = NULL;
> +            xmlNodeProperty = NULL;
> +        }
> +    }
> +
> +    /* 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 temp XML doc"));
> +        goto cleanup;
> +    }
> +
> +    len = xmlBufferLength(xmlBufferNode);
> +    xmlCharCdataContent = xmlBufferContent(xmlBufferNode);
> +    if (!(xmlNodeCdata = xmlNewCDataBlock((xmlDocPtr) xmlDocCdata,
> +                    xmlCharCdataContent, len))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not create CDATA element"));
> +        goto cleanup;
> +    }
> +
> +    /* Add CDATA node to the doc root */
> +    if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeCdata) == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not add CDATA to doc root"));
> +        goto cleanup;
> +    }
> +
> +    /* we did it! */
> +    result = 0;
> +
> + cleanup:
> +    VIR_FREE(items);
> +    ws_xml_destroy_doc(xmlDocCdata);
> +    ws_xml_destroy_doc(xmlDocTemp);
> +    if (xmlBufferNode)
> +        xmlBufferFree(xmlBufferNode);
> +    return result;
> +}
> +
> +
> +/*
> + * hypervInvokeMethod:
> + * @priv: hypervPrivate object associated with the connection
> + * @params: object containing the all necessary information for method
> + * invocation
> + * @res: Optional out parameter to contain the response XML.
> + *
> + * Performs an invocation described by @params, and optionally returns the
> + * XML containing the result. Returns -1 on failure, 0 on success.
> + */
> +int
> +hypervInvokeMethod(hypervPrivate *priv, hypervInvokeParamsListPtr params,
> +        WsXmlDocH *res)
> +{
> +    int result = -1;
> +    size_t i = 0;
> +    int returnCode;
> +    WsXmlDocH paramsDocRoot = NULL;
> +    client_opt_t *options = NULL;
> +    WsXmlDocH response = NULL;
> +    WsXmlNodeH methodNode = NULL;
> +    char *returnValue_xpath = NULL;
> +    char *jobcode_instance_xpath = NULL;
> +    char *returnValue = NULL;
> +    char *instanceID = NULL;
> +    bool completed = false;
> +    virBuffer query = VIR_BUFFER_INITIALIZER;
> +    Msvm_ConcreteJob *job = NULL;
> +    int jobState = -1;
> +    hypervParamPtr p = NULL;
> +    int timeout = HYPERV_JOB_TIMEOUT_MS;
> +
> +    if (hypervCreateInvokeXmlDoc(params, &paramsDocRoot) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                _("Could not create XML document"));
> +        goto cleanup;
> +    }
> +
> +    methodNode = xml_parser_get_root(paramsDocRoot);
> +    if (methodNode == NULL)

Why not report an error here?

> +        goto cleanup;
> +
> +    /* Serialize parameters */
> +    for (i = 0; i < params->nbParams; i++) {
> +        p = &(params->params[i]);
> +
> +        switch (p->type) {
> +            case HYPERV_SIMPLE_PARAM:
> +                if (hypervSerializeSimpleParam(p, params->resourceUri,
> +                            &methodNode) < 0)
> +                    goto cleanup;
> +                break;
> +            case HYPERV_EPR_PARAM:
> +                if (hypervSerializeEprParam(p, priv, params->resourceUri,
> +                            paramsDocRoot, &methodNode) < 0)
> +                    goto cleanup;
> +                break;
> +            case HYPERV_EMBEDDED_PARAM:
> +                if (hypervSerializeEmbeddedParam(p, params->resourceUri,
> +                            &methodNode) < 0)
> +                    goto cleanup;
> +                break;
> +            default:
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                        _("Unknown parameter type"));
> +                goto cleanup;
> +        }
> +    }
> +
> +    /* Invoke the method and get the response */
> +
> +    options = wsmc_options_init();
> +
> +    if (!options) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not init options"));
> +        goto cleanup;
> +    }
> +
> +    wsmc_add_selectors_from_str(options, params->selector);
> +
> +    /* do the invoke */
> +    response = wsmc_action_invoke(priv->client, params->resourceUri, options,
> +            params->method, paramsDocRoot);
> +
> +    /* check return code of invocation */
> +    if (virAsprintf(&returnValue_xpath, "/s:Envelope/s:Body/p:%s_OUTPUT/p:ReturnValue",
> +            params->method) < 0)
> +        goto cleanup;
> +
> +    returnValue = ws_xml_get_xpath_value(response, returnValue_xpath);
> +    if (!returnValue) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Could not get return value for %s invocation"),
> +                       params->method);
> +        goto cleanup;
> +    }
> +
> +    if (virStrToLong_i(returnValue, NULL, 10, &returnCode) < 0)
> +        goto cleanup;
> +
> +    if (returnCode == CIM_RETURNCODE_TRANSITION_STARTED) {
> +        if (virAsprintf(&jobcode_instance_xpath,
> +                    "/s:Envelope/s:Body/p:%s_OUTPUT/p:Job/a:ReferenceParameters/"
> +                    "w:SelectorSet/w:Selector[@Name='InstanceID']",
> +                    params->method) < 0) {
> +            goto cleanup;
> +        }
> +
> +        instanceID = ws_xml_get_xpath_value(response, jobcode_instance_xpath);
> +        if (!instanceID) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("Could not get instance ID for %s invocation"),
> +                           params->method);
> +            goto cleanup;
> +        }
> +
> +        /*
> +         * Poll Hyper-V about the job until either the job completes or fails,
> +         * or 5 minutes have elapsed.
> +         *
> +         * Windows has its own timeout on running WMI method calls (it calls
> +         * these "jobs"), by default set to 1 minute. The administrator can
> +         * change this to whatever they want, however, so we can't rely on it.
> +         *
> +         * Therefore, to avoid waiting in this loop for a very long-running job
> +         * to complete, we instead bail after 5 minutes no matter what. NOTE that
> +         * this does not mean that the remote job has terminated on the Windows
> +         * side! That is up to Windows to control, we don't do anything about it.
> +         */
> +        while (!completed && timeout >= 0) {
> +            virBufferAddLit(&query, MSVM_CONCRETEJOB_WQL_SELECT);
> +            virBufferAsprintf(&query, "where InstanceID = \"%s\"", instanceID);
> +
> +            if (hypervGetMsvmConcreteJobList(priv, &query, &job) < 0
> +                    || job == NULL)
> +                goto cleanup;
> +
> +            jobState = job->data.common->JobState;
> +            switch (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 *) job);
> +                    job = NULL;
> +                    usleep(100 * 1000); /* sleep 100 ms */
> +                    timeout -= 100;
> +                    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, "%s",
> +                                   _("Unknown invocation state"));
> +                    goto cleanup;
> +            }
> +        }
> +        if (!completed && timeout < 0) {
> +            virReportError(VIR_ERR_OPERATION_TIMEOUT,
> +                    _("Timeout waiting for %s invocation"), params->method);
> +            goto cleanup;
> +        }
> +    } else if (returnCode != CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, _("Invocation of %s returned an error: %s (%d)"),
> +                    params->method, hypervReturnCodeToString(returnCode),
> +                    returnCode);
> +        goto cleanup;
> +    }
> +
> +    if (res)
> +        *res = response;
> +
> +    result = 0;
> +
> + cleanup:
> +    if (options)
> +        wsmc_options_destroy(options);
> +    if (response && (res == NULL))
> +        ws_xml_destroy_doc(response);
> +    if (paramsDocRoot)
> +        ws_xml_destroy_doc(paramsDocRoot);
> +    VIR_FREE(returnValue_xpath);
> +    VIR_FREE(jobcode_instance_xpath);
> +    VIR_FREE(returnValue);
> +    VIR_FREE(instanceID);
> +    virBufferFreeAndReset(&query);
> +    hypervFreeObject(priv, (hypervObject *) job);
> +    hypervFreeInvokeParams(params);
> +    return result;
> +}
>
>  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
>   * Object
> diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h
> index 2db5bb7..f39f79f 100644
> --- a/src/hyperv/hyperv_wmi.h
> +++ b/src/hyperv/hyperv_wmi.h
> @@ -151,6 +151,9 @@ int hypervSetEmbeddedProperty(virHashTablePtr table, const char *name,
>  int hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate *priv,
>          const char *name, virHashTablePtr table, hypervWmiClassInfoListPtr info);
>
> +int hypervInvokeMethod(hypervPrivate *priv, hypervInvokeParamsListPtr params,
> +        WsXmlDocH *res);
> +
>  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
>   * CIM/Msvm_ReturnCode
>   */
> diff --git a/src/hyperv/openwsman.h b/src/hyperv/openwsman.h
> index f66ed86..fc2958f 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.9.4
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list



-- 
Matthias Bolte
http://photron.blogspot.com




More information about the libvir-list mailing list