[libvirt] [PATCH] Add basic driver for Microsoft Hyper-V

Matthias Bolte matthias.bolte at googlemail.com
Tue Jul 12 18:49:30 UTC 2011


Domain listing, basic information retrieval and domain life cycle
management is implemented. But currently the domian XML output
lacks the complete devices section.

The driver uses OpenWSMAN to directly communicate with an Hyper-V
server over its WS-Management interface exposed via Microsoft WinRM.

Just like the ESX driver this driver includes a generator that
generates the type definitions for the Hyper-V API that are feed
to OpenWSMAN.

Currently there are some sections in the code that are disabled
because of bugs in OpenWSMAN <= 2.2.6. Patches for those problems
have been posted upstream.

The driver is based on the work of Michael Sievers. This started in
the same master program project group at the University of Paderborn
as the ESX driver.

See Michael's blog for details: http://hyperv4libvirt.wordpress.com/
---
 cfg.mk                                |    1 +
 configure.ac                          |   38 +
 docs/drivers.html.in                  |    1 +
 docs/drvhyperv.html.in                |  103 +++
 docs/index.html.in                    |    3 +
 docs/sitemap.html.in                  |    4 +
 include/libvirt/virterror.h           |    1 +
 libvirt.spec.in                       |    9 +
 po/POTFILES.in                        |    3 +
 src/Makefile.am                       |   52 ++
 src/README                            |    3 +-
 src/driver.h                          |    1 +
 src/hyperv/.gitignore                 |    1 +
 src/hyperv/hyperv_device_monitor.c    |   77 ++
 src/hyperv/hyperv_device_monitor.h    |   29 +
 src/hyperv/hyperv_driver.c            | 1275 +++++++++++++++++++++++++++++++++
 src/hyperv/hyperv_driver.h            |   29 +
 src/hyperv/hyperv_interface_driver.c  |   77 ++
 src/hyperv/hyperv_interface_driver.h  |   29 +
 src/hyperv/hyperv_network_driver.c    |   80 ++
 src/hyperv/hyperv_network_driver.h    |   29 +
 src/hyperv/hyperv_nwfilter_driver.c   |   77 ++
 src/hyperv/hyperv_nwfilter_driver.h   |   29 +
 src/hyperv/hyperv_private.h           |   43 ++
 src/hyperv/hyperv_secret_driver.c     |   77 ++
 src/hyperv/hyperv_secret_driver.h     |   29 +
 src/hyperv/hyperv_storage_driver.c    |   79 ++
 src/hyperv/hyperv_storage_driver.h    |   29 +
 src/hyperv/hyperv_util.c              |  129 ++++
 src/hyperv/hyperv_util.h              |   39 +
 src/hyperv/hyperv_wmi.c               |  692 ++++++++++++++++++
 src/hyperv/hyperv_wmi.h               |  119 +++
 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 ++
 src/libvirt.c                         |   12 +
 src/util/virterror.c                  |    3 +
 39 files changed, 3982 insertions(+), 1 deletions(-)
 create mode 100644 docs/drvhyperv.html.in
 create mode 100644 src/hyperv/.gitignore
 create mode 100644 src/hyperv/hyperv_device_monitor.c
 create mode 100644 src/hyperv/hyperv_device_monitor.h
 create mode 100644 src/hyperv/hyperv_driver.c
 create mode 100644 src/hyperv/hyperv_driver.h
 create mode 100644 src/hyperv/hyperv_interface_driver.c
 create mode 100644 src/hyperv/hyperv_interface_driver.h
 create mode 100644 src/hyperv/hyperv_network_driver.c
 create mode 100644 src/hyperv/hyperv_network_driver.h
 create mode 100644 src/hyperv/hyperv_nwfilter_driver.c
 create mode 100644 src/hyperv/hyperv_nwfilter_driver.h
 create mode 100644 src/hyperv/hyperv_private.h
 create mode 100644 src/hyperv/hyperv_secret_driver.c
 create mode 100644 src/hyperv/hyperv_secret_driver.h
 create mode 100644 src/hyperv/hyperv_storage_driver.c
 create mode 100644 src/hyperv/hyperv_storage_driver.h
 create mode 100644 src/hyperv/hyperv_util.c
 create mode 100644 src/hyperv/hyperv_util.h
 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/cfg.mk b/cfg.mk
index b00cda3..c20b8c9 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -411,6 +411,7 @@ sc_prohibit_xmlGetProp:
 msg_gen_function =
 msg_gen_function += ESX_ERROR
 msg_gen_function += ESX_VI_ERROR
+msg_gen_function += HYPERV_ERROR
 msg_gen_function += PHYP_ERROR
 msg_gen_function += VIR_ERROR
 msg_gen_function += VMX_ERROR
diff --git a/configure.ac b/configure.ac
index e9d5be4..d7ebe79 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,6 +66,7 @@ XMLRPC_REQUIRED=1.14.0
 HAL_REQUIRED=0.5.0
 DEVMAPPER_REQUIRED=1.0.0
 LIBCURL_REQUIRED="7.18.0"
+OPENWSMAN_REQUIRED="2.2.6"
 LIBPCAP_REQUIRED="1.0.0"
 LIBNL_REQUIRED="1.1"
 LIBSSH2_REQUIRED="1.0"
@@ -275,6 +276,8 @@ AC_ARG_WITH([lxc],
   AC_HELP_STRING([--with-lxc], [add Linux Container support @<:@default=check@:>@]),[],[with_lxc=check])
 AC_ARG_WITH([esx],
   AC_HELP_STRING([--with-esx], [add ESX support @<:@default=check@:>@]),[],[with_esx=check])
