[libvirt] [PATCH 14/16] hyperv: domain define and associated functions

Jason Miesionczek jmiesionczek at datto.com
Tue Aug 9 12:39:22 UTC 2016


---
 src/hyperv/hyperv_driver.c | 807 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 807 insertions(+)

diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index bd028ed..716fadb 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -2275,6 +2275,809 @@ hypervDomainUndefine(virDomainPtr domain)
     return hypervDomainUndefineFlags(domain, 0);
 }
 
+/*
+ * Creates 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 result = -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 */
+    if (VIR_ALLOC_N(strTemp, strlen(rasdInstanceID) + 1 + n) < 0)
+        goto cleanup;
+    while (rasdInstanceID[i] != '\0') {
+        strTemp[j] = rasdInstanceID[i];
+        if (rasdInstanceID[i] == '\\') {
+            j++;
+            strTemp[j] = '\\';
+        }
+        i++;
+        j++;
+    }
+    strTemp[j] = '\0';
+
+    /* Create the attribute __PATH */
+    /* FIXME: *__path allocated with 255 characters (static value) */
+    if (VIR_ALLOC_N(*__path, 255) < 0)
+        goto cleanup;
+    sprintf(*__path, "\\\\");
+    strcat(*__path, computerSystem->data->ElementName);
+    strcat(*__path, "\\root\\virtualization:Msvm_ResourceAllocationSettingData.InstanceID=\"");
+    strcat(*__path, strTemp);
+    strcat(*__path, "\"");
+
+    result = 0;
+
+ cleanup:
+    VIR_FREE(strTemp);
+    hypervFreeObject(priv, (hypervObject *)computerSystem);
+    virBufferFreeAndReset(&query);
+
+    return result;
+}
+
+
+
+/* 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 associated detach method
+ */
+ATTRIBUTE_UNUSED static int
+hypervDomainAttachDisk(virDomainPtr domain, virDomainDiskDefPtr disk)
+{
+    int result = -1, nb_params;
+    const char *selector = "CreationClassName=Msvm_VirtualSystemManagementService";
+    char uuid_string[VIR_UUID_STRING_BUFLEN];
+    char *ideRasdPath = NULL, *newDiskDrivePath = NULL;
+    char ideControler[2], ideControlerAddr[2];
+    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;  /* resourceAllocationSettingData subtree -> do not disallocate */
+    Msvm_ResourceAllocationSettingData *diskRasd = NULL;  /* resourceAllocationSettingData2 subtree -> do not disallocate */
+    Msvm_ResourceAllocationSettingData *newDiskDrive = NULL;  /* resourceAllocationSettingData3 subtree -> 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 */
+    if (STREQ(disk->dst, "hda")) {
+        sprintf(ideControler, "%d", 0);
+        sprintf(ideControlerAddr, "%d", 0);
+    } else if (STREQ(disk->dst, "hdb")) {
+        sprintf(ideControler, "%d", 0);
+        sprintf(ideControlerAddr, "%d", 1);
+    } else if (STREQ(disk->dst, "hdc")) {
+        sprintf(ideControler, "%d", 1);
+        sprintf(ideControlerAddr, "%d", 0);
+    } else if (STREQ(disk->dst, "hdd")) {
+        sprintf(ideControler, "%d", 1);
+        sprintf(ideControlerAddr, "%d", 1);
+    } else {
+        /* IDE Controler 0 and address 0 choosen 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 && STREQ(ideRasd->data->Address, ideControler)) {
+            /* 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;
+    if (VIR_ALLOC_N(tab_props, embeddedparam1.nbProps) < 0)
+        goto cleanup;
+    (*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;
+    if (VIR_ALLOC_N(params, nb_params) < 0)
+        goto cleanup;
+    (*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 &&
+            STREQ(newDiskDrive->data->ResourceSubType, "Microsoft Synthetic Disk Drive") &&
+            STREQ(newDiskDrive->data->Parent, ideRasdPath) &&
+            STREQ(newDiskDrive->data->Address, ideControlerAddr)) {
+            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;
+    if (VIR_ALLOC_N(tab_props, embeddedparam2.nbProps) < 0)
+        goto cleanup;
+    (*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;
+    if (VIR_ALLOC_N(params, nb_params) < 0)
+        goto cleanup;
+    (*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;
+    }
+
+    result = 0;
+
+ cleanup:
+    VIR_FREE(ideRasdPath);
+    VIR_FREE(newDiskDrivePath);
+    VIR_FREE(tab_props);
+    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 result;
+}
+
+
+/*
+ * 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;
+    int result = -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: *__path is allocated with 512 characters (static value) */
+    if (VIR_ALLOC_N(*__path, 512) < 0)
+        goto cleanup;
+    sprintf(*__path,
+            "\\\\%s\\root\\virtualization:Msvm_SwitchPort.CreationClassName=\"Msvm_SwitchPort\","
+            "Name=\"%s\",SystemCreationClassName=\"Msvm_VirtualSwitch\",SystemName=\"%s\"",
+            computerSystem->data->ElementName, switchPortName, virtualSwitchSystemName);
+
+    result = 0;
+
+ cleanup:
+    hypervFreeObject(priv, (hypervObject *) computerSystem);
+    virBufferFreeAndReset(&query);
+    return result;
+}
+
+
+
+/* hypervDomainAttachNetwork
+ * FIXME:
+ *   - implement associated detach method
+ */
+ATTRIBUTE_UNUSED static int
+hypervDomainAttachNetwork(virDomainPtr domain, virDomainNetDefPtr net)
+{
+    int result = -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;
+    if (VIR_ALLOC_N(params, nb_params) < 0)
+        goto cleanup;
+    (*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);
+    if (hypervGetSwitchPortPATH(domain, switchPort->data->Name, virtualSwitch->data->Name, &switchPortPATH) < 0) {
+        goto cleanup;
+    }
+
+    embeddedparam.nbProps = 5;
+    if (VIR_ALLOC_N(tab_props, embeddedparam.nbProps) < 0)
+        goto cleanup;
+    (*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;
+    if (VIR_ALLOC_N(params, nb_params) < 0)
+        goto cleanup;
+    (*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;
+    }
+
+    result = 0;
+
+ cleanup:
+    VIR_FREE(virtualSystemIdentifiers);
+    VIR_FREE(switchPortPATH);
+    VIR_FREE(tab_props);
+    VIR_FREE(params);
+    hypervFreeObject(priv, (hypervObject *)switchPort);
+    hypervFreeObject(priv, (hypervObject *)virtualSwitch);
+    virBufferFreeAndReset(&query);
+
+    return result;
+}
+
+
+static int
+hypervDomainAttachDeviceFlags(virDomainPtr domain, const char *xml,
+                              unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int result = -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;
+
+        /* Unsupported device type */
+        default:
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Device attachment of type %d is not implemented"), dev->type);
+            goto cleanup;
+    }
+
+    result = 0;
+
+ cleanup:
+    virDomainDefFree(def);
+    virDomainDeviceDefFree(dev);
+    VIR_FREE(xmlDomain);
+
+    return result;
+}
+
+
+
+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];
+
+    /* Parse XML domain description */
+    if ((def = virDomainDefParseString(xml, priv->caps, priv->xmlopt,
+                                       1 << VIR_DOMAIN_VIRT_HYPERV | VIR_DOMAIN_XML_INACTIVE)) == NULL) {
+        goto cleanup;
+    }
+
+    /* Create the domain if does not exist */
+    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;
+        if (VIR_ALLOC_N(tab_props, embeddedparam.nbProps) < 0)
+            goto cleanup;
+        (*tab_props).name = "ElementName";
+        (*tab_props).val = def->name;
+        embeddedparam.instanceName = "Msvm_VirtualSystemGlobalSettingData";
+        embeddedparam.prop_t = tab_props;
+
+        /* Create invokeXmlParam */
+        nb_params = 1;
+        if (VIR_ALLOC_N(params, nb_params) < 0)
+            goto cleanup;
+        (*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_memory > 0) {
+        if (hypervDomainSetMaxMemory(domain, def->mem.max_memory) < 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 ((int)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);
+    VIR_FREE(tab_props);
+    VIR_FREE(params);
+
+    return domain;
+}
+
+
+
+static virDomainPtr
+hypervDomainCreateXML(virConnectPtr conn, const char *xmlDesc, unsigned int flags)
+{
+    virDomainPtr domain;
+
+    virCheckFlags(VIR_DOMAIN_START_PAUSED | VIR_DOMAIN_START_AUTODESTROY, NULL);
+
+    /* Create the new domain */
+    domain = hypervDomainDefineXML(conn, xmlDesc);
+    if (domain == NULL)
+        return NULL;
+
+    /* Start the 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);
+        }
+    }
+
+    /* FIXME: process autodestroy flag */
+
+    return domain;
+}
+
+
 static virHypervisorDriver hypervHypervisorDriver = {
     .name = "Hyper-V",
     .connectOpen = hypervConnectOpen, /* 0.9.5 */
@@ -2330,6 +3133,10 @@ static virHypervisorDriver hypervHypervisorDriver = {
     .domainSetVcpusFlags = hypervDomainSetVcpusFlags, /* 1.2.10 */
     .domainUndefine = hypervDomainUndefine, /* 1.2.10 */
     .domainUndefineFlags = hypervDomainUndefineFlags, /* 1.2.10 */
+    .domainAttachDevice = hypervDomainAttachDevice, /* 1.2.10 */
+    .domainAttachDeviceFlags = hypervDomainAttachDeviceFlags, /* 1.2.10 */
+    .domainDefineXML = hypervDomainDefineXML, /* 1.2.10 */
+    .domainCreateXML = hypervDomainCreateXML, /* 1.2.10 */
 };
 
 /* Retrieves host system UUID  */
-- 
2.7.4




More information about the libvir-list mailing list