From nobody Fri May 16 23:40:58 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; dkim=fail spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1495227522764279.0218075393167; Fri, 19 May 2017 13:58:42 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4D78CC05AA54; Fri, 19 May 2017 20:58:41 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 24B9118A3A; Fri, 19 May 2017 20:58:41 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D73A64A48D; Fri, 19 May 2017 20:58:40 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v4JKwEqv012477 for ; Fri, 19 May 2017 16:58:14 -0400 Received: by smtp.corp.redhat.com (Postfix) id E100617C53; Fri, 19 May 2017 20:58:14 +0000 (UTC) Received: from mx1.redhat.com (ext-mx10.extmail.prod.ext.phx2.redhat.com [10.5.110.39]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DBAED5DC1D for ; Fri, 19 May 2017 20:58:14 +0000 (UTC) Received: from mail-qt0-f169.google.com (mail-qt0-f169.google.com [209.85.216.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3F0D161E4C for ; Fri, 19 May 2017 20:58:12 +0000 (UTC) Received: by mail-qt0-f169.google.com with SMTP id t26so67634451qtg.0 for ; Fri, 19 May 2017 13:58:12 -0700 (PDT) Received: from silas.datto.lan ([47.19.105.250]) by smtp.gmail.com with ESMTPSA id t66sm2685740qkt.42.2017.05.19.13.58.10 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 May 2017 13:58:10 -0700 (PDT) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4D78CC05AA54 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=datto.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 4D78CC05AA54 Authentication-Results: mx1.redhat.com; dkim=fail reason="signature verification failed" (2048-bit key) header.d=datto-com.20150623.gappssmtp.com header.i=@datto-com.20150623.gappssmtp.com header.b="0aaa3a1T" DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 3F0D161E4C Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=datto.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=sramanujam@datto.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 3F0D161E4C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=datto-com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=l5f5hl9tBXZQgGKn6GIGS5hDduOxjb9VnPP9umFZIbY=; b=0aaa3a1T8tu4Nc71ibKjBAheJUHraqZzfranYSty9frGUHxzQ9wpyQ4cKZ9rYb+ppq zErMh4qWN8I5Wiz9w9bb226XVhMYw5/++v2ADlVSPEbb8n+Hfs8ugDGJ2UP89q+uWFGv IMhnm8OZbAPUUYQXTNHrTTyz9Hyc1GgZKcGzTViFpx4JQv+kqjKZSqW6ijuBsxwYVRes Oo1Q/s9nehCMyYF5QcyhMXDiXB6KJPKhxbQPVKosVhJsYwkf7qyHyvuiJONhZcEo1fIU fYnURA6vByK6FrGyEbRcAjYHF4hguE6y/vg1V/nO0rpkInCxtkHFryH68Fz0LHD3Q8Zw zavg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=l5f5hl9tBXZQgGKn6GIGS5hDduOxjb9VnPP9umFZIbY=; b=pvvB6q56sXB9qPoEwvkyllcv0GG6EMsu+eg8NrPat9y+JxoYeECEEpnX6iVVVweh0J uRAnW/v6F/4Gilisr46g3bwBQ9Y0sF2h6NjfJcW0lNyFITLp0X+OKspFuIBctwJyAGY3 rMqYIk96ftIDjZGSurgO6by6HM77XYCpTHSmP/jPXiqOvANBtz9jlNCHBPBNMMnmGbd7 UFuFDzrQCy+gdibf2N64pHvv3QDRP4e7DhSOOpHrF6OlFCjaa9mppNIruCngPSp3mesk g1PFbzsGZoQkYIdfRfPHAMyV44cZSIWDh/dkHTH5/63/kUY/SQc7i/qSsvxJSqfVO8+z ElaA== X-Gm-Message-State: AODbwcBLHidsmQ6GlOYPbZlLtolcQnozWj4RbLp+HGXWBwVWPxoJ0WVp rpcfDKLLzGZUm3OLXB0= X-Received: by 10.200.55.145 with SMTP id d17mr11616760qtc.57.1495227491156; Fri, 19 May 2017 13:58:11 -0700 (PDT) From: Sri Ramanujam To: libvir-list@redhat.com Date: Fri, 19 May 2017 16:58:00 -0400 Message-Id: <20170519205802.27094-4-sramanujam@datto.com> In-Reply-To: <20170519205802.27094-1-sramanujam@datto.com> References: <20170519205802.27094-1-sramanujam@datto.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Fri, 19 May 2017 20:58:12 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Fri, 19 May 2017 20:58:12 +0000 (UTC) for IP:'209.85.216.169' DOMAIN:'mail-qt0-f169.google.com' HELO:'mail-qt0-f169.google.com' FROM:'sramanujam@datto.com' RCPT:'' X-RedHat-Spam-Score: 0.869 (BAYES_50, DCC_REPUT_00_12, DKIM_SIGNED, DKIM_VALID, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SORBS_SPAM, SPF_PASS) 209.85.216.169 mail-qt0-f169.google.com 209.85.216.169 mail-qt0-f169.google.com X-Scanned-By: MIMEDefang 2.78 on 10.5.110.39 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v4 3/5] hyperv: add hypervInvokeMethod X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 19 May 2017 20:58:42 +0000 (UTC) X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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 @@ */ =20 #include +#include =20 #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" =20 #define WS_SERIALIZER_FREE_MEM_WORKS 0 =20 #define VIR_FROM_THIS VIR_FROM_HYPERV =20 +#define HYPERV_JOB_TIMEOUT_MS 5000 + +VIR_LOG_INIT("hyperv.hyperv_wmi"); =20 static int hypervGetWmiClassInfo(hypervPrivate *priv, hypervWmiClassInfoListPtr list, @@ -394,6 +400,584 @@ hypervAddEmbeddedParam(hypervInvokeParamsListPtr para= ms, hypervPrivate *priv, } =20 =20 +/* + * Serializing parameters to XML and invoking methods + */ + +static int +hypervGetCimTypeInfo(hypervCimTypePtr typemap, const char *name, + hypervCimTypePtr *property) +{ + size_t i =3D 0; + while (typemap[i].name[0] !=3D '\0') { + if (STREQ(typemap[i].name, name)) { + *property =3D &typemap[i]; + return 0; + } + i++; + } + + return -1; +} + + +static int +hypervCreateInvokeXmlDoc(hypervInvokeParamsListPtr params, WsXmlDocH *docR= oot) +{ + int result =3D -1; + char *method =3D NULL; + WsXmlNodeH xmlNodeMethod =3D NULL; + + if (virAsprintf(&method, "%s_INPUT", params->method) < 0) + goto cleanup; + + *docRoot =3D ws_xml_create_doc(NULL, method); + if (*docRoot =3D=3D NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not instantiate XML document")); + goto cleanup; + } + + xmlNodeMethod =3D xml_parser_get_root(*docRoot); + if (xmlNodeMethod =3D=3D 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 =3D 0; + goto cleanup; + + cleanup: + if (result < 0 && *docRoot !=3D NULL) { + ws_xml_destroy_doc(*docRoot); + *docRoot =3D NULL; + } + VIR_FREE(method); + return result; +} + +static int +hypervSerializeSimpleParam(hypervParamPtr p, const char *resourceUri, + WsXmlNodeH *methodNode) +{ + WsXmlNodeH xmlNodeParam =3D NULL; + + xmlNodeParam =3D ws_xml_add_child(*methodNode, resourceUri, + p->simple.name, p->simple.value); + if (xmlNodeParam =3D=3D 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 =3D -1; + WsXmlNodeH xmlNodeParam =3D NULL, + xmlNodeTemp =3D NULL, + xmlNodeAddr =3D NULL, + xmlNodeRef =3D NULL; + xmlNodePtr xmlNodeAddrPtr =3D NULL, + xmlNodeRefPtr =3D NULL; + WsXmlDocH xmlDocResponse =3D NULL; + xmlDocPtr docPtr =3D (xmlDocPtr) doc->parserDoc; + WsXmlNsH ns =3D NULL; + client_opt_t *options =3D NULL; + filter_t *filter =3D NULL; + char *enumContext =3D NULL; + char *query_string =3D NULL; + + /* init and set up options */ + options =3D wsmc_options_init(); + if (!options) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not init opt= ions")); + goto cleanup; + } + wsmc_set_action_option(options, FLAG_ENUMERATION_ENUM_EPR); + + /* Get query and create filter based on it */ + query_string =3D virBufferContentAndReset(p->epr.query); + filter =3D filter_create_simple(WSM_WQL_FILTER_DIALECT, query_string); + if (!filter) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create W= QL filter")); + goto cleanup; + } + + /* enumerate based on the filter from this query */ + xmlDocResponse =3D wsmc_action_enumerate(priv->client, p->epr.info->ro= otUri, + options, filter); + if (hypervVerifyResponse(priv->client, xmlDocResponse, "enumeration") = < 0) + goto cleanup; + + /* Get context */ + enumContext =3D wsmc_get_enum_context(xmlDocResponse); + ws_xml_destroy_doc(xmlDocResponse); + + /* Pull using filter and enum context */ + xmlDocResponse =3D 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 =3D ws_xml_get_soap_body(xmlDocResponse))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get SOAP= body")); + goto cleanup; + } + + if (!(xmlNodeTemp =3D ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ENUMERAT= ION, + WSENUM_PULL_RESP))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get resp= onse")); + goto cleanup; + } + + if (!(xmlNodeTemp =3D ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ENUMERAT= ION, WSENUM_ITEMS))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get resp= onse items")); + goto cleanup; + } + + if (!(xmlNodeTemp =3D ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSI= NG, WSA_EPR))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get EPR = items")); + goto cleanup; + } + + if (!(xmlNodeAddr =3D ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSI= NG, + WSA_ADDRESS))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get EPR = address")); + goto cleanup; + } + + if (!(xmlNodeAddrPtr =3D xmlDocCopyNode((xmlNodePtr) xmlNodeAddr, docP= tr, 1))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not copy EPR= address")); + goto cleanup; + } + + if (!(xmlNodeRef =3D ws_xml_get_child(xmlNodeTemp, 0, XML_NS_ADDRESSIN= G, + WSA_REFERENCE_PARAMETERS))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup EPR item reference parameters")); + goto cleanup; + } + + if (!(xmlNodeRefPtr =3D 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 =3D 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 =3D 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 =3D NULL; + if (!(ns =3D 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) = =3D=3D NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeAddrPtr) =3D=3D NULL= ) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + if (xmlAddChild((xmlNodePtr) xmlNodeParam, xmlNodeRefPtr) =3D=3D NULL)= { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + /* we did it! */ + result =3D 0; + + cleanup: + if (options !=3D NULL) + wsmc_options_destroy(options); + if (filter !=3D 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 =3D -1; + WsXmlNodeH xmlNodeInstance =3D NULL, + xmlNodeProperty =3D NULL, + xmlNodeParam =3D NULL, + xmlNodeArray =3D NULL; + WsXmlDocH xmlDocTemp =3D NULL, + xmlDocCdata =3D NULL; + xmlBufferPtr xmlBufferNode =3D NULL; + const xmlChar *xmlCharCdataContent =3D NULL; + xmlNodePtr xmlNodeCdata =3D NULL; + hypervWmiClassInfoPtr classInfo =3D p->embedded.info; + virHashKeyValuePairPtr items =3D NULL; + hypervCimTypePtr property =3D NULL; + int numKeys =3D -1; + int len =3D 0, i =3D 0; + + if (!(xmlNodeParam =3D ws_xml_add_child(*methodNode, resourceUri, p->e= mbedded.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 =3D ws_xml_create_doc(NULL, "INSTANCE"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create temporary xml doc")); + goto cleanup; + } + + if (!(xmlNodeInstance =3D 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) =3D=3D NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add attribute to node")); + goto cleanup; + } + + /* retrieve parameters out of hash table */ + numKeys =3D virHashSize(p->embedded.table); + items =3D 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 =3D 0; i < numKeys; i++) { + const char *name =3D items[i].key; + const char *value =3D items[i].value; + + if (value !=3D NULL) { + if (hypervGetCimTypeInfo(classInfo->propertyInfo, name, + &property) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not read type information")); + goto cleanup; + } + + if (!(xmlNodeProperty =3D ws_xml_add_child(xmlNodeInstance, NU= LL, + property->isArray ? "PROPERTY.ARRAY" : "PROPER= TY", + 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) = =3D=3D 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", proper= ty->type) =3D=3D 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 =3D ws_xml_add_child(xmlNodeProperty, N= ULL, + "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 : xmlNod= eProperty, + NULL, "VALUE", value) =3D=3D NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to XML node")); + goto cleanup; + } + + xmlNodeArray =3D NULL; + xmlNodeProperty =3D NULL; + } + } + + /* create CDATA node */ + xmlBufferNode =3D 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 =3D xmlBufferLength(xmlBufferNode); + xmlCharCdataContent =3D xmlBufferContent(xmlBufferNode); + if (!(xmlNodeCdata =3D 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) =3D=3D NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add CDATA to doc root")); + goto cleanup; + } + + /* we did it! */ + result =3D 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 =3D -1; + size_t i =3D 0; + int returnCode; + WsXmlDocH paramsDocRoot =3D NULL; + client_opt_t *options =3D NULL; + WsXmlDocH response =3D NULL; + WsXmlNodeH methodNode =3D NULL; + char *returnValue_xpath =3D NULL; + char *jobcode_instance_xpath =3D NULL; + char *returnValue =3D NULL; + char *instanceID =3D NULL; + bool completed =3D false; + virBuffer query =3D VIR_BUFFER_INITIALIZER; + Msvm_ConcreteJob *job =3D NULL; + int jobState =3D -1; + hypervParamPtr p =3D NULL; + int timeout =3D HYPERV_JOB_TIMEOUT_MS; + + if (hypervCreateInvokeXmlDoc(params, ¶msDocRoot) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create XML document")); + goto cleanup; + } + + methodNode =3D xml_parser_get_root(paramsDocRoot); + if (methodNode =3D=3D NULL) + goto cleanup; + + /* Serialize parameters */ + for (i =3D 0; i < params->nbParams; i++) { + p =3D &(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 =3D wsmc_options_init(); + + if (!options) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not init opt= ions")); + goto cleanup; + } + + wsmc_add_selectors_from_str(options, params->selector); + + /* do the invoke */ + response =3D wsmc_action_invoke(priv->client, params->resourceUri, opt= ions, + 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 =3D 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 =3D=3D CIM_RETURNCODE_TRANSITION_STARTED) { + if (virAsprintf(&jobcode_instance_xpath, + "/s:Envelope/s:Body/p:%s_OUTPUT/p:Job/a:ReferenceParam= eters/" + "w:SelectorSet/w:Selector[@Name=3D'InstanceID']", + params->method) < 0) { + goto cleanup; + } + + instanceID =3D ws_xml_get_xpath_value(response, jobcode_instance_x= path); + 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 fa= ils, + * or 5 minutes have elapsed. + * + * Windows has its own timeout on running WMI method calls (it cal= ls + * 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-runnin= g job + * to complete, we instead bail after 5 minutes no matter what. NO= TE that + * this does not mean that the remote job has terminated on the Wi= ndows + * side! That is up to Windows to control, we don't do anything ab= out it. + */ + while (!completed && timeout >=3D 0) { + virBufferAddLit(&query, MSVM_CONCRETEJOB_WQL_SELECT); + virBufferAsprintf(&query, "where InstanceID =3D \"%s\"", insta= nceID); + + if (hypervGetMsvmConcreteJobList(priv, &query, &job) < 0 + || job =3D=3D NULL) + goto cleanup; + + jobState =3D 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 =3D NULL; + usleep(100 * 1000); /* sleep 100 ms */ + timeout -=3D 100; + continue; + case MSVM_CONCRETEJOB_JOBSTATE_COMPLETED: + completed =3D 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 !=3D CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Invocation of %s returne= d an error: %s (%d)"), + params->method, hypervReturnCodeToString(returnCode), + returnCode); + goto cleanup; + } + + if (res) + *res =3D response; + + result =3D 0; + + cleanup: + if (options) + wsmc_options_destroy(options); + if (response && (res =3D=3D 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; +} =20 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *= * * * 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, co= nst char *name, int hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate= *priv, const char *name, virHashTablePtr table, hypervWmiClassInfoListPtr= info); =20 +int hypervInvokeMethod(hypervPrivate *priv, hypervInvokeParamsListPtr para= ms, + 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 =20 +/* wsman-xml.h */ +WsXmlDocH ws_xml_create_doc(const char *rootNsUri, const char *rootName); +WsXmlNodeH xml_parser_get_root(WsXmlDocH doc); + #endif /* __OPENWSMAN_H__ */ --=20 2.9.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list