mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
hyperv: add hypervInvokeMethod
This commit adds support for invoking methods on remote objects via hypervInvokeMethod.
This commit is contained in:
parent
e4a2f5a258
commit
8c28c76a5f
@ -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,
|
||||
@ -405,6 +411,589 @@ 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);
|
||||
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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user