[libvirt] [PATCH v5 0/5] Hyper-V method invocation

Changes from v4: * Changes from review * Added hypervFreeEmbeddedParam Sri Ramanujam (5): hyperv: Functions to work with invocation parameters. hyperv: Generate object property type information. hyperv: add hypervInvokeMethod hyperv: support virDomainSendKey hyperv: Add support for virDomainSetMemory src/hyperv/hyperv_driver.c | 228 +++++++++ src/hyperv/hyperv_wmi.c | 911 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 95 +++- src/hyperv/hyperv_wmi_classes.h | 19 + src/hyperv/hyperv_wmi_generator.input | 116 +++++ src/hyperv/hyperv_wmi_generator.py | 15 +- src/hyperv/openwsman.h | 4 + 7 files changed, 1386 insertions(+), 2 deletions(-) -- 2.9.4

This commit introduces functionality for creating and working with invoke parameters. This commit does not include any code for serializing and actually performing the method invocations; it merely defines the functions and API for using invocation parameters in driver code. HYPERV_DEFAULT_PARAM_COUNT was chosen because almost no method invocations have more than 4 parameters. Functions added: * hypervInitInvokeParamsList * hypervFreeInvokeParams * hypervAddSimpleParam * hypervAddEprParam * hypervCreateEmbeddedParam * hypervSetEmbeddedProperty * hypervAddEmbeddedParam * hypervFreeEmbeddedParam --- src/hyperv/hyperv_wmi.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 79 ++++++++++++++- 2 files changed, 340 insertions(+), 1 deletion(-) diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index a3c7dc0..2732db3 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -2,6 +2,7 @@ * hyperv_wmi.c: general WMI over WSMAN related functions and structures for * managing Microsoft Hyper-V hosts * + * Copyright (C) 2017 Datto Inc * Copyright (C) 2014 Red Hat, Inc. * Copyright (C) 2011 Matthias Bolte <matthias.bolte@googlemail.com> * Copyright (C) 2009 Michael Sievers <msievers83@googlemail.com> @@ -142,6 +143,267 @@ hypervVerifyResponse(WsManClient *client, WsXmlDocH response, } +/* + * Methods to work with method invocation parameters + */ + +/* + * hypervCreateInvokeParamsList: + * @priv: hypervPrivate object associated with the connection. + * @method: The name of the method you are calling + * @selector: The selector for the object you are invoking the method on + * @obj: The WmiInfo of the object class you are invoking the method on. + * + * Create a new InvokeParamsList object for the method call. + * + * Returns a pointer to the newly instantiated object on success, which should + * be freed by hypervInvokeMethod. Otherwise returns NULL. + */ +hypervInvokeParamsListPtr +hypervCreateInvokeParamsList(hypervPrivate *priv, const char *method, + const char *selector, hypervWmiClassInfoListPtr obj) +{ + hypervInvokeParamsListPtr params = NULL; + hypervWmiClassInfoPtr info = NULL; + + if (hypervGetWmiClassInfo(priv, obj, &info) < 0) + goto cleanup; + + if (VIR_ALLOC(params) < 0) + goto cleanup; + + if (VIR_ALLOC_N(params->params, + HYPERV_DEFAULT_PARAM_COUNT) < 0) { + VIR_FREE(params); + goto cleanup; + } + + params->method = method; + params->ns = info->rootUri; + params->resourceUri = info->resourceUri; + params->selector = selector; + params->nbParams = 0; + params->nbAvailParams = HYPERV_DEFAULT_PARAM_COUNT; + + cleanup: + return params; +} + +/* + * hypervFreeInvokeParams: + * @params: Params object to be freed + * + */ +void +hypervFreeInvokeParams(hypervInvokeParamsListPtr params) +{ + hypervParamPtr p = NULL; + size_t i = 0; + + if (params == NULL) + return; + + for (i = 0; i < params->nbParams; i++) { + p = &(params->params[i]); + + switch (p->type) { + case HYPERV_SIMPLE_PARAM: + break; + case HYPERV_EPR_PARAM: + virBufferFreeAndReset(p->epr.query); + break; + case HYPERV_EMBEDDED_PARAM: + hypervFreeEmbeddedParam(p->embedded.table); + break; + default: + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid parameter type passed to free")); + } + } + + VIR_DISPOSE_N(params->params, params->nbAvailParams); + VIR_FREE(params); +} + +static inline int +hypervCheckParams(hypervInvokeParamsListPtr params) +{ + if (params->nbParams + 1 > params->nbAvailParams) { + if (VIR_EXPAND_N(params->params, params->nbAvailParams, 5) < 0) + return -1; + } + + return 0; +} + +/* + * hypervAddSimpleParam: + * @params: Params object to add to + * @name: Name of the parameter + * @value: Value of the parameter + * + * Add a param of type HYPERV_SIMPLE_PARAM, which is essentially a serialized + * key/value pair. + * + * Returns -1 on failure, 0 on success. + */ +int +hypervAddSimpleParam(hypervInvokeParamsListPtr params, const char *name, + const char *value) +{ + int result = -1; + hypervParamPtr p = NULL; + + if (hypervCheckParams(params) < 0) + goto cleanup; + + p = ¶ms->params[params->nbParams]; + p->type = HYPERV_SIMPLE_PARAM; + + p->simple.name = name; + p->simple.value = value; + + params->nbParams++; + + result = 0; + + cleanup: + return result; +} + +/* + * hypervAddEprParam: + * @params: Params object to add to + * @name: Parameter name + * @priv: hypervPrivate object associated with the connection + * @query: WQL filter + * @eprInfo: WmiInfo of the object being filtered + * + * Adds an EPR param to the params list. Returns -1 on failure, 0 on success. + */ +int +hypervAddEprParam(hypervInvokeParamsListPtr params, const char *name, + hypervPrivate *priv, virBufferPtr query, + hypervWmiClassInfoListPtr eprInfo) +{ + hypervParamPtr p = NULL; + hypervWmiClassInfoPtr classInfo = NULL; + + if (hypervGetWmiClassInfo(priv, eprInfo, &classInfo) < 0 || + hypervCheckParams(params) < 0) + return -1; + + p = ¶ms->params[params->nbParams]; + p->type = HYPERV_EPR_PARAM; + p->epr.name = name; + p->epr.query = query; + p->epr.info = classInfo; + params->nbParams++; + + return 0; +} + +/* + * hypervCreateEmbeddedParam: + * @priv: hypervPrivate object associated with the connection + * @info: WmiInfo of the object type to serialize + * + * Instantiates a virHashTable pre-filled with all the properties pre-added + * a key/value pairs set to NULL. The user then sets only those properties that + * they wish to serialize, and passes the table via hypervAddEmbeddedParam. + * + * Returns a pointer to the virHashTable on success, otherwise NULL. + */ +virHashTablePtr +hypervCreateEmbeddedParam(hypervPrivate *priv, hypervWmiClassInfoListPtr info) +{ + size_t i; + int count = 0; + virHashTablePtr table = NULL; + XmlSerializerInfo *typeinfo = NULL; + XmlSerializerInfo *item = NULL; + hypervWmiClassInfoPtr classInfo = NULL; + + /* Get the typeinfo out of the class info list */ + if (hypervGetWmiClassInfo(priv, info, &classInfo) < 0) + goto error; + + typeinfo = classInfo->serializerInfo; + + /* loop through the items to find out how many fields there are */ + for (i = 0; typeinfo[i].name != NULL; i++) {} + count = i; + + table = virHashCreate(count, NULL); + if (table == NULL) + goto error; + + for (i = 0; typeinfo[i].name != NULL; i++) { + item = &typeinfo[i]; + + if (virHashAddEntry(table, item->name, NULL) < 0) + goto error; + } + + return table; + + error: + virHashFree(table); + return NULL; +} + +int +hypervSetEmbeddedProperty(virHashTablePtr table, const char *name, char *value) +{ + return virHashUpdateEntry(table, name, value); +} + +/* + * hypervAddEmbeddedParam: + * @params: Params list to add to + * @priv: hypervPrivate object associated with the connection + * @name: Name of the parameter + * @table: table of properties to add + * @info: WmiInfo of the object to serialize + * + * Add a virHashTable containing object properties as an embedded param to + * an invocation list. Returns -1 on failure, 0 on success. + */ +int +hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate *priv, + const char *name, virHashTablePtr table, hypervWmiClassInfoListPtr info) +{ + hypervParamPtr p = NULL; + hypervWmiClassInfoPtr classInfo = NULL; + + if (hypervCheckParams(params) < 0) + return -1; + + /* Get the typeinfo out of the class info list */ + if (hypervGetWmiClassInfo(priv, info, &classInfo) < 0) + return -1; + + p = ¶ms->params[params->nbParams]; + p->type = HYPERV_EMBEDDED_PARAM; + p->embedded.name = name; + p->embedded.table = table; + p->embedded.info = classInfo; + params->nbParams++; + + return 0; +} + +/* + * hypervFreeEmbeddedParam: + * @param: Pointer to embedded param to free + * + * Free the embedded param hash table. + */ +void +hypervFreeEmbeddedParam(virHashTablePtr p) +{ + virHashFree(p); +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Object diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index edb8efa..54ce5b1 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -28,11 +28,13 @@ # include "hyperv_private.h" # include "hyperv_wmi_classes.h" # include "openwsman.h" - +# include "virhash.h" # define HYPERV_WQL_QUERY_INITIALIZER { NULL, NULL } +# define HYPERV_DEFAULT_PARAM_COUNT 5 + int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, const char *detail); @@ -74,7 +76,82 @@ int hypervEnumAndPull(hypervPrivate *priv, hypervWqlQueryPtr wqlQuery, void hypervFreeObject(hypervPrivate *priv, hypervObject *object); +/* + * Invoke + */ + +typedef enum { + HYPERV_SIMPLE_PARAM, + HYPERV_EPR_PARAM, + HYPERV_EMBEDDED_PARAM +} hypervStorageType; + +struct _hypervSimpleParam { + const char *name; + const char *value; +}; +typedef struct _hypervSimpleParam hypervSimpleParam; + +struct _hypervEprParam { + const char *name; + virBufferPtr query; + hypervWmiClassInfoPtr info; // info of the object this param represents +}; +typedef struct _hypervEprParam hypervEprParam; + +struct _hypervEmbeddedParam { + const char *name; + virHashTablePtr table; + hypervWmiClassInfoPtr info; // info of the object this param represents +}; +typedef struct _hypervEmbeddedParam hypervEmbeddedParam; + +struct _hypervParam { + hypervStorageType type; + union { + hypervSimpleParam simple; + hypervEprParam epr; + hypervEmbeddedParam embedded; + }; +}; +typedef struct _hypervParam hypervParam; +typedef hypervParam *hypervParamPtr; + +struct _hypervInvokeParamsList { + const char *method; + const char *ns; + const char *resourceUri; + const char *selector; + hypervParamPtr params; + size_t nbParams; + size_t nbAvailParams; +}; +typedef struct _hypervInvokeParamsList hypervInvokeParamsList; +typedef hypervInvokeParamsList *hypervInvokeParamsListPtr; + + +hypervInvokeParamsListPtr hypervCreateInvokeParamsList(hypervPrivate *priv, + const char *method, const char *selector, hypervWmiClassInfoListPtr obj); + +void hypervFreeInvokeParams(hypervInvokeParamsListPtr params); + +int hypervAddSimpleParam(hypervInvokeParamsListPtr params, const char *name, + const char *value); + +int hypervAddEprParam(hypervInvokeParamsListPtr params, const char *name, + hypervPrivate *priv, virBufferPtr query, + hypervWmiClassInfoListPtr eprInfo); + +virHashTablePtr hypervCreateEmbeddedParam(hypervPrivate *priv, + hypervWmiClassInfoListPtr info); + +int hypervSetEmbeddedProperty(virHashTablePtr table, const char *name, + char *value); + +int hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate *priv, + const char *name, virHashTablePtr table, hypervWmiClassInfoListPtr info); +void hypervFreeEmbeddedParam(virHashTablePtr p); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CIM/Msvm_ReturnCode */ -- 2.9.4

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
This commit introduces functionality for creating and working with invoke parameters. This commit does not include any code for serializing and actually performing the method invocations; it merely defines the functions and API for using invocation parameters in driver code.
HYPERV_DEFAULT_PARAM_COUNT was chosen because almost no method invocations have more than 4 parameters.
Functions added: * hypervInitInvokeParamsList * hypervFreeInvokeParams * hypervAddSimpleParam * hypervAddEprParam * hypervCreateEmbeddedParam * hypervSetEmbeddedProperty * hypervAddEmbeddedParam * hypervFreeEmbeddedParam --- src/hyperv/hyperv_wmi.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 79 ++++++++++++++- 2 files changed, 340 insertions(+), 1 deletion(-)
This one looks okay. -- Matthias Bolte http://photron.blogspot.com

Update the generator to generate basic property type information for each CIM object representation. Right now, it generates arrays of hypervCimType structs: struct _hypervCimType { const char *name; const char *type; bool isArray; }; --- src/hyperv/hyperv_wmi_classes.h | 19 +++++++++++++++++++ src/hyperv/hyperv_wmi_generator.py | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index f7d596f..ce4643e 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -1,6 +1,7 @@ /* * hyperv_wmi_classes.h: WMI classes for managing Microsoft Hyper-V hosts * + * Copyright (C) 2017 Datto Inc * Copyright (C) 2011 Matthias Bolte <matthias.bolte@googlemail.com> * Copyright (C) 2009 Michael Sievers <msievers83@googlemail.com> * @@ -23,6 +24,7 @@ #ifndef __HYPERV_WMI_CLASSES_H__ # define __HYPERV_WMI_CLASSES_H__ +# include "internal.h" # include "openwsman.h" # include "hyperv_wmi_classes.generated.typedef" @@ -96,6 +98,21 @@ enum _Msvm_ConcreteJob_JobState { }; +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * WMI + */ + +typedef struct _hypervCimType hypervCimType; +typedef hypervCimType *hypervCimTypePtr; +struct _hypervCimType { + /* Parameter name */ + const char *name; + /* Parameter type */ + const char *type; + /* whether parameter is an array type */ + bool isArray; +}; + typedef struct _hypervWmiClassInfo hypervWmiClassInfo; typedef hypervWmiClassInfo *hypervWmiClassInfoPtr; struct _hypervWmiClassInfo { @@ -109,6 +126,8 @@ struct _hypervWmiClassInfo { const char *resourceUri; /* The wsman serializer info - one of the *_TypeInfo structs */ XmlSerializerInfo *serializerInfo; + /* Property type information */ + hypervCimTypePtr propertyInfo; }; diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py index 9aee0b9..9c0acce 100755 --- a/src/hyperv/hyperv_wmi_generator.py +++ b/src/hyperv/hyperv_wmi_generator.py @@ -122,6 +122,14 @@ class WmiClass: source += "SER_END_ITEMS(%s_Data);\n\n" % cls.name + # also generate typemap data while we're here + source += "hypervCimType %s_Typemap[] = {\n" % cls.name + + for property in cls.properties: + source += property.generate_typemap() + source += ' { "", "", 0 },\n' # null terminated + source += '};\n\n' + source += self._define_WmiInfo_struct() source += "\n\n" @@ -222,7 +230,8 @@ class WmiClass: source += " .version = NULL,\n" source += " .rootUri = %s,\n" % cls.uri_info.rootUri source += " .resourceUri = %s_RESOURCE_URI,\n" % cls.name.upper() - source += " .serializerInfo = %s_Data_TypeInfo\n" % cls.name + source += " .serializerInfo = %s_Data_TypeInfo,\n" % cls.name + source += " .propertyInfo = %s_Typemap\n" % cls.name source += " },\n" source += " }\n" @@ -374,6 +383,10 @@ class Property: % (Property.typemap[self.type], class_name.upper(), self.name) + def generate_typemap(self): + return ' { "%s", "%s", %s },\n' % (self.name, self.type.lower(), str(self.is_array).lower()) + + def open_and_print(filename): if filename.startswith("./"): -- 2.9.4

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
Update the generator to generate basic property type information for each CIM object representation. Right now, it generates arrays of hypervCimType structs:
struct _hypervCimType { const char *name; const char *type; bool isArray; }; --- src/hyperv/hyperv_wmi_classes.h | 19 +++++++++++++++++++ src/hyperv/hyperv_wmi_generator.py | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-)
Looks okay. -- Matthias Bolte http://photron.blogspot.com

This commit adds support for invoking methods on remote objects via hypervInvokeMethod. --- src/hyperv/hyperv_wmi.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 8 +- src/hyperv/openwsman.h | 4 + 3 files changed, 601 insertions(+), 2 deletions(-) diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 2732db3..3b65f60 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, @@ -334,6 +340,7 @@ hypervCreateEmbeddedParam(hypervPrivate *priv, hypervWmiClassInfoListPtr info) for (i = 0; typeinfo[i].name != NULL; i++) {} count = i; + count = i + 1; table = virHashCreate(count, NULL); if (table == NULL) goto error; @@ -405,6 +412,590 @@ hypervFreeEmbeddedParam(virHashTablePtr p) virHashFree(p); } +/* + * 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; + + 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 */ + if (virBufferCheckError(p->epr.query) < 0) { + virBufferFreeAndReset(p->epr.query); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid query")); + goto cleanup; + } + 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; + } + + 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; + ssize_t 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))) { + 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))) { + 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))) { + 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))) { + 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))) { + 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, ¶msDocRoot) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create XML document")); + goto cleanup; + } + + methodNode = xml_parser_get_root(paramsDocRoot); + if (!methodNode) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get root of XML document")); + 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)) + 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 54ce5b1..25cc470 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -95,14 +95,14 @@ typedef struct _hypervSimpleParam hypervSimpleParam; struct _hypervEprParam { const char *name; virBufferPtr query; - hypervWmiClassInfoPtr info; // info of the object this param represents + hypervWmiClassInfoPtr info; /* info of the object this param represents */ }; typedef struct _hypervEprParam hypervEprParam; struct _hypervEmbeddedParam { const char *name; virHashTablePtr table; - hypervWmiClassInfoPtr info; // info of the object this param represents + hypervWmiClassInfoPtr info; /* info of the object this param represents */ }; typedef struct _hypervEmbeddedParam hypervEmbeddedParam; @@ -152,6 +152,10 @@ int hypervAddEmbeddedParam(hypervInvokeParamsListPtr params, hypervPrivate *priv const char *name, virHashTablePtr table, hypervWmiClassInfoListPtr info); void hypervFreeEmbeddedParam(virHashTablePtr p); + +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

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
This commit adds support for invoking methods on remote objects via hypervInvokeMethod. --- src/hyperv/hyperv_wmi.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 8 +- src/hyperv/openwsman.h | 4 + 3 files changed, 601 insertions(+), 2 deletions(-)
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 2732db3..3b65f60 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c
@@ -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, @@ -334,6 +340,7 @@ hypervCreateEmbeddedParam(hypervPrivate *priv, hypervWmiClassInfoListPtr info) for (i = 0; typeinfo[i].name != NULL; i++) {} count = i;
+ count = i + 1;
This second assignment is wrong and has to be removed.
table = virHashCreate(count, NULL); if (table == NULL) goto error;
-- Matthias Bolte http://photron.blogspot.com

