#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)
{
+ virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
+ hypervPrivate *priv = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ virBuffer query = VIR_BUFFER_INITIALIZER;
+ Msvm_ComputerSystem *computerSystem = NULL;
+
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
/* Decline if the URI is NULL or the scheme is not hyperv */
return VIR_DRV_OPEN_ERROR;
}
- return VIR_DRV_OPEN_SUCCESS;
+ /* 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 been 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
+hypervDomainDestroyFlags(virDomainPtr domain, unsigned int flags)
+{
+ int result = -1;
+ hypervPrivate *priv = domain->conn->privateData;
+ Msvm_ComputerSystem *computerSystem = NULL;
+ bool in_transition = false;
+
+ virCheckFlags(0, -1);
+
+ 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 int
+hypervDomainDestroy(virDomainPtr domain)
+{
+ return hypervDomainDestroyFlags(domain, 0);
+}
+
+
+
+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;
+
+ /* Flags checked by virDomainDefFormat */
+
+ 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
-hypervClose(virConnectPtr conn ATTRIBUTE_UNUSED)
+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
+hypervDomainCreateWithFlags(virDomainPtr domain, 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;
+ }
+
+ 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
+hypervDomainCreate(virDomainPtr domain)
+{
+ return hypervDomainCreateWithFlags(domain, 0);
+}
+
+
+
+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)
+{
+ int result = -1;
+ hypervPrivate *priv = domain->conn->privateData;
+ Msvm_ComputerSystem *computerSystem = NULL;
+ bool in_transition = false;
+
+ virCheckFlags(0, -1);
+
+ 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)
+{
+ int result = -1;
+ hypervPrivate *priv = domain->conn->privateData;
+ Msvm_ComputerSystem *computerSystem = NULL;
+
+ virCheckFlags(0, -1);
+
+ 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)
+{
+ int result = -1;
+ hypervPrivate *priv = domain->conn->privateData;
+ Msvm_ComputerSystem *computerSystem = NULL;
+
+ virCheckFlags(0, -1);
+
+ 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.5 */
.close = hypervClose, /* 0.9.5 */
+ .type = hypervGetType, /* 0.9.5 */
+ .getHostname = hypervGetHostname, /* 0.9.5 */
+ .nodeGetInfo = hypervNodeGetInfo, /* 0.9.5 */
+ .listDomains = hypervListDomains, /* 0.9.5 */
+ .numOfDomains = hypervNumberOfDomains, /* 0.9.5 */
+ .domainLookupByID = hypervDomainLookupByID, /* 0.9.5 */
+ .domainLookupByUUID = hypervDomainLookupByUUID, /* 0.9.5 */
+ .domainLookupByName = hypervDomainLookupByName, /* 0.9.5 */
+ .domainSuspend = hypervDomainSuspend, /* 0.9.5 */
+ .domainResume = hypervDomainResume, /* 0.9.5 */
+ .domainDestroy = hypervDomainDestroy, /* 0.9.5 */
+ .domainDestroyFlags = hypervDomainDestroyFlags, /* 0.9.5 */
+ .domainGetOSType = hypervDomainGetOSType, /* 0.9.5 */
+ .domainGetInfo = hypervDomainGetInfo, /* 0.9.5 */
+ .domainGetState = hypervDomainGetState, /* 0.9.5 */
+ .domainGetXMLDesc = hypervDomainGetXMLDesc, /* 0.9.5 */
+ .listDefinedDomains = hypervListDefinedDomains, /* 0.9.5 */
+ .numOfDefinedDomains = hypervNumberOfDefinedDomains, /* 0.9.5 */
+ .domainCreate = hypervDomainCreate, /* 0.9.5 */
+ .domainCreateWithFlags = hypervDomainCreateWithFlags, /* 0.9.5 */
+ .isEncrypted = hypervIsEncrypted, /* 0.9.5 */
+ .isSecure = hypervIsSecure, /* 0.9.5 */
+ .domainIsActive = hypervDomainIsActive, /* 0.9.5 */
+ .domainIsPersistent = hypervDomainIsPersistent, /* 0.9.5 */
+ .domainIsUpdated = hypervDomainIsUpdated, /* 0.9.5 */
+ .domainManagedSave = hypervDomainManagedSave, /* 0.9.5 */
+ .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.5 */
+ .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.5 */
};
+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)
{
return -1;
}
+ /* Forward openwsman errors and warnings to libvirt's logging */
+ debug_add_handler(hypervDebugHandler, DEBUG_LEVEL_WARNING, NULL);
+
return 0;
}