[libvirt] [PATCHv2 3/5] hyperv: Add OpenWSMAN based client for the Hyper-V WMI API

Matthias Bolte matthias.bolte at googlemail.com
Wed Aug 3 15:00:12 UTC 2011


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 at googlemail.com>
+ * Copyright (C) 2009 Michael Sievers <msievers83 at googlemail.com>
+ *
+ * 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 at googlemail.com>
+ * Copyright (C) 2009 Michael Sievers <msievers83 at googlemail.com>
+ *
+ * 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 at googlemail.com>
+ * Copyright (C) 2009 Michael Sievers <msievers83 at googlemail.com>
+ *
+ * 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 at googlemail.com>
+ * Copyright (C) 2009 Michael Sievers <msievers83 at googlemail.com>
+ *
+ * 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 at googlemail.com>
+#
+# 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 at googlemail.com>
+ *
+ * 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




More information about the libvir-list mailing list