+AC_ARG_WITH([hyperv],
+  AC_HELP_STRING([--with-hyperv], [add Hyper-V support @<:@default=check@:>@]),[],[with_hyperv=check])
 AC_ARG_WITH([test],
   AC_HELP_STRING([--with-test], [add test driver support @<:@default=yes@:>@]),[],[with_test=yes])
 AC_ARG_WITH([remote],
@@ -1912,6 +1915,35 @@ LIBCURL_CFLAGS="-DCURL_DISABLE_TYPECHECK $LIBCURL_CFLAGS"
 AC_SUBST([LIBCURL_CFLAGS])
 AC_SUBST([LIBCURL_LIBS])
 
+
+dnl
+dnl check for openwsman (Hyper-V)
+dnl
+
+OPENWSMAN_CFLAGS=""
+OPENWSMAN_LIBS=""
+
+if test "$with_hyperv" = "yes" || test "$with_hyperv" = "check"; then
+    PKG_CHECK_MODULES(OPENWSMAN, openwsman >= $OPENWSMAN_REQUIRED, [
+        if test "$with_hyperv" = "check"; then
+            with_hyperv=yes
+        fi
+    ], [
+        if test "$with_hyperv" = "check"; then
+            with_hyperv=no
+            AC_MSG_NOTICE([openwsman is required for the Hyper-V driver, disabling it])
+        elif test "$with_hyperv" = "yes"; then
+            AC_MSG_ERROR([openwsman >= $OPENWSMAN_REQUIRED is required for the Hyper-V driver])
+        fi
+    ])
+fi
+
+if test "$with_hyperv" = "yes" ; then
+    AC_DEFINE_UNQUOTED([WITH_HYPERV], 1, [whether Hyper-V driver is enabled])
+fi
+AM_CONDITIONAL([WITH_HYPERV], [test "$with_hyperv" = "yes"])
+
+
 dnl
 dnl check for python
 dnl
@@ -2414,6 +2446,7 @@ AC_MSG_NOTICE([xenlight: $with_libxl])
 AC_MSG_NOTICE([     LXC: $with_lxc])
 AC_MSG_NOTICE([    PHYP: $with_phyp])
 AC_MSG_NOTICE([     ESX: $with_esx])
+AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
 AC_MSG_NOTICE([    Test: $with_test])
 AC_MSG_NOTICE([  Remote: $with_remote])
 AC_MSG_NOTICE([ Network: $with_network])
@@ -2455,6 +2488,11 @@ AC_MSG_NOTICE([ libcurl: $LIBCURL_CFLAGS $LIBCURL_LIBS])
 else
 AC_MSG_NOTICE([ libcurl: no])
 fi
+if test "$with_hyperv" = "yes" ; then
+AC_MSG_NOTICE([openwsman: $OPENWSMAN_CFLAGS $OPENWSMAN_LIBS])
+else
+AC_MSG_NOTICE([openwsman: no])
+fi
 if test "$with_libssh2" != "no" ; then
 AC_MSG_NOTICE([ libssh2: $LIBSSH2_CFLAGS $LIBSSH2_LIBS])
 else
diff --git a/docs/drivers.html.in b/docs/drivers.html.in
index 0428870..75038fc 100644
--- a/docs/drivers.html.in
+++ b/docs/drivers.html.in
@@ -28,6 +28,7 @@
       <li><strong><a href="drvesx.html">VMware ESX</a></strong></li>
       <li><strong><a href="drvvmware.html">VMware Workstation/Player</a></strong></li>
       <li><strong><a href="drvxen.html">Xen</a></strong></li>
+      <li><strong><a href="drvhyperv.html">Microsoft Hyper-V</a></strong></li>
     </ul>
 
     <h2><a name="stroage">Storage drivers</a></h2>
diff --git a/docs/drvhyperv.html.in b/docs/drvhyperv.html.in
new file mode 100644
index 0000000..dec5969
--- /dev/null
+++ b/docs/drvhyperv.html.in
@@ -0,0 +1,103 @@
+<html><body>
+    <h1>Microsoft Hyper-V hypervisor driver</h1>
+    <ul id="toc"></ul>
+    <p>
+        The libvirt Microsoft Hyper-V driver can manage Hyper-V 2008 R2.
+    </p>
+
+
+    <h2><a name="uri">Connections to the Microsoft Hyper-V driver</a></h2>
+    <p>
+        Some example remote connection URIs for the driver are:
+    </p>
+<pre>
+hyperv://example-hyperv.com                  (over HTTPS)
+hyperv://example-hyperv.com/?transport=http  (over HTTP)
+</pre>
+    <p>
+        <strong>Note</strong>: In contrast to other drivers, the Hyper-V driver
+        is a client-side-only driver. It connects to the Hyper-V server using
+        WS-Management over HTTP(S). Therefore, the
+        <a href="remote.html">remote transport mechanism</a> provided by the
+        remote driver and libvirtd will not work, and you cannot use URIs like
+        <code>hyperv+ssh://example.com</code>.
+    </p>
+
+
+    <h3><a name="uriformat">URI Format</a></h3>
+    <p>
+        URIs have this general form (<code>[...]</code> marks an optional part).
+    </p>
+<pre>
+hyperv://[username@]hostname[:port]/[?extraparameters]
+</pre>
+    <p>
+        The default HTTPS ports is 5986. If the port parameter is given, it
+        overrides the default port.
+    </p>
+
+
+    <h4><a name="extraparams">Extra parameters</a></h4>
+    <p>
+        Extra parameters can be added to a URI as part of the query string
+        (the part following <code>?</code>). A single parameter is formed by a
+        <code>name=value</code> pair. Multiple parameters are separated by
+        <code>&</code>.
+    </p>
+<pre>
+?transport=http
+</pre>
+    <p>
+        The driver understands the extra parameters shown below.
+    </p>
+    <table class="top_table">
+        <tr>
+            <th>Name</th>
+            <th>Values</th>
+            <th>Meaning</th>
+        </tr>
+        <tr>
+            <td>
+                <code>transport</code>
+            </td>
+            <td>
+                <code>http</code> or <code>https</code>
+            </td>
+            <td>
+                Overrides the default HTTPS transport. The default HTTP port
+                is 5985.
+            </td>
+        </tr>
+    </table>
+
+
+    <h3><a name="auth">Authentication</a></h3>
+    <p>
+        In order to perform any useful operation the driver needs to log into
+        the Hyper-V server. Therefore, only <code>virConnectOpenAuth</code> can
+        be used to connect to an Hyper-V server, <code>virConnectOpen</code> and
+        <code>virConnectOpenReadOnly</code> don't work.
+        To log into an Hyper-V server the driver will request credentials using
+        the callback passed to the <code>virConnectOpenAuth</code> function.
+        The driver passes the hostname as challenge parameter to the callback.
+    </p>
+    <p>
+        <strong>Note</strong>: Currently only <code>Basic</code> authentication
+        is supported by libvirt. This method is disabled by default on the
+        Hyper-V server and can be enabled via the WinRM commandline tool.
+    </p>
+<pre>
+winrm set winrm/config/service/auth @{Basic="true"}
+</pre>
+    <p>
+        To allow <code>Basic</code> authentication with HTTP transport WinRM
+        needs to allow unencrypted communication. This can be enabled via the
+        WinRM commandline tool. Although this is not the recommended
+        communication mode.
+    </p>
+<pre>
+winrm set winrm/config/service @{AllowUnencrypted="true"}
+</pre>
+
+
+</body></html>
diff --git a/docs/index.html.in b/docs/index.html.in
index 64eb84d..73c2bf8 100644
--- a/docs/index.html.in
+++ b/docs/index.html.in
@@ -63,6 +63,9 @@
         The <a href="http://www.vmware.com/">VMware Workstation and Player</a> hypervisors
       </li>
       <li>
+        The <a href="http://www.microsoft.com/hyper-v-server/">Microsoft Hyper-V</a> hypervisor
+      </li>
+      <li>
         Storage on IDE/SCSI/USB disks, FibreChannel, LVM, iSCSI, NFS and filesystems
       </li>
     </ul>
diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in
index 897ee94..2c71763 100644
--- a/docs/sitemap.html.in
+++ b/docs/sitemap.html.in
@@ -202,6 +202,10 @@
                 <a href="drvvmware.html">VMware Workstation / Player</a>
                 <span>Driver for VMware Workstation / Player</span>
               </li>
+              <li>
+                <a href="drvhyperv.html">Microsoft Hyper-V</a>
+                <span>Driver for Microsoft Hyper-V</span>
+              </li>
             </ul>
           </li>
           <li>
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index efa4796..bd64eb4 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -82,6 +82,7 @@ typedef enum {
     VIR_FROM_EVENT = 40,       /* Error from event loop impl */
     VIR_FROM_LIBXL = 41,	/* Error from libxenlight driver */
     VIR_FROM_LOCKING = 42,      /* Error from lock manager */
+    VIR_FROM_HYPERV = 43,       /* Error from Hyper-V driver */
 } virErrorDomain;
 
 
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 230237e..c971681 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -50,6 +50,7 @@
 # Then the hypervisor drivers that talk a native remote protocol
 %define with_phyp          0%{!?_without_phyp:1}
 %define with_esx           0%{!?_without_esx:1}
+%define with_hyperv        0%{!?_without_hyperv:1}
 %define with_xenapi        0%{!?_without_xenapi:1}
 
 # Then the secondary host drivers
@@ -437,6 +438,9 @@ BuildRequires: libcurl-devel
 BuildRequires: curl-devel
 %endif
 %endif
+%if %{with_hyperv}
+BuildRequires: openwsman-devel >= 2.2.6
+%endif
 %if %{with_audit}
 BuildRequires: audit-libs-devel
 %endif
@@ -569,6 +573,10 @@ of recent versions of Linux (and other OSes).
 %define _without_esx --without-esx
 %endif
 
+%if ! %{with_hyperv}
+%define _without_hyperv --without-hyperv
+%endif
+
 %if ! %{with_vmware}
 %define _without_vmware --without-vmware
 %endif
@@ -687,6 +695,7 @@ of recent versions of Linux (and other OSes).
            %{?_without_one} \
            %{?_without_phyp} \
            %{?_without_esx} \
+           %{?_without_hyperv} \
            %{?_without_vmware} \
            %{?_without_network} \
            %{?_with_rhel5_api} \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5782cbf..809ace6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -28,6 +28,9 @@ src/esx/esx_vi.c
 src/esx/esx_vi_methods.c
 src/esx/esx_vi_types.c
 src/fdstream.c
+src/hyperv/hyperv_driver.c
+src/hyperv/hyperv_util.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 39f0cf8..7b7a959 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -379,6 +379,32 @@ ESX_DRIVER_EXTRA_DIST =						\
 		esx/esx_vi_generator.py					\
 		$(ESX_DRIVER_GENERATED)
 
+HYPERV_DRIVER_SOURCES =								\
+		hyperv/hyperv_private.h							\
+		hyperv/hyperv_driver.c hyperv/hyperv_driver.h				\
+		hyperv/hyperv_interface_driver.c hyperv/hyperv_interface_driver.h	\
+		hyperv/hyperv_network_driver.c hyperv/hyperv_network_driver.h		\
+		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_util.c hyperv/hyperv_util.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
 
@@ -809,6 +835,31 @@ libvirt_driver_esx_la_SOURCES = $(ESX_DRIVER_SOURCES)
 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
+else
+noinst_LTLIBRARIES += libvirt_driver_hyperv.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_hyperv.la
+endif
+libvirt_driver_hyperv_la_CFLAGS = $(OPENWSMAN_CFLAGS) \
+		-I at top_srcdir@/src/conf -I at top_srcdir@/src/vmx $(AM_CFLAGS)
+libvirt_driver_hyperv_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_hyperv_la_LIBADD = $(OPENWSMAN_LIBS)
+if WITH_DRIVER_MODULES
+libvirt_driver_hyperv_la_LIBADD += ../gnulib/lib/libgnu.la
+libvirt_driver_hyperv_la_LDFLAGS += -module -avoid-version
+endif
+libvirt_driver_hyperv_la_SOURCES = $(HYPERV_DRIVER_SOURCES)
+endif
+
 if WITH_NETWORK
 if WITH_DRIVER_MODULES
 mod_LTLIBRARIES += libvirt_driver_network.la
@@ -1000,6 +1051,7 @@ EXTRA_DIST +=							\
 		$(LIBXL_DRIVER_SOURCES)			\
 		$(ESX_DRIVER_SOURCES)				\
 		$(ESX_DRIVER_EXTRA_DIST)			\
+		$(HYPERV_DRIVER_SOURCES)			\
 		$(NETWORK_DRIVER_SOURCES)			\
 		$(INTERFACE_DRIVER_SOURCES)			\
 		$(STORAGE_DRIVER_SOURCES)			\
diff --git a/src/README b/src/README
index f95a8b7..00d11d1 100644
--- a/src/README
+++ b/src/README
@@ -26,6 +26,7 @@ There are two core shared modules to be aware of:
 Then there are the hypervisor implementations:
 
  * esx/          - VMware ESX and GSX support using vSphere API over SOAP
+ * hyperv/       - Microsoft Hyper-V support using WinRM
  * lxc/          - Linux Native Containers
  * openvz/       - OpenVZ containers using cli tools
  * phyp/         - IBM Power Hypervisor using CLI tools over SSH
@@ -41,7 +42,7 @@ Then there are the hypervisor implementations:
 
 Finally some secondary drivers that are shared for several HVs.
 Currently these are used by LXC, OpenVZ, QEMU, UML and Xen drivers.
-The ESX, Power Hypervisor, Remote, Test & VirtualBox drivers all
+The ESX, Hyper-V, Power Hypervisor, Remote, Test & VirtualBox drivers all
 implement the secondary drivers directly
 
  * cpu/          - CPU feature management
diff --git a/src/driver.h b/src/driver.h
index 70ea4c2..589f232 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -29,6 +29,7 @@ typedef enum {
     VIR_DRV_XENAPI = 12,
     VIR_DRV_VMWARE = 13,
     VIR_DRV_LIBXL = 14,
+    VIR_DRV_HYPERV = 15,
 } virDrvNo;
 
 
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_device_monitor.c b/src/hyperv/hyperv_device_monitor.c
new file mode 100644
index 0000000..2bf1eb6
--- /dev/null
+++ b/src/hyperv/hyperv_device_monitor.c
@@ -0,0 +1,77 @@
+
+/*
+ * hyperv_device_monitor.c: device monitor functions for managing
+ *                          Microsoft Hyper-V host devices
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_device_monitor.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static virDrvOpenStatus
+hypervDeviceOpen(virConnectPtr conn,
+                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                 unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->devMonPrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervDeviceClose(virConnectPtr conn)
+{
+    conn->devMonPrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virDeviceMonitor hypervDeviceMonitor = {
+    "Hyper-V",
+    .open = hypervDeviceOpen, /* 0.9.4 */
+    .close = hypervDeviceClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervDeviceRegister(void)
+{
+    return virRegisterDeviceMonitor(&hypervDeviceMonitor);
+}
diff --git a/src/hyperv/hyperv_device_monitor.h b/src/hyperv/hyperv_device_monitor.h
new file mode 100644
index 0000000..864e8af
--- /dev/null
+++ b/src/hyperv/hyperv_device_monitor.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_device_monitor.h: device monitor functions for managing
+ *                          Microsoft Hyper-V host devices
+ *
+ * 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 __HYPERV_DEVICE_MONITOR_H__
+# define __HYPERV_DEVICE_MONITOR_H__
+
+int hypervDeviceRegister(void);
+
+#endif /* __HYPERV_DEVICE_MONITOR_H__ */
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
new file mode 100644
index 0000000..a1d56a5
--- /dev/null
+++ b/src/hyperv/hyperv_driver.c
@@ -0,0 +1,1275 @@
+
+/*
+ * hyperv_driver.c: core driver functions 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 "datatypes.h"
+#include "domain_conf.h"
+#include "authhelper.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_driver.h"
+#include "hyperv_interface_driver.h"
+#include "hyperv_network_driver.h"
+#include "hyperv_storage_driver.h"
+#include "hyperv_device_monitor.h"
+#include "hyperv_secret_driver.h"
+#include "hyperv_nwfilter_driver.h"
+#include "hyperv_private.h"
+#include "hyperv_util.h"
+#include "hyperv_wmi.h"
+#include "openwsman.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static void
+hypervFreePrivate(hypervPrivate **priv)
+{
+    if (priv == NULL || *priv == NULL) {
+        return;
+    }
+
+    if ((*priv)->client != NULL) {
+        /* FIXME: This leaks memory due to bugs in openwsman <= 2.2.6 */
+        wsmc_release((*priv)->client);
+    }
+
+    hypervFreeParsedUri(&(*priv)->parsedUri);
+    VIR_FREE(*priv);
+}
+
+
+
+static virDrvOpenStatus
+hypervOpen(virConnectPtr conn, virConnectAuthPtr auth,
+           unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
+    hypervPrivate *priv = NULL;
+    char *username = NULL;
+    char *password = NULL;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    /* Decline if the URI is NULL or the scheme is not hyperv */
+    if (conn->uri == NULL || conn->uri->scheme == NULL ||
+        STRCASENEQ(conn->uri->scheme, "hyperv")) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    /* Require server part */
+    if (conn->uri->server == NULL) {
+        HYPERV_ERROR(VIR_ERR_INVALID_ARG, "%s",
+                     _("URI is missing the server part"));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    /* Require auth */
+    if (auth == NULL || auth->cb == NULL) {
+        HYPERV_ERROR(VIR_ERR_INVALID_ARG, "%s",
+                     _("Missing or invalid auth pointer"));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    /* Allocate per-connection private data */
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (hypervParseUri(&priv->parsedUri, conn->uri) < 0) {
+        goto cleanup;
+    }
+
+    /* Set the port dependent on the transport protocol if no port is
+     * specified. This allows us to rely on the port parameter being
+     * correctly set when building URIs later on, without the need to
+     * distinguish between the situations port == 0 and port != 0 */
+    if (conn->uri->port == 0) {
+        if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+            conn->uri->port = 5986;
+        } else {
+            conn->uri->port = 5985;
+        }
+    }
+
+    /* Request credentials */
+    if (conn->uri->user != NULL) {
+        username = strdup(conn->uri->user);
+
+        if (username == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    } else {
+        username = virRequestUsername(auth, "administrator", conn->uri->server);
+
+        if (username == NULL) {
+            HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
+            goto cleanup;
+        }
+    }
+
+    password = virRequestPassword(auth, username, conn->uri->server);
+
+    if (password == NULL) {
+        HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Password request failed"));
+        goto cleanup;
+    }
+
+    /* Initialize the openwsman connection */
+    priv->client = wsmc_create(conn->uri->server, conn->uri->port, "/wsman",
+                               priv->parsedUri->transport, username, password);
+
+    if (priv->client == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Could not create openwsman client"));
+        goto cleanup;
+    }
+
+    if (wsmc_transport_init(priv->client, NULL) != 0) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                     _("Could not initialize openwsman transport"));
+        goto cleanup;
+    }
+
+    /* FIXME: Currently only basic authentication is supported  */
+    wsman_transport_set_auth_method(priv->client, "basic");
+
+    /* Check if the connection can be established and if the server has the
+     * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList
+     * succeeds than the connection has be established. If the returned list
+     * is empty than the server isn't a Hyper-V server. */
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("%s is not a Hyper-V server"), conn->uri->server);
+        goto cleanup;
+    }
+
+    conn->privateData = priv;
+
+    result = VIR_DRV_OPEN_SUCCESS;
+
+  cleanup:
+    if (result == VIR_DRV_OPEN_ERROR) {
+        hypervFreePrivate(&priv);
+    }
+
+    VIR_FREE(username);
+    VIR_FREE(password);
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervClose(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    hypervFreePrivate(&priv);
+
+    conn->privateData = NULL;
+
+    return 0;
+}
+
+
+
+static const char *
+hypervGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return "Hyper-V";
+}
+
+
+
+static char *
+hypervGetHostname(virConnectPtr conn)
+{
+    char *hostname = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Win32_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, WIN32_COMPUTERSYSTEM_WQL_SELECT);
+
+    if (hypervGetWin32ComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_ComputerSystem");
+        goto cleanup;
+    }
+
+    hostname = strdup(computerSystem->data->DNSHostName);
+
+    if (hostname == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return hostname;
+}
+
+
+
+static int
+hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+    int result = -1;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Win32_ComputerSystem *computerSystem = NULL;
+    Win32_Processor *processorList = NULL;
+    Win32_Processor *processor = NULL;
+    char *tmp;
+
+    memset(info, 0, sizeof (*info));
+
+    virBufferAddLit(&query, WIN32_COMPUTERSYSTEM_WQL_SELECT);
+
+    /* Get Win32_ComputerSystem */
+    if (hypervGetWin32ComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_ComputerSystem");
+        goto cleanup;
+    }
+
+    /* Get Win32_Processor list */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Win32_ComputerSystem.Name=\"%s\"} "
+                      "where AssocClass = Win32_ComputerSystemProcessor "
+                      "ResultClass = Win32_Processor",
+                      computerSystem->data->Name);
+
+    if (hypervGetWin32ProcessorList(priv, &query, &processorList) < 0) {
+        goto cleanup;
+    }
+
+    if (processorList == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s"),
+                     "Win32_Processor");
+        goto cleanup;
+    }
+
+    /* Strip the string to fit more relevant information in 32 chars */
+    tmp = processorList->data->Name;
+
+    while (*tmp != '\0') {
+        if (STRPREFIX(tmp, "  ")) {
+            memmove(tmp, tmp + 1, strlen(tmp + 1) + 1);
+            continue;
+        } else if (STRPREFIX(tmp, "(R)") || STRPREFIX(tmp, "(C)")) {
+            memmove(tmp, tmp + 3, strlen(tmp + 3) + 1);
+            continue;
+        } else if (STRPREFIX(tmp, "(TM)")) {
+            memmove(tmp, tmp + 4, strlen(tmp + 4) + 1);
+            continue;
+        }
+
+        ++tmp;
+    }
+
+    /* Fill struct */
+    if (virStrncpy(info->model, processorList->data->Name,
+                   sizeof (info->model) - 1, sizeof (info->model)) == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("CPU model %s too long for destination"),
+                     processorList->data->Name);
+        goto cleanup;
+    }
+
+    info->memory = computerSystem->data->TotalPhysicalMemory / 1024; /* byte to kilobyte */
+    info->mhz = processorList->data->MaxClockSpeed;
+    info->nodes = 1;
+    info->sockets = 0;
+
+    for (processor = processorList; processor != NULL;
+         processor = processor->next) {
+        ++info->sockets;
+    }
+
+    info->cores = processorList->data->NumberOfCores;
+    info->threads = info->cores / processorList->data->NumberOfLogicalProcessors;
+    info->cpus = info->sockets * info->cores;
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)processorList);
+
+    return result;
+}
+
+
+
+static int
+hypervListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    if (maxids == 0) {
+        return 0;
+    }
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_ACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ids[count++] = computerSystem->data->ProcessID;
+
+        if (count >= maxids) {
+            break;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
+}
+
+
+
+static int
+hypervNumberOfDomains(virConnectPtr conn)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_ACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ++count;
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByID(virConnectPtr conn, int id)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAsprintf(&query, "and ProcessID = %d", id);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN, _("No domain with ID %d"), id);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virUUIDFormat(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) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN,
+                     _("No domain with UUID %s"), uuid_string);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static virDomainPtr
+hypervDomainLookupByName(virConnectPtr conn, const char *name)
+{
+    virDomainPtr domain = NULL;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAsprintf(&query, "and ElementName = \"%s\"", name);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem == NULL) {
+        HYPERV_ERROR(VIR_ERR_NO_DOMAIN,
+                     _("No domain with name %s"), name);
+        goto cleanup;
+    }
+
+    hypervMsvmComputerSystemToDomain(conn, computerSystem, &domain);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return domain;
+}
+
+
+
+static int
+hypervDomainSuspend(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainResume(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not paused"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainDestroy(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    bool in_transition = false;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (!hypervIsMsvmComputerSystemActive(computerSystem, &in_transition) ||
+        in_transition) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static char *
+hypervDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    char *osType = strdup("hvm");
+
+    if (osType == NULL) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return osType;
+}
+
+
+
+static int
+hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL;
+    Msvm_ProcessorSettingData *processorSettingData = NULL;
+    Msvm_MemorySettingData *memorySettingData = NULL;
+
+    memset(info, 0, sizeof (*info));
+
+    virUUIDFormat(domain->uuid, uuid_string);
+
+    /* Get Msvm_ComputerSystem */
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    /* Get Msvm_VirtualSystemSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+                      "Name=\"%s\"} "
+                      "where AssocClass = Msvm_SettingsDefineState "
+                      "ResultClass = Msvm_VirtualSystemSettingData",
+                      uuid_string);
+
+    if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query,
+                                                  &virtualSystemSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_VirtualSystemSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_ProcessorSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_ProcessorSettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmProcessorSettingDataList(priv, &query,
+                                              &processorSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (processorSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_ProcessorSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_MemorySettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_MemorySettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmMemorySettingDataList(priv, &query,
+                                           &memorySettingData) < 0) {
+        goto cleanup;
+    }
+
+
+    if (memorySettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_MemorySettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Fill struct */
+    info->state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem);
+    info->maxMem = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */
+    info->memory = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
+    info->nrVirtCpu = processorSettingData->data->VirtualQuantity;
+    info->cpuTime = 0;
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData);
+    hypervFreeObject(priv, (hypervObject *)processorSettingData);
+    hypervFreeObject(priv, (hypervObject *)memorySettingData);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainGetState(virDomainPtr domain, int *state, int *reason,
+                     unsigned int flags)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    virCheckFlags(0, -1);
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    *state = hypervMsvmComputerSystemEnabledStateToDomainState(computerSystem);
+
+    if (reason != NULL) {
+        *reason = 0;
+    }
+
+    result = 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static char *
+hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+    char *xml = NULL;
+    hypervPrivate *priv = domain->conn->privateData;
+    virDomainDefPtr def = NULL;
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL;
+    Msvm_ProcessorSettingData *processorSettingData = NULL;
+    Msvm_MemorySettingData *memorySettingData = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    virUUIDFormat(domain->uuid, uuid_string);
+
+    /* Get Msvm_ComputerSystem */
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    /* Get Msvm_VirtualSystemSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\","
+                      "Name=\"%s\"} "
+                      "where AssocClass = Msvm_SettingsDefineState "
+                      "ResultClass = Msvm_VirtualSystemSettingData",
+                      uuid_string);
+
+    if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query,
+                                                  &virtualSystemSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_VirtualSystemSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_ProcessorSettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_ProcessorSettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmProcessorSettingDataList(priv, &query,
+                                              &processorSettingData) < 0) {
+        goto cleanup;
+    }
+
+    if (processorSettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_ProcessorSettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Get Msvm_MemorySettingData */
+    virBufferAsprintf(&query,
+                      "associators of "
+                      "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} "
+                      "where AssocClass = Msvm_VirtualSystemSettingDataComponent "
+                      "ResultClass = Msvm_MemorySettingData",
+                      virtualSystemSettingData->data->InstanceID);
+
+    if (hypervGetMsvmMemorySettingDataList(priv, &query,
+                                           &memorySettingData) < 0) {
+        goto cleanup;
+    }
+
+
+    if (memorySettingData == NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not lookup %s for domain %s"),
+                     "Msvm_MemorySettingData",
+                     computerSystem->data->ElementName);
+        goto cleanup;
+    }
+
+    /* Fill struct */
+    def->virtType = VIR_DOMAIN_VIRT_HYPERV;
+
+    if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) {
+        def->id = computerSystem->data->ProcessID;
+    } else {
+        def->id = -1;
+    }
+
+    if (virUUIDParse(computerSystem->data->Name, def->uuid) < 0) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR,
+                     _("Could not parse UUID from string '%s'"),
+                     computerSystem->data->Name);
+        return NULL;
+    }
+
+    def->name = strdup(computerSystem->data->ElementName);
+
+    if (def->name == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virtualSystemSettingData->data->Notes != NULL) {
+        def->description = strdup(virtualSystemSettingData->data->Notes);
+
+        if (def->description == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    def->mem.max_balloon = memorySettingData->data->Limit * 1024; /* megabyte to kilobyte */
+    def->mem.cur_balloon = memorySettingData->data->VirtualQuantity * 1024; /* megabyte to kilobyte */
+
+    def->vcpus = processorSettingData->data->VirtualQuantity;
+    def->maxvcpus = processorSettingData->data->VirtualQuantity;
+
+    def->os.type = strdup("hvm");
+
+    if (def->os.type == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* FIXME: devices section is totally missing */
+
+    xml = virDomainDefFormat(def, flags);
+
+  cleanup:
+    virDomainDefFree(def);
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData);
+    hypervFreeObject(priv, (hypervObject *)processorSettingData);
+    hypervFreeObject(priv, (hypervObject *)memorySettingData);
+
+    return xml;
+}
+
+
+
+static int
+hypervListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+    int i;
+
+    if (maxnames == 0) {
+        return 0;
+    }
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_INACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        names[count] = strdup(computerSystem->data->ElementName);
+
+        if (names[count] == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        ++count;
+
+        if (count >= maxnames) {
+            break;
+        }
+    }
+
+    success = true;
+
+  cleanup:
+    if (!success) {
+        for (i = 0; i < count; ++i) {
+            VIR_FREE(names[i]);
+        }
+
+        count = -1;
+    }
+
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return count;
+}
+
+
+
+static int
+hypervNumberOfDefinedDomains(virConnectPtr conn)
+{
+    bool success = false;
+    hypervPrivate *priv = conn->privateData;
+    virBuffer query = VIR_BUFFER_INITIALIZER;
+    Msvm_ComputerSystem *computerSystemList = NULL;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    int count = 0;
+
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT);
+    virBufferAddLit(&query, "where ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL);
+    virBufferAddLit(&query, "and ");
+    virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_INACTIVE);
+
+    if (hypervGetMsvmComputerSystemList(priv, &query,
+                                        &computerSystemList) < 0) {
+        goto cleanup;
+    }
+
+    for (computerSystem = computerSystemList; computerSystem != NULL;
+         computerSystem = computerSystem->next) {
+        ++count;
+    }
+
+    success = true;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystemList);
+
+    return success ? count : -1;
+}
+
+
+
+static int
+hypervDomainCreate(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (hypervIsMsvmComputerSystemActive(computerSystem, NULL)) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is already active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervIsEncrypted(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+
+
+static int
+hypervIsSecure(virConnectPtr conn)
+{
+    hypervPrivate *priv = conn->privateData;
+
+    if (STRCASEEQ(priv->parsedUri->transport, "https")) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+
+
+static int
+hypervDomainIsActive(virDomainPtr domain)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    result = hypervIsMsvmComputerSystemActive(computerSystem, NULL) ? 1 : 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainIsPersistent(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    /* Hyper-V has no concept of transient domains, so all of them are persistent */
+    return 1;
+}
+
+
+
+static int
+hypervDomainIsUpdated(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+
+
+static int
+hypervDomainManagedSave(virDomainPtr domain,
+                        unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+    bool in_transition = false;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (!hypervIsMsvmComputerSystemActive(computerSystem, &in_transition) ||
+        in_transition) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain is not active or is in state transition"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainHasManagedSaveImage(virDomainPtr domain,
+                                unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    result = computerSystem->data->EnabledState ==
+             MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED ? 1 : 0;
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static int
+hypervDomainManagedSaveRemove(virDomainPtr domain,
+                              unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -1;
+    hypervPrivate *priv = domain->conn->privateData;
+    Msvm_ComputerSystem *computerSystem = NULL;
+
+    if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) {
+        goto cleanup;
+    }
+
+    if (computerSystem->data->EnabledState !=
+        MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED) {
+        HYPERV_ERROR(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("Domain has no managed save image"));
+        goto cleanup;
+    }
+
+    result = hypervInvokeMsvmComputerSystemRequestStateChange
+               (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED);
+
+  cleanup:
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+
+    return result;
+}
+
+
+
+static virDriver hypervDriver = {
+    .no = VIR_DRV_HYPERV,
+    .name = "Hyper-V",
+    .open = hypervOpen, /* 0.9.4 */
+    .close = hypervClose, /* 0.9.4 */
+    .type = hypervGetType, /* 0.9.4 */
+    .getHostname = hypervGetHostname, /* 0.9.4 */
+    .nodeGetInfo = hypervNodeGetInfo, /* 0.9.4 */
+    .listDomains = hypervListDomains, /* 0.9.4 */
+    .numOfDomains = hypervNumberOfDomains, /* 0.9.4 */
+    .domainLookupByID = hypervDomainLookupByID, /* 0.9.4 */
+    .domainLookupByUUID = hypervDomainLookupByUUID, /* 0.9.4 */
+    .domainLookupByName = hypervDomainLookupByName, /* 0.9.4 */
+    .domainSuspend = hypervDomainSuspend, /* 0.9.4 */
+    .domainResume = hypervDomainResume, /* 0.9.4 */
+    .domainDestroy = hypervDomainDestroy, /* 0.9.4 */
+    .domainGetOSType = hypervDomainGetOSType, /* 0.9.4 */
+    .domainGetInfo = hypervDomainGetInfo, /* 0.9.4 */
+    .domainGetState = hypervDomainGetState, /* 0.9.4 */
+    .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.4 */
+    .listDefinedDomains = hypervListDefinedDomains, /* 0.9.4 */
+    .numOfDefinedDomains = hypervNumberOfDefinedDomains, /* 0.9.4 */
+    .domainCreate = hypervDomainCreate, /* 0.9.4 */
+    .isEncrypted = hypervIsEncrypted, /* 0.9.4 */
+    .isSecure = hypervIsSecure, /* 0.9.4 */
+    .domainIsActive = hypervDomainIsActive, /* 0.9.4 */
+    .domainIsPersistent = hypervDomainIsPersistent, /* 0.9.4 */
+    .domainIsUpdated = hypervDomainIsUpdated, /* 0.9.4 */
+    .domainManagedSave = hypervDomainManagedSave, /* 0.9.4 */
+    .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.4 */
+    .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.4 */
+};
+
+
+
+static void
+hypervDebugHandler(const char *message, debug_level_e level,
+                   void *user_data ATTRIBUTE_UNUSED)
+{
+    switch (level) {
+      case DEBUG_LEVEL_ERROR:
+      case DEBUG_LEVEL_CRITICAL:
+        VIR_ERROR(_("openwsman error: %s"), message);
+        break;
+
+      case DEBUG_LEVEL_WARNING:
+        VIR_WARN("openwsman warning: %s", message);
+        break;
+
+      default:
+        /* Ignore the rest */
+        break;
+    }
+}
+
+
+
+int
+hypervRegister(void)
+{
+    if (virRegisterDriver(&hypervDriver) < 0 ||
+        hypervInterfaceRegister() < 0 ||
+        hypervNetworkRegister() < 0 ||
+        hypervStorageRegister() < 0 ||
+        hypervDeviceRegister() < 0 ||
+        hypervSecretRegister() < 0 ||
+        hypervNWFilterRegister() < 0) {
+        return -1;
+    }
+
+    /* Forward openwsman errors and warnings to libvirt's logging */
+    debug_add_handler(hypervDebugHandler, DEBUG_LEVEL_WARNING, NULL);
+
+    return 0;
+}
diff --git a/src/hyperv/hyperv_driver.h b/src/hyperv/hyperv_driver.h
new file mode 100644
index 0000000..17ffa2c
--- /dev/null
+++ b/src/hyperv/hyperv_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_driver.h: core driver functions 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_DRIVER_H__
+# define __HYPERV_DRIVER_H__
+
+int hypervRegister(void);
+
+#endif /* __HYPERV_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c
new file mode 100644
index 0000000..9dd3360
--- /dev/null
+++ b/src/hyperv/hyperv_interface_driver.c
@@ -0,0 +1,77 @@
+
+/*
+ * hyperv_interface_driver.c: interface driver functions for managing
+ *                            Microsoft Hyper-V host interfaces
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_interface_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static virDrvOpenStatus
+hypervInterfaceOpen(virConnectPtr conn,
+                    virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                    unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->interfacePrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervInterfaceClose(virConnectPtr conn)
+{
+    conn->interfacePrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virInterfaceDriver hypervInterfaceDriver = {
+    .name = "Hyper-V",
+    .open = hypervInterfaceOpen, /* 0.9.4 */
+    .close = hypervInterfaceClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervInterfaceRegister(void)
+{
+    return virRegisterInterfaceDriver(&hypervInterfaceDriver);
+}
diff --git a/src/hyperv/hyperv_interface_driver.h b/src/hyperv/hyperv_interface_driver.h
new file mode 100644
index 0000000..730234c
--- /dev/null
+++ b/src/hyperv/hyperv_interface_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_interface_driver.h: interface driver functions for managing
+ *                            Microsoft Hyper-V host interfaces
+ *
+ * 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 __HYPERV_INTERFACE_DRIVER_H__
+# define __HYPERV_INTERFACE_DRIVER_H__
+
+int hypervInterfaceRegister(void);
+
+#endif /* __HYPERV_INTERFACE_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c
new file mode 100644
index 0000000..5e054fc
--- /dev/null
+++ b/src/hyperv/hyperv_network_driver.c
@@ -0,0 +1,80 @@
+
+/*
+ * hyperv_network_driver.c: network driver functions for managing
+ *                          Microsoft Hyper-V host networks
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "network_conf.h"
+#include "hyperv_private.h"
+#include "hyperv_network_driver.h"
+#include "hyperv_util.h"
+#include "hyperv_wmi.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static virDrvOpenStatus
+hypervNetworkOpen(virConnectPtr conn,
+                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                  unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->networkPrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervNetworkClose(virConnectPtr conn)
+{
+    conn->networkPrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virNetworkDriver hypervNetworkDriver = {
+    .name = "Hyper-V",
+    .open = hypervNetworkOpen, /* 0.9.4 */
+    .close = hypervNetworkClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervNetworkRegister(void)
+{
+    return virRegisterNetworkDriver(&hypervNetworkDriver);
+}
diff --git a/src/hyperv/hyperv_network_driver.h b/src/hyperv/hyperv_network_driver.h
new file mode 100644
index 0000000..49c856f
--- /dev/null
+++ b/src/hyperv/hyperv_network_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_network_driver.h: network driver functions for managing
+ *                          Microsoft Hyper-V host networks
+ *
+ * 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 __HYPERV_NETWORK_DRIVER_H__
+# define __HYPERV_NETWORK_DRIVER_H__
+
+int hypervNetworkRegister(void);
+
+#endif /* __HYPERV_NETWORK_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c
new file mode 100644
index 0000000..9774108
--- /dev/null
+++ b/src/hyperv/hyperv_nwfilter_driver.c
@@ -0,0 +1,77 @@
+
+/*
+ * hyperv_nwfilter_driver.c: nwfilter driver functions for managing
+ *                           Microsoft Hyper-V firewall rules
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_nwfilter_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static virDrvOpenStatus
+hypervNWFilterOpen(virConnectPtr conn,
+                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                   unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->nwfilterPrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervNWFilterClose(virConnectPtr conn)
+{
+    conn->nwfilterPrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virNWFilterDriver hypervNWFilterDriver = {
+    .name = "Hyper-V",
+    .open = hypervNWFilterOpen, /* 0.9.4 */
+    .close = hypervNWFilterClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervNWFilterRegister(void)
+{
+    return virRegisterNWFilterDriver(&hypervNWFilterDriver);
+}
diff --git a/src/hyperv/hyperv_nwfilter_driver.h b/src/hyperv/hyperv_nwfilter_driver.h
new file mode 100644
index 0000000..ef4f660
--- /dev/null
+++ b/src/hyperv/hyperv_nwfilter_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_nwfilter_driver.h: nwfilter driver functions for managing
+ *                           Microsoft Hyper-V firewall rules
+ *
+ * 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 __HYPERV_NWFILTER_DRIVER_H__
+# define __HYPERV_NWFILTER_DRIVER_H__
+
+int hypervNWFilterRegister(void);
+
+#endif /* __HYPERV_NWFILTER_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h
new file mode 100644
index 0000000..1588f90
--- /dev/null
+++ b/src/hyperv/hyperv_private.h
@@ -0,0 +1,43 @@
+
+/*
+ * hyperv_private.h: private driver struct for the Microsoft Hyper-V driver
+ *
+ * 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_PRIVATE_H__
+# define __HYPERV_PRIVATE_H__
+
+# include "internal.h"
+# include "virterror_internal.h"
+# include "openwsman.h"
+# include "hyperv_util.h"
+
+# define HYPERV_ERROR(code, ...)                                              \
+    virReportErrorHelper(VIR_FROM_HYPERV, code, __FILE__, __FUNCTION__,       \
+                         __LINE__, __VA_ARGS__)
+
+typedef struct _hypervPrivate hypervPrivate;
+
+struct _hypervPrivate {
+    hypervParsedUri *parsedUri;
+    WsManClient *client;
+};
+
+#endif /* __HYPERV_PRIVATE_H__ */
diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c
new file mode 100644
index 0000000..314bfd5
--- /dev/null
+++ b/src/hyperv/hyperv_secret_driver.c
@@ -0,0 +1,77 @@
+
+/*
+ * hyperv_secret_driver.c: secret driver functions for Microsoft Hyper-V
+ *                         secret manipulation
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_secret_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_Microsoft Hyper-V
+
+
+
+static virDrvOpenStatus
+hypervSecretOpen(virConnectPtr conn,
+                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                 unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->secretPrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervSecretClose(virConnectPtr conn)
+{
+    conn->secretPrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virSecretDriver hypervSecretDriver = {
+    .name = "Hyper-V",
+    .open = hypervSecretOpen, /* 0.9.4 */
+    .close = hypervSecretClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervSecretRegister(void)
+{
+    return virRegisterSecretDriver(&hypervSecretDriver);
+}
diff --git a/src/hyperv/hyperv_secret_driver.h b/src/hyperv/hyperv_secret_driver.h
new file mode 100644
index 0000000..a7e9f25
--- /dev/null
+++ b/src/hyperv/hyperv_secret_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_secret_driver.h: secret driver functions for Microsoft Hyper-V
+ *                         secret manipulation
+ *
+ * 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 __HYPERV_SECRET_DRIVER_H__
+# define __HYPERV_SECRET_DRIVER_H__
+
+int hypervSecretRegister(void);
+
+#endif /* __HYPERV_SECRET_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c
new file mode 100644
index 0000000..2cb4878
--- /dev/null
+++ b/src/hyperv/hyperv_storage_driver.c
@@ -0,0 +1,79 @@
+
+/*
+ * hyperv_storage_driver.c: storage driver functions for managing
+ *                          Microsoft Hyper-V host storage
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "storage_conf.h"
+#include "storage_file.h"
+#include "hyperv_private.h"
+#include "hyperv_storage_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+static virDrvOpenStatus
+hypervStorageOpen(virConnectPtr conn,
+                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+                  unsigned int flags ATTRIBUTE_UNUSED)
+{
+    if (conn->driver->no != VIR_DRV_HYPERV) {
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    conn->storagePrivateData = conn->privateData;
+
+    return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+
+static int
+hypervStorageClose(virConnectPtr conn)
+{
+    conn->storagePrivateData = NULL;
+
+    return 0;
+}
+
+
+
+static virStorageDriver hypervStorageDriver = {
+    .name = "Hyper-V",
+    .open = hypervStorageOpen, /* 0.9.4 */
+    .close = hypervStorageClose, /* 0.9.4 */
+};
+
+
+
+int
+hypervStorageRegister(void)
+{
+    return virRegisterStorageDriver(&hypervStorageDriver);
+}
diff --git a/src/hyperv/hyperv_storage_driver.h b/src/hyperv/hyperv_storage_driver.h
new file mode 100644
index 0000000..c9bca22
--- /dev/null
+++ b/src/hyperv/hyperv_storage_driver.h
@@ -0,0 +1,29 @@
+
+/*
+ * hyperv_storage_driver.h: storage driver methods for managing
+ *                          Microsoft Hyper-V host storage
+ *
+ * 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 __HYPERV_STORAGE_DRIVER_H__
+# define __HYPERV_STORAGE_DRIVER_H__
+
+int hypervStorageRegister(void);
+
+#endif /* __HYPERV_STORAGE_DRIVER_H__ */
diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c
new file mode 100644
index 0000000..298cfe0
--- /dev/null
+++ b/src/hyperv/hyperv_util.c
@@ -0,0 +1,129 @@
+
+/*
+ * hyperv_util.c: utility functions for the Microsoft Hyper-V driver
+ *
+ * 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
+ *
+ */
+
+#include <config.h>
+
+#include "internal.h"
+#include "datatypes.h"
+#include "qparams.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "hyperv_private.h"
+#include "hyperv_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_HYPERV
+
+
+
+int
+hypervParseUri(hypervParsedUri **parsedUri, xmlURIPtr uri)
+{
+    int result = -1;
+    struct qparam_set *queryParamSet = NULL;
+    struct qparam *queryParam = NULL;
+    int i;
+
+    if (parsedUri == NULL || *parsedUri != NULL) {
+        HYPERV_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+        return -1;
+    }
+
+    if (VIR_ALLOC(*parsedUri) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+#ifdef HAVE_XMLURI_QUERY_RAW
+    queryParamSet = qparam_query_parse(uri->query_raw);
+#else
+    queryParamSet = qparam_query_parse(uri->query);
+#endif
+
+    if (queryParamSet == NULL) {
+        goto cleanup;
+    }
+
+    for (i = 0; i < queryParamSet->n; i++) {
+        queryParam = &queryParamSet->p[i];
+
+        if (STRCASEEQ(queryParam->name, "transport")) {
+            VIR_FREE((*parsedUri)->transport);
+
+            (*parsedUri)->transport = strdup(queryParam->value);
+
+            if ((*parsedUri)->transport == NULL) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            if (STRNEQ((*parsedUri)->transport, "http") &&
+                STRNEQ((*parsedUri)->transport, "https")) {
+                HYPERV_ERROR(VIR_ERR_INVALID_ARG,
+                             _("Query parameter 'transport' has unexpected value "
+                               "'%s' (should be http|https)"),
+                             (*parsedUri)->transport);
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Ignoring unexpected query parameter '%s'",
+                     queryParam->name);
+        }
+    }
+
+    if ((*parsedUri)->transport == NULL) {
+        (*parsedUri)->transport = strdup("https");
+
+        if ((*parsedUri)->transport == NULL) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    result = 0;
+
+  cleanup:
+    if (result < 0) {
+        hypervFreeParsedUri(parsedUri);
+    }
+
+    if (queryParamSet != NULL) {
+        free_qparam_set(queryParamSet);
+    }
+
+    return result;
+}
+
+
+
+void
+hypervFreeParsedUri(hypervParsedUri **parsedUri)
+{
+    if (parsedUri == NULL || *parsedUri == NULL) {
+        return;
+    }
+
+    VIR_FREE((*parsedUri)->transport);
+
+    VIR_FREE(*parsedUri);
+}
diff --git a/src/hyperv/hyperv_util.h b/src/hyperv/hyperv_util.h
new file mode 100644
index 0000000..a6fa6a1
--- /dev/null
+++ b/src/hyperv/hyperv_util.h
@@ -0,0 +1,39 @@
+/*
+ * hyperv_util.h: utility functions for the Microsoft Hyper-V driver
+ *
+ * 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 __HYPERV_UTIL_H__
+# define __HYPERV_UTIL_H__
+
+# include <libxml/uri.h>
+
+# include "internal.h"
+
+typedef struct _hypervParsedUri hypervParsedUri;
+
+struct _hypervParsedUri {
+    char *transport;
+};
+
+int hypervParseUri(hypervParsedUri **parsedUri, xmlURIPtr uri);
+
+void hypervFreeParsedUri(hypervParsedUri **parsedUri);
+
+#endif /* __HYPERV_UTIL_H__ */
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c
new file mode 100644
index 0000000..c584b03
--- /dev/null
+++ b/src/hyperv/hyperv_wmi.c
@@ -0,0 +1,692 @@
+
+/*
+ * 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>
+
+#ifdef WIN32
+# include <windows.h>
+#endif
+
+#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;
+
+#ifdef WIN32
+                Sleep(100);
+#else
+                usleep(100 * 1000);
+#endif
+
+                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..18c05da
--- /dev/null
+++ b/src/hyperv/hyperv_wmi.h
@@ -0,0 +1,119 @@
+
+/*
+ * 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 "openwsman.h"
+# include "hyperv_private.h"
+# include "hyperv_wmi_classes.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__ */
diff --git a/src/libvirt.c b/src/libvirt.c
index 7e70caa..8eb8905 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -66,6 +66,9 @@
 # ifdef WITH_ESX
 #  include "esx/esx_driver.h"
 # endif
+# ifdef WITH_HYPERV
+#  include "hyperv/hyperv_driver.h"
+# endif
 # ifdef WITH_XENAPI
 #  include "xenapi/xenapi_driver.h"
 # endif
@@ -446,6 +449,9 @@ virInitialize(void)
 # ifdef WITH_ESX
     virDriverLoadModule("esx");
 # endif
+# ifdef WITH_HYPERV
+    virDriverLoadModule("hyperv");
+# endif
 # ifdef WITH_XENAPI
     virDriverLoadModule("xenapi");
 # endif
@@ -474,6 +480,9 @@ virInitialize(void)
 # ifdef WITH_ESX
     if (esxRegister() == -1) return -1;
 # endif
+# ifdef WITH_HYPERV
+    if (hypervRegister() == -1) return -1;
+# endif
 # ifdef WITH_XENAPI
     if (xenapiRegister() == -1) return -1;
 # endif
@@ -1038,6 +1047,9 @@ do_open (const char *name,
              STRCASEEQ(ret->uri->scheme, "esx") ||
              STRCASEEQ(ret->uri->scheme, "gsx") ||
 #endif
+#ifndef WITH_HYPERV
+             STRCASEEQ(ret->uri->scheme, "hyperv") ||
+#endif
 #ifndef WITH_XENAPI
              STRCASEEQ(ret->uri->scheme, "xenapi") ||
 #endif
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 75058f3..e13bac3 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -172,6 +172,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_LOCKING:
             dom = "Locking ";
             break;
+        case VIR_FROM_HYPERV:
+            dom = "Hyper-V ";
+            break;
     }
     return(dom);
 }
-- 
1.7.4.1




More information about the libvir-list mailing list