libvirt/src/hyperv/hyperv_driver.c
Daniel P. Berrange 4445e16bfa Lookup auth credentials in config file before prompting
When SASL requests auth credentials, try to look them up in the
config file first. If any are found, remove them from the list
that the user is prompted for

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-03-23 13:24:07 +00:00

1341 lines
37 KiB
C

/*
* hyperv_driver.c: core driver functions for managing Microsoft Hyper-V hosts
*
* Copyright (C) 2011 Matthias Bolte <matthias.bolte@googlemail.com>
* Copyright (C) 2009 Michael Sievers <msievers83@googlemail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include "internal.h"
#include "datatypes.h"
#include "domain_conf.h"
#include "virauth.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)
{
virDrvOpenStatus result = VIR_DRV_OPEN_ERROR;
char *plus;
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 NULL */
if (conn->uri == NULL || conn->uri->scheme == NULL) {
return VIR_DRV_OPEN_DECLINED;
}
/* Decline if the scheme is not hyperv */
plus = strchr(conn->uri->scheme, '+');
if (plus == NULL) {
if (STRCASENEQ(conn->uri->scheme, "hyperv")) {
return VIR_DRV_OPEN_DECLINED;
}
} else {
if (plus - conn->uri->scheme != 6 ||
STRCASENEQLEN(conn->uri->scheme, "hyperv", 6)) {
return VIR_DRV_OPEN_DECLINED;
}
HYPERV_ERROR(VIR_ERR_INVALID_ARG,
_("Transport '%s' in URI scheme is not supported, try again "
"without the transport part"), plus + 1);
return VIR_DRV_OPEN_ERROR;
}
/* 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 = virAuthGetUsername(conn, auth, "hyperv", "administrator", conn->uri->server);
if (username == NULL) {
HYPERV_ERROR(VIR_ERR_AUTH_FAILED, "%s", _("Username request failed"));
goto cleanup;
}
}
password = virAuthGetPassword(conn, auth, "hyperv", 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
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
hypervIsAlive(virConnectPtr conn)
{
hypervPrivate *priv = conn->privateData;
/* XXX we should be able to do something better than this is simple, safe,
* and good enough for now. In worst case, the function will return true
* even though the connection is not alive.
*/
if (priv->client)
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 */
.isAlive = hypervIsAlive, /* 0.9.8 */
};
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;
}