This commit adds support for virDomainSendKey. It also serves as an example of how to use the new method invocation APIs with a single "simple" type parameter. --- src/hyperv/hyperv_driver.c | 123 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.c | 7 ++ src/hyperv/hyperv_wmi.h | 3 +- src/hyperv/hyperv_wmi_generator.input | 86 ++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0ca5971..3f5b94e 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -35,6 +35,8 @@ #include "hyperv_wmi.h" #include "openwsman.h" #include "virstring.h" +#include "virkeycode.h" +#include "intprops.h" #define VIR_FROM_THIS VIR_FROM_HYPERV @@ -1373,6 +1375,126 @@ hypervConnectListAllDomains(virConnectPtr conn, #undef MATCH +static int +hypervDomainSendKey(virDomainPtr domain, unsigned int codeset, + unsigned int holdtime, unsigned int *keycodes, int nkeycodes, + unsigned int flags) +{ + int result = -1; + size_t i = 0; + int keycode = 0; + int *translatedKeycodes = NULL; + hypervPrivate *priv = domain->conn->privateData; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + char *selector = NULL; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_Keyboard *keyboard = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + hypervInvokeParamsListPtr params = NULL; + char keycodeStr[INT_BUFSIZE_BOUND(int)]; + + virCheckFlags(0, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + virBufferAsprintf(&query, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where ResultClass = Msvm_Keyboard", + uuid_string); + + if (hypervGetMsvmKeyboardList(priv, &query, &keyboard) < 0) + goto cleanup; + + if (VIR_ALLOC_N(translatedKeycodes, nkeycodes) < 0) + goto cleanup; + + /* translate keycodes to win32 and generate keyup scancodes. */ + for (i = 0; i < nkeycodes; i++) { + if (codeset != VIR_KEYCODE_SET_WIN32) { + keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_WIN32, + keycodes[i]); + + if (keycode < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not translate keycode")); + goto cleanup; + } + translatedKeycodes[i] = keycode; + } + } + + if (virAsprintf(&selector, + "CreationClassName=Msvm_Keyboard&DeviceID=%s&" + "SystemCreationClassName=Msvm_ComputerSystem&" + "SystemName=%s", keyboard->data.common->DeviceID, uuid_string) < 0) + goto cleanup; + + /* press the keys */ + for (i = 0; i < nkeycodes; i++) { + params = NULL; + + snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]); + + params = hypervCreateInvokeParamsList(priv, "PressKey", selector, + Msvm_Keyboard_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create param")); + goto cleanup; + } + + if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0) + goto cleanup; + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not press key %d"), + translatedKeycodes[i]); + goto cleanup; + } + } + + /* simulate holdtime by sleeping */ + if (holdtime > 0) + usleep(holdtime * 1000); + + /* release the keys */ + for (i = 0; i < nkeycodes; i++) { + params = NULL; + + snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]); + params = hypervCreateInvokeParamsList(priv, "ReleaseKey", selector, + Msvm_Keyboard_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create param")); + goto cleanup; + } + + if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0) + goto cleanup; + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not release key %s"), + keycodeStr); + goto cleanup; + } + } + + result = 0; + + cleanup: + VIR_FREE(translatedKeycodes); + VIR_FREE(selector); + hypervFreeObject(priv, (hypervObject *) keyboard); + hypervFreeObject(priv, (hypervObject *) computerSystem); + virBufferFreeAndReset(&query); + return result; +} static virHypervisorDriver hypervHypervisorDriver = { @@ -1408,6 +1530,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainManagedSave = hypervDomainManagedSave, /* 0.9.5 */ .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.5 */ .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.5 */ + .domainSendKey = hypervDomainSendKey, /* TODO: version */ .connectIsAlive = hypervConnectIsAlive, /* 0.9.8 */ }; diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 3b65f60..ad5b93e 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -1343,6 +1343,13 @@ hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query, (hypervObject **) list); } +int hypervGetMsvmKeyboardList(hypervPrivate *priv, virBufferPtr query, + Msvm_Keyboard **list) +{ + return hypervGetWmiClassList(priv, Msvm_Keyboard_WmiInfo, query, + (hypervObject **) list); +} + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 25cc470..5c9da04 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -219,7 +219,8 @@ int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv, int hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query, Msvm_MemorySettingData **list); - +int hypervGetMsvmKeyboardList(hypervPrivate *priv, virBufferPtr query, + Msvm_Keyboard **list); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Msvm_ComputerSystem diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index d7f819e..4ccda04 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -956,3 +956,89 @@ class Msvm_VirtualHardDiskSettingData uint32 PhysicalSectorSize string VirtualDiskId end + +class Msvm_Keyboard + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + string SystemCreationClassName + string SystemName + string CreationClassName + string DeviceID + boolean PowerManagementSupported + uint16 PowerManagementCapabilities[] + uint16 Availability + uint16 StatusInfo + uint32 LastErrorCode + string ErrorDescription + boolean ErrorCleared + string OtherIdentifyingInfo[] + uint64 PowerOnHours + uint64 TotalPowerOnHours + string IdentifyingDescriptions[] + uint16 AdditionalAvailability[] + uint64 MaxQuiesceTime + uint16 LocationIndicator + boolean IsLocked + string Layout + uint16 NumberOfFunctionKeys + uint16 Password +end + + +class v2/Msvm_Keyboard + string InstanceID + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 CommunicationStatus + uint16 DetailedStatus + uint16 OperatingStatus + uint16 PrimaryStatus + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + uint16 AvailableRequestedStates[] + uint16 TransitioningToState + string SystemCreationClassName + string SystemName + string CreationClassName + string DeviceID + boolean PowerManagementSupported + uint16 PowerManagementCapabilities[] + uint16 Availability + uint16 StatusInfo + uint32 LastErrorCode + string ErrorDescription + boolean ErrorCleared + string OtherIdentifyingInfo[] + uint64 PowerOnHours + uint64 TotalPowerOnHours + string IdentifyingDescriptions[] + uint16 AdditionalAvailability[] + uint64 MaxQuiesceTime + boolean IsLocked + string Layout + uint16 NumberOfFunctionKeys + uint16 Password + boolean UnicodeSupported +end -- 2.9.4

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
This commit adds support for virDomainSendKey. It also serves as an example of how to use the new method invocation APIs with a single "simple" type parameter. --- src/hyperv/hyperv_driver.c | 123 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.c | 7 ++ src/hyperv/hyperv_wmi.h | 3 +- src/hyperv/hyperv_wmi_generator.input | 86 ++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0ca5971..3f5b94e 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c
@@ -1373,6 +1375,126 @@ hypervConnectListAllDomains(virConnectPtr conn, #undef MATCH
+static int +hypervDomainSendKey(virDomainPtr domain, unsigned int codeset, + unsigned int holdtime, unsigned int *keycodes, int nkeycodes, + unsigned int flags) +{ + int result = -1; + size_t i = 0; + int keycode = 0; + int *translatedKeycodes = NULL; + hypervPrivate *priv = domain->conn->privateData; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + char *selector = NULL; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_Keyboard *keyboard = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + hypervInvokeParamsListPtr params = NULL; + char keycodeStr[INT_BUFSIZE_BOUND(int)]; + + virCheckFlags(0, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + virBufferAsprintf(&query, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where ResultClass = Msvm_Keyboard", + uuid_string); + + if (hypervGetMsvmKeyboardList(priv, &query, &keyboard) < 0) + goto cleanup; + + if (VIR_ALLOC_N(translatedKeycodes, nkeycodes) < 0) + goto cleanup; + + /* translate keycodes to win32 and generate keyup scancodes. */ + for (i = 0; i < nkeycodes; i++) { + if (codeset != VIR_KEYCODE_SET_WIN32) { + keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_WIN32, + keycodes[i]); + + if (keycode < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not translate keycode")); + goto cleanup; + } + translatedKeycodes[i] = keycode; + } + } + + if (virAsprintf(&selector, + "CreationClassName=Msvm_Keyboard&DeviceID=%s&" + "SystemCreationClassName=Msvm_ComputerSystem&" + "SystemName=%s", keyboard->data.common->DeviceID, uuid_string) < 0) + goto cleanup; + + /* press the keys */ + for (i = 0; i < nkeycodes; i++) { + params = NULL;
Setting params to NULL here is pointless, because the hypervCreateInvokeParamsList result will be assigned to it under all circumstances.
+ snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]); + + params = hypervCreateInvokeParamsList(priv, "PressKey", selector, + Msvm_Keyboard_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create param")); + goto cleanup; + } + + if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0)
If hypervAddSimpleParam fails then params will be leaked here. Add a call to hypervFreeInvokeParams here.
+ goto cleanup; + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not press key %d"), + translatedKeycodes[i]); + goto cleanup; + } + } + + /* simulate holdtime by sleeping */ + if (holdtime > 0) + usleep(holdtime * 1000); + + /* release the keys */ + for (i = 0; i < nkeycodes; i++) { + params = NULL;
Setting params to NULL here is pointless, because the hypervCreateInvokeParamsList result will be assigned to it under all circumstances.
+ + snprintf(keycodeStr, sizeof(keycodeStr), "%d", translatedKeycodes[i]); + params = hypervCreateInvokeParamsList(priv, "ReleaseKey", selector, + Msvm_Keyboard_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create param")); + goto cleanup; + } + + if (hypervAddSimpleParam(params, "keyCode", keycodeStr) < 0)
If hypervAddSimpleParam fails then params will be leaked here. Add a call to hypervFreeInvokeParams here.
+ goto cleanup; + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not release key %s"), + keycodeStr); + goto cleanup; + } + } + + result = 0; + + cleanup: + VIR_FREE(translatedKeycodes); + VIR_FREE(selector); + hypervFreeObject(priv, (hypervObject *) keyboard); + hypervFreeObject(priv, (hypervObject *) computerSystem); + virBufferFreeAndReset(&query); + return result; +}
-- Matthias Bolte http://photron.blogspot.com

Introduces support for virDomainSetMemory. This also serves an an example for how to use the new method invocation API with a more complicated method, this time including an EPR and embedded param. --- src/hyperv/hyperv_driver.c | 105 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.c | 51 +++++++++++++++++ src/hyperv/hyperv_wmi.h | 11 ++++ src/hyperv/hyperv_wmi_generator.input | 30 ++++++++++ 4 files changed, 197 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 3f5b94e..f557408 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1497,6 +1497,109 @@ hypervDomainSendKey(virDomainPtr domain, unsigned int codeset, } +static int +hypervDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory, + unsigned int flags) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + char *memory_str = NULL; + hypervInvokeParamsListPtr params = NULL; + unsigned long memory_mb = VIR_ROUND_UP(VIR_DIV_UP(memory, 1024), 2); + Msvm_VirtualSystemSettingData *vssd = NULL; + Msvm_MemorySettingData *memsd = NULL; + virBuffer eprQuery = VIR_BUFFER_INITIALIZER; + virHashTablePtr memResource = NULL; + + virCheckFlags(0, -1); + + if (virAsprintf(&memory_str, "%lu", memory_mb) < 0) + goto cleanup; + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) < 0) + goto cleanup; + + if (hypervGetMsvmMemorySettingDataFromVSSD(priv, vssd->data.common->InstanceID, + &memsd) < 0) + goto cleanup; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + params = hypervCreateInvokeParamsList(priv, "ModifyVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR, + Msvm_VirtualSystemManagementService_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create params")); + goto cleanup; + } + + virBufferAddLit(&eprQuery, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&eprQuery, "where Name = \"%s\"", uuid_string); + + if (hypervAddEprParam(params, "ComputerSystem", priv, &eprQuery, + Msvm_ComputerSystem_WmiInfo) < 0) + goto cleanup; + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + params = hypervCreateInvokeParamsList(priv, "ModifyResourceSettings", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR, + Msvm_VirtualSystemManagementService_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create params")); + goto cleanup; + } + } + + memResource = hypervCreateEmbeddedParam(priv, Msvm_MemorySettingData_WmiInfo); + if (!memResource) + goto cleanup; + + if (hypervSetEmbeddedProperty(memResource, "VirtualQuantity", memory_str) < 0) + goto cleanup; + + if (hypervSetEmbeddedProperty(memResource, "InstanceID", + memsd->data.common->InstanceID) < 0) + goto cleanup; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + if (hypervAddEmbeddedParam(params, priv, "ResourceSettingData", + memResource, Msvm_MemorySettingData_WmiInfo) < 0) + goto cleanup; + + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + if (hypervAddEmbeddedParam(params, priv, "ResourceSettings", + memResource, Msvm_MemorySettingData_WmiInfo) < 0) + goto cleanup; + } + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not set memory")); + goto cleanup; + } + + /* set embedded param to NULL on success to avoid double-free in cleanup */ + memResource = NULL; + + result = 0; + cleanup: + VIR_FREE(memory_str); + hypervFreeEmbeddedParam(memResource); + hypervFreeObject(priv, (hypervObject *) vssd); + hypervFreeObject(priv, (hypervObject *) memsd); + return result; +} + + +static int +hypervDomainSetMemory(virDomainPtr domain, unsigned long memory) +{ + return hypervDomainSetMemoryFlags(domain, memory, 0); +} + + static virHypervisorDriver hypervHypervisorDriver = { .name = "Hyper-V", .connectOpen = hypervConnectOpen, /* 0.9.5 */ @@ -1531,6 +1634,8 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.5 */ .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.5 */ .domainSendKey = hypervDomainSendKey, /* TODO: version */ + .domainSetMemory = hypervDomainSetMemory, /* TODO: version */ + .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* TODO: version */ .connectIsAlive = hypervConnectIsAlive, /* 0.9.8 */ }; diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index ad5b93e..1e5e73a 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -1636,3 +1636,54 @@ hypervMsvmComputerSystemFromDomain(virDomainPtr domain, return 0; } + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_VirtualSystemSettingData + */ + +int +hypervGetMsvmVirtualSystemSettingDataFromUUID(hypervPrivate *priv, + const char *uuid_string, Msvm_VirtualSystemSettingData **list) +{ + virBuffer query = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&query, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where AssocClass = Msvm_SettingsDefineState " + "ResultClass = Msvm_VirtualSystemSettingData", + uuid_string); + + if (hypervGetWmiClassList(priv, Msvm_VirtualSystemSettingData_WmiInfo, &query, + (hypervObject **) list) < 0 || *list == NULL) + return -1; + + return 0; +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_MemorySettingData + */ + +int +hypervGetMsvmMemorySettingDataFromVSSD(hypervPrivate *priv, + const char *vssd_instanceid, Msvm_MemorySettingData **list) +{ + virBuffer query = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&query, + "associators of " + "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " + "where AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_MemorySettingData", + vssd_instanceid); + + if (hypervGetWmiClassList(priv, Msvm_MemorySettingData_WmiInfo, &query, + (hypervObject **) list) < 0 || *list == NULL) + return -1; + + return 0; +} diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 5c9da04..cc53078 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -35,6 +35,9 @@ # define HYPERV_DEFAULT_PARAM_COUNT 5 +# define MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR \ + "CreationClassName=Msvm_VirtualSystemManagementService" + int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, const char *detail); @@ -212,6 +215,10 @@ int hypervGetMsvmVirtualSystemSettingDataList(hypervPrivate *priv, virBufferPtr query, Msvm_VirtualSystemSettingData **list); +int hypervGetMsvmVirtualSystemSettingDataFromUUID(hypervPrivate *priv, + const char *uuid_string, + Msvm_VirtualSystemSettingData **list); + int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv, virBufferPtr query, Msvm_ProcessorSettingData **list); @@ -219,6 +226,10 @@ int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv, int hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query, Msvm_MemorySettingData **list); +int hypervGetMsvmMemorySettingDataFromVSSD(hypervPrivate *priv, + const char *vssd_instanceid, + Msvm_MemorySettingData **list); + int hypervGetMsvmKeyboardList(hypervPrivate *priv, virBufferPtr query, Msvm_Keyboard **list); diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index 4ccda04..da19765 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -787,6 +787,36 @@ class Msvm_VirtualSystemManagementService boolean Started end +class v2/Msvm_VirtualSystemManagementService + string InstanceID + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 CommunicationStatus + uint16 DetailedStatus + uint16 OperatingStatus + uint16 PrimaryStatus + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + uint16 AvailableRequestedStates[] + uint16 TransitioningToState + string SystemCreationClassName + string SystemName + string CreationClassName + string PrimaryOwnerName + string PrimaryOwnerContact + string StartMode + boolean Started +end class Msvm_VirtualSystemGlobalSettingData string Caption -- 2.9.4

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
Introduces support for virDomainSetMemory. This also serves an an example for how to use the new method invocation API with a more complicated method, this time including an EPR and embedded param. --- src/hyperv/hyperv_driver.c | 105 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.c | 51 +++++++++++++++++ src/hyperv/hyperv_wmi.h | 11 ++++ src/hyperv/hyperv_wmi_generator.input | 30 ++++++++++ 4 files changed, 197 insertions(+)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 3f5b94e..f557408 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1497,6 +1497,109 @@ hypervDomainSendKey(virDomainPtr domain, unsigned int codeset, }
+static int +hypervDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory, + unsigned int flags) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + char *memory_str = NULL; + hypervInvokeParamsListPtr params = NULL; + unsigned long memory_mb = VIR_ROUND_UP(VIR_DIV_UP(memory, 1024), 2); + Msvm_VirtualSystemSettingData *vssd = NULL; + Msvm_MemorySettingData *memsd = NULL; + virBuffer eprQuery = VIR_BUFFER_INITIALIZER; + virHashTablePtr memResource = NULL; + + virCheckFlags(0, -1); + + if (virAsprintf(&memory_str, "%lu", memory_mb) < 0) + goto cleanup; + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) < 0) + goto cleanup; + + if (hypervGetMsvmMemorySettingDataFromVSSD(priv, vssd->data.common->InstanceID, + &memsd) < 0) + goto cleanup; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + params = hypervCreateInvokeParamsList(priv, "ModifyVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR, + Msvm_VirtualSystemManagementService_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create params")); + goto cleanup; + } + + virBufferAddLit(&eprQuery, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&eprQuery, "where Name = \"%s\"", uuid_string); + + if (hypervAddEprParam(params, "ComputerSystem", priv, &eprQuery, + Msvm_ComputerSystem_WmiInfo) < 0) + goto cleanup; + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + params = hypervCreateInvokeParamsList(priv, "ModifyResourceSettings", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR, + Msvm_VirtualSystemManagementService_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create params")); + goto cleanup; + } + } + + memResource = hypervCreateEmbeddedParam(priv, Msvm_MemorySettingData_WmiInfo); + if (!memResource) + goto cleanup; + + if (hypervSetEmbeddedProperty(memResource, "VirtualQuantity", memory_str) < 0) + goto cleanup; + + if (hypervSetEmbeddedProperty(memResource, "InstanceID", + memsd->data.common->InstanceID) < 0) + goto cleanup; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + if (hypervAddEmbeddedParam(params, priv, "ResourceSettingData", + memResource, Msvm_MemorySettingData_WmiInfo) < 0) + goto cleanup; + + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + if (hypervAddEmbeddedParam(params, priv, "ResourceSettings", + memResource, Msvm_MemorySettingData_WmiInfo) < 0) + goto cleanup; + } +
memResource has to be set to NULL here, as I explained in my previous mail. hypervInvokeMethod will always free memResource. Therefore, hypervInvokeMethod will free memResource even if it fails and the code below go to cleanup, with memResource != NULL. Then memResource will be freed again, resulting in a double-free. That's why memResource needs to be set to NULL before calling hypervInvokeMethod, not afterwards.
+ if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not set memory")); + goto cleanup; + } + + /* set embedded param to NULL on success to avoid double-free in cleanup */ + memResource = NULL;
Setting memResource to NULL here is too late.
+ + result = 0; + cleanup: + VIR_FREE(memory_str); + hypervFreeEmbeddedParam(memResource); + hypervFreeObject(priv, (hypervObject *) vssd); + hypervFreeObject(priv, (hypervObject *) memsd); + return result; +}
-- Matthias Bolte http://photron.blogspot.com

2017-06-12 22:13 GMT+02:00 Sri Ramanujam <sramanujam@datto.com>:
Changes from v4: * Changes from review * Added hypervFreeEmbeddedParam
Sri Ramanujam (5): hyperv: Functions to work with invocation parameters. hyperv: Generate object property type information. hyperv: add hypervInvokeMethod hyperv: support virDomainSendKey hyperv: Add support for virDomainSetMemory
This series is missing a patch for the docs/news.xml announcing the two new driver functions. -- Matthias Bolte http://photron.blogspot.com
participants (2)
-
Matthias Bolte
-
Sri Ramanujam