diff --git a/src/Makefile.am b/src/Makefile.am index 3c7adae492bf6205bbe64e44ebc2033887305bbe..e2dc77e3d4e1899e21ee925b0a388a8be66bcacc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -912,8 +912,6 @@ HYPERV_DRIVER_SOURCES = \ hyperv/openwsman.h HYPERV_DRIVER_GENERATED = \ - hyperv/hyperv_wmi.generated.c \ - hyperv/hyperv_wmi.generated.h \ hyperv/hyperv_wmi_classes.generated.c \ hyperv/hyperv_wmi_classes.generated.h \ hyperv/hyperv_wmi_classes.generated.typedef diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index b642a025d229a333c7cfc7c2186f8ffd08319b13..090ea243ba5d30d7ee7d2955d5fcd89980b95802 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -55,7 +55,67 @@ hypervFreePrivate(hypervPrivate **priv) VIR_FREE(*priv); } +static int +hypervInitConnection(virConnectPtr conn, hypervPrivate *priv, + char *username, char *password) +{ + virBuffer query = VIR_BUFFER_INITIALIZER; + hypervWqlQuery wqlQuery = HYPERV_WQL_QUERY_INITIALIZER; + hypervObject *computerSystem = NULL; + int ret = -1; + + /* Initialize the openwsman connection */ + priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman", + priv->parsedUri->transport, username, password); + + if (priv->client == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create openwsman client")); + goto cleanup; + } + + if (wsmc_transport_init(priv->client, NULL) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not initialize openwsman transport")); + goto cleanup; + } + + /* FIXME: Currently only basic authentication is supported */ + wsman_transport_set_auth_method(priv->client, "basic"); + + wqlQuery.info = Msvm_ComputerSystem_WmiInfo; + wqlQuery.query = &query; + + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAddLit(&query, "WHERE "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL); + + /* try query using V2 namespace (for Hyper-V 2012+) */ + priv->wmiVersion = HYPERV_WMI_VERSION_V2; + + if (hypervEnumAndPull(priv, &wqlQuery, &computerSystem) < 0) { + /* rebuild query because hypervEnumAndPull consumes it */ + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAddLit(&query, "WHERE "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL); + + /* fall back to V1 namespace (for Hyper-V 2008) */ + priv->wmiVersion = HYPERV_WMI_VERSION_V1; + + if (hypervEnumAndPull(priv, &wqlQuery, &computerSystem) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s is not a Hyper-V server"), conn->uri->server); + goto cleanup; + } + } + + ret = 0; + cleanup: + hypervFreeObject(priv, computerSystem); + + return ret; +} static virDrvOpenStatus hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, @@ -67,8 +127,6 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, hypervPrivate *priv = NULL; char *username = NULL; char *password = NULL; - virBuffer query = VIR_BUFFER_INITIALIZER; - Msvm_ComputerSystem *computerSystem = NULL; virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); @@ -147,41 +205,9 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, goto cleanup; } - /* Initialize the openwsman connection */ - priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman", - priv->parsedUri->transport, username, password); - if (priv->client == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Could not create openwsman client")); + if (hypervInitConnection(conn, priv, username, password) < 0) goto cleanup; - } - - if (wsmc_transport_init(priv->client, NULL) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Could not initialize openwsman transport")); - goto cleanup; - } - - /* FIXME: Currently only basic authentication is supported */ - wsman_transport_set_auth_method(priv->client, "basic"); - - /* Check if the connection can be established and if the server has the - * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList - * succeeds than the connection has been established. If the returned list - * is empty than the server isn't a Hyper-V server. */ - virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); - virBufferAddLit(&query, "where "); - virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL); - - if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) - goto cleanup; - - if (computerSystem == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("%s is not a Hyper-V server"), conn->uri->server); - goto cleanup; - } conn->privateData = priv; priv = NULL; @@ -191,7 +217,6 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, hypervFreePrivate(&priv); VIR_FREE(username); VIR_FREE(password); - hypervFreeObject(priv, (hypervObject *)computerSystem); return result; } @@ -240,7 +265,7 @@ hypervConnectGetHostname(virConnectPtr conn) goto cleanup; } - ignore_value(VIR_STRDUP(hostname, computerSystem->data->DNSHostName)); + ignore_value(VIR_STRDUP(hostname, computerSystem->data.common->DNSHostName)); cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); @@ -282,7 +307,7 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) "{Win32_ComputerSystem.Name=\"%s\"} " "where AssocClass = Win32_ComputerSystemProcessor " "ResultClass = Win32_Processor", - computerSystem->data->Name); + computerSystem->data.common->Name); if (hypervGetWin32ProcessorList(priv, &query, &processorList) < 0) goto cleanup; @@ -295,7 +320,7 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) } /* Strip the string to fit more relevant information in 32 chars */ - tmp = processorList->data->Name; + tmp = processorList->data.common->Name; while (*tmp != '\0') { if (STRPREFIX(tmp, " ")) { @@ -313,16 +338,16 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) } /* Fill struct */ - if (virStrncpy(info->model, processorList->data->Name, + if (virStrncpy(info->model, processorList->data.common->Name, sizeof(info->model) - 1, sizeof(info->model)) == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("CPU model %s too long for destination"), - processorList->data->Name); + processorList->data.common->Name); goto cleanup; } - info->memory = computerSystem->data->TotalPhysicalMemory / 1024; /* byte to kilobyte */ - info->mhz = processorList->data->MaxClockSpeed; + info->memory = computerSystem->data.common->TotalPhysicalMemory / 1024; /* byte to kilobyte */ + info->mhz = processorList->data.common->MaxClockSpeed; info->nodes = 1; info->sockets = 0; @@ -331,8 +356,8 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) ++info->sockets; } - info->cores = processorList->data->NumberOfCores; - info->threads = info->cores / processorList->data->NumberOfLogicalProcessors; + info->cores = processorList->data.common->NumberOfCores; + info->threads = info->cores / processorList->data.common->NumberOfLogicalProcessors; info->cpus = info->sockets * info->cores; result = 0; @@ -372,7 +397,7 @@ hypervConnectListDomains(virConnectPtr conn, int *ids, int maxids) for (computerSystem = computerSystemList; computerSystem != NULL; computerSystem = computerSystem->next) { - ids[count++] = computerSystem->data->ProcessID; + ids[count++] = computerSystem->data.common->ProcessID; if (count >= maxids) break; @@ -532,7 +557,7 @@ hypervDomainSuspend(virDomainPtr domain) if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; - if (computerSystem->data->EnabledState != + if (computerSystem->data.common->EnabledState != MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not active")); @@ -560,7 +585,7 @@ hypervDomainResume(virDomainPtr domain) if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; - if (computerSystem->data->EnabledState != + if (computerSystem->data.common->EnabledState != MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not paused")); @@ -666,7 +691,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_VirtualSystemSettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } @@ -676,7 +701,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_ProcessorSettingData", - virtualSystemSettingData->data->InstanceID); + virtualSystemSettingData->data.common->InstanceID); if (hypervGetMsvmProcessorSettingDataList(priv, &query, &processorSettingData) < 0) { @@ -687,7 +712,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_ProcessorSettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } @@ -697,7 +722,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_MemorySettingData", - virtualSystemSettingData->data->InstanceID); + virtualSystemSettingData->data.common->InstanceID); if (hypervGetMsvmMemorySettingDataList(priv, &query, &memorySettingData) < 0) { @@ -709,15 +734,15 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_MemorySettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } /* Fill struct */ info->state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem); - info->maxMem = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */ - info->memory = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */ - info->nrVirtCpu = processorSettingData->data->VirtualQuantity; + info->maxMem = memorySettingData->data.common->Limit * 1024; /* megabyte to kilobyte */ + info->memory = memorySettingData->data.common->VirtualQuantity * 1024; /* megabyte to kilobyte */ + info->nrVirtCpu = processorSettingData->data.common->VirtualQuantity; info->cpuTime = 0; result = 0; @@ -803,7 +828,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_VirtualSystemSettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } @@ -813,7 +838,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_ProcessorSettingData", - virtualSystemSettingData->data->InstanceID); + virtualSystemSettingData->data.common->InstanceID); if (hypervGetMsvmProcessorSettingDataList(priv, &query, &processorSettingData) < 0) { @@ -824,7 +849,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_ProcessorSettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } @@ -834,7 +859,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " "where AssocClass = Msvm_VirtualSystemSettingDataComponent " "ResultClass = Msvm_MemorySettingData", - virtualSystemSettingData->data->InstanceID); + virtualSystemSettingData->data.common->InstanceID); if (hypervGetMsvmMemorySettingDataList(priv, &query, &memorySettingData) < 0) { @@ -846,7 +871,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), "Msvm_MemorySettingData", - computerSystem->data->ElementName); + computerSystem->data.common->ElementName); goto cleanup; } @@ -854,34 +879,34 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) def->virtType = VIR_DOMAIN_VIRT_HYPERV; if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) { - def->id = computerSystem->data->ProcessID; + def->id = computerSystem->data.common->ProcessID; } else { def->id = -1; } - if (virUUIDParse(computerSystem->data->Name, def->uuid) < 0) { + if (virUUIDParse(computerSystem->data.common->Name, def->uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not parse UUID from string '%s'"), - computerSystem->data->Name); + computerSystem->data.common->Name); return NULL; } - if (VIR_STRDUP(def->name, computerSystem->data->ElementName) < 0) + if (VIR_STRDUP(def->name, computerSystem->data.common->ElementName) < 0) goto cleanup; - if (VIR_STRDUP(def->description, virtualSystemSettingData->data->Notes) < 0) + if (VIR_STRDUP(def->description, virtualSystemSettingData->data.common->Notes) < 0) goto cleanup; - virDomainDefSetMemoryTotal(def, memorySettingData->data->Limit * 1024); /* megabyte to kilobyte */ - def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */ + virDomainDefSetMemoryTotal(def, memorySettingData->data.common->Limit * 1024); /* megabyte to kilobyte */ + def->mem.cur_balloon = memorySettingData->data.common->VirtualQuantity * 1024; /* megabyte to kilobyte */ if (virDomainDefSetVcpusMax(def, - processorSettingData->data->VirtualQuantity, + processorSettingData->data.common->VirtualQuantity, NULL) < 0) goto cleanup; if (virDomainDefSetVcpus(def, - processorSettingData->data->VirtualQuantity) < 0) + processorSettingData->data.common->VirtualQuantity) < 0) goto cleanup; def->os.type = VIR_DOMAIN_OSTYPE_HVM; @@ -930,7 +955,7 @@ hypervConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxn for (computerSystem = computerSystemList; computerSystem != NULL; computerSystem = computerSystem->next) { - if (VIR_STRDUP(names[count], computerSystem->data->ElementName) < 0) + if (VIR_STRDUP(names[count], computerSystem->data.common->ElementName) < 0) goto cleanup; ++count; @@ -1154,7 +1179,7 @@ hypervDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags) if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; - result = computerSystem->data->EnabledState == + result = computerSystem->data.common->EnabledState == MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED ? 1 : 0; cleanup: @@ -1177,7 +1202,7 @@ hypervDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags) if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; - if (computerSystem->data->EnabledState != + if (computerSystem->data.common->EnabledState != MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain has no managed save image")); @@ -1280,7 +1305,7 @@ hypervConnectListAllDomains(virConnectPtr conn, /* managed save filter */ if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE)) { - bool mansave = computerSystem->data->EnabledState == + bool mansave = computerSystem->data.common->EnabledState == MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED; if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index b2b52435c70d58e7b3d3a0623139ab845fb74623..a3c7dc0750423d0d546e30cb1d793fd71476b157 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -36,15 +36,56 @@ #define WS_SERIALIZER_FREE_MEM_WORKS 0 -#define ROOT_CIMV2 \ - "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*" +#define VIR_FROM_THIS VIR_FROM_HYPERV -#define ROOT_VIRTUALIZATION \ - "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*" -#define VIR_FROM_THIS VIR_FROM_HYPERV +static int +hypervGetWmiClassInfo(hypervPrivate *priv, hypervWmiClassInfoListPtr list, + hypervWmiClassInfoPtr *info) +{ + const char *version = "v2"; + size_t i; + + if (list->count == 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("The WMI class info list is empty")); + return -1; + } + /* if there's just one WMI class and isn't versioned, assume "shared" */ + if (list->count == 1 && list->objs[0]->version == NULL) { + *info = list->objs[0]; + return 0; + } + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) + version = "v1"; + + for (i = 0; i < list->count; i++) { + if (STRCASEEQ(list->objs[i]->version, version)) { + *info = list->objs[i]; + return 0; + } + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not match WMI class info for version %s"), + version); + + return -1; +} + +static int +hypervGetWmiClassList(hypervPrivate *priv, hypervWmiClassInfoListPtr wmiInfo, + virBufferPtr query, hypervObject **wmiClass) +{ + hypervWqlQuery wqlQuery = HYPERV_WQL_QUERY_INITIALIZER; + + wqlQuery.info = wmiInfo; + wqlQuery.query = query; + + return hypervEnumAndPull(priv, &wqlQuery, wmiClass); +} int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, @@ -106,16 +147,16 @@ hypervVerifyResponse(WsManClient *client, WsXmlDocH response, * Object */ -/* This function guarantees that query is freed, even on failure */ +/* This function guarantees that wqlQuery->query is reset, even on failure */ int -hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, - XmlSerializerInfo *serializerInfo, const char *resourceUri, - const char *className, hypervObject **list) +hypervEnumAndPull(hypervPrivate *priv, hypervWqlQueryPtr wqlQuery, + hypervObject **list) { int result = -1; WsSerializerContextH serializerContext; client_opt_t *options = NULL; char *query_string = NULL; + hypervWmiClassInfoPtr wmiInfo = NULL; filter_t *filter = NULL; WsXmlDocH response = NULL; char *enumContext = NULL; @@ -125,11 +166,12 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, XML_TYPE_PTR data = NULL; hypervObject *object; - if (virBufferCheckError(query) < 0) { - virBufferFreeAndReset(query); + if (virBufferCheckError(wqlQuery->query) < 0) { + virBufferFreeAndReset(wqlQuery->query); return -1; } - query_string = virBufferContentAndReset(query); + + query_string = virBufferContentAndReset(wqlQuery->query); if (list == NULL || *list != NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); @@ -137,6 +179,9 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, return -1; } + if (hypervGetWmiClassInfo(priv, wqlQuery->info, &wmiInfo) < 0) + goto cleanup; + serializerContext = wsmc_get_serialization_context(priv->client); options = wsmc_options_init(); @@ -155,7 +200,8 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, goto cleanup; } - response = wsmc_action_enumerate(priv->client, root, options, filter); + response = wsmc_action_enumerate(priv->client, wmiInfo->rootUri, options, + filter); if (hypervVerifyResponse(priv->client, response, "enumeration") < 0) goto cleanup; @@ -166,7 +212,7 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, response = NULL; while (enumContext != NULL && *enumContext != '\0') { - response = wsmc_action_pull(priv->client, resourceUri, options, + response = wsmc_action_pull(priv->client, wmiInfo->resourceUri, options, filter, enumContext); if (hypervVerifyResponse(priv->client, response, "pull") < 0) @@ -196,11 +242,12 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, goto cleanup; } - if (ws_xml_get_child(node, 0, resourceUri, className) == NULL) + if (ws_xml_get_child(node, 0, wmiInfo->resourceUri, + wmiInfo->name) == NULL) break; - data = ws_deserialize(serializerContext, node, serializerInfo, - className, resourceUri, NULL, 0, 0); + data = ws_deserialize(serializerContext, node, wmiInfo->serializerInfo, + wmiInfo->name, wmiInfo->resourceUri, NULL, 0, 0); if (data == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -211,8 +258,8 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, if (VIR_ALLOC(object) < 0) goto cleanup; - object->serializerInfo = serializerInfo; - object->data = data; + object->info = wmiInfo; + object->data.common = data; data = NULL; @@ -248,7 +295,7 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, /* FIXME: ws_serializer_free_mem is broken in openwsman <= 2.2.6, * see hypervFreeObject for a detailed explanation. */ if (ws_serializer_free_mem(serializerContext, data, - serializerInfo) < 0) { + wmiInfo->serializerInfo) < 0) { VIR_ERROR(_("Could not free deserialized data")); } #endif @@ -287,8 +334,8 @@ hypervFreeObject(hypervPrivate *priv ATTRIBUTE_UNUSED, hypervObject *object) * them in wsmc_release. So this doesn't result in a real * memory leak, but just in piling up unused memory until * the connection is closed. */ - if (ws_serializer_free_mem(serializerContext, object->data, - object->serializerInfo) < 0) { + if (ws_serializer_free_mem(serializerContext, object->data.common, + object->info->serializerInfo) < 0) { VIR_ERROR(_("Could not free deserialized data")); } #endif @@ -381,6 +428,70 @@ hypervReturnCodeToString(int returnCode) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Generic "Get WMI class list" helpers + */ + +int +hypervGetMsvmComputerSystemList(hypervPrivate *priv, virBufferPtr query, + Msvm_ComputerSystem **list) +{ + return hypervGetWmiClassList(priv, Msvm_ComputerSystem_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetMsvmConcreteJobList(hypervPrivate *priv, virBufferPtr query, + Msvm_ConcreteJob **list) +{ + return hypervGetWmiClassList(priv, Msvm_ConcreteJob_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetWin32ComputerSystemList(hypervPrivate *priv, virBufferPtr query, + Win32_ComputerSystem **list) +{ + return hypervGetWmiClassList(priv, Win32_ComputerSystem_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetWin32ProcessorList(hypervPrivate *priv, virBufferPtr query, + Win32_Processor **list) +{ + return hypervGetWmiClassList(priv, Win32_Processor_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetMsvmVirtualSystemSettingDataList(hypervPrivate *priv, + virBufferPtr query, + Msvm_VirtualSystemSettingData **list) +{ + return hypervGetWmiClassList(priv, Msvm_VirtualSystemSettingData_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv, + virBufferPtr query, + Msvm_ProcessorSettingData **list) +{ + return hypervGetWmiClassList(priv, Msvm_ProcessorSettingData_WmiInfo, query, + (hypervObject **) list); +} + +int +hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query, + Msvm_MemorySettingData **list) +{ + return hypervGetWmiClassList(priv, Msvm_MemorySettingData_WmiInfo, query, + (hypervObject **) list); +} + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Msvm_ComputerSystem */ @@ -402,6 +513,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, virBuffer query = VIR_BUFFER_INITIALIZER; Msvm_ConcreteJob *concreteJob = NULL; bool completed = false; + const char *resourceUri = MSVM_COMPUTERSYSTEM_V2_RESOURCE_URI; virUUIDFormat(domain->uuid, uuid_string); @@ -410,6 +522,9 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, virAsprintf(&properties, "RequestedState=%d", requestedState) < 0) goto cleanup; + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) + resourceUri = MSVM_COMPUTERSYSTEM_V1_RESOURCE_URI; + options = wsmc_options_init(); if (options == NULL) { @@ -422,7 +537,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, wsmc_add_prop_from_str(options, properties); /* Invoke method */ - response = wsmc_action_invoke(priv->client, MSVM_COMPUTERSYSTEM_RESOURCE_URI, + response = wsmc_action_invoke(priv->client, resourceUri, options, "RequestStateChange", NULL); if (hypervVerifyResponse(priv->client, response, "invocation") < 0) @@ -471,7 +586,7 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, goto cleanup; } - switch (concreteJob->data->JobState) { + switch (concreteJob->data.common->JobState) { case MSVM_CONCRETEJOB_JOBSTATE_NEW: case MSVM_CONCRETEJOB_JOBSTATE_STARTING: case MSVM_CONCRETEJOB_JOBSTATE_RUNNING: @@ -530,7 +645,7 @@ int hypervMsvmComputerSystemEnabledStateToDomainState (Msvm_ComputerSystem *computerSystem) { - switch (computerSystem->data->EnabledState) { + switch (computerSystem->data.common->EnabledState) { case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN: return VIR_DOMAIN_NOSTATE; @@ -570,7 +685,7 @@ hypervIsMsvmComputerSystemActive(Msvm_ComputerSystem *computerSystem, if (in_transition != NULL) *in_transition = false; - switch (computerSystem->data->EnabledState) { + switch (computerSystem->data.common->EnabledState) { case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN: return false; @@ -615,17 +730,17 @@ hypervMsvmComputerSystemToDomain(virConnectPtr conn, return -1; } - if (virUUIDParse(computerSystem->data->Name, uuid) < 0) { + if (virUUIDParse(computerSystem->data.common->Name, uuid) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not parse UUID from string '%s'"), - computerSystem->data->Name); + computerSystem->data.common->Name); return -1; } if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) - id = computerSystem->data->ProcessID; + id = computerSystem->data.common->ProcessID; - *domain = virGetDomain(conn, computerSystem->data->ElementName, uuid, id); + *domain = virGetDomain(conn, computerSystem->data.common->ElementName, uuid, id); return *domain ? 0 : -1; } @@ -661,7 +776,3 @@ hypervMsvmComputerSystemFromDomain(virDomainPtr domain, return 0; } - - - -#include "hyperv_wmi.generated.c" diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 563475c65c75f18ae7b37702b1af8346a3301219..edb8efa3d24a92ea6af0effb6269413ed5c1ca61 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -31,7 +31,7 @@ -typedef struct _hypervObject hypervObject; +# define HYPERV_WQL_QUERY_INITIALIZER { NULL, NULL } int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, const char *detail); @@ -41,8 +41,9 @@ int hypervVerifyResponse(WsManClient *client, WsXmlDocH response, /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Object */ -typedef struct _hypervObjectUnified hypervObjectUnified; -struct _hypervObjectUnified { + +typedef struct _hypervObject hypervObject; +struct _hypervObject { /* Unserialized data from wsman response. The member called "common" has * properties that are the same type and name for all "versions" of given * WMI class. This means that calling code does not have to make any @@ -57,18 +58,17 @@ struct _hypervObjectUnified { } data; /* The info used to make wsman request */ hypervWmiClassInfoPtr info; - hypervObjectUnified *next; + hypervObject *next; }; -struct _hypervObject { - XmlSerializerInfo *serializerInfo; - XML_TYPE_PTR data; - hypervObject *next; +typedef struct _hypervWqlQuery hypervWqlQuery; +typedef hypervWqlQuery *hypervWqlQueryPtr; +struct _hypervWqlQuery { + virBufferPtr query; + hypervWmiClassInfoListPtr info; }; -int hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, - const char *root, XmlSerializerInfo *serializerInfo, - const char *resourceUri, const char *className, +int hypervEnumAndPull(hypervPrivate *priv, hypervWqlQueryPtr wqlQuery, hypervObject **list); void hypervFreeObject(hypervPrivate *priv, hypervObject *object); @@ -111,6 +111,35 @@ const char *hypervReturnCodeToString(int returnCode); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Generic "Get WMI class list" helpers + */ + +int hypervGetMsvmComputerSystemList(hypervPrivate *priv, virBufferPtr query, + Msvm_ComputerSystem **list); + +int hypervGetMsvmConcreteJobList(hypervPrivate *priv, virBufferPtr query, + Msvm_ConcreteJob **list); + +int hypervGetWin32ComputerSystemList(hypervPrivate *priv, virBufferPtr query, + Win32_ComputerSystem **list); + +int hypervGetWin32ProcessorList(hypervPrivate *priv, virBufferPtr query, + Win32_Processor **list); + +int hypervGetMsvmVirtualSystemSettingDataList(hypervPrivate *priv, + virBufferPtr query, + Msvm_VirtualSystemSettingData **list); + +int hypervGetMsvmProcessorSettingDataList(hypervPrivate *priv, + virBufferPtr query, + Msvm_ProcessorSettingData **list); + +int hypervGetMsvmMemorySettingDataList(hypervPrivate *priv, virBufferPtr query, + Msvm_MemorySettingData **list); + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Msvm_ComputerSystem */ @@ -131,8 +160,4 @@ int hypervMsvmComputerSystemToDomain(virConnectPtr conn, int hypervMsvmComputerSystemFromDomain(virDomainPtr domain, Msvm_ComputerSystem **computerSystem); - - -# include "hyperv_wmi.generated.h" - #endif /* __HYPERV_WMI_H__ */ diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index b0f3e3c43a205b6a3a6297f8f3f9fe6826c9fd75..f7d596febf73018418b4060e4054a359a449e2ac 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -27,6 +27,15 @@ # include "hyperv_wmi_classes.generated.typedef" +# define ROOT_CIMV2 \ + "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*" + +# define ROOT_VIRTUALIZATION \ + "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*" + +# define ROOT_VIRTUALIZATION_V2 \ + "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/v2/*" + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index 209a9ff140539329540f27dc497ffc4b7d62b18a..d7f819edee3c47e8b85b84230496c7a64f244763 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -56,6 +56,55 @@ class Msvm_ComputerSystem end +class v2/Msvm_ComputerSystem + string InstanceID + string Caption + string Description + string ElementName + datetime InstallDate + 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 CreationClassName + string Name + string PrimaryOwnerName + string PrimaryOwnerContact + string Roles[] + string NameFormat + string OtherIdentifyingInfo[] + string IdentifyingDescriptions[] + uint16 Dedicated[] + string OtherDedicatedDescriptions[] + uint16 ResetCapability + uint16 PowerManagementCapabilities[] + uint64 OnTimeInMilliseconds + uint32 ProcessID + datetime TimeOfLastConfigurationChange + uint16 NumberOfNumaNodes + uint16 ReplicationState + uint16 ReplicationHealth + uint16 ReplicationMode + uint16 FailedOverReplicationType + uint16 LastReplicationType + datetime LastApplicationConsistentReplicationTime + datetime LastReplicationTime + datetime LastSuccessfulBackupTime + uint16 EnhancedSessionModeState +end + + class Msvm_ConcreteJob string Caption string Description @@ -96,6 +145,51 @@ class Msvm_ConcreteJob end +class v2/Msvm_ConcreteJob + 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 + string JobStatus + datetime TimeSubmitted + datetime ScheduledStartTime + datetime StartTime + datetime ElapsedTime + uint32 JobRunTimes + uint8 RunMonth + sint8 RunDay + sint8 RunDayOfWeek + datetime RunStartInterval + uint16 LocalOrUtcTime + datetime UntilTime + string Notify + string Owner + uint32 Priority + uint16 PercentComplete + boolean DeleteOnCompletion + uint16 ErrorCode + string ErrorDescription + string ErrorSummaryDescription + uint16 RecoveryAction + string OtherRecoveryAction + uint16 JobState + datetime TimeOfLastStateChange + datetime TimeBeforeRemoval + boolean Cancellable + uint16 JobType +end + + class Msvm_MemorySettingData string Caption string Description @@ -126,6 +220,38 @@ class Msvm_MemorySettingData end +class v2/Msvm_MemorySettingData + string InstanceID + string Caption + string Description + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Reservation + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + string AddressOnParent + string VirtualQuantityUnits + boolean DynamicMemoryEnabled + uint32 TargetMemoryBuffer + boolean IsVirtualized + boolean SwapFilesInUse + uint64 MaxMemoryBlocksPerNumaNode +end + + class Msvm_ProcessorSettingData string Caption string Description @@ -159,6 +285,37 @@ class Msvm_ProcessorSettingData end +class v2/Msvm_ProcessorSettingData + string InstanceID + string Caption + string Description + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Reservation + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + string AddressOnParent + string VirtualQuantityUnits + boolean LimitCPUID + boolean LimitProcessorFeatures + uint64 MaxProcessorsPerNumaNode + uint64 MaxNumaNodesPerSocket +end + + class Msvm_VirtualSystemSettingData string Caption string Description @@ -184,6 +341,55 @@ class Msvm_VirtualSystemSettingData end +class v2/Msvm_VirtualSystemSettingData + string InstanceID + string Caption + string Description + string ElementName + string VirtualSystemIdentifier + string VirtualSystemType + string Notes[] + datetime CreationTime + string ConfigurationID + string ConfigurationDataRoot + string ConfigurationFile + string SnapshotDataRoot + string SuspendDataRoot + string SwapFileDataRoot + string LogDataRoot + uint16 AutomaticStartupAction + datetime AutomaticStartupActionDelay + uint16 AutomaticStartupActionSequenceNumber + uint16 AutomaticShutdownAction + uint16 AutomaticRecoveryAction + string RecoveryFile + string BIOSGUID + string BIOSSerialNumber + string BaseBoardSerialNumber + string ChassisSerialNumber + string ChassisAssetTag + boolean BIOSNumLock + uint16 BootOrder[] + string Parent + boolean IsSaved + string AdditionalRecoveryInformation + boolean AllowFullSCSICommandSet + uint32 DebugChannelId + uint16 DebugPortEnabled + uint32 DebugPort + string Version + boolean IncrementalBackupEnabled + boolean VirtualNumaEnabled + boolean AllowReducedFcRedundancy + string VirtualSystemSubType + string BootSourceOrder[] + boolean PauseAfterBootFailure + uint16 NetworkBootPreferredProtocol + boolean SecureBootEnabled + uint64 LowMmioGapSize +end + + class Win32_ComputerSystem uint16 AdminPasswordStatus boolean AutomaticManagedPagefile @@ -607,39 +813,6 @@ class Msvm_VirtualSystemGlobalSettingData end -class Msvm_VirtualSwitch - string Caption - string Description - string ElementName - datetime InstallDate - uint16 OperationalStatus[] - string StatusDescriptions[] - string Status - uint16 HealthState - uint16 EnabledState - string OtherEnabledState - uint16 RequestedState - uint16 EnabledDefault - datetime TimeOfLastStateChange - string CreationClassName - string Name - string PrimaryOwnerContact - string PrimaryOwnerName - string Roles[] - string NameFormat - string OtherIdentifyingInfo[] - string IdentifyingDescriptions[] - uint16 Dedicated[] - string OtherDedicatedDescriptions[] - uint16 ResetCapability - uint16 PowerManagementCapabilities[] - string ScopeOfResidence - uint32 NumLearnableAddresses - uint32 MaxVMQOffloads - uint32 MaxChimneyOffloads -end - - class Msvm_ResourceAllocationSettingData string Caption string Description diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py index 8c62882d61e7ce454c04ba6b262c393226063d2f..c15d97adc5b70be12f8db2240ac05268b5e869d5 100755 --- a/src/hyperv/hyperv_wmi_generator.py +++ b/src/hyperv/hyperv_wmi_generator.py @@ -24,130 +24,310 @@ import sys import os import os.path +separator = "/*" + ("*" * 50) + "*\n" +wmi_version_separator = "/" +wmi_classes_by_name = {} + +class WmiClass: + """Represents WMI class and provides methods to generate C code. + + This class holds one or more instances of WmiClassVersion because with the + Windows 2012 release, Microsoft introduced "v2" version of Msvm_* family of + classes that need different URI for making wsman requests and also have + some additional/changed properties (though many of the properies are the + same as in "v1". Therefore, this class makes sure that C code is generated + for each of them while avoiding name conflics, identifies common members, + and defined *_WmiInfo structs holding info about each version so the driver + code can make the right choices based on which Hyper-V host it's connected + to. + """ + + def __init__(self, name, versions = []): + self.name = name + self.versions = versions + self.common = None -separator = "/* " + ("* " * 37) + "*\n" + def prepare(self): + """Prepares the class for code generation + Makes sure that "versioned" classes are sorted by version, identifies + common properies and ensures that they are aligned by name and + type in each version + """ + # sort vesioned classes by version in case input file did not have them + # in order + self.versions = sorted(self.versions, key=lambda cls: cls.version) + # if there's more than one verion make sure first one has name suffixed + # because we'll generate "common" memeber and will be the "base" name + if len(self.versions) > 1: + first = self.versions[0] + if first.version == None: + first.version = "v1" + first.name = "%s_%s" % (first.name, first.version) -class Class: - def __init__(self, name, properties): - self.name = name - self.properties = properties + # finally, identify common members in all versions and make sure they + # are in the same order - to ensure C struct member alignment + self._align_property_members() - def generate_header(self): + def generate_classes_header(self): + """Generate C header code and return it as string + + Declares: + <class_name>_Data - used as one of hypervObject->data members + <class_name>_TypeInfo - used as wsman XmlSerializerInfo + <class_name> - "inherits" hypervObject struct + """ + name_upper = self.name.upper() header = separator header += " * %s\n" % self.name header += " */\n" header += "\n" - header += "int hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list);\n" \ - % (self.name.replace("_", ""), self.name) - header += "\n" + header += "#define %s_CLASSNAME \\\n" % name_upper + header += " \"%s\"\n" % self.name header += "\n" + header += "#define %s_WQL_SELECT \\\n" % name_upper + header += " \"SELECT * FROM %s \"\n" % self.name header += "\n" + header += "extern hypervWmiClassInfoListPtr %s_WmiInfo;\n\n" % self.name + + header += self._declare_data_structs() + header += self._declare_hypervObject_struct() return header + def generate_classes_source(self): + """Returns a C code string defining wsman data structs + + Defines: + <class_name>_Data structs + <class_name>_WmiInfo - list holding metadata (e.g. request URIs) for + each known version of WMI class. + """ + + source = separator + source += " * %s\n" % self.name + source += " */\n" + + for cls in self.versions: + source += "SER_START_ITEMS(%s_Data)\n" % cls.name + + for property in cls.properties: + source += property.generate_classes_source(cls.name) + + source += "SER_END_ITEMS(%s_Data);\n\n" % cls.name + + + source += self._define_WmiInfo_struct() + source += "\n\n" + + return source + + def generate_classes_typedef(self): - typedef = "typedef struct _%s_Data %s_Data;\n" % (self.name, self.name) - typedef += "typedef struct _%s %s;\n" % (self.name, self.name) + """Returns C string for typdefs""" + + typedef = "typedef struct _%s %s;\n" % (self.name, self.name) + + if self.common is not None: + typedef += "typedef struct _%s_Data %s_Data;\n" % (self.name, self.name) + + for cls in self.versions: + typedef += "typedef struct _%s_Data %s_Data;\n" % (cls.name, cls.name) return typedef - def generate_classes_header(self): - name_upper = self.name.upper() - header = separator - header += " * %s\n" % self.name - header += " */\n" - header += "\n" - header += "#define %s_RESOURCE_URI \\\n" % name_upper + def _declare_data_structs(self): + """Returns string C code declaring data structs. - if self.name.startswith("Win32_") or self.name.startswith("CIM_"): - header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/%s\"\n" % self.name - else: - header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/%s\"\n" % self.name + The *_Data structs are members of hypervObject data union. Each one has + corresponding *_TypeInfo that is used for wsman unserialization of + response XML into the *_Data structs. If there's a "common" member, it + won't have corresponding *_TypeInfo becuase this is a special case only + used to provide a common "view" of v1, v2 etc members + """ - header += "\n" - header += "#define %s_CLASSNAME \\\n" % name_upper - header += " \"%s\"\n" % self.name - header += "\n" - header += "#define %s_WQL_SELECT \\\n" % name_upper - header += " \"select * from %s \"\n" % self.name - header += "\n" - header += "struct _%s_Data {\n" % self.name + header = "" + if self.common is not None: + header += "struct _%s_Data {\n" % self.name + for property in self.common: + header += property.generate_classes_header() + header += "};\n\n" - for property in self.properties: - header += property.generate_classes_header() + # Declare actual data struct for each versions + for cls in self.versions: + header += "#define %s_RESOURCE_URI \\\n" % cls.name.upper() + header += " \"%s\"\n" % cls.uri_info.resourceUri + header += "\n" + header += "struct _%s_Data {\n" % cls.name + for property in cls.properties: + header += property.generate_classes_header() + header += "};\n\n" + header += "SER_DECLARE_TYPE(%s_Data);\n" % cls.name - header += "};\n" - header += "\n" - header += "SER_DECLARE_TYPE(%s_Data);\n" % self.name - header += "\n" + return header + + + def _declare_hypervObject_struct(self): + """Return string for C code declaring hypervObject instance""" + + header = "\n/* must match hypervObject */\n" header += "struct _%s {\n" % self.name - header += " XmlSerializerInfo *serializerInfo;\n" - header += " %s_Data *data;\n" % self.name + header += " union {\n" + + # if there's common use it as "common" else first and only version is + # the "common" member + if self.common is not None: + header += " %s_Data *common;\n" % self.name + else: + header += " %s_Data *common;\n" % self.versions[0].name + + for cls in self.versions: + header += " %s_Data *%s;\n" % (cls.name, cls.version) + + header += " } data;\n" + header += " hypervWmiClassInfoPtr info;\n" header += " %s *next;\n" % self.name header += "};\n" - header += "\n" - header += "\n" - header += "\n" + + header += "\n\n\n" return header - def generate_source(self): - name_upper = self.name.upper() + def _define_WmiInfo_struct(self): + """Return string for C code defining *_WmiInfo struct - source = separator - source += " * %s\n" % self.name - source += " */\n" - source += "\n" - source += "int\n" - source += "hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list)\n" \ - % (self.name.replace("_", ""), self.name) - source += "{\n" - - if self.name.startswith("Win32_") or self.name.startswith("CIM_"): - source += " return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n" - else: - source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\n" + Those structs hold info with meta-data needed to make wsman requests for + each version of WMI class + """ + + source = "hypervWmiClassInfoListPtr %s_WmiInfo = &(hypervWmiClassInfoList) {\n" % self.name + source += " .count = %d,\n" % len(self.versions) + source += " .objs = (hypervWmiClassInfoPtr []) {\n" + + for cls in self.versions: + source += " &(hypervWmiClassInfo) {\n" + source += " .name = %s_CLASSNAME,\n" % self.name.upper() + if cls.version is not None: + source += " .version = \"%s\",\n" % cls.version + else: + 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 += " },\n" - source += " %s_Data_TypeInfo,\n" % self.name - source += " %s_RESOURCE_URI,\n" % name_upper - source += " %s_CLASSNAME,\n" % name_upper - source += " (hypervObject **)list);\n" - source += "}\n" - source += "\n" - source += "\n" - source += "\n" + source += " }\n" + source += "};\n" return source - def generate_classes_source(self): - name_upper = self.name.upper() + def _align_property_members(self): + """Identifies common properties in all class versions. - source = separator - source += " * %s\n" % self.name - source += " */\n" - source += "\n" - source += "SER_START_ITEMS(%s_Data)\n" % self.name + Makes sure that properties in all versions are ordered with common + members first and that they are in the same order. This makes the + generated C structs memory aligned and safe to access via the "common" + struct that "shares" members with v1, v2 etc. + """ - for property in self.properties: - source += property.generate_classes_source(self.name) + num_classes = len(self.versions) + common = {} + property_info = {} - source += "SER_END_ITEMS(%s_Data);\n" % self.name - source += "\n" - source += "\n" - source += "\n" + if num_classes < 2: + return + + # count property occurences in all class versions + for cls in self.versions: + for prop in cls.properties: + # consdered same if matches by name AND type + key = "%s_%s" % (prop.name, prop.type) + + if key in property_info: + property_info[key][1] += 1 + else: + property_info[key] = [prop, 1] + + # isolate those that are common for all and keep track of their postions + pos = 0 + for key in property_info: + info = property_info[key] + # exists in all class versions + if info[1] == num_classes: + common[info[0].name] = [info[0], pos] + pos += 1 + + # alter each versions's property list so that common members are first + # and in the same order as in the common dictionary + total = len(common) + for cls in self.versions: + index = 0 + count = len(cls.properties) + + while index < count: + prop = cls.properties[index] + + # it's a "common" property + if prop.name in common: + pos = common[prop.name][1] + + # move to the same position as in "common" dictionary + if index != pos: + tmp = cls.properties[pos] + cls.properties[pos] = prop + cls.properties[index] = tmp + else: + index += 1 + else: + index += 1 + + # finally, get common properties as list sorted by position in dictionary + tmp = sorted(common.values(), key=lambda x: x[1]) + self.common = [] + for x in tmp: + self.common.append(x[0]) + + + +class ClassUriInfo: + """Prepares URI information needed for wsman requests.""" + + def __init__(self, wmi_name, version): + self.rootUri = "ROOT_CIMV2" + self.resourceUri = None + baseUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2" + + if wmi_name.startswith("Msvm_"): + baseUri = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization" + self.rootUri = "ROOT_VIRTUALIZATION" + + if version == "v2": + baseUri += "/v2" + self.rootUri = "ROOT_VIRTUALIZATION_V2" + + self.resourceUri = "%s/%s" % (baseUri, wmi_name) + + + +class WmiClassVersion: + """Represents specific version of WMI class.""" + + def __init__(self, name, version, properties, uri_info): + self.name = name + self.version = version + self.properties = properties + self.uri_info = uri_info - return source class Property: @@ -155,9 +335,13 @@ class Property: "string" : "STR", "datetime" : "STR", "int8" : "INT8", + "sint8" : "INT8", "int16" : "INT16", + "sint16" : "INT16", "int32" : "INT32", + "sint32" : "INT32", "int64" : "INT64", + "sint64" : "INT64", "uint8" : "UINT8", "uint16" : "UINT16", "uint32" : "UINT32", @@ -217,8 +401,15 @@ def parse_class(block): assert header_items[0] == "class" name = header_items[1] - properties = [] + version = None + wmi_name = name + ns_separator = name.find(wmi_version_separator) + + if ns_separator != -1: + version = name[:ns_separator] + wmi_name = name[ns_separator + 1:] + name = "%s_%s" % (wmi_name, version) for line in block[1:]: # expected format: <type> <name> @@ -236,7 +427,13 @@ def parse_class(block): properties.append(Property(type=items[0], name=items[1], is_array=is_array)) - return Class(name=name, properties=properties) + cls = WmiClassVersion(name=name, version=version, properties=properties, + uri_info=ClassUriInfo(wmi_name, version)) + + if wmi_name in wmi_classes_by_name: + wmi_classes_by_name[wmi_name].versions.append(cls) + else: + wmi_classes_by_name[wmi_name] = WmiClass(wmi_name, [cls]) @@ -248,15 +445,12 @@ def main(): input_filename = os.path.join(os.getcwd(), "hyperv_wmi_generator.input") output_dirname = os.getcwd() - header = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.h")) - source = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.c")) classes_typedef = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.typedef")) classes_header = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.h")) classes_source = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.c")) # parse input file number = 0 - classes_by_name = {} block = None for line in file(input_filename, "rb").readlines(): @@ -279,8 +473,7 @@ def main(): if block is not None: if line == "end": if block[0][1].startswith("class"): - cls = parse_class(block) - classes_by_name[cls.name] = cls + parse_class(block) block = None else: @@ -289,21 +482,20 @@ def main(): # write output files notice = "/* Generated by hyperv_wmi_generator.py */\n\n\n\n" - header.write(notice) - source.write(notice) classes_typedef.write(notice) classes_header.write(notice) classes_source.write(notice) - names = classes_by_name.keys() + names = wmi_classes_by_name.keys() names.sort() for name in names: - header.write(classes_by_name[name].generate_header()) - source.write(classes_by_name[name].generate_source()) - classes_typedef.write(classes_by_name[name].generate_classes_typedef()) - classes_header.write(classes_by_name[name].generate_classes_header()) - classes_source.write(classes_by_name[name].generate_classes_source()) + cls = wmi_classes_by_name[name] + cls.prepare() + + classes_typedef.write(cls.generate_classes_typedef()) + classes_header.write(cls.generate_classes_header()) + classes_source.write(cls.generate_classes_source())