--- src/Makefile.am | 1 + src/hyperv/hyperv_driver.c | 62 ++++++- src/hyperv/hyperv_driver_2012.c | 299 ++++++++++++++++++++++++++++++++++ src/hyperv/hyperv_driver_2012.h | 55 +++++++ src/hyperv/hyperv_private.h | 4 + src/hyperv/hyperv_wmi.h | 3 + src/hyperv/hyperv_wmi_generator.input | 35 +++- src/hyperv/hyperv_wmi_generator.py | 11 +- 8 files changed, 462 insertions(+), 8 deletions(-) create mode 100644 src/hyperv/hyperv_driver_2012.c create mode 100644 src/hyperv/hyperv_driver_2012.h diff --git a/src/Makefile.am b/src/Makefile.am index d03e6b0..edc2db3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -888,6 +888,7 @@ ESX_DRIVER_EXTRA_DIST = \ HYPERV_DRIVER_SOURCES = \ hyperv/hyperv_private.h \ hyperv/hyperv_driver.c hyperv/hyperv_driver.h \ + hyperv/hyperv_driver_2012.c hyperv/hyperv_driver_2012.h \ hyperv/hyperv_network_driver.c hyperv/hyperv_network_driver.h \ hyperv/hyperv_util.c hyperv/hyperv_util.h \ hyperv/hyperv_wmi.c hyperv/hyperv_wmi.h \ diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 716fadb..63baef8 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -30,6 +30,7 @@ #include "virlog.h" #include "viruuid.h" #include "hyperv_driver.h" +#include "hyperv_driver_2012.h" #include "hyperv_network_driver.h" #include "hyperv_private.h" #include "hyperv_util.h" @@ -65,6 +66,35 @@ hypervFreePrivate(hypervPrivate **priv) /* Forward declaration of hypervCapsInit */ static virCapsPtr hypervCapsInit(hypervPrivate *priv); +static virHypervisorDriver hypervHypervisorDriver; + +static char * +hypervNodeGetWindowsVersion(hypervPrivate *priv) +{ + virBuffer query = VIR_BUFFER_INITIALIZER; + Win32_OperatingSystem *operatingSystem = NULL; + + /* Get Win32_OperatingSystem */ + virBufferAddLit(&query, WIN32_OPERATINGSYSTEM_WQL_SELECT); + + if (hypervGetWin32OperatingSystemList(priv, &query, &operatingSystem) < 0) { + goto cleanup; + } + + if (operatingSystem == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get Win32_OperatingSystem")); + goto cleanup; + } + + return operatingSystem->data->Version; + + cleanup: + hypervFreeObject(priv, (hypervObject *) operatingSystem); + virBufferFreeAndReset(&query); + + return NULL; +} static virDrvOpenStatus hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, @@ -78,6 +108,9 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, char *password = NULL; virBuffer query = VIR_BUFFER_INITIALIZER; Msvm_ComputerSystem *computerSystem = NULL; + Msvm_ComputerSystem_2012 *computerSystem2012 = NULL; + char *windowsVersion = NULL; + char *hypervVersion = (char *)calloc(4, sizeof(char)); virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); @@ -175,6 +208,16 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, /* FIXME: Currently only basic authentication is supported */ wsman_transport_set_auth_method(priv->client, "basic"); + windowsVersion = hypervNodeGetWindowsVersion(priv); + if (windowsVersion == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not determine Windows version")); + goto cleanup; + } + + strncpy(hypervVersion, windowsVersion, 3); + priv->hypervVersion = hypervVersion; + /* Check if the connection can be established and if the server has the * Hyper-V role installed. If the call to hypervGetMsvmComputerSystemList * succeeds than the connection has been established. If the returned list @@ -183,15 +226,25 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, virBufferAddLit(&query, "where "); virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_PHYSICAL); - if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) - goto cleanup; + if (strcmp(priv->hypervVersion, HYPERV_VERSION_2008) == 0) { + if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) + goto cleanup; + } else if (strcmp(priv->hypervVersion, HYPERV_VERSION_2012) == 0) { + if (hypervGetMsvmComputerSystem2012List(priv, &query, &computerSystem2012) < 0) + goto cleanup; + } - if (computerSystem == NULL) { + if (computerSystem == NULL && computerSystem2012 == NULL) { virReportError(VIR_ERR_INTERNAL_ERROR, _("%s is not a Hyper-V server"), conn->uri->server); goto cleanup; } + if (computerSystem2012 != NULL) { + hypervHypervisorDriver.connectListAllDomains = hypervConnectListAllDomains2012; + hypervHypervisorDriver.domainGetState = hypervDomainGetState2012; + } + /* Setup capabilities */ priv->caps = hypervCapsInit(priv); if (priv->caps == NULL) { @@ -209,8 +262,9 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, hypervFreePrivate(&priv); VIR_FREE(username); VIR_FREE(password); + free(hypervVersion); hypervFreeObject(priv, (hypervObject *)computerSystem); - + hypervFreeObject(priv, (hypervObject *)computerSystem2012); return result; } diff --git a/src/hyperv/hyperv_driver_2012.c b/src/hyperv/hyperv_driver_2012.c new file mode 100644 index 0000000..6c2b3b6 --- /dev/null +++ b/src/hyperv/hyperv_driver_2012.c @@ -0,0 +1,299 @@ +#include "hyperv_driver_2012.h" + +static int +hypervMsvmComputerSystemEnabledStateToDomainState2012( + Msvm_ComputerSystem_2012 *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: /* managed save */ + 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; + } +} + +static int +hypervMsvmComputerSystemFromDomain2012(virDomainPtr domain, + Msvm_ComputerSystem_2012 **computerSystem) +{ + hypervPrivate *priv = domain->conn->privateData; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + virBuffer query = VIR_BUFFER_INITIALIZER; + + if (computerSystem == NULL || *computerSystem != NULL) { + virReportError(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 (hypervGetMsvmComputerSystem2012List(priv, &query, computerSystem) < 0) + return -1; + + if (*computerSystem == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with UUID %s"), uuid_string); + return -1; + } + + return 0; +} + +static bool +hypervIsMsvmComputerSystemActive2012(Msvm_ComputerSystem_2012 *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: /* managed save */ + 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; + } +} + +static int +hypervMsvmComputerSystemToDomain2012(virConnectPtr conn, + Msvm_ComputerSystem_2012 *computerSystem, + virDomainPtr *domain) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (domain == NULL || *domain != NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + if (virUUIDParse(computerSystem->data->Name, uuid) < 0) { + virReportError(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 (hypervIsMsvmComputerSystemActive2012(computerSystem, NULL)) { + (*domain)->id = computerSystem->data->ProcessID; + } else { + (*domain)->id = -1; + } + + return 0; +} + +int +hypervDomainGetState2012(virDomainPtr domain, int *state, int *reason, + unsigned int flags) +{ + int result = -1; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem_2012 *computerSystem = NULL; + + virCheckFlags(0, -1); + + if (hypervMsvmComputerSystemFromDomain2012(domain, &computerSystem) < 0) + goto cleanup; + + *state = hypervMsvmComputerSystemEnabledStateToDomainState2012(computerSystem); + + if (reason != NULL) + *reason = 0; + + result = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + + return result; +} + +#define MATCH(FLAG) (flags & (FLAG)) +int +hypervConnectListAllDomains2012(virConnectPtr conn, + virDomainPtr **domains, + unsigned int flags) +{ + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ComputerSystem_2012 *computerSystemList = NULL; + Msvm_ComputerSystem_2012 *computerSystem = NULL; + size_t ndoms; + virDomainPtr domain; + virDomainPtr *doms = NULL; + int count = 0; + int ret = -1; + size_t i; + + virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1); + + /* check for filter combinations that return no results: + * persistent: all hyperv guests are persistent + * snapshot: the driver does not support snapshot management + * autostart: the driver does not support autostarting guests + */ + if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && + !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && + !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && + !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT))) { + if (domains && VIR_ALLOC_N(*domains, 1) < 0) + goto cleanup; + + ret = 0; + goto cleanup; + } + + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAddLit(&query, "where "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_VIRTUAL); + + /* construct query with filter depending on flags */ + if (!(MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && + MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE))) { + if (MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { + virBufferAddLit(&query, "and "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_ACTIVE); + } + + if (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { + virBufferAddLit(&query, "and "); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_INACTIVE); + } + } + + if (hypervGetMsvmComputerSystem2012List(priv, &query, + &computerSystemList) < 0) + goto cleanup; + + if (domains) { + if (VIR_ALLOC_N(doms, 1) < 0) + goto cleanup; + ndoms = 1; + } + + for (computerSystem = computerSystemList; computerSystem != NULL; + computerSystem = computerSystem->next) { + + /* filter by domain state */ + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE)) { + int st = hypervMsvmComputerSystemEnabledStateToDomainState2012(computerSystem); + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && + st == VIR_DOMAIN_RUNNING) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && + st == VIR_DOMAIN_PAUSED) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && + st == VIR_DOMAIN_SHUTOFF) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && + (st != VIR_DOMAIN_RUNNING && + st != VIR_DOMAIN_PAUSED && + st != VIR_DOMAIN_SHUTOFF)))) + continue; + } + + /* managed save filter */ + if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_MANAGEDSAVE)) { + bool mansave = computerSystem->data->EnabledState == + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_SUSPENDED; + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave))) + continue; + } + + if (!doms) { + count++; + continue; + } + + if (VIR_RESIZE_N(doms, ndoms, count, 2) < 0) + goto cleanup; + + domain = NULL; + + if (hypervMsvmComputerSystemToDomain2012(conn, computerSystem, + &domain) < 0) + goto cleanup; + + doms[count++] = domain; + } + + if (doms) + *domains = doms; + doms = NULL; + ret = count; + + cleanup: + if (doms) { + for (i = 0; i < count; ++i) + virObjectUnref(doms[i]); + + VIR_FREE(doms); + } + + hypervFreeObject(priv, (hypervObject *)computerSystemList); + + return ret; +} + +#undef MATCH diff --git a/src/hyperv/hyperv_driver_2012.h b/src/hyperv/hyperv_driver_2012.h new file mode 100644 index 0000000..45eb15b --- /dev/null +++ b/src/hyperv/hyperv_driver_2012.h @@ -0,0 +1,55 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __HYPERV_DRIVER_2012_H__ +# define __HYPERV_DRIVER_2012_H__ + +#include <config.h> + +#include "internal.h" +#include "datatypes.h" +#include "virdomainobjlist.h" +#include "virauth.h" +#include "viralloc.h" +#include "virlog.h" +#include "viruuid.h" +#include "hyperv_driver.h" +#include "hyperv_network_driver.h" +#include "hyperv_private.h" +#include "hyperv_util.h" +#include "hyperv_wmi.h" +#include "openwsman.h" +#include "virstring.h" +#include "virtypedparam.h" + +#define VIR_FROM_THIS VIR_FROM_HYPERV + +int +hypervConnectListAllDomains2012(virConnectPtr conn, + virDomainPtr **domains, + unsigned int flags); + +int +hypervDomainGetState2012(virDomainPtr domain, int *state, int *reason, + unsigned int flags); + +#endif /* __HYPERV_DRIVER_2012_H__ */ diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h index 2dfce6e..db4e15a 100644 --- a/src/hyperv/hyperv_private.h +++ b/src/hyperv/hyperv_private.h @@ -37,6 +37,10 @@ struct _hypervPrivate { WsManClient *client; virCapsPtr caps; virDomainXMLOptionPtr xmlopt; + char *hypervVersion; }; +#define HYPERV_VERSION_2008 "6.1" +#define HYPERV_VERSION_2012 "6.3" + #endif /* __HYPERV_PRIVATE_H__ */ diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 67f45fb..be2f429 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -35,6 +35,9 @@ #define ROOT_VIRTUALIZATION \ "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*" +#define ROOT_VIRTUALIZATION_V2 \ + "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/v2/*" + typedef struct _hypervObject hypervObject; int hyperyVerifyResponse(WsManClient *client, WsXmlDocH response, diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index 28a5bdc..cf136ca 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -55,6 +55,37 @@ class Msvm_ComputerSystem uint16 AssignedNumaNodeList[] end +class Msvm_ComputerSystem_2012 + 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 @@ -196,7 +227,7 @@ class Win32_ComputerSystem string Caption uint16 ChassisBootupState string CreationClassName - int16 CurrentTimeZone +# uint16 CurrentTimeZone boolean DaylightInEffect string Description string DNSHostName @@ -466,7 +497,7 @@ class Win32_OperatingSystem string CSCreationClassName string CSDVersion string CSName - uint16 CurrentTimeZone +# uint16 CurrentTimeZone boolean DataExecutionPrevention_Available boolean DataExecutionPrevention_32BitApplications boolean DataExecutionPrevention_Drivers diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py index 8384634..ed40a79 100755 --- a/src/hyperv/hyperv_wmi_generator.py +++ b/src/hyperv/hyperv_wmi_generator.py @@ -61,6 +61,9 @@ class Class: def generate_classes_header(self): name_upper = self.name.upper() + class_name = self.name + if self.name.endswith("_2012"): + class_name = class_name[:-5] header = separator header += " * %s\n" % self.name @@ -70,15 +73,17 @@ class Class: if self.name.startswith("Win32_") or self.name.startswith("CIM_DataFile"): header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/%s\"\n" % self.name + elif self.name.endswith("_2012"): + header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/v2/%s\"\n" % class_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 += " \"%s\"\n" % class_name header += "\n" header += "#define %s_WQL_SELECT \\\n" % name_upper - header += " \"select * from %s \"\n" % self.name + header += " \"select * from %s \"\n" % class_name header += "\n" header += "struct _%s_Data {\n" % self.name @@ -134,6 +139,8 @@ class Class: if self.name.startswith("Win32_") or self.name.startswith("CIM_DataFile"): source += " return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n" + elif self.name.endswith("_2012"): + source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION_V2,\n" else: source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\n" -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list