Authors: Simon Rastello (Bull), Adrien Kantcheff (Bull), Yves Vinter (Bull) *** Summary of new features added in hyperv driver version 1.2.9 *** - Added a mutex to prevent concurrent requests from being run simultaneously [WSMAN libray not thread-safe] - Support of default authentication (credentials specified in ~/.config/libvirt/auth.conf) - Support of new types of WSMAN requests involving passing complex parameters (simple types, EPR, embedded objects) Required a new auto-generated header file to get the type of objects attributes (hyperv_wmi_classes_attr.generated.h) - New functions: - host management (in hyperv_driver module) - capabilities (limited) - domain management (in hyperv_driver module) - domain creation from an XML description - domain destruction - attachment of pre-existing disk images on IDE controller - attachment of Synthetic network devices - memory and vcpu management (get and set methods) - autostart, shutdown, ... - network management (in hyperv_network_driver module) - list available networks - informations for a specified network Required the declaration of new classes (in hyperv_wmi_generator.input) - Fixed several memory leak issues *** Important note *** The current implementation of the driver does not support the new WMI root/virtualization/v2 name space. It is not compatible with the last version of Hyper-V coming with Windows Server 2012 R2. *** Detail of the updates by module *** hyperv_driver.c +++++++++++++++ - Support of default authentication (credentials specified in ~/.config/libvirt/auth.conf) - Support of new libvirt functions .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 1.2.9 */ .domainGetMaxVcpus = hypervDomainGetMaxVcpus, /* 1.2.9 */ .domainShutdown = hypervDomainShutdown, /* 1.2.9 */ .domainShutdownFlags = hypervDomainShutdownFlags, /* 1.2.9 */ .domainGetSchedulerParametersFlags = hypervDomainGetSchedulerParametersFlags, /* 1.2.9 */ .domainGetSchedulerParameters = hypervDomainGetSchedulerParameters, /* 1.2.9 */ .domainGetSchedulerType = hypervDomainGetSchedulerType, /* 1.2.9 */ .connectGetCapabilities = hypervConnectGetCapabilities, /* 1.2.9 */ .connectGetVersion = hypervConnectGetVersion, /* 1.2.9 */ .domainSetAutostart = hypervDomainSetAutostart, /* 1.2.9 */ .domainSetMaxMemory = hypervDomainSetMaxMemory, /* 1.2.9 */ .domainDefineXML = hypervDomainDefineXML, /* 1.2.9 */ .domainSetMemory = hypervDomainSetMemory, /* 1.2.9 */ .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* 1.2.9 */ .domainSetVcpus = hypervDomainSetVcpus, /* 1.2.9 */ .domainSetVcpusFlags = hypervDomainSetVcpusFlags, /* 1.2.9 */ .domainAttachDevice = hypervDomainAttachDevice, /* 1.2.9 */ .domainAttachDeviceFlags = hypervDomainAttachDeviceFlags, /* 1.2.9 */ .connectGetMaxVcpus = hypervConnectGetMaxVcpus, /* 1.2.9 */ .domainCreateXML = hypervDomainCreateXML, /* 1.2.9 */ .nodeGetFreeMemory = hypervNodeGetFreeMemory, /* 1.2.9 */ .domainGetVcpus = hypervDomainGetVcpus, /* 1.2.9 */ .domainUndefine = hypervDomainUndefine, /* 1.2.9 */ .domainUndefineFlags = hypervDomainUndefineFlags, /* 1.2.9 */ .domainGetAutostart = hypervDomainGetAutostart, /* 1.2.9 */ - Updated libvirt functions .connectOpen = hypervConnectOpen, /* 0.9.5 */ Support of default authentication (credentials specified in ~/.config/libvirt/auth.conf) - New internal functions - hypervLookupHostSystemBiosUuid - hypervCapsInit - hypervGetResourceAllocationSettingDataPATH - hypervGetSwitchPortPATH - hypervDomainAttachDisk Used by hypervDomainAttachDevice Currently support only attachments on the IDE controller (targets hda, hdb, hdc, hdd) - hypervDomainAttachNetwork Used by hypervDomainAttachDevice Support attachment of synthetic network adapters (Legacy adapters are not supported) - integer2string - Notes related to devices attachments - hypervDomainAttachDevice does not support attachment of ISO images (DVD drives) - attachment of disk drives on the iSCSI controller is not yet supported - devices detachment (drives or network) is not yet implemented - networks and disk images must have been provisioned manually - attached devices are not displayed in the domain XML description (hypervDomainGetXMLDesc) hyperv_network_driver.c +++++++++++++++++++++++ - Support of new libvirt function .connectNumOfNetworks = hypervConnectNumOfNetworks, /* 1.2.9 */ .connectListNetworks = hypervConnectListNetworks, /* 1.2.9 */ .connectNumOfDefinedNetworks = hypervConnectNumOfDefinedNetworks, /* 1.2.9 */ .connectListDefinedNetworks = hypervConnectListDefinedNetworks, /* 1.2.9 */ .networkLookupByName = hypervNetworkLookupByName, /* 1.2.9 */ .networkGetXMLDesc = hypervNetworkGetXMLDesc, /* 1.2.9 */ hyperv_private.h ++++++++++++++++ - Added Caps, XMLOption and a Mutex in the private structure hyperv_wmi.c ++++++++++++ - Added an internal flag to dump WSMAN requests (DUMP_REQUEST) - Support of new types of WSMAN requests involving passing complex parameters (simple types, EPR, embedded objects) - New functions - hypervInvokeMethod - hypervMsvmVirtualSwitchToNetwork Used by hypervNetworkLookupByName (hyperv_network_driver.c) - New internal functions (used by hypervInvokeMethod) - hypervCreateXmlStruct - hypervGetPropType - hypervAddEmbeddedParam - hypervAddSimpleParam - hypervAddEprParam - hypervInvokeMethodXml - Updated functions - hypervEnumAndPull - hypervInvokeMsvmComputerSystemRequestStateChange Added a mutex to protect against concurrent requests Added a call to dump WSMAN request in dump mode hyperv_wmi.h ++++++++++++ - Added structures for passing new types of parameters (Simple, EPR, Embedded) - Defined a new method to allow WSMAN requests with these different types of parameters (hypervInvokeMethod) hyperv_wmi_generator.input ++++++++++++++++++++++++++ - Added new classes - CIM_DataFile - Win32_ComputerSystemProduct - Msvm_VirtualSystemManagementService - Msvm_VirtualSystemGlobalSettingData - Msvm_ResourceAllocationSettingData - Msvm_AllocationCapabilities - Msvm_VirtualSwitch - Msvm_SwitchPort - Msvm_SyntheticEthernetPortSettingData - Msvm_VirtualSwitchManagementService - Win32_OperatingSystem - Win32_PerfFormattedData_HvStats_HyperVHypervisorVirtualProcessor - Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor hyperv_wmi_generator.py +++++++++++++++++++++++ - Takes into account the CIM_DataFile class (from the root/cimv2 WMI name space) - Generated a new header file "hyperv_wmi_classes_attr.generated.h" for getting the type of objects attributes - Added new functions for generating this new file - generate_tab_classes Generates an entry for the declaration of cimClasses types - generate_tabs_types Generates declarations of cimTypes types - generate_type_tab Generates an entry for the declaration of cimTypes types - print_type_header Generates the declaration of structures cimClasses and cimTypes openwsman.h +++++++++++ - Added functions prototypes from wsman-xml.h to handle XmlDoc Reported-by: Yves Vinter <yves.vinter@xxxxxxxx> --- diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index aed9307..80fbb92 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -20,7 +20,15 @@ * */ +/* + * This implementation does not support the new WMI root/virtualization/v2 namespace. + * It is therefore not compatible with Hyper-V v3 and Windows Server 2012 R2. + * + */ + #include <config.h> +#include <string.h> +#include <stdlib.h> #include "internal.h" #include "datatypes.h" @@ -41,6 +49,7 @@ #include "hyperv_wmi.h" #include "openwsman.h" #include "virstring.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_HYPERV @@ -58,12 +67,100 @@ hypervFreePrivate(hypervPrivate **priv) wsmc_release((*priv)->client); } + if ((*priv)->caps != NULL) + virObjectUnref((*priv)->caps); + if ((*priv)->xmlopt != NULL) + virObjectUnref((*priv)->xmlopt); + + /* Destroy the mutex */ + pthread_mutex_destroy(&(*priv)->mutex); + hypervFreeParsedUri(&(*priv)->parsedUri); VIR_FREE(*priv); } +static int +hypervLookupHostSystemBiosUuid(hypervPrivate *priv, unsigned char *uuid) +{ + Win32_ComputerSystemProduct *computerSystem = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + int result = -1; + + virBufferAddLit(&query, WIN32_COMPUTERSYSTEMPRODUCT_WQL_SELECT); + + if (hypervGetWin32ComputerSystemProductList(priv, &query, &computerSystem) < 0) { + goto cleanup; + } + + if (computerSystem == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, + _("Unable to get Win32_ComputerSystemProduct")); + goto cleanup; + } + + if (virUUIDParse(computerSystem->data->UUID, uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + computerSystem->data->UUID); + goto cleanup; + } + + result = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); + return result; +} + + + +static virCapsPtr hypervCapsInit(hypervPrivate *priv) +{ + virCapsPtr caps = NULL; + virCapsGuestPtr guest = NULL; + + caps = virCapabilitiesNew(VIR_ARCH_X86_64, 1, 1); + + if (caps == NULL) { + virReportOOMError(); + return NULL; + } + //virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x0c, 0x29 }); + + if (hypervLookupHostSystemBiosUuid(priv,caps->host.host_uuid) < 0) { + goto failure; + } + + /* i686 */ + guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_I686, NULL, NULL, 0, NULL); + if (guest == NULL) { + goto failure; + } + if (virCapabilitiesAddGuestDomain(guest, "hyperv", NULL, NULL, 0, NULL) == NULL) { + goto failure; + } + + /* x86_64 */ + guest = virCapabilitiesAddGuest(caps, "hvm", VIR_ARCH_X86_64, NULL, NULL, 0, NULL); + if (guest == NULL) { + goto failure; + } + if (virCapabilitiesAddGuestDomain(guest, "hyperv", NULL, NULL, 0, NULL) == NULL) { + goto failure; + } + + return caps; + + failure: + virObjectUnref(caps); + return NULL; +} + + + static virDrvOpenStatus hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags) { @@ -108,12 +205,16 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags return VIR_DRV_OPEN_ERROR; } - /* Require auth */ - if (auth == NULL || auth->cb == NULL) { + /* Uses default authentification mechanism when not provided */ + if (auth == NULL) + auth = virConnectAuthPtrDefault; + else { + if (auth->cb == NULL) { virReportError(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) @@ -192,7 +293,20 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags goto cleanup; } + /* Setup capabilities */ + priv->caps = hypervCapsInit(priv); + if (priv->caps == NULL) { + goto cleanup; + } + + /* Init xmlopt to parse Domain XML */ + priv->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL); + conn->privateData = priv; + + /* Initialize the mutex */ + pthread_mutex_init(&priv->mutex, NULL); + priv = NULL; result = VIR_DRV_OPEN_SUCCESS; @@ -200,6 +314,7 @@ hypervConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, unsigned int flags hypervFreePrivate(&priv); VIR_FREE(username); VIR_FREE(password); + virBufferFreeAndReset(&query); hypervFreeObject(priv, (hypervObject *)computerSystem); return result; @@ -254,6 +369,7 @@ hypervConnectGetHostname(virConnectPtr conn) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); return hostname; } @@ -352,6 +468,7 @@ hypervNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); hypervFreeObject(priv, (hypervObject *)processorList); + virBufferFreeAndReset(&query); return result; } @@ -396,6 +513,7 @@ hypervConnectListDomains(virConnectPtr conn, int *ids, int maxids) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystemList); + virBufferFreeAndReset(&query); return success ? count : -1; } @@ -432,6 +550,7 @@ hypervConnectNumOfDomains(virConnectPtr conn) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystemList); + virBufferFreeAndReset(&query); return success ? count : -1; } @@ -464,6 +583,7 @@ hypervDomainLookupByID(virConnectPtr conn, int id) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); return domain; } @@ -500,6 +620,7 @@ hypervDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); return domain; } @@ -533,6 +654,7 @@ hypervDomainLookupByName(virConnectPtr conn, const char *name) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); return domain; } @@ -748,6 +870,7 @@ hypervDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); hypervFreeObject(priv, (hypervObject *)processorSettingData); hypervFreeObject(priv, (hypervObject *)memorySettingData); + virBufferFreeAndReset(&query); return result; } @@ -783,7 +906,10 @@ hypervDomainGetState(virDomainPtr domain, int *state, int *reason, } - +/* hypervDomainGetXMLDesc + * FIXME: + * - does not display attached devices (disk, nic) + */ static char * hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) { @@ -915,6 +1041,7 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); hypervFreeObject(priv, (hypervObject *)processorSettingData); hypervFreeObject(priv, (hypervObject *)memorySettingData); + virBufferFreeAndReset(&query); return xml; } @@ -971,6 +1098,7 @@ hypervConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxn } hypervFreeObject(priv, (hypervObject *)computerSystemList); + virBufferFreeAndReset(&query); return count; } @@ -1007,6 +1135,7 @@ hypervConnectNumOfDefinedDomains(virConnectPtr conn) cleanup: hypervFreeObject(priv, (hypervObject *)computerSystemList); + virBufferFreeAndReset(&query); return success ? count : -1; } @@ -1346,6 +1475,7 @@ hypervConnectListAllDomains(virConnectPtr conn, } hypervFreeObject(priv, (hypervObject *)computerSystemList); + virBufferFreeAndReset(&query); return ret; } @@ -1353,6 +1483,1778 @@ hypervConnectListAllDomains(virConnectPtr conn, +static int +hypervConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) +{ + int res = -1; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ProcessorSettingData *processorSettingData = NULL; + + /* Get Msvm_ProcessorSettingData maximum definition */ + virBufferAddLit(&query, "SELECT * FROM Msvm_ProcessorSettingData " + "WHERE InstanceID LIKE 'Microsoft:Definition%Maximum'"); + + if (hypervGetMsvmProcessorSettingDataList(priv, &query, &processorSettingData) < 0) { + goto cleanup; + } + + if (processorSettingData == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get maximum definition of Msvm_ProcessorSettingData")); + goto cleanup; + } + + res = processorSettingData->data->SocketCount * + processorSettingData->data->ProcessorsPerSocket; + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) processorSettingData); + return res; +} + + + +static int +hypervDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) +{ + int ret = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_ProcessorSettingData *processorSettingData = NULL; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + + virCheckFlags(VIR_DOMAIN_VCPU_LIVE |VIR_DOMAIN_VCPU_CONFIG |VIR_DOMAIN_VCPU_MAXIMUM, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + /* Get Msvm_ComputerSystem */ + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) { + goto cleanup; + } + + // If @flags includes VIR_DOMAIN_VCPU_LIVE, + // this will query a running domain (which will fail if domain is not active) + if (flags & VIR_DOMAIN_VCPU_LIVE) { + if (computerSystem->data->EnabledState != MSVM_COMPUTERSYSTEM_ENABLEDSTATE_ENABLED) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not active")); + goto cleanup; + } + } + + // If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then the maximum virtual CPU limit is queried + if (flags & VIR_DOMAIN_VCPU_MAXIMUM) { + ret = hypervConnectGetMaxVcpus(domain->conn, NULL); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), + "Msvm_VirtualSystemSettingData", computerSystem->data->ElementName); + goto cleanup; + } + + /* Get Msvm_ProcessorSettingData */ + virBufferFreeAndReset(&query); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), + "Msvm_ProcessorSettingData", computerSystem->data->ElementName); + goto cleanup; + } + + ret = processorSettingData->data->VirtualQuantity; + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *)computerSystem); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)processorSettingData); + return ret; +} + + + +static int +hypervDomainGetMaxVcpus(virDomainPtr dom) +{ + // If the guest is inactive, this is basically the same as virConnectGetMaxVcpus() + return (hypervDomainIsActive(dom)) ? + hypervDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |VIR_DOMAIN_VCPU_MAXIMUM)) + : hypervConnectGetMaxVcpus(dom->conn, NULL); +} + + + +static int +hypervDomainShutdownFlags(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) { + virReportError(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 hypervDomainShutdown(virDomainPtr dom) +{ + return hypervDomainShutdownFlags(dom, 0); +} + + + +static int +hypervDomainGetSchedulerParametersFlags(virDomainPtr dom, virTypedParameterPtr params, + int *nparams, unsigned int flags) +{ + hypervPrivate *priv = dom->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_ProcessorSettingData *processorSettingData = NULL; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + virBuffer query = VIR_BUFFER_INITIALIZER; + int ret = -1; + int saved_nparams = 0; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |VIR_DOMAIN_AFFECT_CONFIG |VIR_TYPED_PARAM_STRING_OKAY, -1); + + /* We don't return strings, and thus trivially support this flag. */ + flags &= ~VIR_TYPED_PARAM_STRING_OKAY; + + virUUIDFormat(dom->uuid, uuid_string); + + /* Get Msvm_ComputerSystem */ + if (hypervMsvmComputerSystemFromDomain(dom, &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) { + virReportError(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) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not lookup %s for domain %s"), + "Msvm_ProcessorSettingData",computerSystem->data->ElementName); + goto cleanup; + } + + if (virTypedParameterAssign(¶ms[0], VIR_DOMAIN_SCHEDULER_LIMIT, + VIR_TYPED_PARAM_LLONG, processorSettingData->data->Limit) < 0) + goto cleanup; + saved_nparams++; + + if (*nparams > saved_nparams) { + if (virTypedParameterAssign(¶ms[1],VIR_DOMAIN_SCHEDULER_RESERVATION, + VIR_TYPED_PARAM_LLONG, processorSettingData->data->Reservation) < 0) + goto cleanup; + saved_nparams++; + } + + if (*nparams > saved_nparams) { + if (virTypedParameterAssign(¶ms[2],VIR_DOMAIN_SCHEDULER_WEIGHT, + VIR_TYPED_PARAM_UINT, processorSettingData->data->Weight) < 0) + goto cleanup; + saved_nparams++; + } + + *nparams = saved_nparams; + + ret = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)processorSettingData); + virBufferFreeAndReset(&query); + return ret; +} + + + +static int +hypervDomainGetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params, int *nparams) +{ + return hypervDomainGetSchedulerParametersFlags(dom, params, nparams, VIR_DOMAIN_AFFECT_CURRENT); +} + + + +static char* +hypervDomainGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED, int *nparams) +{ + char *type = strdup("allocation"); + + if (type == NULL) { + virReportOOMError(); + return NULL; + } + + if (nparams != NULL) { + *nparams = 3; /* reservation, limit, weight */ + } + + return type; +} + + + +static char* +hypervConnectGetCapabilities(virConnectPtr conn) +{ + hypervPrivate *priv = conn->privateData; + char *xml = virCapabilitiesFormatXML(priv->caps); + + if (xml == NULL) { + virReportOOMError(); + return NULL; + } + + return xml; +} + + +static int +hypervConnectGetVersion(virConnectPtr conn, unsigned long *version) +{ + int ret = -1; + hypervPrivate *priv = conn->privateData; + CIM_DataFile *datafile = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + char * p; + + virBufferAddLit(&query, " Select * from CIM_DataFile where Name='c:\\\\windows\\\\system32\\\\vmms.exe' "); + + if (hypervGetCIMDataFileList(priv, &query, &datafile) < 0) {goto cleanup;} + + // check the result of convertion + if (datafile == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for domain %s"), + "Msvm_VirtualSystemSettingData", + datafile->data->Version); + goto cleanup; + } + + /* Delete release number and last digit of build number 1.1.111x.xxxx */ + p = strrchr(datafile->data->Version,'.'); + if (p == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse version number from '%s'"), + datafile->data->Version); + goto cleanup; + } + p--; + *p = '\0'; + + /*Parse Version String to Long*/ + if (virParseVersionString(datafile->data->Version, + version, true) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse version number from '%s'"), + datafile->data->Version); + goto cleanup; + } + + ret = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)datafile); + virBufferFreeAndReset(&query); + return ret; +} + + + +static unsigned long long +hypervNodeGetFreeMemory(virConnectPtr conn) +{ + unsigned long long res = 0; + hypervPrivate *priv = conn->privateData; + 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 free memory in bytes + res = operatingSystem->data->FreePhysicalMemory * 1024; + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) operatingSystem); + return res; +} + + + +static int +hypervDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo, + unsigned char *cpumaps, int maplen) +{ + int count = 0, i; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor + *hypervVirtualProcessor = NULL; + + //FIXME: no information stored in cpumaps + if (cpumaps == NULL) { + cpumaps = (unsigned char *) calloc(maxinfo, maplen); + } + + /* Loop for each vCPU */ + for (i = 0; i < maxinfo; i++) { + + /* Get vCPU stats */ + hypervFreeObject(priv, (hypervObject *)hypervVirtualProcessor); + hypervVirtualProcessor = NULL; + virBufferFreeAndReset(&query); + virBufferAddLit(&query, + WIN32_PERFRAWDATA_HVSTATS_HYPERVHYPERVISORVIRTUALPROCESSOR_WQL_SELECT); + // Attribute Name format : <domain_name>:Hv VP <vCPU_number> + virBufferAsprintf(&query, "where Name = \"%s:Hv VP %d\"", domain->name, i); + + if (hypervGetWin32PerfRawDataHvStatsHyperVHypervisorVirtualProcessorList( + priv, &query, &hypervVirtualProcessor) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get stats on vCPU #%d"), i); + continue; + } + + /* Fill structure info */ + info[i].number = i; + if (hypervVirtualProcessor == NULL) { + info[i].state = VIR_VCPU_OFFLINE; + info[i].cpuTime = 0LLU; + info[i].cpu = -1; + } else { + info[i].state = VIR_VCPU_RUNNING; + info[i].cpuTime = hypervVirtualProcessor->data->PercentTotalRunTime; + info[i].cpu = i; + } + + count++; + } + + hypervFreeObject(priv, (hypervObject *)hypervVirtualProcessor); + virBufferFreeAndReset(&query); + return count; +} + + + +static int +hypervDomainSetAutostart(virDomainPtr domain, int autostart) +{ + int res = -1; + invokeXmlParam *params = NULL; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + virBuffer queryVssd = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + properties_t *tab_props = NULL; + eprParam eprparam; + embeddedParam embeddedparam; + int nb_params; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + + virUUIDFormat(domain->uuid, uuid_string); + + /* PREPARE EPR PARAM */ + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"",uuid_string); + eprparam.query = &query; + eprparam.wmiProviderURI = ROOT_VIRTUALIZATION; + + /* PREPARE EMBEDDED PARAM */ + virBufferAsprintf(&queryVssd, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where AssocClass = Msvm_SettingsDefineState " + "ResultClass = Msvm_VirtualSystemSettingData", + uuid_string); + + if (hypervGetMsvmVirtualSystemSettingDataList(priv, &queryVssd, + &virtualSystemSettingData) < 0) { + goto cleanup; + } + + embeddedparam.nbProps = 2; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "AutomaticStartupAction"; + (*tab_props).val = autostart ? "2" : "0"; + (*(tab_props+1)).name = "InstanceID"; + (*(tab_props+1)).val = virtualSystemSettingData->data->InstanceID; + + embeddedparam.instanceName = "Msvm_VirtualSystemGlobalSettingData"; + embeddedparam.prop_t = tab_props; + + /* CREATE invokeXmlParam tab */ + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "ComputerSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam; + (*(params+1)).name = "SystemSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam; + + res = hypervInvokeMethod(priv, params, nb_params, "ModifyVirtualSystem", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector); + + cleanup: + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + VIR_FREE(tab_props); + VIR_FREE(params); + virBufferFreeAndReset(&query); + virBufferFreeAndReset(&queryVssd); + return res; +} + + + +static int +hypervDomainGetAutostart(virDomainPtr domain, int *autostart) +{ + int res = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemGlobalSettingData *vsgsd = NULL; + + virUUIDFormat(domain->uuid, uuid_string); + virBufferAddLit(&query, MSVM_VIRTUALSYSTEMGLOBALSETTINGDATA_WQL_SELECT); + virBufferAsprintf(&query, "where SystemName = \"%s\"", uuid_string); + + if (hypervGetMsvmVirtualSystemGlobalSettingDataList(priv, + &query, &vsgsd) < 0) { + goto cleanup; + } + + *autostart = vsgsd->data->AutomaticStartupAction; + res = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)vsgsd); + virBufferFreeAndReset(&query); + return res; +} + + +/* Convert an integer value into a string */ +static char *integer2string(unsigned long value) +{ + int sz; + char *ret; + + sz = snprintf (NULL, 0, "%lu", value); + ret = (char *) malloc ((sz+1)*sizeof(char)); + if (ret != NULL) + sprintf(ret, "%lu", value); + + return ret; +} + + +static int +hypervDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) +{ + int res = -1; + invokeXmlParam *params = NULL; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + properties_t *tab_props = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + virBuffer query2 = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + Msvm_MemorySettingData *memorySettingData = NULL; + eprParam eprparam; + embeddedParam embeddedparam; + int nb_params; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + unsigned long memory_mb = memory/1024; + char *memory_str = NULL; + + // Memory value must be a multiple of 2 MB; round up it accordingly if necessary + if (memory_mb % 2) memory_mb++; + + // Convert the memory value as a string value + memory_str = integer2string(memory_mb); + + virUUIDFormat(domain->uuid, uuid_string); + + VIR_DEBUG("memory=%sMb, uuid=%s", memory_str, uuid_string); + + // PREPARE EPR PARAM + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"",uuid_string); + eprparam.query = &query; + eprparam.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM 1 + /* Get Msvm_VirtualSystemSettingData */ + virBufferAsprintf(&query2, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where AssocClass = Msvm_SettingsDefineState " + "ResultClass = Msvm_VirtualSystemSettingData", + uuid_string); + + if (hypervGetMsvmVirtualSystemSettingDataList(priv, &query2, + &virtualSystemSettingData) < 0) { + goto cleanup; + } + + /* Get Msvm_MemorySettingData */ + virBufferFreeAndReset(&query2); + virBufferAsprintf(&query2, + "associators of " + "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " + "where AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_MemorySettingData", + virtualSystemSettingData->data->InstanceID); + + if (hypervGetMsvmMemorySettingDataList(priv, &query2, + &memorySettingData) < 0) { + goto cleanup; + } + + embeddedparam.nbProps = 2; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "Limit"; + (*tab_props).val = memory_str; + (*(tab_props+1)).name = "InstanceID"; + (*(tab_props+1)).val = memorySettingData->data->InstanceID; + embeddedparam.instanceName = "Msvm_MemorySettingData"; + embeddedparam.prop_t = tab_props; + embeddedparam.nbProps = 2; + + // CREATE invokeXmlParam + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + + (*params).name = "ComputerSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam; + + res = hypervInvokeMethod(priv, params, nb_params, "ModifyVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector); + + cleanup: + VIR_FREE(tab_props); + VIR_FREE(params); + VIR_FREE(memory_str); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)memorySettingData); + virBufferFreeAndReset(&query); + virBufferFreeAndReset(&query2); + return res; +} + + + +/* + * Create the attribute __PATH for the RASD object. The attribute is build like this: + * \\<host_name>\root\virtualization:Msvm_ResourceAllocationSettingData.InstanceID="<rasdInstanceID>" + * where backslashes in rasdInstanceID are doubled + */ +static int +hypervGetResourceAllocationSettingDataPATH(virDomainPtr domain, char *rasdInstanceID, char **__path) +{ + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ComputerSystem *computerSystem = NULL; + char *strTemp = NULL; + int ret = -1, i = 0, j = 0, n = 0; + + virUUIDFormat(domain->uuid, uuid_string); + + /* Get host name */ + virBufferAsprintf(&query, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where AssocClass = Msvm_HostedDependency " + "ResultClass = Msvm_ComputerSystem", + uuid_string); + if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) { + goto cleanup; + } + if (computerSystem == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, _("No domain with UUID %s"), uuid_string); + goto cleanup; + } + + /* Count the number of backslash character */ + strTemp = strchr(rasdInstanceID, '\\'); + while (strTemp != NULL) { + n++; + strTemp = strchr(++strTemp, '\\'); + } + /* Double the blackslashes */ + strTemp = (char *) malloc(strlen(rasdInstanceID) + (n+1)*sizeof(char)); + while (rasdInstanceID[i] != '\0') { + strTemp[j] = rasdInstanceID[i]; + if (rasdInstanceID[i] == '\\') { + j++; + strTemp[j] = '\\'; + } + i++; + j++; + } + strTemp[j] = '\0'; + + /* Create the attribute __PATH */ + //FIXME: ret is allocated with 255 characters (static value) + *__path = (char *) malloc(sizeof(*__path) * 255); + sprintf(*__path, "\\\\"); + strcat(*__path, computerSystem->data->ElementName); + strcat(*__path, "\\root\\virtualization:Msvm_ResourceAllocationSettingData.InstanceID=\""); + strcat(*__path, strTemp); + strcat(*__path, "\""); + + ret = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); + free(strTemp); + return ret; +} + + + +/* + * Create the attribute __PATH for the SwitchPort object. The attribute is build like this: + * \\<host_name>\root\virtualization:Msvm_SwitchPort.CreationClassName="Msvm_SwitchPort", + * Name="<switchPortName>",SystemCreationClassName="Msvm_VirtualSwitch", + * SystemName="<virtualSwitchSystemName>" + */ +static int +hypervGetSwitchPortPATH(virDomainPtr domain, char *switchPortName, + char *virtualSwitchSystemName, char **__path) +{ + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ComputerSystem *computerSystem = NULL; + char *strTemp = NULL; + int ret = -1; + + virUUIDFormat(domain->uuid, uuid_string); + + /* Get host name */ + virBufferAsprintf(&query, + "associators of " + "{Msvm_ComputerSystem.CreationClassName=\"Msvm_ComputerSystem\"," + "Name=\"%s\"} " + "where AssocClass = Msvm_HostedDependency " + "ResultClass = Msvm_ComputerSystem", + uuid_string); + if (hypervGetMsvmComputerSystemList(priv, &query, &computerSystem) < 0) { + goto cleanup; + } + if (computerSystem == NULL) { + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with UUID %s"), uuid_string); + goto cleanup; + } + + + /* Create the attribute __PATH */ + //FIXME: ret is allocated with 511 characters (static value) + *__path = (char *) malloc(sizeof(*__path) * 511); + sprintf(*__path, + "\\\\%s\\root\\virtualization:Msvm_SwitchPort.CreationClassName=\"Msvm_SwitchPort\"," + "Name=\"%s\",SystemCreationClassName=\"Msvm_VirtualSwitch\",SystemName=\"%s\"", + computerSystem->data->ElementName, switchPortName, virtualSwitchSystemName); + + ret = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); + free(strTemp); + return ret; +} + + + +/* + * Memory size in KiB + */ +static int +hypervDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory, + unsigned int flags ATTRIBUTE_UNUSED) +{ + int res = -1, nb_params; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + invokeXmlParam *params = NULL; + properties_t *tab_props = NULL; + eprParam eprparam; + embeddedParam embeddedparam; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + Msvm_MemorySettingData *memorySettingData = NULL; + unsigned long memory_mb = memory/1024; + char *memory_str = NULL; + + // Memory value must be a multiple of 2 MB; round up it accordingly if necessary + if (memory_mb % 2) memory_mb++; + + // Convert the memory value as a string value + memory_str = integer2string(memory_mb); + + virUUIDFormat(domain->uuid, uuid_string); + + VIR_DEBUG("memory=%sMb, uuid=%s", memory_str, uuid_string); + + /* 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; + } + + /* Get Msvm_MemorySettingData */ + virBufferFreeAndReset(&query); + 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; + } + + // PREPARE EPR PARAM + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"",uuid_string); + eprparam.query = &query; + eprparam.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM + embeddedparam.nbProps = 2; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "VirtualQuantity"; + (*tab_props).val = memory_str; + (*(tab_props+1)).name = "InstanceID"; + (*(tab_props+1)).val = memorySettingData->data->InstanceID; + embeddedparam.instanceName = "Msvm_MemorySettingData"; + embeddedparam.prop_t = tab_props; + + // CREATE invokeXmlParam + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "ComputerSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam; + + if (hypervInvokeMethod(priv, params, nb_params, "ModifyVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not set domain memory")); + goto cleanup; + } + + res = 0; + + cleanup: + VIR_FREE(tab_props); + VIR_FREE(params); + VIR_FREE(memory_str); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)memorySettingData); + virBufferFreeAndReset(&query); + return res; +} + + +static int +hypervDomainSetMemory(virDomainPtr domain, unsigned long memory) +{ + return hypervDomainSetMemoryFlags(domain, memory, 0); +} + + +static int +hypervDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus, + unsigned int flags ATTRIBUTE_UNUSED) +{ + int res = -1; + invokeXmlParam *params = NULL; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + properties_t *tab_props = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + Msvm_ProcessorSettingData *processorSettingData = NULL; + eprParam eprparam; + embeddedParam embeddedparam; + int nb_params; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + char *nvcpus_str = NULL; + + // Convert nvcpus as a string value + nvcpus_str = integer2string(nvcpus); + virUUIDFormat(domain->uuid, uuid_string); + + VIR_DEBUG("nvcpus=%s, uuid=%s", nvcpus_str, uuid_string); + + /* 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; + } + + /* Get Msvm_ProcessorSettingData */ + virBufferFreeAndReset(&query); + 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) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup Msvm_ProcessorSettingData for domain %s"), + virtualSystemSettingData->data->ElementName); + goto cleanup; + } + + // PREPARE EPR PARAM + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"",uuid_string); + eprparam.query = &query; + eprparam.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM + embeddedparam.nbProps = 2; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "VirtualQuantity"; + (*tab_props).val = nvcpus_str; + (*(tab_props+1)).name = "InstanceID"; + (*(tab_props+1)).val = processorSettingData->data->InstanceID; + embeddedparam.instanceName = "Msvm_ProcessorSettingData"; + embeddedparam.prop_t = tab_props; + + // CREATE invokeXmlParam + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "ComputerSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam; + + if (hypervInvokeMethod(priv, params, nb_params, "ModifyVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not set domain vcpus")); + goto cleanup; + } + + res = 0; + + cleanup: + VIR_FREE(tab_props); + VIR_FREE(params); + VIR_FREE(nvcpus_str); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)processorSettingData); + virBufferFreeAndReset(&query); + return res; +} + + + +static int +hypervDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) +{ + return hypervDomainSetVcpusFlags(domain, nvcpus, 0); +} + + +/* hypervDomainAttachDisk + * FIXME: + * - added ressources must me removed in case of error + * - allow attaching disks on iSCSI (implemented only on IDE) + * - allow attaching ISO images (on DVD devices) + * - implement corresponding detach function + */ +static int +hypervDomainAttachDisk(virDomainPtr domain, virDomainDiskDefPtr disk) +{ + int ret = -1, nb_params; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + char *ideRasdPath = NULL, *newDiskDrivePath = NULL; + char *ideControler = NULL, *ideControlerAddr = NULL; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; + Msvm_ResourceAllocationSettingData *resourceAllocationSettingData = NULL; + Msvm_ResourceAllocationSettingData *resourceAllocationSettingData2 = NULL; + Msvm_ResourceAllocationSettingData *resourceAllocationSettingData3 = NULL; + Msvm_ResourceAllocationSettingData *resourceAllocationSettingData4 = NULL; + Msvm_ResourceAllocationSettingData *ideRasd = NULL; /* Part of resourceAllocationSettingData -> do not disallocate */ + Msvm_ResourceAllocationSettingData *diskRasd = NULL; /* Part of resourceAllocationSettingData2 -> do not disallocate */ + Msvm_ResourceAllocationSettingData *newDiskDrive = NULL; /* Part of resourceAllocationSettingData3 -> do not disallocate */ + Msvm_AllocationCapabilities *allocationCapabilities = NULL; + Msvm_AllocationCapabilities *allocationCapabilities2 = NULL; + invokeXmlParam *params = NULL; + properties_t *tab_props = NULL; + eprParam eprparam1, eprparam2; + embeddedParam embeddedparam1, embeddedparam2; + + /* Initialization */ + virUUIDFormat(domain->uuid, uuid_string); + + // Set IDE Controler 0 or 1 and address 0 or 1 + ideControler = (char *) malloc(2*sizeof(char)); + ideControlerAddr = (char *) malloc(2*sizeof(char)); + if (strcmp(disk->dst, "hda") == 0) { + sprintf(ideControler, "%d", 0); + sprintf(ideControlerAddr, "%d", 0); + } else if (strcmp(disk->dst, "hdb") == 0) { + sprintf(ideControler, "%d", 0); + sprintf(ideControlerAddr, "%d", 1); + } else if (strcmp(disk->dst, "hdc") == 0) { + sprintf(ideControler, "%d", 1); + sprintf(ideControlerAddr, "%d", 0); + } else if (strcmp(disk->dst, "hdd") == 0) { + sprintf(ideControler, "%d", 1); + sprintf(ideControlerAddr, "%d", 1); + } else { + // IDE Controler 0 and address 0 by default + sprintf(ideControler, "%d", 0); + sprintf(ideControlerAddr, "%d", 0); + } + + VIR_DEBUG("src=%s, dst=IDE Controller %s:%s, uuid=%s", + disk->src->path, ideControler, ideControlerAddr, uuid_string); + + /* Get the current VM settings object */ + 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; + } + + /* Get the settings for IDE Controller on the VM */ + virBufferFreeAndReset(&query); + virBufferAsprintf(&query, + "associators of " + "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " + "where AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_ResourceAllocationSettingData", + virtualSystemSettingData->data->InstanceID); + if (hypervGetMsvmResourceAllocationSettingDataList(priv, &query, + &resourceAllocationSettingData) < 0) { + goto cleanup; + } + ideRasd = resourceAllocationSettingData; + while (ideRasd != NULL) { + if (ideRasd->data->ResourceType == 5 && + strcmp(ideRasd->data->Address, ideControler) == 0) { + // IDE Controller 0 or 1 + break; + } + ideRasd = ideRasd->next; + } + if (ideRasd == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not find IDE Controller %s"), ideControler); + goto cleanup; + } + + /* Get the settings for 'Microsoft Synthetic Disk Drive' */ + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_ALLOCATIONCAPABILITIES_WQL_SELECT); + virBufferAddLit(&query, "WHERE ResourceSubType = 'Microsoft Synthetic Disk Drive'"); + if (hypervGetMsvmAllocationCapabilitiesList(priv, &query, + &allocationCapabilities) < 0) { + goto cleanup; + } + + /* Get default values for 'Microsoft Synthetic Disk Drive' */ + virBufferFreeAndReset(&query); + virBufferAsprintf(&query, + "associators of " + "{Msvm_AllocationCapabilities.InstanceID=\"%s\"} " + "where AssocClass = Msvm_SettingsDefineCapabilities " + "ResultClass = Msvm_ResourceAllocationSettingData", + allocationCapabilities->data->InstanceID); + if (hypervGetMsvmResourceAllocationSettingDataList(priv, &query, + &resourceAllocationSettingData2) < 0) { + goto cleanup; + } + diskRasd = resourceAllocationSettingData2; + while (diskRasd != NULL) { + if (strstr(diskRasd->data->InstanceID, "Default") != NULL) { + // Default values + break; + } + diskRasd = diskRasd->next; + } + if (diskRasd == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get default values for 'Microsoft Synthetic Disk Drive'")); + goto cleanup; + } + + /* Create the attribute _PATH for the RASD object */ + if (hypervGetResourceAllocationSettingDataPATH(domain, + ideRasd->data->InstanceID, &ideRasdPath) < 0) { + goto cleanup; + } + + /* Add default disk drive */ + // PREPARE EPR PARAM + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string); + eprparam1.query = &query; + eprparam1.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM 1 + embeddedparam1.nbProps = 4; + tab_props = (properties_t *) malloc(embeddedparam1.nbProps * sizeof(properties_t)); + (*tab_props).name = "Parent"; + (*tab_props).val = ideRasdPath; + (*(tab_props+1)).name = "Address"; + (*(tab_props+1)).val = ideControlerAddr; + (*(tab_props+2)).name = "ResourceType"; + (*(tab_props+2)).val = "22"; + (*(tab_props+3)).name = "ResourceSubType"; + (*(tab_props+3)).val = diskRasd->data->ResourceSubType; + embeddedparam1.instanceName = MSVM_RESOURCEALLOCATIONSETTINGDATA_CLASSNAME; + embeddedparam1.prop_t = tab_props; + + // CREATE invokeXmlParam tab + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "TargetSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam1; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam1; + + if (hypervInvokeMethod(priv, params, nb_params, "AddVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add default disk drive")); + goto cleanup; + } + + /* Get the instance of the new default drive disk */ + virBufferFreeAndReset(&query); + virBufferAsprintf(&query, + "associators of " + "{Msvm_VirtualSystemSettingData.InstanceID=\"%s\"} " + "where AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_ResourceAllocationSettingData", + virtualSystemSettingData->data->InstanceID); + if (hypervGetMsvmResourceAllocationSettingDataList(priv, &query, + &resourceAllocationSettingData3) < 0) { + goto cleanup; + } + newDiskDrive = resourceAllocationSettingData3; + while (newDiskDrive != NULL) { + if (newDiskDrive->data->ResourceType == 22 && + strcmp(newDiskDrive->data->ResourceSubType, "Microsoft Synthetic Disk Drive") == 0 && + strcmp(newDiskDrive->data->Parent, ideRasdPath) == 0 && + strcmp(newDiskDrive->data->Address, ideControlerAddr) == 0) { + break; + } + newDiskDrive = newDiskDrive->next; + } + if (newDiskDrive == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find 'Microsoft Synthetic Disk Drive'")); + goto cleanup; + } + + /* Get the settings for 'Microsoft Virtual Hard Disk' */ + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_ALLOCATIONCAPABILITIES_WQL_SELECT); + virBufferAddLit(&query, "WHERE ResourceSubType = 'Microsoft Virtual Hard Disk'"); + if (hypervGetMsvmAllocationCapabilitiesList(priv, &query, + &allocationCapabilities2) < 0) { + goto cleanup; + } + + /* Get default values for 'Microsoft Virtual Hard Drive' */ + virBufferFreeAndReset(&query); + virBufferAsprintf(&query, + "associators of " + "{Msvm_AllocationCapabilities.InstanceID=\"%s\"} " + "where AssocClass = Msvm_SettingsDefineCapabilities " + "ResultClass = Msvm_ResourceAllocationSettingData", + allocationCapabilities2->data->InstanceID); + if (hypervGetMsvmResourceAllocationSettingDataList(priv, &query, + &resourceAllocationSettingData4) < 0) { + goto cleanup; + } + diskRasd = resourceAllocationSettingData4; + while (diskRasd != NULL) { + if (strstr(diskRasd->data->InstanceID, "Default") != NULL) { + // Default values + break; + } + diskRasd = diskRasd->next; + } + if (diskRasd == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get default values for 'Microsoft Virtual Hard Drive'")); + goto cleanup; + } + + /* Create the attribute _PATH for the RASD object */ + if (hypervGetResourceAllocationSettingDataPATH(domain, + newDiskDrive->data->InstanceID, &newDiskDrivePath) < 0) { + goto cleanup; + } + + /* Add the new VHD */ + // PREPARE EPR PARAM 2 + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string); + eprparam2.query = &query; + eprparam2.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM 2 + VIR_FREE(tab_props); + embeddedparam2.nbProps = 4; + tab_props = (properties_t *) malloc(embeddedparam2.nbProps * sizeof(properties_t)); + (*tab_props).name = "Parent"; + (*tab_props).val = newDiskDrivePath; + (*(tab_props+1)).name = "Connection"; + (*(tab_props+1)).val = disk->src->path; + (*(tab_props+2)).name = "ResourceType"; + (*(tab_props+2)).val = "21"; + (*(tab_props+3)).name = "ResourceSubType"; + (*(tab_props+3)).val = diskRasd->data->ResourceSubType; + embeddedparam2.instanceName = MSVM_RESOURCEALLOCATIONSETTINGDATA_CLASSNAME; + embeddedparam2.prop_t = tab_props; + + // CREATE invokeXmlParam tab + VIR_FREE(params); + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "TargetSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam2; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam2; + + if (hypervInvokeMethod(priv, params, nb_params, "AddVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not attach hard disk drive")); + goto cleanup; + } + + ret = 0; + + cleanup: + if (ideRasdPath != NULL) VIR_FREE(ideRasdPath); + if (newDiskDrivePath != NULL) VIR_FREE(newDiskDrivePath); + if (ideControler != NULL) VIR_FREE(ideControler); + if (ideControlerAddr != NULL) VIR_FREE(ideControlerAddr); + if (tab_props != NULL) VIR_FREE(tab_props); + if (params != NULL) VIR_FREE(params); + hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); + hypervFreeObject(priv, (hypervObject *)resourceAllocationSettingData); + hypervFreeObject(priv, (hypervObject *)resourceAllocationSettingData2); + hypervFreeObject(priv, (hypervObject *)resourceAllocationSettingData3); + hypervFreeObject(priv, (hypervObject *)resourceAllocationSettingData4); + hypervFreeObject(priv, (hypervObject *)allocationCapabilities); + hypervFreeObject(priv, (hypervObject *)allocationCapabilities2); + virBufferFreeAndReset(&query); + + return ret; +} + + + +/* hypervDomainAttachNetwork + * FIXME: + * - implement corresponding detach function + */ +static int +hypervDomainAttachNetwork(virDomainPtr domain, virDomainNetDefPtr net) +{ + int ret = -1, nb_params; + const char *selector1 = "CreationClassName=Msvm_VirtualSwitchManagementService"; + const char *selector2 = "CreationClassName=Msvm_VirtualSystemManagementService"; + char uuid_string[VIR_UUID_STRING_BUFLEN], guid_string[VIR_UUID_STRING_BUFLEN]; + unsigned char guid[VIR_UUID_BUFLEN]; + char *virtualSystemIdentifiers = NULL, *switchPortPATH = NULL; + hypervPrivate *priv = domain->conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + eprParam eprparam1, eprparam2; + simpleParam simpleparam1, simpleparam2, simpleparam3; + embeddedParam embeddedparam; + properties_t *tab_props = NULL; + invokeXmlParam *params = NULL; + Msvm_SwitchPort *switchPort = NULL; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + /* Initialization */ + virUUIDFormat(domain->uuid, uuid_string); + + VIR_DEBUG("network=%s, uuid=%s", net->data.network.name, uuid_string); + + /* Create virtual switch port */ + // PREPARE EPR PARAM 1 + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where ElementName = \"%s\"", net->data.network.name); + eprparam1.query = &query; + eprparam1.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE SIMPLE PARAMS + virUUIDGenerate(guid); + virUUIDFormat(guid, guid_string); + simpleparam1.value = guid_string; + simpleparam2.value = "Dynamic Ethernet Switch Port"; + simpleparam3.value = ""; + + // CREATE invokeXmlParam tab + nb_params = 4; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "VirtualSwitch"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam1; + (*(params+1)).name = "Name"; + (*(params+1)).type = SIMPLE_PARAM; + (*(params+1)).param = &simpleparam1; + (*(params+2)).name = "FriendlyName"; + (*(params+2)).type = SIMPLE_PARAM; + (*(params+2)).param = &simpleparam2; + (*(params+3)).name = "ScopeOfResidence"; + (*(params+3)).type = SIMPLE_PARAM; + (*(params+3)).param = &simpleparam3; + + if (hypervInvokeMethod(priv, params, nb_params, "CreateSwitchPort", + MSVM_VIRTUALSWITCHMANAGEMENTSERVICE_RESOURCE_URI, selector1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not create port for virtual switch '%s'"), net->data.network.name); + goto cleanup; + } + + /* Get a reference of the switch port created previously */ + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_SWITCHPORT_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", guid_string); + if (hypervGetMsvmSwitchPortList(priv, &query, &switchPort) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Method hypervGetMsvmSwitchPortList failed with query=%s"), query.e); + goto cleanup; + } + if (switchPort == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get switch port with Name=%s"), guid_string); + goto cleanup; + } + + /* Get a reference of the given virtual switch */ + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where ElementName = \"%s\"", net->data.network.name); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitch) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Method hypervGetMsvmVirtualSwitchList failed with query=%s"), query.e); + goto cleanup; + } + if (virtualSwitch == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get virtual switch '%s'"), net->data.network.name); + goto cleanup; + } + + /* Add the synthetic ethernet port to the VM */ + // PREPARE EPR PARAM 2 + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string); + eprparam2.query = &query; + eprparam2.wmiProviderURI = ROOT_VIRTUALIZATION; + + // PREPARE EMBEDDED PARAM + virUUIDGenerate(guid); + virUUIDFormat(guid, guid_string); + virtualSystemIdentifiers = (char *) malloc((strlen(guid_string)+3) * sizeof(char)); + sprintf(virtualSystemIdentifiers, "{%s}", guid_string); + hypervGetSwitchPortPATH(domain, switchPort->data->Name, + virtualSwitch->data->Name, &switchPortPATH); + embeddedparam.nbProps = 5; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "Connection"; + (*tab_props).val = switchPortPATH; + (*(tab_props+1)).name = "ElementName"; + (*(tab_props+1)).val = "Network Adapter"; + (*(tab_props+2)).name = "VirtualSystemIdentifiers"; + (*(tab_props+2)).val = virtualSystemIdentifiers; + (*(tab_props+3)).name = "ResourceType"; + (*(tab_props+3)).val = "10"; + (*(tab_props+4)).name = "ResourceSubType"; + (*(tab_props+4)).val = "Microsoft Synthetic Ethernet Port"; + embeddedparam.instanceName = MSVM_SYNTHETICETHERNETPORTSETTINGDATA_CLASSNAME; + embeddedparam.prop_t = tab_props; + + // CREATE invokeXmlParam tab + VIR_FREE(params); + nb_params = 2; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "TargetSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam2; + (*(params+1)).name = "ResourceSettingData"; + (*(params+1)).type = EMBEDDED_PARAM; + (*(params+1)).param = &embeddedparam; + + if (hypervInvokeMethod(priv, params, nb_params, "AddVirtualSystemResources", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector2) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not attach the network")); + goto cleanup; + } + + ret = 0; + + cleanup: + if (virtualSystemIdentifiers != NULL) VIR_FREE(virtualSystemIdentifiers); + if (switchPortPATH != NULL) VIR_FREE(switchPortPATH); + if (tab_props!= NULL) VIR_FREE(tab_props); + if (params != NULL) VIR_FREE(params); + hypervFreeObject(priv, (hypervObject *)switchPort); + hypervFreeObject(priv, (hypervObject *)virtualSwitch); + virBufferFreeAndReset(&query); + + return ret; +} + + +static int +hypervDomainAttachDeviceFlags(virDomainPtr domain, const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + int ret = -1; + hypervPrivate *priv = domain->conn->privateData; + virDomainDefPtr def = NULL; + virDomainDeviceDefPtr dev = NULL; + char *xmlDomain = NULL; + + // Get domain definition + if ((xmlDomain = hypervDomainGetXMLDesc(domain, 0)) == NULL) { + goto cleanup; + } + if ((def = virDomainDefParseString(xmlDomain, priv->caps, priv->xmlopt, + 1 << VIR_DOMAIN_VIRT_HYPERV, VIR_DOMAIN_XML_INACTIVE)) == NULL) { + goto cleanup; + } + + // Get domain device definition + if ((dev = virDomainDeviceDefParse(xml, def, priv->caps, + priv->xmlopt, VIR_DOMAIN_XML_INACTIVE)) == NULL) { + goto cleanup; + } + + switch (dev->type) { + /* Device = disk */ + case VIR_DOMAIN_DEVICE_DISK: + if (hypervDomainAttachDisk(domain, dev->data.disk) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not attach disk")); + goto cleanup; + } + VIR_DEBUG("Disk attached"); + break; + + /* Device = network */ + case VIR_DOMAIN_DEVICE_NET: + if (hypervDomainAttachNetwork(domain, dev->data.net) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not attach network")); + goto cleanup; + } + VIR_DEBUG("Network attached"); + break; + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device attachment of type %d is not implemented"), dev->type); + goto cleanup; + } + + ret = 0; + + cleanup: + virDomainDefFree(def); + virDomainDeviceDefFree(dev); + if (xmlDomain != NULL) VIR_FREE(xmlDomain); + + return ret; +} + + + +static int +hypervDomainAttachDevice(virDomainPtr domain, const char *xml) +{ + return hypervDomainAttachDeviceFlags(domain, xml, 0); +} + + + +static virDomainPtr +hypervDomainDefineXML(virConnectPtr conn, const char *xml) +{ + hypervPrivate *priv = conn->privateData; + virDomainDefPtr def = NULL; + virDomainPtr domain = NULL; + invokeXmlParam *params = NULL; + properties_t *tab_props = NULL; + embeddedParam embeddedparam; + int nb_params, i; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + + // Parsing XML + if ((def = virDomainDefParseString(xml, priv->caps, priv->xmlopt, + 1 << VIR_DOMAIN_VIRT_HYPERV, VIR_DOMAIN_XML_INACTIVE)) == NULL) { + goto cleanup; + } + + /* Create the VM if not exists */ + if (!(def->uuid != NULL && + (domain = hypervDomainLookupByUUID(conn, def->uuid)) != NULL)) { + + // PREPARE EMBEDDED PARAM + /* Edit only VM name */ + //FIXME: cannot edit VM UUID + embeddedparam.nbProps = 1; + tab_props = (properties_t *) malloc(embeddedparam.nbProps * sizeof(properties_t)); + (*tab_props).name = "ElementName"; + (*tab_props).val = def->name; + embeddedparam.instanceName = "Msvm_VirtualSystemGlobalSettingData"; + embeddedparam.prop_t = tab_props; + + // CREATE invokeXmlParam + nb_params = 1; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "SystemSettingData"; + (*params).type = EMBEDDED_PARAM; + (*params).param = &embeddedparam; + + /* Create VM */ + if (hypervInvokeMethod(priv, params, nb_params, "DefineVirtualSystem", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not create new domain %s"), def->name); + goto cleanup; + } + + // Get domain pointer + domain = hypervDomainLookupByName(conn, def->name); + + VIR_DEBUG("Domain created: name=%s, uuid=%s", + domain->name, virUUIDFormat(domain->uuid, uuid_string)); + } + + /* Set VM maximum memory */ + if (def->mem.max_balloon > 0) { + if (hypervDomainSetMaxMemory(domain, def->mem.max_balloon) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not set VM maximum memory")); + } + } + + /* Set VM memory */ + if (def->mem.cur_balloon > 0) { + if (hypervDomainSetMemory(domain, def->mem.cur_balloon) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not set VM memory")); + } + } + + /* Set VM vcpus */ + if (def->vcpus > 0) { + if (hypervDomainSetVcpus(domain, def->vcpus) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not set VM vCPUs")); + } + } + + /* Attach networks */ + for (i = 0; i < def->nnets; i++) { + if (hypervDomainAttachNetwork(domain, def->nets[i]) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not attach network")); + } + } + + /* Attach disks */ + for (i = 0; i < def->ndisks; i++) { + if (hypervDomainAttachDisk(domain, def->disks[i]) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not attach disk")); + } + } + + cleanup: + virDomainDefFree(def); + if (tab_props != NULL) VIR_FREE(tab_props); + if (params != NULL) VIR_FREE(params); + + return domain; +} + + + +static virDomainPtr +hypervDomainCreateXML(virConnectPtr conn, const char *xmlDesc, unsigned int flags) +{ + virDomainPtr domain; + + virCheckFlags(VIR_DOMAIN_NONE |VIR_DOMAIN_START_PAUSED |VIR_DOMAIN_START_AUTODESTROY, NULL); + + // Create new domain + domain = hypervDomainDefineXML(conn, xmlDesc); + if (domain == NULL) + return NULL; + + // Start domain + if (hypervInvokeMsvmComputerSystemRequestStateChange(domain, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not start the domain %s"), domain->name); + return domain; + } + + // If the VIR_DOMAIN_START_PAUSED flag is set, + // the guest domain will be started, but its CPUs will remain paused + if (flags & VIR_DOMAIN_START_PAUSED) { + if (hypervDomainSuspend(domain) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not pause the domain %s"), domain->name); + } + } + + // If the VIR_DOMAIN_START_AUTODESTROY flag is set, + // the guest domain will be automatically destroyed + // when the virConnectPtr object is finally released + if (flags & VIR_DOMAIN_START_AUTODESTROY) { + //FIXME: wait till virConnectPtr is released + if (hypervDomainDestroy(domain) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not destroy the domain %s"), domain->name); + } + } + + return domain; +} + + + +static int +hypervDomainUndefineFlags(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED) +{ + int result = -1, nb_params; + const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService"; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + invokeXmlParam *params = NULL; + eprParam eprparam; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_ComputerSystem *computerSystem = NULL; + + virCheckFlags(0, -1); + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) { + goto cleanup; + } + + /* Shutdown the VM if not disabled */ + if (computerSystem->data->EnabledState != + MSVM_COMPUTERSYSTEM_ENABLEDSTATE_DISABLED) { + if (hypervDomainShutdown(domain) < 0) { + goto cleanup; + } + } + + /* Deleting the VM */ + + // PREPARE EPR PARAM + virBufferFreeAndReset(&query); + virBufferAddLit(&query, MSVM_COMPUTERSYSTEM_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string); + eprparam.query = &query; + eprparam.wmiProviderURI = ROOT_VIRTUALIZATION; + + // CREATE invokeXmlParam tab + nb_params = 1; + params = (invokeXmlParam *) malloc(nb_params * sizeof(invokeXmlParam)); + (*params).name = "ComputerSystem"; + (*params).type = EPR_PARAM; + (*params).param = &eprparam; + + // DESTROY VM + if (hypervInvokeMethod(priv, params, nb_params, "DestroyVirtualSystem", + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_RESOURCE_URI, selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not delete domain")); + goto cleanup; + } + + result = 0; + + cleanup: + if (params != NULL) VIR_FREE(params); + hypervFreeObject(priv, (hypervObject *)computerSystem); + virBufferFreeAndReset(&query); + + return result; +} + + + +static int +hypervDomainUndefine(virDomainPtr domain) +{ + return hypervDomainUndefineFlags(domain, 0); +} + + static virDriver hypervDriver = { .no = VIR_DRV_HYPERV, @@ -1389,6 +3291,31 @@ static virDriver hypervDriver = { .domainHasManagedSaveImage = hypervDomainHasManagedSaveImage, /* 0.9.5 */ .domainManagedSaveRemove = hypervDomainManagedSaveRemove, /* 0.9.5 */ .connectIsAlive = hypervConnectIsAlive, /* 0.9.8 */ + .domainGetVcpusFlags = hypervDomainGetVcpusFlags, /* 1.2.9 */ + .domainGetMaxVcpus = hypervDomainGetMaxVcpus, /* 1.2.9 */ + .domainShutdown = hypervDomainShutdown, /* 1.2.9 */ + .domainShutdownFlags = hypervDomainShutdownFlags, /* 1.2.9 */ + .domainGetSchedulerParametersFlags = hypervDomainGetSchedulerParametersFlags, /* 1.2.9 */ + .domainGetSchedulerParameters = hypervDomainGetSchedulerParameters, /* 1.2.9 */ + .domainGetSchedulerType = hypervDomainGetSchedulerType, /* 1.2.9 */ + .connectGetCapabilities = hypervConnectGetCapabilities, /* 1.2.9 */ + .connectGetVersion = hypervConnectGetVersion, /* 1.2.9 */ + .domainSetAutostart = hypervDomainSetAutostart, /* 1.2.9 */ + .domainSetMaxMemory = hypervDomainSetMaxMemory, /* 1.2.9 */ + .domainDefineXML = hypervDomainDefineXML, /* 1.2.9 */ + .domainSetMemory = hypervDomainSetMemory, /* 1.2.9 */ + .domainSetMemoryFlags = hypervDomainSetMemoryFlags, /* 1.2.9 */ + .domainSetVcpus = hypervDomainSetVcpus, /* 1.2.9 */ + .domainSetVcpusFlags = hypervDomainSetVcpusFlags, /* 1.2.9 */ + .domainAttachDevice = hypervDomainAttachDevice, /* 1.2.9 */ + .domainAttachDeviceFlags = hypervDomainAttachDeviceFlags, /* 1.2.9 */ + .connectGetMaxVcpus = hypervConnectGetMaxVcpus, /* 1.2.9 */ + .domainCreateXML = hypervDomainCreateXML, /* 1.2.9 */ + .nodeGetFreeMemory = hypervNodeGetFreeMemory, /* 1.2.9 */ + .domainGetVcpus = hypervDomainGetVcpus, /* 1.2.9 */ + .domainUndefine = hypervDomainUndefine, /* 1.2.9 */ + .domainUndefineFlags = hypervDomainUndefineFlags, /* 1.2.9 */ + .domainGetAutostart = hypervDomainGetAutostart, /* 1.2.9 */ }; diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index 6f54f44..ad24431 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -28,6 +28,9 @@ #include "viralloc.h" #include "viruuid.h" #include "hyperv_network_driver.h" +#include "virstring.h" +#include "hyperv_wmi.h" +#include "network_conf.h" #define VIR_FROM_THIS VIR_FROM_HYPERV @@ -60,11 +63,246 @@ hypervNetworkClose(virConnectPtr conn) } +static int +hypervConnectNumOfNetworks(virConnectPtr conn) +{ + int ret = -1, count = 0; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitchList = NULL; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where HealthState = %d", 5); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitchList) < 0) { + goto cleanup; + } + + for (virtualSwitch = virtualSwitchList; virtualSwitch != NULL; + virtualSwitch = virtualSwitch->next) { + count++; + } + + ret = count; + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) virtualSwitchList); + return ret; +} + + +static int +hypervConnectListNetworks(virConnectPtr conn, char **const names, int maxnames) +{ + int i, count = 0; + bool success = false; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitchList = NULL; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + if (maxnames <= 0) { + return 0; + } + + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where HealthState = %d", 5); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitchList) < 0) { + goto cleanup; + } + + for (virtualSwitch = virtualSwitchList; virtualSwitch != NULL; + virtualSwitch = virtualSwitch->next) { + if (VIR_STRDUP(names[count], virtualSwitch->data->ElementName) < 0) { + goto cleanup; + } + count++; + if (count >= maxnames) { + break; + } + } + + success = true; + + cleanup: + if (!success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + count = -1; + } + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) virtualSwitchList); + return count; +} + + +static int +hypervConnectNumOfDefinedNetworks(virConnectPtr conn) +{ + int ret = -1, count = 0; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitchList = NULL; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where HealthState <> %d", 5); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitchList) < 0) { + goto cleanup; + } + + for (virtualSwitch = virtualSwitchList; virtualSwitch != NULL; + virtualSwitch = virtualSwitch->next) { + count++; + } + + ret = count; + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) virtualSwitchList); + return ret; +} + + +static int +hypervConnectListDefinedNetworks(virConnectPtr conn, char **const names, int maxnames) +{ + int i, count = 0; + bool success = false; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitchList = NULL; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + if (maxnames <= 0) { + return 0; + } + + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where HealthState <> %d", 5); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitchList) < 0) { + goto cleanup; + } + + for (virtualSwitch = virtualSwitchList; virtualSwitch != NULL; + virtualSwitch = virtualSwitch->next) { + if (VIR_STRDUP(names[count], virtualSwitch->data->ElementName) < 0) { + goto cleanup; + } + count++; + if (count >= maxnames) { + break; + } + } + + success = true; + + cleanup: + if (!success) { + for (i = 0; i < count; ++i) { + VIR_FREE(names[i]); + } + count = -1; + } + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) virtualSwitchList); + return count; +} + + +static virNetworkPtr +hypervNetworkLookupByName(virConnectPtr conn, const char *name) +{ + virNetworkPtr network = NULL; + hypervPrivate *priv = conn->privateData; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where Description = \"%s\" and ElementName = \"%s\"", + "Microsoft Virtual Switch", name); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitch) < 0) { + goto cleanup; + } + if (virtualSwitch == NULL) { + virReportError(VIR_ERR_NO_NETWORK, + _("No network found with name %s"), name); + goto cleanup; + } + + hypervMsvmVirtualSwitchToNetwork(conn, virtualSwitch, &network); + + cleanup: + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *) virtualSwitch); + return network; +} + + +static char * +hypervNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags) +{ + char *xml = NULL; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = network->conn->privateData; + virNetworkDefPtr def = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + Msvm_VirtualSwitch *virtualSwitch = NULL; + + /* Flags checked by virNetworkDefFormat */ + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + goto cleanup; + } + + virUUIDFormat(network->uuid, uuid_string); + + /* Get Msvm_VirtualSwitch */ + virBufferAddLit(&query, MSVM_VIRTUALSWITCH_WQL_SELECT); + virBufferAsprintf(&query, "where Name = \"%s\"", uuid_string); + if (hypervGetMsvmVirtualSwitchList(priv, &query, &virtualSwitch) < 0) { + goto cleanup; + } + if (virtualSwitch == NULL) { + virReportError(VIR_ERR_NO_NETWORK, + _("No network found with UUID %s"), uuid_string); + goto cleanup; + } + + /* Fill struct */ + if (virUUIDParse(virtualSwitch->data->Name, def->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + virtualSwitch->data->Name); + return NULL; + } + + if (VIR_STRDUP(def->name, virtualSwitch->data->ElementName) < 0) + goto cleanup; + + xml = virNetworkDefFormat(def, flags); + + cleanup: + virNetworkDefFree(def); + virBufferFreeAndReset(&query); + hypervFreeObject(priv, (hypervObject *)virtualSwitch); + return xml; +} static virNetworkDriver hypervNetworkDriver = { .name = "Hyper-V", .networkOpen = hypervNetworkOpen, /* 0.9.5 */ .networkClose = hypervNetworkClose, /* 0.9.5 */ + .connectNumOfNetworks = hypervConnectNumOfNetworks, /* 1.2.9 */ + .connectListNetworks = hypervConnectListNetworks, /* 1.2.9 */ + .connectNumOfDefinedNetworks = hypervConnectNumOfDefinedNetworks, /* 1.2.9 */ + .connectListDefinedNetworks = hypervConnectListDefinedNetworks, /* 1.2.9 */ + .networkLookupByName = hypervNetworkLookupByName, /* 1.2.9 */ + .networkGetXMLDesc = hypervNetworkGetXMLDesc, /* 1.2.9 */ }; diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h index 574bb5f..7c28053 100644 --- a/src/hyperv/hyperv_private.h +++ b/src/hyperv/hyperv_private.h @@ -27,12 +27,21 @@ # include "virerror.h" # include "hyperv_util.h" # include "openwsman.h" +# include "capabilities.h" +# include "domain_conf.h" + +#ifndef WIN32 +# include <pthread.h> +#endif typedef struct _hypervPrivate hypervPrivate; struct _hypervPrivate { hypervParsedUri *parsedUri; WsManClient *client; + virCapsPtr caps; + virDomainXMLOptionPtr xmlopt; /* to parse Domain XML */ + pthread_mutex_t mutex; /* to protect against concurrent calls (openwsman library not thread-safe) */ }; #endif /* __HYPERV_PRIVATE_H__ */ diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index acb705c..e84e208 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -33,16 +33,752 @@ #include "hyperv_wmi.h" #include "virstring.h" +# include <wsman-xml-api.h> +# include <wsman-client.h> +# include <wsman-client-transport.h> +# include <wsman-soap.h> +# include <libxml/tree.h> +# include "hyperv_wmi_classes_attr.generated.h" + #define WS_SERIALIZER_FREE_MEM_WORKS 0 -#define ROOT_CIMV2 \ - "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*" +#define VIR_FROM_THIS VIR_FROM_HYPERV -#define ROOT_VIRTUALIZATION \ - "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/*" +/* Flag to dump WSMAN requests */ +#define DUMP_REQUEST 0 -#define VIR_FROM_THIS VIR_FROM_HYPERV +/* + CAUTION: Special note regarding multi-threading + The openwsman library is not thread-safe (as reported in issue #10 "Simultaneous WsMan queries") + It has not been designed to allow to share the same connection for concurrent calls to wsmc_action_xxxx fonctions. + This implementation of this hyperv libvirt driver shares the same connection for all these calls. + Therefore, we have used a mutex to protect all functions that make usage of the wsmc_action_xxxx fonctions. +*/ + + +/* + * Prototypes of internals functions + */ + +const char * +hypervGetPropType(const char * className, const char *attrName); + +int +hypervCreateXmlStruct(const char *methodName, const char *classURI, WsXmlDocH *xmlDocRoot, WsXmlNodeH *xmlNodeMethod); + +int +hypervAddEmbeddedParam(properties_t *prop_t, int nbProps, const char *paramName, const char *instanceName, const char *classURI, WsXmlNodeH *parentNode); + +int +hypervAddSimpleParam(const char *paramName, const char* value, const char *classURI, WsXmlNodeH *parentNode); + +int +hypervAddEprParam(const char *paramName, virBufferPtr query, const char *root, const char *classURI, WsXmlNodeH *parentNode, WsXmlDocH doc, hypervPrivate *priv); + +int +hypervInvokeMethodXml(hypervPrivate *priv, WsXmlDocH xmlDocRoot, const char *methodName, const char *ressourceURI, const char *selector); + + + +/* Create XML structure */ +int +hypervCreateXmlStruct(const char *methodName, const char *classURI, + WsXmlDocH *xmlDocRoot, WsXmlNodeH *xmlNodeMethod) +{ + + virBuffer method_buff = VIR_BUFFER_INITIALIZER; + char *methodNameInput = NULL; + + virBufferAsprintf(&method_buff, "%s_INPUT", methodName); + methodNameInput = virBufferContentAndReset(&method_buff); + + if (methodNameInput == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not create Xml Doc")); + goto cleanup; + } + + *xmlDocRoot = ws_xml_create_doc(NULL, methodNameInput); + if (*xmlDocRoot == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not create Xml Doc with given parameter xmlDocRoot")); + goto cleanup; + } + + *xmlNodeMethod = xml_parser_get_root(*xmlDocRoot); + if (*xmlNodeMethod == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get xmlDocRoot root node")); + goto cleanup; + } + + //add namespace to xmlNodeMethode + ws_xml_set_ns(*xmlNodeMethod, classURI, "p"); + + VIR_FREE(methodNameInput); + return 0; + + cleanup: + + VIR_FREE(methodNameInput); + if (*xmlDocRoot != NULL) { + ws_xml_destroy_doc(*xmlDocRoot); + *xmlDocRoot = NULL; + } + return -1; +} + + +/* Get attribute type of a given attribute */ +const char * +hypervGetPropType(const char * className, const char *attrName) +{ + const char * res = NULL; + int i,y; + + i = 0; + while ( cimClasses[i].name[0] != '\0') { + if(strcmp(cimClasses[i].name,className ) == 0){ + y = 0; + while ( cimClasses[i].cimTypesPtr[y].name[0] != '\0') { + if(strcmp(cimClasses[i].cimTypesPtr[y].name,attrName ) == 0){ + res = cimClasses[i].cimTypesPtr[y].type; + break; + } + y++; + } + break; + } + i++; + } + return res; +} + + +/* Adding an Embedded Instance node to a parent node given in parameter */ +int +hypervAddEmbeddedParam(properties_t *prop_t, int nbProps, const char *paramName, + const char *instanceName, const char *classURI, WsXmlNodeH *parentNode) +{ + + int result = -1; + WsXmlNodeH xmlNodeInstance = NULL; + WsXmlNodeH xmlNodeProperty = NULL; + WsXmlNodeH xmlNodeParam = NULL; + WsXmlNodeH xmlNodeArray = NULL; + WsXmlDocH xmlDocTemp = NULL; + WsXmlDocH xmlDocCdata = NULL; + xmlBufferPtr xmlBufferNode = NULL; + const xmlChar *xmlCharCdataContent = NULL; + xmlNodePtr xmlNodeCdata = NULL; + char* type = NULL; /* Must not be freed */ + char* typeCopy = NULL; + bool isArray = false; + int len = 0; + int i = 0; + + /* Add child to given parent node*/ + xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, NULL); + if (xmlNodeParam == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child node to xmlNodeParam")); + goto cleanup; + } + + /* Create temp Xml doc */ + /* INSTANCE node */ + xmlDocTemp = ws_xml_create_doc(NULL, "INSTANCE"); + if (xmlDocTemp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not create temporary Xml doc")); + goto cleanup; + } + + xmlNodeInstance = xml_parser_get_root(xmlDocTemp); + if (xmlNodeInstance == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get root of temporary Xml doc")); + goto cleanup; + } + + /* Add CLASSNAME node to INSTANCE node */ + if (ws_xml_add_node_attr(xmlNodeInstance, NULL, "CLASSNAME", instanceName) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add attribute to node ")); + goto cleanup; + } + + /* Property nodes */ + while (i < nbProps) { + + if (prop_t[i].name == NULL && prop_t[i].val == NULL ) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get properties from array ")); + goto cleanup; + } + + type = (char *) hypervGetPropType(instanceName,prop_t[i].name); + if (type == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get properties from array ")); + goto cleanup; + } + + /* Check if the attribute is an array or not */ + if (strstr(type, "[]") != NULL) { + // The attribute is an array + isArray = true; + // Remove "[]" from the type; must be done on a copy + if (typeCopy != NULL) VIR_FREE(typeCopy); + typeCopy = strndup(type, strlen(type)-2); + type = typeCopy; + } else { + isArray = false; + } + + xmlNodeProperty = ws_xml_add_child(xmlNodeInstance, NULL, + (isArray)?"PROPERTY.ARRAY":"PROPERTY", NULL); + if (xmlNodeProperty == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add child to node")); + goto cleanup; + } + + if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "NAME", prop_t[i].name) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add attribute to node")); + goto cleanup; + } + + if (ws_xml_add_node_attr(xmlNodeProperty, NULL, "TYPE", type) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add attribute to node")); + goto cleanup; + } + + /* Add the node VALUE.ARRAY if the attribute is an array */ + if (isArray) { + xmlNodeArray = ws_xml_add_child(xmlNodeProperty, NULL, "VALUE.ARRAY", NULL); + if (xmlNodeArray == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add child to node")); + goto cleanup; + } + } + + if (ws_xml_add_child((isArray)?xmlNodeArray:xmlNodeProperty, NULL, "VALUE",prop_t[i].val) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add child to node")); + goto cleanup; + } + + xmlNodeArray = NULL; + xmlNodeProperty = NULL; + i++; + } + + /* Create CDATA node */ + xmlBufferNode = xmlBufferCreate(); + if (xmlNodeDump(xmlBufferNode,(xmlDocPtr)xmlDocTemp->parserDoc , (xmlNodePtr) xmlNodeInstance, 0, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get root of temporary Xml doc")); + goto cleanup; + } + + len = xmlBufferLength(xmlBufferNode); + xmlCharCdataContent = xmlBufferContent(xmlBufferNode); + xmlNodeCdata = xmlNewCDataBlock ((xmlDocPtr)xmlDocCdata, xmlCharCdataContent, len ); + if (xmlNodeCdata == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get root of temporary Xml doc")); + goto cleanup; + } + /*adding CDATA node child to the root node of the main doc given*/ + if (xmlAddChild((xmlNodePtr)xmlNodeParam, xmlNodeCdata ) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not get root of temporary Xml doc")); + goto cleanup; + } + + result = 0; + + cleanup: + ws_xml_destroy_doc(xmlDocCdata); + ws_xml_destroy_doc(xmlDocTemp); + if (typeCopy != NULL) VIR_FREE(typeCopy); + if (xmlBufferNode != NULL) xmlBufferFree(xmlBufferNode); + + return result; +} + + +/* Adding an Simple param node to a parent node given in parameter */ +int +hypervAddSimpleParam(const char *paramName, const char* value, + const char *classURI, WsXmlNodeH *parentNode) +{ + + int result = -1; + WsXmlNodeH xmlNodeParam = NULL; + + xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, value); + if (xmlNodeParam == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create simple param")); + goto cleanup; + } + + result = 0; + + cleanup: + return result; +} + + +/* Adding EPR param node to a parent node given in parameter */ +int +hypervAddEprParam(const char *paramName, virBufferPtr query, const char *root, + const char *classURI, WsXmlNodeH *parentNode, WsXmlDocH doc, hypervPrivate *priv) +{ + + int result = -1; + WsXmlNodeH xmlNodeParam = NULL; + WsXmlNodeH xmlNodTemp = NULL; + WsXmlNodeH xmlNodeAdr = NULL; + WsXmlNodeH xmlNodeRef = NULL; + WsXmlDocH xmlDocResponse = NULL; + WsXmlNsH ns = NULL; + client_opt_t *options = NULL; + filter_t *filter = NULL; + char *enumContext = NULL; + char *query_string; + xmlNodePtr xmlNodeAdrPtr = NULL; + xmlNodePtr xmlNodeRefPtr = NULL; + xmlDocPtr docPtr = (xmlDocPtr) doc->parserDoc; + + /* Protection against concurrent calls (the openwsman library is not thread-safe) */ + pthread_mutex_lock(&priv->mutex); + + /* Request options and filter */ + options = wsmc_options_init(); + + if (options == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not initialize options")); + goto cleanup; + } + +#if DUMP_REQUEST + wsmc_set_action_option(options, FLAG_DUMP_REQUEST); +#endif + + wsmc_set_action_option(options, FLAG_ENUMERATION_ENUM_EPR); + + query_string = virBufferContentAndReset(query); + filter = filter_create_simple(WSM_WQL_FILTER_DIALECT,query_string); + if (filter == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not create filter")); + goto cleanup; + } + + /* Invoke enumerate action*/ + xmlDocResponse = wsmc_action_enumerate(priv->client,root, options, filter); + + /* Check return value */ + if (hyperyVerifyResponse(priv->client, xmlDocResponse, "enumeration") < 0) { + goto cleanup; + } + + /* Get enumerate conext*/ + enumContext = wsmc_get_enum_context(xmlDocResponse); + + ws_xml_destroy_doc(xmlDocResponse); + + + /* Invoke pull action*/ + xmlDocResponse = wsmc_action_pull(priv->client, classURI, options, filter, enumContext); + + /* Check return value */ + if (hyperyVerifyResponse(priv->client, xmlDocResponse, "pull") < 0) { + goto cleanup; + } + + /* Extract EPR nodes childs */ + xmlNodTemp = ws_xml_get_soap_body(xmlDocResponse); + if (xmlNodTemp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup SOAP body")); + goto cleanup; + } + + xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ENUMERATION, WSENUM_PULL_RESP); + if (xmlNodTemp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response")); + goto cleanup; + } + + xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ENUMERATION, WSENUM_ITEMS); + if (xmlNodTemp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response items")); + goto cleanup; + } + + xmlNodTemp = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_EPR); + if (xmlNodTemp == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response item EPR")); + goto cleanup; + } + + xmlNodeAdr = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_ADDRESS); + if (xmlNodeAdr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response item ADDRESS")); + goto cleanup; + } + xmlNodeAdrPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeAdr, docPtr, 1); + if (xmlNodeAdrPtr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not copy item ADDRESS")); + goto cleanup; + } + + xmlNodeRef = ws_xml_get_child(xmlNodTemp, 0, XML_NS_ADDRESSING, WSA_REFERENCE_PARAMETERS); + if (xmlNodeRef == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not lookup pull response item REFERENCE PARAMETERS")); + goto cleanup; + } + xmlNodeRefPtr = xmlDocCopyNode((xmlNodePtr) xmlNodeRef, docPtr, 1); + if (xmlNodeRefPtr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not copy item REFERENCE PARAMETERS")); + goto cleanup; + } + + /* Build XmlDoc with adding previous EPR nodes childs */ + xmlNodeParam = ws_xml_add_child(*parentNode, classURI, paramName, NULL); + if (xmlNodeParam == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child node to xmlNodeParam")); + goto cleanup; + } + +/* + The folowing line has been commented because of a memory corruption issue reported in the openwsman library + [ issue #43 - xml_parser_ns_add: alloc item size, not pointer size ] + xmlNodeSetLang((xmlNodePtr) xmlNodeParam, BAD_CAST "en-US"); +*/ + ns = ws_xml_ns_add(xmlNodeParam, "http://schemas.xmlsoap.org/ws/2004/08/addressing", "a"); + if (ns == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not set namespace adressing to xmlNodeParam")); + goto cleanup; + } + + ns = NULL; + ns = ws_xml_ns_add(xmlNodeParam, "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd", "w"); + if (ns == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not set namespace wsman to xmlNodeParam")); + goto cleanup; + } + + if (xmlAddChild( (xmlNodePtr)*parentNode,(xmlNodePtr) xmlNodeParam) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + if (xmlAddChild( (xmlNodePtr)xmlNodeParam, xmlNodeAdrPtr) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + if (xmlAddChild( (xmlNodePtr)xmlNodeParam, xmlNodeRefPtr) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not add child to xml parent node")); + goto cleanup; + } + + result = 0; + + cleanup: + if (options != NULL) { + wsmc_options_destroy(options); + } + if (filter != NULL) { + filter_destroy(filter); + } + ws_xml_destroy_doc(xmlDocResponse); + VIR_FREE(enumContext); + VIR_FREE(query_string); + /* Unlock the mutex */ + pthread_mutex_unlock(&priv->mutex); + + return result; +} + + +/* Call wsmc_action_invoke() function of OpenWsman API with XML tree given in parameters*/ +int +hypervInvokeMethodXml(hypervPrivate *priv,WsXmlDocH xmlDocRoot, + const char *methodName, const char *ressourceURI, const char *selector) +{ + + int result = -1; + int returnCode; + char *instanceID = NULL; + char *xpath_expr_string = NULL; + char *returnValue = NULL; + virBuffer query = VIR_BUFFER_INITIALIZER; + virBuffer xpath_expr_buff = VIR_BUFFER_INITIALIZER; + client_opt_t *options = NULL; + WsXmlDocH response = NULL; + Msvm_ConcreteJob *concreteJob = NULL; + bool completed = false; + bool locked; + + /* Protection against concurrent calls (the openwsman library is not thread-safe) */ + pthread_mutex_lock(&priv->mutex); + locked = true; + + options = wsmc_options_init(); + + if (options == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not initialize options")); + goto cleanup; + } + +#if DUMP_REQUEST + wsmc_set_action_option(options, FLAG_DUMP_REQUEST); +#endif + + wsmc_add_selectors_from_str(options, selector); + + /* Invoke action */ + response = wsmc_action_invoke(priv->client,ressourceURI,options,methodName,xmlDocRoot); + + virBufferAsprintf(&xpath_expr_buff, "/s:Envelope/s:Body/p:%s_OUTPUT/p:ReturnValue", methodName); + xpath_expr_string = virBufferContentAndReset(&xpath_expr_buff); + + if (xpath_expr_string == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "ReturnValue", "RequestStateChange"); + goto cleanup; + } + + /* Check return value */ + returnValue = ws_xml_get_xpath_value(response, xpath_expr_string); + + VIR_FREE(xpath_expr_string); + xpath_expr_string = NULL; + + if (returnValue == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "ReturnValue", "RequestStateChange"); + goto cleanup; + } + + if (virStrToLong_i(returnValue, NULL, 10, &returnCode) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse return code from '%s'"), returnValue); + goto cleanup; + } + + if (returnCode == CIM_RETURNCODE_TRANSITION_STARTED) { + + virBufferAsprintf(&xpath_expr_buff, "/s:Envelope/s:Body/p:%s_OUTPUT/p:Job/a:ReferenceParameters/w:SelectorSet/w:Selector[@Name='InstanceID']", methodName); + xpath_expr_string = virBufferContentAndReset(&xpath_expr_buff); + + if (xpath_expr_string == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "InstanceID", "RequestStateChange"); + goto cleanup; + } + + /* Get concrete job object */ + instanceID = ws_xml_get_xpath_value(response, xpath_expr_string); + + if (instanceID == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not lookup %s for %s invocation"), + "InstanceID", "RequestStateChange"); + goto cleanup; + } + + /* hypervGetMsvmConcreteJobList calls hypervEnumAndPull which also tries to lock priv->mutex */ + pthread_mutex_unlock(&priv->mutex); + locked = false; + + /* 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) { + virReportError(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; + + usleep(100 * 1000); + 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: + goto cleanup; + + default: + virReportError(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) { + virReportError(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); + if (response != NULL) + ws_xml_destroy_doc(response); + VIR_FREE(returnValue); + VIR_FREE(instanceID); + VIR_FREE(xpath_expr_string); + hypervFreeObject(priv, (hypervObject *)concreteJob); + virBufferFreeAndReset(&query); + virBufferFreeAndReset(&xpath_expr_buff); + + /* Unlock the mutex if needed */ + if (locked == true) pthread_mutex_unlock(&priv->mutex); + + return result; +} + + +/* Generate a XML tree with all param_t given in parameters */ +int +hypervInvokeMethod(hypervPrivate *priv, invokeXmlParam *param_t, int nbParameters, + const char* methodName, const char* providerURI, const char *selector) +{ + + int res = -1; + WsXmlDocH doc = NULL; + WsXmlNodeH methodNode = NULL; + eprParam *epr; + embeddedParam *embedded; + simpleParam *simple; + int i =0; + + if (hypervCreateXmlStruct(methodName,providerURI,&doc,&methodNode) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not create xml base structure")); + goto cleanup; + } + + while ( i < nbParameters) { + switch (param_t[i].type){ + case EPR_PARAM: + epr = (eprParam*)param_t[i].param; + if (hypervAddEprParam(param_t[i].name, epr->query,epr->wmiProviderURI,providerURI,&methodNode,doc,priv) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add EPR param to xml base structure ")); + goto cleanup; + } + break; + case EMBEDDED_PARAM: + embedded = (embeddedParam*)param_t[i].param; + if (hypervAddEmbeddedParam(embedded->prop_t,embedded->nbProps,param_t[i].name,embedded->instanceName,providerURI,&methodNode) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add embedded instance param to xml base structure ")); + goto cleanup; + } + break; + case SIMPLE_PARAM: + simple = (simpleParam*)param_t[i].param; + if (hypervAddSimpleParam(param_t[i].name,simple->value,providerURI,&methodNode) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Could not add embedded instance param to xml base structure ")); + goto cleanup; + } + break; + } + i++; + } + + if (hypervInvokeMethodXml(priv,doc,methodName,providerURI,selector) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Error during invocation action")); + goto cleanup; + } + + res = 0; + + cleanup: + if (doc != NULL) + ws_xml_destroy_doc(doc); + + return res; +} int @@ -128,8 +864,13 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, return -1; } - if (virBufferCheckError(query) < 0) + if (virBufferError(query)) { + virReportOOMError(); return -1; + } + + /* Protection against concurrent calls (the openwsman library is not thread-safe) */ + pthread_mutex_lock(&priv->mutex); serializerContext = wsmc_get_serialization_context(priv->client); @@ -141,6 +882,10 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, goto cleanup; } +#if DUMP_REQUEST + wsmc_set_action_option(options, FLAG_DUMP_REQUEST); +#endif + query_string = virBufferContentAndReset(query); filter = filter_create_simple(WSM_WQL_FILTER_DIALECT, query_string); @@ -259,6 +1004,9 @@ hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *root, VIR_FREE(enumContext); hypervFreeObject(priv, head); + /* Unlock the mutex */ + pthread_mutex_unlock(&priv->mutex); + return result; } @@ -403,9 +1151,14 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, virBuffer query = VIR_BUFFER_INITIALIZER; Msvm_ConcreteJob *concreteJob = NULL; bool completed = false; + bool locked; virUUIDFormat(domain->uuid, uuid_string); + /* Protection against concurrent calls (the openwsman library is not thread-safe) */ + pthread_mutex_lock(&priv->mutex); + locked = true; + if (virAsprintf(&selector, "Name=%s&CreationClassName=Msvm_ComputerSystem", uuid_string) < 0 || virAsprintf(&properties, "RequestedState=%d", requestedState) < 0) @@ -419,6 +1172,10 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, goto cleanup; } +#if DUMP_REQUEST + wsmc_set_action_option(options, FLAG_DUMP_REQUEST); +#endif + wsmc_add_selectors_from_str(options, selector); wsmc_add_prop_from_str(options, properties); @@ -457,6 +1214,10 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, goto cleanup; } + /* hypervGetMsvmConcreteJobList calls hypervEnumAndPull which also tries to lock priv->mutex */ + pthread_mutex_unlock(&priv->mutex); + locked = false; + /* FIXME: Poll every 100ms until the job completes or fails. There * seems to be no other way than polling. */ while (!completed) { @@ -527,12 +1288,15 @@ hypervInvokeMsvmComputerSystemRequestStateChange(virDomainPtr domain, VIR_FREE(instanceID); hypervFreeObject(priv, (hypervObject *)concreteJob); + /* Unlock the mutex if needed */ + if (locked == true) pthread_mutex_unlock(&priv->mutex); + return result; } int hypervMsvmComputerSystemEnabledStateToDomainState - (Msvm_ComputerSystem *computerSystem) +(Msvm_ComputerSystem *computerSystem) { switch (computerSystem->data->EnabledState) { case MSVM_COMPUTERSYSTEM_ENABLEDSTATE_UNKNOWN: @@ -676,5 +1440,31 @@ hypervMsvmComputerSystemFromDomain(virDomainPtr domain, } +int +hypervMsvmVirtualSwitchToNetwork(virConnectPtr conn, + Msvm_VirtualSwitch *virtualSwitch, virNetworkPtr *network) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + + if (network == NULL || *network != NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument")); + return -1; + } + + if (virUUIDParse(virtualSwitch->data->Name, uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse UUID from string '%s'"), + virtualSwitch->data->Name); + return -1; + } + + *network = virGetNetwork(conn, virtualSwitch->data->ElementName, uuid); + + if (*network == NULL) { + return -1; + } + + return 0; +} #include "hyperv_wmi.generated.c" diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 5fbbbac..f4ac319 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -24,11 +24,61 @@ #ifndef __HYPERV_WMI_H__ # define __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/*" + # include "virbuffer.h" # include "hyperv_private.h" # include "hyperv_wmi_classes.h" # include "openwsman.h" +/* + * Type of parameters for hypervInvokeMethod function + */ + +enum _PARAM_Type { + EPR_PARAM = 0, + SIMPLE_PARAM = 1, + EMBEDDED_PARAM = 2, +}; + +typedef struct _invokeXmlParam invokeXmlParam; +struct _invokeXmlParam{ + const char *name; + int type; + void *param; +}; + +typedef struct _eprParam eprParam; +struct _eprParam{ + virBufferPtr query; + const char *wmiProviderURI; +}; + +typedef struct _simpleParam simpleParam; +struct _simpleParam{ + const char *value; +}; + +typedef struct _properties_t properties_t; +struct _properties_t{ + const char *name; + const char *val; +}; + +typedef struct _embeddedParam embeddedParam; +struct _embeddedParam{ + const char *instanceName; + properties_t *prop_t; + int nbProps; +}; + + +int +hypervInvokeMethod(hypervPrivate *priv, invokeXmlParam *parameters, int nbParameters,const char* methodName, const char* providerURI, const char *selector); typedef struct _hypervObject hypervObject; @@ -53,7 +103,7 @@ int hypervEnumAndPull(hypervPrivate *priv, virBufferPtr query, const char *resourceUri, const char *className, hypervObject **list); -void hypervFreeObject(hypervPrivate *priv, hypervObject *object); +void hypervFreeObject(hypervPrivate *priv ATTRIBUTE_UNUSED, hypervObject *object); @@ -114,6 +164,13 @@ int hypervMsvmComputerSystemFromDomain(virDomainPtr domain, Msvm_ComputerSystem **computerSystem); +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_VirtualSwitch + */ + +int hypervMsvmVirtualSwitchToNetwork(virConnectPtr conn, + Msvm_VirtualSwitch *virtualSwitch, virNetworkPtr *network); + # include "hyperv_wmi.generated.h" diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index 97f9dff..7f828d3 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -12,8 +12,8 @@ # ... # end # -# Allowed values for <type> are: boolean, string, datetime, int8, int16, -# int32, int64, uint8, uint16, uint32 and uint64 +# Allowed values for <type> are: boolean, string, datetime, sint8, sint16, +# sint32, sint64, uint8, uint16, uint32 and uint64 # # The property <name> can be followed by [] to define a dynamic array. # @@ -72,8 +72,8 @@ class Msvm_ConcreteJob datetime ElapsedTime uint32 JobRunTimes uint8 RunMonth - int8 RunDay - int8 RunDayOfWeek + sint8 RunDay + sint8 RunDayOfWeek datetime RunStartInterval uint16 LocalOrUtcTime datetime UntilTime @@ -196,7 +196,7 @@ class Win32_ComputerSystem string Caption uint16 ChassisBootupState string CreationClassName - int16 CurrentTimeZone + sint16 CurrentTimeZone boolean DaylightInEffect string Description string DNSHostName @@ -219,7 +219,7 @@ class Win32_ComputerSystem uint8 OEMLogoBitmap[] string OEMStringArray[] boolean PartOfDomain - int64 PauseAfterReset + sint64 PauseAfterReset uint16 PCSystemType uint16 PowerManagementCapabilities[] boolean PowerManagementSupported @@ -229,8 +229,8 @@ class Win32_ComputerSystem string PrimaryOwnerContact string PrimaryOwnerName uint16 ResetCapability - int16 ResetCount - int16 ResetLimit + sint16 ResetCount + sint16 ResetLimit string Roles[] string Status string SupportContactDescription[] @@ -296,3 +296,517 @@ class Win32_Processor string Version uint32 VoltageCaps end + + +class CIM_DataFile + uint32 AccessMask + boolean Archive + string Caption + boolean Compressed + string CompressionMethod + string CreationClassName + datetime CreationDate + string CSCreationClassName + string CSName + string Description + string Drive + string EightDotThreeFileName + boolean Encrypted + string EncryptionMethod + string Extension + string FileName + uint64 FileSize + string FileType + string FSCreationClassName + string FSName + boolean Hidden + datetime InstallDate + uint64 InUseCount + datetime LastAccessed + datetime LastModified + string Manufacturer + string Name + string Path + boolean Readable + string Status + boolean System + string Version + boolean Writeable +end + + +class Win32_ComputerSystemProduct + string Caption + string Description + string IdentifyingNumber + string Name + string SKUNumber + string UUID + string Vendor + string Version +end + +class Msvm_VirtualSystemManagementService + 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 SystemCreationClassName + string SystemName + string CreationClassName + string Name + string PrimaryOwnerName + string PrimaryOwnerContact + string StartMode + boolean Started +end + +class Msvm_VirtualSystemGlobalSettingData + string Caption + string Description + string ElementName + string InstanceID + string SystemName + uint16 SettingType + uint16 VirtualSystemType + string OtherVirtualSystemType + boolean AutoActivate + datetime CreationTime + string ExternalDataRoot + string SnapshotDataRoot + uint16 AutomaticStartupAction + datetime AutomaticStartupActionDelay + uint16 AutomaticShutdownAction + uint16 AutomaticRecoveryAction + string AdditionalRecoveryInformation + string ScopeOfResidence + uint32 DebugChannelId + boolean AllowFullSCSICommandSet + string Version +end + +class Msvm_ResourceAllocationSettingData + 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 + string VirtualSystemIdentifiers[] +end + +class Msvm_AllocationCapabilities + string Caption + string Description + string ElementName + string InstanceID + string OtherResourceType + uint16 RequestTypesSupported + string ResourceSubType + uint16 ResourceType + uint16 SharingMode + uint16 SupportedAddStates[] + uint16 SupportedRemoveStates[] +end + +class Msvm_VirtualSwitch + 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 PrimaryOwnerContact + string PrimaryOwnerName + string Roles[] + string NameFormat + string OtherIdentifyingInfo[] + string IdentifyingDescriptions[] + uint16 Dedicated[] + string OtherDedicatedDescriptions[] + uint16 ResetCapability + uint16 PowerManagementCapabilities[] + string ScopeOfResidence + uint32 NumLearnableAddresses + uint32 MaxVMQOffloads + uint32 MaxChimneyOffloads +end + +class Msvm_SwitchPort + string Caption + string ElementName + datetime InstallDate + string StatusDescriptions[] + string Status + uint16 HealthState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + string SystemCreationClassName + string SystemName + string CreationClassName + string Description + uint16 OperationalStatus[] + uint16 EnabledState + datetime TimeOfLastStateChange + string Name + string NameFormat + uint16 ProtocolType + uint16 ProtocolIFType + string OtherTypeDescription + boolean BroadcastResetSupported + uint16 PortNumber + string ScopeOfResidence + uint32 VMQOffloadWeight + uint32 ChimneyOffloadWeight + uint32 VMQOffloadUsage + uint32 ChimneyOffloadUsage + uint32 VMQOffloadLimit + uint32 ChimneyOffloadLimit + boolean AllowMacSpoofing +end + +class Msvm_SyntheticEthernetPortSettingData + 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 + string VirtualSystemIdentifiers[] + boolean StaticMacAddress +end + +class Msvm_VirtualSwitchManagementService + 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 SystemCreationClassName + string SystemName + string CreationClassName + string Name + string PrimaryOwnerName + string PrimaryOwnerContact + string StartMode + boolean Started +end + +class Win32_OperatingSystem + string BootDevice + string BuildNumber + string BuildType + string Caption + string CodeSet + string CountryCode + string CreationClassName + string CSCreationClassName + string CSDVersion + string CSName + sint16 CurrentTimeZone + boolean DataExecutionPrevention_Available + boolean DataExecutionPrevention_32BitApplications + boolean DataExecutionPrevention_Drivers + uint8 DataExecutionPrevention_SupportPolicy + boolean Debug + string Description + boolean Distributed + uint32 EncryptionLevel + uint8 ForegroundApplicationBoost + uint64 FreePhysicalMemory + uint64 FreeSpaceInPagingFiles + uint64 FreeVirtualMemory + datetime InstallDate + uint32 LargeSystemCache + datetime LastBootUpTime + datetime LocalDateTime + string Locale + string Manufacturer + uint32 MaxNumberOfProcesses + uint64 MaxProcessMemorySize + string MUILanguages[] + string Name + uint32 NumberOfLicensedUsers + uint32 NumberOfProcesses + uint32 NumberOfUsers + uint32 OperatingSystemSKU + string Organization + string OSArchitecture + uint32 OSLanguage + uint32 OSProductSuite + uint16 OSType + string OtherTypeDescription + boolean PAEEnabled + string PlusProductID + string PlusVersionNumber + boolean PortableOperatingSystem + boolean Primary + uint32 ProductType + string RegisteredUser + string SerialNumber + uint16 ServicePackMajorVersion + uint16 ServicePackMinorVersion + uint64 SizeStoredInPagingFiles + string Status + uint32 SuiteMask + string SystemDevice + string SystemDirectory + string SystemDrive + uint64 TotalSwapSpaceSize + uint64 TotalVirtualMemorySize + uint64 TotalVisibleMemorySize + string Version + string WindowsDirectory +end + +class Win32_PerfFormattedData_HvStats_HyperVHypervisorVirtualProcessor + uint64 AddressDomainFlushesPersec + uint64 AddressSpaceEvictionsPersec + uint64 AddressSpaceFlushesPersec + uint64 AddressSpaceSwitchesPersec + uint64 APICEOIAccessesPersec + uint64 APICIPIsSentPersec + uint64 APICMMIOAccessesPersec + uint64 APICSelfIPIsSentPersec + uint64 APICTPRAccessesPersec + string Caption + uint64 ControlRegisterAccessesCost + uint64 ControlRegisterAccessesPersec + uint64 CPUIDInstructionsCost + uint64 CPUIDInstructionsPersec + uint64 CPUWaitTimePerDispatch + uint64 DebugRegisterAccessesCost + uint64 DebugRegisterAccessesPersec + string Description + uint64 EmulatedInstructionsCost + uint64 EmulatedInstructionsPersec + uint64 ExternalInterruptsCost + uint64 ExternalInterruptsPersec + uint64 Frequency_Object + uint64 Frequency_PerfTime + uint64 Frequency_Sys100NS + uint64 GlobalGVARangeFlushesPersec + uint64 GPASpaceHypercallsPersec + uint64 GuestPageTableMapsPersec + uint64 HardwareInterruptsPersec + uint64 HLTInstructionsCost + uint64 HLTInstructionsPersec + uint64 HypercallsCost + uint64 HypercallsPersec + uint64 IOInstructionsCost + uint64 IOInstructionsPersec + uint64 IOInterceptMessagesPersec + uint64 LargePageTLBFillsPersec + uint64 LocalFlushedGVARangesPersec + uint64 LogicalProcessorDispatchesPersec + uint64 LogicalProcessorHypercallsPersec + uint64 LogicalProcessorMigrationsPersec + uint64 LongSpinWaitHypercallsPersec + uint64 MemoryInterceptMessagesPersec + uint64 MSRAccessesCost + uint64 MSRAccessesPersec + uint64 MWAITInstructionsCost + uint64 MWAITInstructionsPersec + string Name + uint64 NestedPageFaultInterceptsCost + uint64 NestedPageFaultInterceptsPersec + uint64 OtherHypercallsPersec + uint64 OtherInterceptsCost + uint64 OtherInterceptsPersec + uint64 OtherMessagesPersec + uint64 PageFaultInterceptsCost + uint64 PageFaultInterceptsPersec + uint64 PageInvalidationsCost + uint64 PageInvalidationsPersec + uint64 PageTableAllocationsPersec + uint64 PageTableEvictionsPersec + uint64 PageTableReclamationsPersec + uint64 PageTableResetsPersec + uint64 PageTableValidationsPersec + uint64 PageTableWriteInterceptsPersec + uint64 PendingInterruptsCost + uint64 PendingInterruptsPersec + uint64 PercentGuestRunTime + uint64 PercentHypervisorRunTime + uint64 PercentRemoteRunTime + uint64 PercentTotalRunTime + uint64 ReflectedGuestPageFaultsPersec + uint64 SmallPageTLBFillsPersec + uint64 SyntheticInterruptHypercallsPersec + uint64 SyntheticInterruptsPersec + uint64 Timestamp_Object + uint64 Timestamp_PerfTime + uint64 Timestamp_Sys100NS + uint64 TotalInterceptsCost + uint64 TotalInterceptsPersec + uint64 TotalMessagesPersec + uint64 VirtualInterruptHypercallsPersec + uint64 VirtualInterruptsPersec + uint64 VirtualMMUHypercallsPersec + uint64 VirtualProcessorHypercallsPersec +end + +class Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor + uint64 AddressDomainFlushesPersec + uint64 AddressSpaceEvictionsPersec + uint64 AddressSpaceFlushesPersec + uint64 AddressSpaceSwitchesPersec + uint64 APICEOIAccessesPersec + uint64 APICIPIsSentPersec + uint64 APICMMIOAccessesPersec + uint64 APICSelfIPIsSentPersec + uint64 APICTPRAccessesPersec + string Caption + uint64 ControlRegisterAccessesCost + uint64 ControlRegisterAccessesCost_Base + uint64 ControlRegisterAccessesPersec + uint64 CPUIDInstructionsCost + uint64 CPUIDInstructionsCost_Base + uint64 CPUIDInstructionsPersec + uint64 CPUWaitTimePerDispatch + uint64 CPUWaitTimePerDispatch_Base + uint64 DebugRegisterAccessesCost + uint64 DebugRegisterAccessesCost_Base + uint64 DebugRegisterAccessesPersec + string Description + uint64 EmulatedInstructionsCost + uint64 EmulatedInstructionsCost_Base + uint64 EmulatedInstructionsPersec + uint64 ExternalInterruptsCost + uint64 ExternalInterruptsCost_Base + uint64 ExternalInterruptsPersec + uint64 Frequency_Object + uint64 Frequency_PerfTime + uint64 Frequency_Sys100NS + uint64 GlobalGVARangeFlushesPersec + uint64 GPASpaceHypercallsPersec + uint64 GuestPageTableMapsPersec + uint64 HardwareInterruptsPersec + uint64 HLTInstructionsCost + uint64 HLTInstructionsCost_Base + uint64 HLTInstructionsPersec + uint64 HypercallsCost + uint64 HypercallsCost_Base + uint64 HypercallsPersec + uint64 IOInstructionsCost + uint64 IOInstructionsCost_Base + uint64 IOInstructionsPersec + uint64 IOInterceptMessagesPersec + uint64 LargePageTLBFillsPersec + uint64 LocalFlushedGVARangesPersec + uint64 LogicalProcessorDispatchesPersec + uint64 LogicalProcessorHypercallsPersec + uint64 LogicalProcessorMigrationsPersec + uint64 LongSpinWaitHypercallsPersec + uint64 MemoryInterceptMessagesPersec + uint64 MSRAccessesCost + uint64 MSRAccessesCost_Base + uint64 MSRAccessesPersec + uint64 MWAITInstructionsCost + uint64 MWAITInstructionsCost_Base + uint64 MWAITInstructionsPersec + string Name + uint64 NestedPageFaultInterceptsCost + uint64 NestedPageFaultInterceptsCost_Base + uint64 NestedPageFaultInterceptsPersec + uint64 OtherHypercallsPersec + uint64 OtherInterceptsCost + uint64 OtherInterceptsCost_Base + uint64 OtherInterceptsPersec + uint64 OtherMessagesPersec + uint64 PageFaultInterceptsCost + uint64 PageFaultInterceptsCost_Base + uint64 PageFaultInterceptsPersec + uint64 PageInvalidationsCost + uint64 PageInvalidationsCost_Base + uint64 PageInvalidationsPersec + uint64 PageTableAllocationsPersec + uint64 PageTableEvictionsPersec + uint64 PageTableReclamationsPersec + uint64 PageTableResetsPersec + uint64 PageTableValidationsPersec + uint64 PageTableWriteInterceptsPersec + uint64 PendingInterruptsCost + uint64 PendingInterruptsCost_Base + uint64 PendingInterruptsPersec + uint64 PercentGuestRunTime + uint64 PercentGuestRunTime_Base + uint64 PercentHypervisorRunTime + uint64 PercentHypervisorRunTime_Base + uint64 PercentRemoteRunTime + uint64 PercentRemoteRunTime_Base + uint64 PercentTotalRunTime + uint64 PercentTotalRunTime_Base + uint64 ReflectedGuestPageFaultsPersec + uint64 SmallPageTLBFillsPersec + uint64 SyntheticInterruptHypercallsPersec + uint64 SyntheticInterruptsPersec + uint64 Timestamp_Object + uint64 Timestamp_PerfTime + uint64 Timestamp_Sys100NS + uint64 TotalInterceptsCost + uint64 TotalInterceptsCost_Base + uint64 TotalInterceptsPersec + uint64 TotalMessagesPersec + uint64 VirtualInterruptHypercallsPersec + uint64 VirtualInterruptsPersec + uint64 VirtualMMUHypercallsPersec + uint64 VirtualProcessorHypercallsPersec +end \ No newline at end of file diff --git a/src/hyperv/hyperv_wmi_generator.py b/src/hyperv/hyperv_wmi_generator.py index f767d54..a785df2 100755 --- a/src/hyperv/hyperv_wmi_generator.py +++ b/src/hyperv/hyperv_wmi_generator.py @@ -68,7 +68,7 @@ class Class: header += "\n" header += "#define %s_RESOURCE_URI \\\n" % name_upper - if self.name.startswith("Win32_"): + 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 else: header += " \"http://schemas.microsoft.com/wbem/wsman/1/wmi/root/virtualization/%s\"\n" % self.name @@ -113,7 +113,7 @@ class Class: % (self.name.replace("_", ""), self.name) source += "{\n" - if self.name.startswith("Win32_"): + if self.name.startswith("Win32_") or self.name.startswith("CIM_DataFile"): source += " return hypervEnumAndPull(priv, query, ROOT_CIMV2,\n" else: source += " return hypervEnumAndPull(priv, query, ROOT_VIRTUALIZATION,\n" @@ -149,15 +149,32 @@ class Class: return source + def generate_tab_classes(self): + tab_class = " {(\"%s" % self.name + tab_class += "\"),cimTypes_%s" % self.name + tab_class += "}" + + return tab_class + + def generate_tabs_types(self): + tab_types = "CimTypes cimTypes_%s[] = {\n" % self.name + for property in self.properties[:-1]: + tab_types += property.generate_type_tab() + tab_types += ",\n" + property = self.properties[len(self.properties)-1] + tab_types += property.generate_type_tab() + tab_types += ",\n\t{(\"\\0\"),(\"\\0\")}\n};\n" + + return tab_types class Property: typemap = {"boolean" : "BOOL", "string" : "STR", "datetime" : "STR", - "int8" : "INT8", - "int16" : "INT16", - "int32" : "INT32", - "int64" : "INT64", + "sint8" : "INT8", + "sint16" : "INT16", + "sint32" : "INT32", + "sint64" : "INT64", "uint8" : "UINT8", "uint16" : "UINT16", "uint32" : "UINT32", @@ -189,7 +206,14 @@ class Property: return " SER_NS_%s(%s_RESOURCE_URI, \"%s\", 1),\n" \ % (Property.typemap[self.type], class_name.upper(), self.name) - + def generate_type_tab(self): + tab_class = " {(\"%s" % self.name + tab_class += "\"),(\"%s" % self.type + #If the attribute is an array, "[]" is added at the end of the type + if self.is_array: + tab_class += "[]" + tab_class += "\")}" + return tab_class def open_and_print(filename): if filename.startswith("./"): @@ -238,7 +262,19 @@ def parse_class(block): return Class(name=name, properties=properties) +def print_type_header(): + header_types = "struct cimTypes{\n" + header_types += " const char *name;\n" + header_types += " const char *type;\n" + header_types += "};\n" + header_types += "typedef struct cimTypes CimTypes;\n\n" + header_types += "struct cimClasses{\n" + header_types += " const char *name;\n" + header_types += " CimTypes *cimTypesPtr;\n" + header_types += "};\n" + header_types += "typedef struct cimClasses CimClasses;\n\n" + return header_types def main(): if "srcdir" in os.environ: @@ -254,6 +290,8 @@ def main(): 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")) + classes_test_header = open_and_print(os.path.join(output_dirname, "hyperv_wmi_classes_attr.generated.h")) + # parse input file number = 0 classes_by_name = {} @@ -295,6 +333,9 @@ def main(): classes_header.write(notice) classes_source.write(notice) + classes_test_header.write(notice) + classes_test_header.write(print_type_header()) + names = classes_by_name.keys() names.sort() @@ -305,7 +346,15 @@ def main(): classes_header.write(classes_by_name[name].generate_classes_header()) classes_source.write(classes_by_name[name].generate_classes_source()) - + for name in names: + classes_test_header.write(classes_by_name[name].generate_tabs_types()) + classes_test_header.write("CimClasses cimClasses[] = {\n") + for name in names[:-1]: + classes_test_header.write(classes_by_name[name].generate_tab_classes()) + classes_test_header.write(",\n") + last_name = names[len(names)-1] + classes_test_header.write(classes_by_name[last_name].generate_tab_classes()) + classes_test_header.write(",\n\t{(\"\\0\"),NULL}\n};") if __name__ == "__main__": main() diff --git a/src/hyperv/openwsman.h b/src/hyperv/openwsman.h index f66ed86..49b3e39 100644 --- a/src/hyperv/openwsman.h +++ b/src/hyperv/openwsman.h @@ -44,3 +44,7 @@ # endif #endif /* __OPENWSMAN_H__ */ + +/*wsman-xml.h*/ +WsXmlDocH ws_xml_create_doc( const char *rootNsUri, const char *rootName); +WsXmlNodeH xml_parser_get_root(WsXmlDocH doc); -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list