Add a generator script to generate the structs and serialization information for OpenWSMAN. openwsman.h collects workarounds for problems in OpenWSMAN <= 2.2.6. There are also disabled sections that would use ws_serializer_free_mem but can't because it's broken in OpenWSMAN <= 2.2.6. Patches to fix this have been posted upstream. --- v2: - no changes po/POTFILES.in | 1 + src/Makefile.am | 25 ++- src/hyperv/.gitignore | 1 + src/hyperv/hyperv_private.h | 7 + src/hyperv/hyperv_wmi.c | 684 +++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi.h | 121 ++++++ src/hyperv/hyperv_wmi_classes.c | 37 ++ src/hyperv/hyperv_wmi_classes.h | 94 +++++ src/hyperv/hyperv_wmi_generator.input | 294 ++++++++++++++ src/hyperv/hyperv_wmi_generator.py | 309 +++++++++++++++ src/hyperv/openwsman.h | 47 +++ 11 files changed, 1619 insertions(+), 1 deletions(-) create mode 100644 src/hyperv/.gitignore create mode 100644 src/hyperv/hyperv_wmi.c create mode 100644 src/hyperv/hyperv_wmi.h create mode 100644 src/hyperv/hyperv_wmi_classes.c create mode 100644 src/hyperv/hyperv_wmi_classes.h create mode 100644 src/hyperv/hyperv_wmi_generator.input create mode 100755 src/hyperv/hyperv_wmi_generator.py create mode 100644 src/hyperv/openwsman.h diff --git a/po/POTFILES.in b/po/POTFILES.in index ddeef34..b7b2854 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -29,6 +29,7 @@ src/esx/esx_vi_methods.c src/esx/esx_vi_types.c src/fdstream.c src/hyperv/hyperv_driver.c +src/hyperv/hyperv_wmi.c src/interface/netcf_driver.c src/internal.h src/libvirt.c diff --git a/src/Makefile.am b/src/Makefile.am index 7d95652..1eaedc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -410,7 +410,23 @@ HYPERV_DRIVER_SOURCES = \ hyperv/hyperv_storage_driver.c hyperv/hyperv_storage_driver.h \ hyperv/hyperv_device_monitor.c hyperv/hyperv_device_monitor.h \ hyperv/hyperv_secret_driver.c hyperv/hyperv_secret_driver.h \ - hyperv/hyperv_nwfilter_driver.c hyperv/hyperv_nwfilter_driver.h + hyperv/hyperv_nwfilter_driver.c hyperv/hyperv_nwfilter_driver.h \ + hyperv/hyperv_wmi.c hyperv/hyperv_wmi.h \ + hyperv/hyperv_wmi_classes.c hyperv/hyperv_wmi_classes.h \ + 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 + +HYPERV_DRIVER_EXTRA_DIST = \ + hyperv/hyperv_wmi_generator.input \ + hyperv/hyperv_wmi_generator.py \ + $(HYPERV_DRIVER_GENERATED) + NETWORK_DRIVER_SOURCES = \ network/bridge_driver.h network/bridge_driver.c @@ -843,6 +859,12 @@ libvirt_driver_esx_la_DEPENDENCIES = $(ESX_DRIVER_GENERATED) endif +BUILT_SOURCES += $(HYPERV_DRIVER_GENERATED) + +$(HYPERV_DRIVER_GENERATED): $(srcdir)/hyperv/hyperv_wmi_generator.input \ + $(srcdir)/hyperv/hyperv_wmi_generator.py + $(AM_V_GEN)srcdir=$(srcdir) $(srcdir)/hyperv/hyperv_wmi_generator.py + if WITH_HYPERV if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_hyperv.la @@ -1053,6 +1075,7 @@ EXTRA_DIST += \ $(ESX_DRIVER_SOURCES) \ $(ESX_DRIVER_EXTRA_DIST) \ $(HYPERV_DRIVER_SOURCES) \ + $(HYPERV_DRIVER_EXTRA_DIST) \ $(NETWORK_DRIVER_SOURCES) \ $(INTERFACE_DRIVER_SOURCES) \ $(STORAGE_DRIVER_SOURCES) \ diff --git a/src/hyperv/.gitignore b/src/hyperv/.gitignore new file mode 100644 index 0000000..29e1d48 --- /dev/null +++ b/src/hyperv/.gitignore @@ -0,0 +1 @@ +*.generated.* diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h index 17bdd60..0d5370e 100644 --- a/src/hyperv/hyperv_private.h +++ b/src/hyperv/hyperv_private.h @@ -26,9 +26,16 @@ # include "internal.h" # include "virterror_internal.h" +# include "openwsman.h" # define HYPERV_ERROR(code, ...) \ virReportErrorHelper(VIR_FROM_HYPERV, code, __FILE__, __FUNCTION__, \ __LINE__, __VA_ARGS__) +typedef struct _hypervPrivate hypervPrivate; + +struct _hypervPrivate { + WsManClient *client; +}; + #endif /* __HYPERV_PRIVATE_H__ */ diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c new file mode 100644 index 0000000..dcfc3f9 --- /dev/null +++ b/src/hyperv/hyperv_wmi.c @@ -0,0 +1,684 @@ + +/* + * hyperv_wmi.h: general WMI over WSMAN related functions and structures for + * managing Microsoft Hyper-V hosts + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "virterror_internal.h" +#include "datatypes.h" +#include "logging.h" +#include "memory.h" +#include "util.h" +#include "uuid.h" +#include "buf.h" +#include "hyperv_private.h" +#include "hyperv_wmi.h" + +#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 VIR_FROM_THIS VIR_FROM_HYPERV + + + +int +hyperyVerifyResponse(WsManClient *client, WsXmlDocH response, + const char *detail) +{ + int lastError = wsmc_get_last_error(client); + int responseCode = wsmc_get_response_code(client); + WsManFault *fault; + + if (lastError != WS_LASTERR_OK) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Transport error during %s: %s (%d)"), + detail, wsman_transport_get_last_error_string(lastError), + lastError); + return -1; + } + + if (responseCode != 200 && responseCode != 400 && responseCode != 500) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Unexpected HTTP response during %s: %d"), + detail, responseCode); + return -1; + } + + if (response == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Empty response during %s"), detail); + return -1; + } + + if (wsmc_check_for_fault(response)) { + fault = wsmc_fault_new(); + + if (fault == NULL) { + virReportOOMError(); + return -1; + } + + wsmc_get_fault_data(response, fault); + + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("SOAP fault during %s: code '%s', subcode '%s', " + "reason '%s', detail '%s'"), + detail, NULLSTR(fault->code), NULLSTR(fault->subcode), + NULLSTR(fault->reason), NULLSTR(fault->fault_detail)); + + wsmc_fault_destroy(fault); + return -1; + } + + return 0; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Object + */ + +int +hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, + XmlSerializerInfo *serializerInfo, const char *resourceUri, + const char *className, hypervObject **list) +{ + int result = -1; + WsSerializerContextH serializerContext; + client_opt_t *options = NULL; + char *query_string = NULL; + filter_t *filter = NULL; + WsXmlDocH response = NULL; + char *enumContext = NULL; + hypervObject *head = NULL; + hypervObject *tail = NULL; + WsXmlNodeH node = NULL; + XML_TYPE_PTR data = NULL; + hypervObject *object; + + if (list == NULL || *list != NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + if (virBufferError(query)) { + virReportOOMError(); + return -1; + } + + serializerContext = wsmc_get_serialization_context(priv->client); + + options = wsmc_options_init(); + + if (options == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not initialize options")); + goto cleanup; + } + + query_string = virBufferContentAndReset(query); + filter = filter_create_simple(WSM_WQL_FILTER_DIALECT, query_string); + + if (filter == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create filter")); + goto cleanup; + } + + response = wsmc_action_enumerate(priv->client, root, options, filter); + + if (hyperyVerifyResponse(priv->client, response, "enumeration") < 0) { + goto cleanup; + } + + enumContext = wsmc_get_enum_context(response); + + ws_xml_destroy_doc(response); + response = NULL; + + while (enumContext != NULL && *enumContext != '\0' ) { + response = wsmc_action_pull(priv->client, resourceUri, options, + filter, enumContext); + + if (hyperyVerifyResponse(priv->client, response, "pull") < 0) { + goto cleanup; + } + + node = ws_xml_get_soap_body(response); + + if (node == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup SOAP body")); + goto cleanup; + } + + node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP); + + if (node == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response")); + goto cleanup; + } + + node = ws_xml_get_child(node, 0, XML_NS_ENUMERATION, WSENUM_ITEMS); + + if (node == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response items")); + goto cleanup; + } + + if (ws_xml_get_child(node, 0, resourceUri, className) == NULL) { + break; + } + + data = ws_deserialize(serializerContext, node, serializerInfo, + className, resourceUri, NULL, 0, 0); + + if (data == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not deserialize pull response item")); + goto cleanup; + } + + if (VIR_ALLOC(object) < 0) { + virReportOOMError(); + goto cleanup; + } + + object->serializerInfo = serializerInfo; + object->data = data; + + data = NULL; + + if (head == NULL) { + head = object; + } else { + tail->next = object; + } + + tail = object; + + VIR_FREE(enumContext); + enumContext = wsmc_get_enum_context(response); + + ws_xml_destroy_doc(response); + response = NULL; + } + + *list = head; + head = NULL; + + result = 0; + + cleanup: + if (options != NULL) { + wsmc_options_destroy(options); + } + + if (filter != NULL) { + filter_destroy(filter); + } + + if (data != NULL) { +#if 0 + /* 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) { + VIR_ERROR(_("Could not free deserialized data")); + } +#endif + } + + VIR_FREE(query_string); + ws_xml_destroy_doc(response); + VIR_FREE(enumContext); + hypervFreeObject(priv, head); + + return result; +} + +void +hypervFreeObject(hypervPrivate *priv ATTRIBUTE_UNUSED, hypervObject *object) +{ + hypervObject *next; +#if 0 + WsSerializerContextH serializerContext; +#endif + + if (object == NULL) { + return; + } + +#if 0 + serializerContext = wsmc_get_serialization_context(priv->client); +#endif + + while (object != NULL) { + next = object->next; + +#if 0 + /* FIXME: ws_serializer_free_mem is broken in openwsman <= 2.2.6, + * but this is not that critical, because openwsman keeps + * track of all allocations of the deserializer and frees + * 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) { + VIR_ERROR(_("Could not free deserialized data")); + } +#endif + + VIR_FREE(object); + + object = next; + } +} + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * CIM/Msvm_ReturnCode + */ + +const char * +hypervReturnCodeToString(int returnCode) +{ + switch (returnCode) { + case CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR: + return _("Completed with no error"); + + case CIM_RETURNCODE_NOT_SUPPORTED: + return _("Not supported"); + + case CIM_RETURNCODE_UNKNOWN_ERROR: + return _("Unknown error"); + + case CIM_RETURNCODE_CANNOT_COMPLETE_WITHIN_TIMEOUT_PERIOD: + return _("Cannot complete within timeout period"); + + case CIM_RETURNCODE_FAILED: + return _("Failed"); + + case CIM_RETURNCODE_INVALID_PARAMETER: + return _("Invalid parameter"); + + case CIM_RETURNCODE_IN_USE: + return _("In use"); + + case CIM_RETURNCODE_TRANSITION_STARTED: + return _("Transition started"); + + case CIM_RETURNCODE_INVALID_STATE_TRANSITION: + return _("Invalid state transition"); + + case CIM_RETURNCODE_TIMEOUT_PARAMETER_NOT_SUPPORTED: + return _("Timeout parameter not supported"); + + case CIM_RETURNCODE_BUSY: + return _("Busy"); + + case MSVM_RETURNCODE_FAILED: + return _("Failed"); + + case MSVM_RETURNCODE_ACCESS_DENIED: + return _("Access denied"); + + case MSVM_RETURNCODE_NOT_SUPPORTED: + return _("Not supported"); + + case MSVM_RETURNCODE_STATUS_IS_UNKNOWN: + return _("Status is unknown"); + + case MSVM_RETURNCODE_TIMEOUT: + return _("Timeout"); + + case MSVM_RETURNCODE_INVALID_PARAMETER: + return _("Invalid parameter"); + + case MSVM_RETURNCODE_SYSTEM_IS_IN_USE: + return _("System is in use"); + + case MSVM_RETURNCODE_INVALID_STATE_FOR_THIS_OPERATION: + return _("Invalid state for this operation"); + + case MSVM_RETURNCODE_INCORRECT_DATA_TYPE: + return _("Incorrect data type"); + + case MSVM_RETURNCODE_SYSTEM_IS_NOT_AVAILABLE: + return _("System is not available"); + + case MSVM_RETURNCODE_OUT_OF_MEMORY: + return _("Out of memory"); + + default: + return _("Unknown return code"); + } +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ComputerSystem + */ + +int +hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, + int requestedState) +{ + int result = -1; + hypervPrivate *priv = domain->conn->privateData; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + WsXmlDocH response = NULL; + client_opt_t *options = NULL; + char *selector = NULL; + char *properties = NULL; + char *returnValue = NULL; + int returnCode; + char *instanceID = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ConcreteJob *concreteJob = NULL; + bool completed = false; + + virUUIDFormat(domain->uuid, uuid_string); + + if (virAsprintf(&selector, "Name=%s&CreationClassName=Msvm_ComputerSystem", + uuid_string) < 0 || + virAsprintf(&properties, "RequestedState=%d", requestedState) < 0) { + virReportOOMError(); + goto cleanup; + } + + options = wsmc_options_init(); + + if (options == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not initialize options")); + goto cleanup; + } + + wsmc_add_selectors_from_str(options, selector); + wsmc_add_prop_from_str(options, properties); + + /* Invoke method */ + response = wsmc_action_invoke(priv->client, MSVM_COMPUTERSYSTEM_RESOURCE_URI, + options, "RequestStateChange", NULL); + + if (hyperyVerifyResponse(priv->client, response, "invocation") < 0) { + goto cleanup; + } + + /* Check return value */ + returnValue = ws_xml_get_xpath_value(response, (char *)"/s:Envelope/s:Body/p:RequestStateChange_OUTPUT/p:ReturnValue"); + + if (returnValue == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "ReturnValue", "RequestStateChange"); + goto cleanup; + } + + if (virStrToLong_i(returnValue, NULL, 10, &returnCode) < 0) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not parse return code from '%s'"), returnValue); + goto cleanup; + } + + if (returnCode == CIM_RETURNCODE_TRANSITION_STARTED) { + /* Get concrete job object */ + instanceID = ws_xml_get_xpath_value(response, (char *)"/s:Envelope/s:Body/p:RequestStateChange_OUTPUT/p:Job/a:ReferenceParameters/w:SelectorSet/w:Selector[@Name='InstanceID']"); + + if (instanceID == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "InstanceID", "RequestStateChange"); + goto cleanup; + } + + /* FIXME: Poll every 100ms until the job completes or fails. There + * seems to be no other way than polling. */ + while (!completed) { + virBufferAddLit(&query, MSVM_CONCRETEJOB_WQL_SELECT); + virBufferAsprintf(&query, "where InstanceID = \"%s\"", instanceID); + + if (hypervGetMsvmConcreteJobList(priv, &query, &concreteJob) < 0) { + goto cleanup; + } + + if (concreteJob == NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "Msvm_ConcreteJob", "RequestStateChange"); + goto cleanup; + } + + switch (concreteJob->data->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 *)concreteJob); + concreteJob = NULL; + + usleep(100 * 1000); + 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: + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Concrete job for %s invocation is in error state"), + "RequestStateChange"); + goto cleanup; + + default: + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Concrete job for %s invocation is in unknown state"), + "RequestStateChange"); + goto cleanup; + } + } + } else if (returnCode != CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Invocation of %s returned an error: %s (%d)"), + "RequestStateChange", hypervReturnCodeToString(returnCode), + returnCode); + goto cleanup; + } + + result = 0; + + cleanup: + if (options != NULL) { + wsmc_options_destroy(options); + } + + ws_xml_destroy_doc(response); + VIR_FREE(selector); + VIR_FREE(properties); + VIR_FREE(returnValue); + VIR_FREE(instanceID); + hypervFreeObject(priv, (hypervObject *)concreteJob); + + return result; +} + +int +hypervMsvmComputerSystemEnabledStateToDomainState + (Msvm_ComputerSystem *computerSystem) +{ + switch (computerSystem->data->EnabledState) { + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN: + return VIR_DOMAIN_NOSTATE; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED: + return VIR_DOMAIN_RUNNING; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_DISABLED: + return VIR_DOMAIN_SHUTOFF; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED: + return VIR_DOMAIN_PAUSED; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED: + return VIR_DOMAIN_SHUTOFF; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STARTING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SNAPSHOTTING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SAVING: + return VIR_DOMAIN_RUNNING; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STOPPING: + return VIR_DOMAIN_SHUTDOWN; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_RESUMING: + return VIR_DOMAIN_RUNNING; + + default: + return VIR_DOMAIN_NOSTATE; + } +} + +bool +hypervIsMsvmComputerSystemActive(Msvm_ComputerSystem *computerSystem, + bool *in_transition) +{ + if (in_transition != NULL) { + *in_transition = false; + } + + switch (computerSystem->data->EnabledState) { + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN: + return false; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED: + return true; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_DISABLED: + return false; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED: + return true; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED: + return false; + + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STARTING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SNAPSHOTTING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SAVING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STOPPING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSING: + case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_RESUMING: + if (in_transition != NULL) { + *in_transition = true; + } + + return true; + + default: + return false; + } +} + +int +hypervMsvmComputerSystemToDomain(virConnectPtr conn, + Msvm_ComputerSystem *computerSystem, + virDomainPtr *domain) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (domain == NULL || *domain != NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + if (virUUIDParse(computerSystem->data->Name, uuid) < 0) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + computerSystem->data->Name); + return -1; + } + + *domain = virGetDomain(conn, computerSystem->data->ElementName, uuid); + + if (*domain == NULL) { + return -1; + } + + if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) { + (*domain)->id = computerSystem->data->ProcessID; + } else { + (*domain)->id = -1; + } + + return 0; +} + +int +hypervMsvmComputerSystemFromDomain(virDomainPtr domain, + Msvm_ComputerSystem **computerSystem) +{ + hypervPrivate *priv = domain->conn->privateData; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + virBuffer query = VIR_BUFFER_INITIALIZER; + + if (computerSystem == NULL || *computerSystem != NULL) { + HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + virUUIDFormat(domain->uuid, uuid_string); + + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAddLit(&query, "where "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL); + virBufferAsprintf(&query, "and Name = \"%s\"", uuid_string); + + if (hypervGetMsvmComputerSystemList(priv, &query, computerSystem) < 0) { + return -1; + } + + if (*computerSystem == NULL) { + HYPERV_ERROR(VIR_ERR_NO_DOMAIN, + _("No domain with UUID %s"), uuid_string); + return -1; + } + + return 0; +} + + + +#include "hyperv_wmi.generated.c" diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h new file mode 100644 index 0000000..fae6d4f --- /dev/null +++ b/src/hyperv/hyperv_wmi.h @@ -0,0 +1,121 @@ + +/* + * hyperv_wmi.h: general WMI over WSMAN related functions and structures for + * managing Microsoft Hyper-V hosts + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_WMI_H__ +# define __HYPERV_WMI_H__ + +# include "buf.h" +# include "hyperv_private.h" +# include "hyperv_wmi_classes.h" +# include "openwsman.h" + + + +typedef struct _hypervObject hypervObject; + +int hyperyVerifyResponse(WsManClient *client, WsXmlDocH response, + const char *detail); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Object + */ + +struct _hypervObject { + XmlSerializerInfo *serializerInfo; + XML_TYPE_PTR data; + hypervObject *next; +}; + +int hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, + const char *root, XmlSerializerInfo *serializerInfo, + const char *resourceUri, const char *className, + hypervObject **list); + +void hypervFreeObject(hypervPrivate *priv, hypervObject *object); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * CIM/Msvm_ReturnCode + */ + +enum _CIM_ReturnCode { + CIM_RETURNCODE_COMPLETED_WITH_NO_ERROR = 0, + CIM_RETURNCODE_NOT_SUPPORTED = 1, + CIM_RETURNCODE_UNKNOWN_ERROR = 2, + CIM_RETURNCODE_CANNOT_COMPLETE_WITHIN_TIMEOUT_PERIOD = 3, + CIM_RETURNCODE_FAILED = 4, + CIM_RETURNCODE_INVALID_PARAMETER = 5, + CIM_RETURNCODE_IN_USE = 6, + CIM_RETURNCODE_TRANSITION_STARTED = 4096, + CIM_RETURNCODE_INVALID_STATE_TRANSITION = 4097, + CIM_RETURNCODE_TIMEOUT_PARAMETER_NOT_SUPPORTED = 4098, + CIM_RETURNCODE_BUSY = 4099, +}; + +enum _Msvm_ReturnCode { + MSVM_RETURNCODE_FAILED = 32768, + MSVM_RETURNCODE_ACCESS_DENIED = 32769, + MSVM_RETURNCODE_NOT_SUPPORTED = 32770, + MSVM_RETURNCODE_STATUS_IS_UNKNOWN = 32771, + MSVM_RETURNCODE_TIMEOUT = 32772, + MSVM_RETURNCODE_INVALID_PARAMETER = 32773, + MSVM_RETURNCODE_SYSTEM_IS_IN_USE = 32774, + MSVM_RETURNCODE_INVALID_STATE_FOR_THIS_OPERATION = 32775, + MSVM_RETURNCODE_INCORRECT_DATA_TYPE = 32776, + MSVM_RETURNCODE_SYSTEM_IS_NOT_AVAILABLE = 32777, + MSVM_RETURNCODE_OUT_OF_MEMORY = 32778, +}; + +const char *hypervReturnCodeToString(int returnCode); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ComputerSystem + */ + +int hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, + int requestedState); + +int hypervMsvmComputerSystemEnabledStateToDomainState + (Msvm_ComputerSystem *computerSystem); + +bool hypervIsMsvmComputerSystemActive(Msvm_ComputerSystem *computerSystem, + bool *in_transition); + +int hypervMsvmComputerSystemToDomain(virConnectPtr conn, + Msvm_ComputerSystem *computerSystem, + virDomainPtr *domain); + +int hypervMsvmComputerSystemFromDomain(virDomainPtr domain, + Msvm_ComputerSystem **computerSystem); + + + +# include "hyperv_wmi.generated.h" + +#endif /* __HYPERV_WMI_H__ */ diff --git a/src/hyperv/hyperv_wmi_classes.c b/src/hyperv/hyperv_wmi_classes.c new file mode 100644 index 0000000..ed5e314 --- /dev/null +++ b/src/hyperv/hyperv_wmi_classes.c @@ -0,0 +1,37 @@ + +/* + * hyperv_wmi_classes.c: WMI classes for managing Microsoft Hyper-V hosts + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "hyperv_wmi_classes.h" + +SER_TYPEINFO_BOOL; +SER_TYPEINFO_STRING; +SER_TYPEINFO_INT8; +SER_TYPEINFO_INT16; +SER_TYPEINFO_INT32; +SER_TYPEINFO_UINT8; +SER_TYPEINFO_UINT16; +SER_TYPEINFO_UINT32; + +#include "hyperv_wmi_classes.generated.c" diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h new file mode 100644 index 0000000..5c97ca6 --- /dev/null +++ b/src/hyperv/hyperv_wmi_classes.h @@ -0,0 +1,94 @@ + +/* + * hyperv_wmi_classes.h: WMI classes for managing Microsoft Hyper-V hosts + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_WMI_CLASSES_H__ +# define __HYPERV_WMI_CLASSES_H__ + +# include "openwsman.h" + +# include "hyperv_wmi_classes.generated.typedef" + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ComputerSystem + */ + +# define MSVM_COMPUTERSYSTEM_WQL_VIRTUAL \ + "Description = \"Microsoft Virtual Machine\" " + +# define MSVM_COMPUTERSYSTEM_WQL_PHYSICAL \ + "Description = \"Microsoft Hosting Computer System\" " + +# define MSVM_COMPUTERSYSTEM_WQL_ACTIVE \ + "(EnabledState != 0 and EnabledState != 3 and EnabledState != 32769) " + +# define MSVM_COMPUTERSYSTEM_WQL_INACTIVE \ + "(EnabledState = 0 or EnabledState = 3 or EnabledState = 32769) " + +enum _Msvm_ComputerSystem_EnabledState { + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN = 0, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED = 2, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_DISABLED = 3, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED = 32768, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED = 32769, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STARTING = 32770, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SNAPSHOTTING = 32771, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SAVING = 32773, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STOPPING = 32774, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSING = 32776, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_RESUMING = 32777 /* active */ +}; + +enum _Msvm_ComputerSystem_RequestedState { + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED = 32768, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED = 32769, +}; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ConcreteJob + */ + +enum _Msvm_ConcreteJob_JobState { + MSVM_CONCRETEJOB_JOBSTATE_NEW = 2, + MSVM_CONCRETEJOB_JOBSTATE_STARTING = 3, + MSVM_CONCRETEJOB_JOBSTATE_RUNNING = 4, + MSVM_CONCRETEJOB_JOBSTATE_SUSPENDED = 5, + MSVM_CONCRETEJOB_JOBSTATE_SHUTTING_DOWN = 6, + MSVM_CONCRETEJOB_JOBSTATE_COMPLETED = 7, + MSVM_CONCRETEJOB_JOBSTATE_TERMINATED = 8, + MSVM_CONCRETEJOB_JOBSTATE_KILLED = 9, + MSVM_CONCRETEJOB_JOBSTATE_EXCEPTION = 10, + MSVM_CONCRETEJOB_JOBSTATE_SERVICE = 11, +}; + + + +# include "hyperv_wmi_classes.generated.h" + +#endif /* __HYPERV_WMI_CLASSES_H__ */ diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input new file mode 100644 index 0000000..da874ac --- /dev/null +++ b/src/hyperv/hyperv_wmi_generator.input @@ -0,0 +1,294 @@ +# +# Definitions of WMI classes used as input for the hyperv_wmi_generator.py +# script. +# +# This format is line-based, so end-of-line is important. +# +# +# Class definition: +# +# class <name> +# <type> <name> +# ... +# end +# +# Allowed values for <type> are: boolean, string, datetime, int8, int16, +# int32, int64, uint8, uint16, uint32 and uint64 +# +# The property <name> can be followed by [] to define a dynamic array. +# + + +class Msvm_ComputerSystem + 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 PrimaryOwnerName + string PrimaryOwnerContact + string Roles[] + string NameFormat + string OtherIdentifyingInfo[] + string IdentifyingDescriptions[] + uint16 Dedicated[] + string OtherDedicatedDescriptions[] + uint16 ResetCapability + uint16 PowerManagementCapabilities[] + uint64 OnTimeInMilliseconds + datetime TimeOfLastConfigurationChange + uint32 ProcessID + uint16 AssignedNumaNodeList[] +end + + +class Msvm_ConcreteJob + string Caption + string Description + string ElementName + datetime InstallDate + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + string JobStatus + datetime TimeSubmitted + datetime ScheduledStartTime + datetime StartTime + datetime ElapsedTime + uint32 JobRunTimes + uint8 RunMonth + int8 RunDay + int8 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 + string InstanceID + string Name + uint16 JobState + datetime TimeOfLastStateChange + datetime TimeBeforeRemoval + boolean Cancellable +end + + +class Msvm_MemorySettingData + string Caption + string Description + string InstanceID + 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 + boolean IsVirtualized + string DeviceID + string DeviceIDFormat + boolean DynamicMemoryEnabled +# uint32 TargetMemoryBuffer # Available only on Windows Server 2008 R2 SP1 +end + + +class Msvm_ProcessorSettingData + string Caption + string Description + string InstanceID + 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 + boolean IsVirtualized + string DeviceID + string DeviceIDFormat + uint16 ProcessorsPerSocket + uint16 SocketCount + boolean ThreadsEnabled + boolean LimitCPUID + boolean LimitProcessorFeatures +end + + +class Msvm_VirtualSystemSettingData + string Caption + string Description + string ElementName + string InstanceID + string SystemName + uint16 SettingType + uint16 VirtualSystemType + string OtherVirtualSystemType + boolean AutoActivate + datetime CreationTime + string Notes + string BIOSGUID + string BIOSSerialNumber + string BaseBoardSerialNumber + string ChassisSerialNumber + string ChassisAssetTag + boolean BIOSNumLock + uint16 BootOrder[] + string Parent + uint16 NumaNodeList[] + boolean NumaNodesAreRequired +end + + +class Win32_ComputerSystem + uint16 AdminPasswordStatus + boolean AutomaticManagedPagefile + boolean AutomaticResetBootOption + boolean AutomaticResetCapability + uint16 BootOptionOnLimit + uint16 BootOptionOnWatchDog + boolean BootROMSupported + string BootupState + string Caption + uint16 ChassisBootupState + string CreationClassName + int16 CurrentTimeZone + boolean DaylightInEffect + string Description + string DNSHostName + string Domain + uint16 DomainRole + boolean EnableDaylightSavingsTime + uint16 FrontPanelResetStatus + boolean InfraredSupported +# string InitialLoadInfo # MSDN documents it, but it's not there + datetime InstallDate + uint16 KeyboardPasswordStatus + string LastLoadInfo + string Manufacturer + string Model + string Name + string NameFormat + boolean NetworkServerModeEnabled + uint32 NumberOfLogicalProcessors + uint32 NumberOfProcessors + uint8 OEMLogoBitmap[] + string OEMStringArray[] + boolean PartOfDomain + int64 PauseAfterReset + uint16 PCSystemType + uint16 PowerManagementCapabilities[] + boolean PowerManagementSupported + uint16 PowerOnPasswordStatus + uint16 PowerState + uint16 PowerSupplyState + string PrimaryOwnerContact + string PrimaryOwnerName + uint16 ResetCapability + int16 ResetCount + int16 ResetLimit + string Roles[] + string Status + string SupportContactDescription[] + uint16 SystemStartupDelay + string SystemStartupOptions[] + uint8 SystemStartupSetting + string SystemType + uint16 ThermalState + uint64 TotalPhysicalMemory + string UserName + uint16 WakeUpType + string Workgroup +end + + +class Win32_Processor + uint16 AddressWidth + uint16 Architecture + uint16 Availability + string Caption + uint32 ConfigManagerErrorCode + boolean ConfigManagerUserConfig + uint16 CpuStatus + string CreationClassName + uint32 CurrentClockSpeed + uint16 CurrentVoltage + uint16 DataWidth + string Description + string DeviceID + boolean ErrorCleared + string ErrorDescription + uint32 ExtClock + uint16 Family + datetime InstallDate + uint32 L2CacheSize + uint32 L2CacheSpeed + uint32 L3CacheSize + uint32 L3CacheSpeed + uint32 LastErrorCode + uint16 Level + uint16 LoadPercentage + string Manufacturer + uint32 MaxClockSpeed + string Name + uint32 NumberOfCores + uint32 NumberOfLogicalProcessors + string OtherFamilyDescription + string PNPDeviceID + uint16 PowerManagementCapabilities[] + boolean PowerManagementSupported + string ProcessorId + uint16 ProcessorType + uint16 Revision + string Role + string SocketDesignation + string Status + uint16 StatusInfo + string Stepping + string SystemCreationClassName + string SystemName + string UniqueId + uint16 UpgradeMethod + string Version + uint32 VoltageCaps +end diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py new file mode 100755 index 0000000..077c3a0 --- /dev/null +++ b/src/hyperv/hyperv_wmi_generator.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python + +# +# hyperv_wmi_generator.py: generates most of the WMI type mapping code +# +# Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import sys +import os +import os.path + + + +separator = "/* " + ("* " * 37) + "*\n" + + + +class Class: + def __init__(self, name, properties): + self.name = name + self.properties = properties + + + def generate_header(self): + 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 += "\n" + header += "\n" + + return header + + + 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) + + 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 + + if self.name.startswith("Win32_"): + 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 + + 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 + + for property in self.properties: + header += property.generate_classes_header() + + header += "};\n" + header += "\n" + header += "SER_DECLARE_TYPE(%s_Data);\n" % self.name + header += "\n" + header += "struct _%s {\n" % self.name + header += " XmlSerializerInfo *serializerInfo;\n" + header += " %s_Data *data;\n" % self.name + header += " %s *next;\n" % self.name + header += "};\n" + header += "\n" + header += "\n" + header += "\n" + + return header + + + def generate_source(self): + name_upper = self.name.upper() + + 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_"): + source += " return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n" + else: + source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\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" + + return source + + + def generate_classes_source(self): + name_upper = self.name.upper() + + source = separator + source += " * %s\n" % self.name + source += " */\n" + source += "\n" + source += "SER_START_ITEMS(%s_Data)\n" % self.name + + for property in self.properties: + source += property.generate_classes_source(self.name) + + source += "SER_END_ITEMS(%s_Data);\n" % self.name + source += "\n" + source += "\n" + source += "\n" + + return source + + +class Property: + typemap = {"boolean" : "BOOL", + "string" : "STR", + "datetime" : "STR", + "int8" : "INT8", + "int16" : "INT16", + "int32" : "INT32", + "int64" : "INT64", + "uint8" : "UINT8", + "uint16" : "UINT16", + "uint32" : "UINT32", + "uint64" : "UINT64"} + + + def __init__(self, type, name, is_array): + if type not in Property.typemap: + report_error("unhandled property type %s" % type) + + self.type = type + self.name = name + self.is_array = is_array + + + def generate_classes_header(self): + if self.is_array: + return " XML_TYPE_DYN_ARRAY %s;\n" % self.name + else: + return " XML_TYPE_%s %s;\n" \ + % (Property.typemap[self.type], self.name) + + + def generate_classes_source(self, class_name): + if self.is_array: + return " SER_NS_DYN_ARRAY(%s_RESOURCE_URI, \"%s\", 0, 0, %s),\n" \ + % (class_name.upper(), self.name, self.type) + else: + return " SER_NS_%s(%s_RESOURCE_URI, \"%s\", 1),\n" \ + % (Property.typemap[self.type], class_name.upper(), self.name) + + + +def open_and_print(filename): + if filename.startswith("./"): + print " GEN " + filename[2:] + else: + print " GEN " + filename + + return open(filename, "wb") + + + +def report_error(message): + print "error: " + message + sys.exit(1) + + + +def parse_class(block): + # expected format: class <name> + header_items = block[0][1].split() + + if len(header_items) != 2: + report_error("line %d: invalid block header" % (number)) + + assert header_items[0] == "class" + + name = header_items[1] + + properties = [] + + for line in block[1:]: + # expected format: <type> <name> + items = line[1].split() + + if len(items) != 2: + report_error("line %d: invalid property" % line[0]) + + if items[1].endswith("[]"): + items[1] = items[1][:-2] + is_array = True + else: + is_array = False + + properties.append(Property(type=items[0], name=items[1], + is_array=is_array)) + + return Class(name=name, properties=properties) + + + +def main(): + if "srcdir" in os.environ: + input_filename = os.path.join(os.environ["srcdir"], "hyperv/hyperv_wmi_generator.input") + output_dirname = os.path.join(os.environ["srcdir"], "hyperv") + else: + 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(): + number += 1 + + if "#" in line: + line = line[:line.index("#")] + + line = line.lstrip().rstrip() + + if len(line) < 1: + continue + + if line.startswith("class"): + if block is not None: + report_error("line %d: nested block found" % (number)) + else: + block = [] + + if block is not None: + if line == "end": + if block[0][1].startswith("class"): + cls = parse_class(block) + classes_by_name[cls.name] = cls + + block = None + else: + block.append((number, line)) + + # write output files + header.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + source.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_typedef.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_header.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_source.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + + names = 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()) + + + +if __name__ == "__main__": + main() diff --git a/src/hyperv/openwsman.h b/src/hyperv/openwsman.h new file mode 100644 index 0000000..8bc0604 --- /dev/null +++ b/src/hyperv/openwsman.h @@ -0,0 +1,47 @@ + +/* + * openwsman.h: workarounds for bugs in openwsman + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __OPENWSMAN_H__ +# define __OPENWSMAN_H__ + +/* Workaround openwsman <= 2.2.6 unconditionally defining optarg. Just pretend + * that u/os.h was already included. Need to explicitly include time.h because + * wsman-xml-serializer.h needs it and u/os.h would have included it. */ +# include <time.h> +# define _LIBU_OS_H_ +# include <wsman-api.h> + +/* wsman-xml-serializer.h in openwsman <= 2.2.6 is missing this defines */ +# ifndef SER_NS_INT8 +# define SER_NS_INT8(ns, n, x) SER_NS_INT8_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT16 +# define SER_NS_INT16(ns, n, x) SER_NS_INT16_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT32 +# define SER_NS_INT32(ns, n, x) SER_NS_INT32_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT64 +# define SER_NS_INT64(ns, n, x) SER_NS_INT64_FLAGS(ns, n, x, 0) +# endif + +#endif /* __OPENWSMAN_H__ */ -- 1.7.4.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list