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@top_srcdir@/src/conf -I@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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "internal.h" +#include "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@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_WMI_H__ +# define __HYPERV_WMI_H__ + +# include "buf.h" +# include "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@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "hyperv_wmi_classes.h" + +SER_TYPEINFO_BOOL; +SER_TYPEINFO_STRING; +SER_TYPEINFO_INT8; +SER_TYPEINFO_INT16; +SER_TYPEINFO_INT32; +SER_TYPEINFO_UINT8; +SER_TYPEINFO_UINT16; +SER_TYPEINFO_UINT32; + +#include "hyperv_wmi_classes.generated.c" diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h new file mode 100644 index 0000000..5c97ca6 --- /dev/null +++ b/src/hyperv/hyperv_wmi_classes.h @@ -0,0 +1,94 @@ + +/* + * hyperv_wmi_classes.h: WMI classes for managing Microsoft Hyper-V hosts + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * Copyright (C) 2009 Michael Sievers <msievers83@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __HYPERV_WMI_CLASSES_H__ +# define __HYPERV_WMI_CLASSES_H__ + +# include "openwsman.h" + +# include "hyperv_wmi_classes.generated.typedef" + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ComputerSystem + */ + +# define MSVM_COMPUTERSYSTEM_WQL_VIRTUAL \ + "Description = \"Microsoft Virtual Machine\" " + +# define MSVM_COMPUTERSYSTEM_WQL_PHYSICAL \ + "Description = \"Microsoft Hosting Computer System\" " + +# define MSVM_COMPUTERSYSTEM_WQL_ACTIVE \ + "(EnabledState != 0 and EnabledState != 3 and EnabledState != 32769) " + +# define MSVM_COMPUTERSYSTEM_WQL_INACTIVE \ + "(EnabledState = 0 or EnabledState = 3 or EnabledState = 32769) " + +enum _Msvm_ComputerSystem_EnabledState { + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN = 0, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED = 2, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_DISABLED = 3, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED = 32768, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED = 32769, /* inactive */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STARTING = 32770, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SNAPSHOTTING = 32771, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SAVING = 32773, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_STOPPING = 32774, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSING = 32776, /* active */ + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_RESUMING = 32777 /* active */ +}; + +enum _Msvm_ComputerSystem_RequestedState { + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED = 32768, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED = 32769, +}; + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ConcreteJob + */ + +enum _Msvm_ConcreteJob_JobState { + MSVM_CONCRETEJOB_JOBSTATE_NEW = 2, + MSVM_CONCRETEJOB_JOBSTATE_STARTING = 3, + MSVM_CONCRETEJOB_JOBSTATE_RUNNING = 4, + MSVM_CONCRETEJOB_JOBSTATE_SUSPENDED = 5, + MSVM_CONCRETEJOB_JOBSTATE_SHUTTING_DOWN = 6, + MSVM_CONCRETEJOB_JOBSTATE_COMPLETED = 7, + MSVM_CONCRETEJOB_JOBSTATE_TERMINATED = 8, + MSVM_CONCRETEJOB_JOBSTATE_KILLED = 9, + MSVM_CONCRETEJOB_JOBSTATE_EXCEPTION = 10, + MSVM_CONCRETEJOB_JOBSTATE_SERVICE = 11, +}; + + + +# include "hyperv_wmi_classes.generated.h" + +#endif /* __HYPERV_WMI_CLASSES_H__ */ diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input new file mode 100644 index 0000000..da874ac --- /dev/null +++ b/src/hyperv/hyperv_wmi_generator.input @@ -0,0 +1,294 @@ +# +# Definitions of WMI classes used as input for the hyperv_wmi_generator.py +# script. +# +# This format is line-based, so end-of-line is important. +# +# +# Class definition: +# +# class <name> +# <type> <name> +# ... +# end +# +# Allowed values for <type> are: boolean, string, datetime, int8, int16, +# int32, int64, uint8, uint16, uint32 and uint64 +# +# The property <name> can be followed by [] to define a dynamic array. +# + + +class Msvm_ComputerSystem + string Caption + string Description + string ElementName + datetime InstallDate + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + string CreationClassName + string Name + string PrimaryOwnerName + string PrimaryOwnerContact + string Roles[] + string NameFormat + string OtherIdentifyingInfo[] + string IdentifyingDescriptions[] + uint16 Dedicated[] + string OtherDedicatedDescriptions[] + uint16 ResetCapability + uint16 PowerManagementCapabilities[] + uint64 OnTimeInMilliseconds + datetime TimeOfLastConfigurationChange + uint32 ProcessID + uint16 AssignedNumaNodeList[] +end + + +class Msvm_ConcreteJob + string Caption + string Description + string ElementName + datetime InstallDate + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + string JobStatus + datetime TimeSubmitted + datetime ScheduledStartTime + datetime StartTime + datetime ElapsedTime + uint32 JobRunTimes + uint8 RunMonth + int8 RunDay + int8 RunDayOfWeek + datetime RunStartInterval + uint16 LocalOrUtcTime + datetime UntilTime + string Notify + string Owner + uint32 Priority + uint16 PercentComplete + boolean DeleteOnCompletion + uint16 ErrorCode + string ErrorDescription + string ErrorSummaryDescription + uint16 RecoveryAction + string OtherRecoveryAction + string InstanceID + string Name + uint16 JobState + datetime TimeOfLastStateChange + datetime TimeBeforeRemoval + boolean Cancellable +end + + +class Msvm_MemorySettingData + string Caption + string Description + string InstanceID + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Reservation + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + boolean IsVirtualized + string DeviceID + string DeviceIDFormat + boolean DynamicMemoryEnabled +# uint32 TargetMemoryBuffer # Available only on Windows Server 2008 R2 SP1 +end + + +class Msvm_ProcessorSettingData + string Caption + string Description + string InstanceID + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Reservation + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + boolean IsVirtualized + string DeviceID + string DeviceIDFormat + uint16 ProcessorsPerSocket + uint16 SocketCount + boolean ThreadsEnabled + boolean LimitCPUID + boolean LimitProcessorFeatures +end + + +class Msvm_VirtualSystemSettingData + string Caption + string Description + string ElementName + string InstanceID + string SystemName + uint16 SettingType + uint16 VirtualSystemType + string OtherVirtualSystemType + boolean AutoActivate + datetime CreationTime + string Notes + string BIOSGUID + string BIOSSerialNumber + string BaseBoardSerialNumber + string ChassisSerialNumber + string ChassisAssetTag + boolean BIOSNumLock + uint16 BootOrder[] + string Parent + uint16 NumaNodeList[] + boolean NumaNodesAreRequired +end + + +class Win32_ComputerSystem + uint16 AdminPasswordStatus + boolean AutomaticManagedPagefile + boolean AutomaticResetBootOption + boolean AutomaticResetCapability + uint16 BootOptionOnLimit + uint16 BootOptionOnWatchDog + boolean BootROMSupported + string BootupState + string Caption + uint16 ChassisBootupState + string CreationClassName + int16 CurrentTimeZone + boolean DaylightInEffect + string Description + string DNSHostName + string Domain + uint16 DomainRole + boolean EnableDaylightSavingsTime + uint16 FrontPanelResetStatus + boolean InfraredSupported +# string InitialLoadInfo # MSDN documents it, but it's not there + datetime InstallDate + uint16 KeyboardPasswordStatus + string LastLoadInfo + string Manufacturer + string Model + string Name + string NameFormat + boolean NetworkServerModeEnabled + uint32 NumberOfLogicalProcessors + uint32 NumberOfProcessors + uint8 OEMLogoBitmap[] + string OEMStringArray[] + boolean PartOfDomain + int64 PauseAfterReset + uint16 PCSystemType + uint16 PowerManagementCapabilities[] + boolean PowerManagementSupported + uint16 PowerOnPasswordStatus + uint16 PowerState + uint16 PowerSupplyState + string PrimaryOwnerContact + string PrimaryOwnerName + uint16 ResetCapability + int16 ResetCount + int16 ResetLimit + string Roles[] + string Status + string SupportContactDescription[] + uint16 SystemStartupDelay + string SystemStartupOptions[] + uint8 SystemStartupSetting + string SystemType + uint16 ThermalState + uint64 TotalPhysicalMemory + string UserName + uint16 WakeUpType + string Workgroup +end + + +class Win32_Processor + uint16 AddressWidth + uint16 Architecture + uint16 Availability + string Caption + uint32 ConfigManagerErrorCode + boolean ConfigManagerUserConfig + uint16 CpuStatus + string CreationClassName + uint32 CurrentClockSpeed + uint16 CurrentVoltage + uint16 DataWidth + string Description + string DeviceID + boolean ErrorCleared + string ErrorDescription + uint32 ExtClock + uint16 Family + datetime InstallDate + uint32 L2CacheSize + uint32 L2CacheSpeed + uint32 L3CacheSize + uint32 L3CacheSpeed + uint32 LastErrorCode + uint16 Level + uint16 LoadPercentage + string Manufacturer + uint32 MaxClockSpeed + string Name + uint32 NumberOfCores + uint32 NumberOfLogicalProcessors + string OtherFamilyDescription + string PNPDeviceID + uint16 PowerManagementCapabilities[] + boolean PowerManagementSupported + string ProcessorId + uint16 ProcessorType + uint16 Revision + string Role + string SocketDesignation + string Status + uint16 StatusInfo + string Stepping + string SystemCreationClassName + string SystemName + string UniqueId + uint16 UpgradeMethod + string Version + uint32 VoltageCaps +end diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py new file mode 100755 index 0000000..077c3a0 --- /dev/null +++ b/src/hyperv/hyperv_wmi_generator.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python + +# +# hyperv_wmi_generator.py: generates most of the WMI type mapping code +# +# Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import sys +import os +import os.path + + + +separator = "/* " + ("* " * 37) + "*\n" + + + +class Class: + def __init__(self, name, properties): + self.name = name + self.properties = properties + + + def generate_header(self): + name_upper = self.name.upper() + + header = separator + header += " * %s\n" % self.name + header += " */\n" + header += "\n" + header += "int hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list);\n" \ + % (self.name.replace("_", ""), self.name) + header += "\n" + header += "\n" + header += "\n" + + return header + + + def generate_classes_typedef(self): + typedef = "typedef struct _%s_Data %s_Data;\n" % (self.name, self.name) + typedef += "typedef struct _%s %s;\n" % (self.name, self.name) + + return typedef + + + def generate_classes_header(self): + name_upper = self.name.upper() + + header = separator + header += " * %s\n" % self.name + header += " */\n" + header += "\n" + header += "#define %s_RESOURCE_URI \\\n" % name_upper + + if self.name.startswith("Win32_"): + header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/%s\"\n" % self.name + else: + header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/%s\"\n" % self.name + + header += "\n" + header += "#define %s_CLASSNAME \\\n" % name_upper + header += " \"%s\"\n" % self.name + header += "\n" + header += "#define %s_WQL_SELECT \\\n" % name_upper + header += " \"select * from %s \"\n" % self.name + header += "\n" + header += "struct _%s_Data {\n" % self.name + + for property in self.properties: + header += property.generate_classes_header() + + header += "};\n" + header += "\n" + header += "SER_DECLARE_TYPE(%s_Data);\n" % self.name + header += "\n" + header += "struct _%s {\n" % self.name + header += " XmlSerializerInfo *serializerInfo;\n" + header += " %s_Data *data;\n" % self.name + header += " %s *next;\n" % self.name + header += "};\n" + header += "\n" + header += "\n" + header += "\n" + + return header + + + def generate_source(self): + name_upper = self.name.upper() + + source = separator + source += " * %s\n" % self.name + source += " */\n" + source += "\n" + source += "int\n" + source += "hypervGet%sList(hypervPrivate *priv, virBufferPtr query, %s **list)\n" \ + % (self.name.replace("_", ""), self.name) + source += "{\n" + + if self.name.startswith("Win32_"): + source += " return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n" + else: + source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\n" + + source += " %s_Data_TypeInfo,\n" % self.name + source += " %s_RESOURCE_URI,\n" % name_upper + source += " %s_CLASSNAME,\n" % name_upper + source += " (hypervObject **)list);\n" + source += "}\n" + source += "\n" + source += "\n" + source += "\n" + + return source + + + def generate_classes_source(self): + name_upper = self.name.upper() + + source = separator + source += " * %s\n" % self.name + source += " */\n" + source += "\n" + source += "SER_START_ITEMS(%s_Data)\n" % self.name + + for property in self.properties: + source += property.generate_classes_source(self.name) + + source += "SER_END_ITEMS(%s_Data);\n" % self.name + source += "\n" + source += "\n" + source += "\n" + + return source + + +class Property: + typemap = {"boolean" : "BOOL", + "string" : "STR", + "datetime" : "STR", + "int8" : "INT8", + "int16" : "INT16", + "int32" : "INT32", + "int64" : "INT64", + "uint8" : "UINT8", + "uint16" : "UINT16", + "uint32" : "UINT32", + "uint64" : "UINT64"} + + + def __init__(self, type, name, is_array): + if type not in Property.typemap: + report_error("unhandled property type %s" % type) + + self.type = type + self.name = name + self.is_array = is_array + + + def generate_classes_header(self): + if self.is_array: + return " XML_TYPE_DYN_ARRAY %s;\n" % self.name + else: + return " XML_TYPE_%s %s;\n" \ + % (Property.typemap[self.type], self.name) + + + def generate_classes_source(self, class_name): + if self.is_array: + return " SER_NS_DYN_ARRAY(%s_RESOURCE_URI, \"%s\", 0, 0, %s),\n" \ + % (class_name.upper(), self.name, self.type) + else: + return " SER_NS_%s(%s_RESOURCE_URI, \"%s\", 1),\n" \ + % (Property.typemap[self.type], class_name.upper(), self.name) + + + +def open_and_print(filename): + if filename.startswith("./"): + print " GEN " + filename[2:] + else: + print " GEN " + filename + + return open(filename, "wb") + + + +def report_error(message): + print "error: " + message + sys.exit(1) + + + +def parse_class(block): + # expected format: class <name> + header_items = block[0][1].split() + + if len(header_items) != 2: + report_error("line %d: invalid block header" % (number)) + + assert header_items[0] == "class" + + name = header_items[1] + + properties = [] + + for line in block[1:]: + # expected format: <type> <name> + items = line[1].split() + + if len(items) != 2: + report_error("line %d: invalid property" % line[0]) + + if items[1].endswith("[]"): + items[1] = items[1][:-2] + is_array = True + else: + is_array = False + + properties.append(Property(type=items[0], name=items[1], + is_array=is_array)) + + return Class(name=name, properties=properties) + + + +def main(): + if "srcdir" in os.environ: + input_filename = os.path.join(os.environ["srcdir"], "hyperv/hyperv_wmi_generator.input") + output_dirname = os.path.join(os.environ["srcdir"], "hyperv") + else: + input_filename = os.path.join(os.getcwd(), "hyperv_wmi_generator.input") + output_dirname = os.getcwd() + + header = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.h")) + source = open_and_print(os.path.join(output_dirname, "hyperv_wmi.generated.c")) + classes_typedef = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.typedef")) + classes_header = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.h")) + classes_source = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes.generated.c")) + + # parse input file + number = 0 + classes_by_name = {} + block = None + + for line in file(input_filename, "rb").readlines(): + number += 1 + + if "#" in line: + line = line[:line.index("#")] + + line = line.lstrip().rstrip() + + if len(line) < 1: + continue + + if line.startswith("class"): + if block is not None: + report_error("line %d: nested block found" % (number)) + else: + block = [] + + if block is not None: + if line == "end": + if block[0][1].startswith("class"): + cls = parse_class(block) + classes_by_name[cls.name] = cls + + block = None + else: + block.append((number, line)) + + # write output files + header.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + source.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_typedef.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_header.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + classes_source.write("/* Generated by hyperv_wmi_generator.py */\n\n\n\n") + + names = classes_by_name.keys() + names.sort() + + for name in names: + header.write(classes_by_name[name].generate_header()) + source.write(classes_by_name[name].generate_source()) + classes_typedef.write(classes_by_name[name].generate_classes_typedef()) + classes_header.write(classes_by_name[name].generate_classes_header()) + classes_source.write(classes_by_name[name].generate_classes_source()) + + + +if __name__ == "__main__": + main() diff --git a/src/hyperv/openwsman.h b/src/hyperv/openwsman.h new file mode 100644 index 0000000..8bc0604 --- /dev/null +++ b/src/hyperv/openwsman.h @@ -0,0 +1,47 @@ + +/* + * openwsman.h: workarounds for bugs in openwsman + * + * Copyright (C) 2011 Matthias Bolte <matthias.bolte@xxxxxxxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __OPENWSMAN_H__ +# define __OPENWSMAN_H__ + +/* Workaround openwsman <= 2.2.6 unconditionally defining optarg. Just pretend + * that u/os.h was already included. Need to explicitly include time.h because + * wsman-xml-serializer.h needs it and u/os.h would have included it. */ +# include <time.h> +# define _LIBU_OS_H_ +# include <wsman-api.h> + +/* wsman-xml-serializer.h in openwsman <= 2.2.6 is missing this defines */ +# ifndef SER_NS_INT8 +# define SER_NS_INT8(ns, n, x) SER_NS_INT8_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT16 +# define SER_NS_INT16(ns, n, x) SER_NS_INT16_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT32 +# define SER_NS_INT32(ns, n, x) SER_NS_INT32_FLAGS(ns, n, x, 0) +# endif +# ifndef SER_NS_INT64 +# define SER_NS_INT64(ns, n, x) SER_NS_INT64_FLAGS(ns, n, x, 0) +# endif + +#endif /* __OPENWSMAN_H__ */ 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list