Co-authored-by: Sri Ramanujam <sramanujam(a)datto.com>
Signed-off-by: Matt Coleman <matt(a)datto.com>
---
src/hyperv/hyperv_driver.c | 244 +++++++++++++++++++++++++++++++-
src/hyperv/hyperv_wmi_classes.h | 1 +
2 files changed, 242 insertions(+), 3 deletions(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
index 1ad52e598a..a3da2ec524 100644
--- a/src/hyperv/hyperv_driver.c
+++ b/src/hyperv/hyperv_driver.c
@@ -327,6 +327,30 @@ hypervGetDeviceParentRasdFromDeviceId(const char *parentDeviceId,
}
+static char *
+hypervGetInstanceIDFromXMLResponse(WsXmlDocH response)
+{
+ WsXmlNodeH envelope = NULL;
+ char *instanceId = NULL;
+
+ envelope = ws_xml_get_soap_envelope(response);
+ if (!envelope) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid XML
response"));
+ return NULL;
+ }
+
+ instanceId = ws_xml_get_xpath_value(response, (char
*)"//w:Selector[@Name='InstanceID']");
+
+ if (!instanceId) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not find selectors in method response"));
+ return NULL;
+ }
+
+ return instanceId;
+}
+
+
static int
hypervDomainCreateSCSIController(virDomainPtr domain)
{
@@ -359,10 +383,175 @@ hypervDomainCreateSCSIController(virDomainPtr domain)
static int
-hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def)
+hypervDomainAddVirtualDiskParent(virDomainPtr domain,
+ virDomainDiskDefPtr disk,
+ Msvm_ResourceAllocationSettingData *controller,
+ const char *hostname,
+ WsXmlDocH *response)
{
+ g_autoptr(GHashTable) controllerResource = NULL;
+ g_autofree char *parentInstanceIDEscaped = NULL;
+ g_autofree char *parent__PATH = NULL;
+ g_autofree char *addressString = g_strdup_printf("%u",
disk->info.addr.drive.unit);
+ g_autofree char *resourceType = NULL;
+
+ resourceType = g_strdup_printf("%d", MSVM_RASD_RESOURCETYPE_DISK_DRIVE);
+
+ controllerResource =
hypervCreateEmbeddedParam(Msvm_ResourceAllocationSettingData_WmiInfo);
+ if (!controllerResource)
+ return -1;
+
+ parentInstanceIDEscaped = virStringReplace(controller->data->InstanceID,
"\\", "\\\\");
+ parent__PATH = g_strdup_printf("\\\\%s\\Root\\Virtualization\\V2:"
+
"Msvm_ResourceAllocationSettingData.InstanceID=\"%s\"",
+ hostname, parentInstanceIDEscaped);
+ if (!parent__PATH)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(controllerResource, "Parent", parent__PATH)
< 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(controllerResource, "AddressOnParent",
addressString) < 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(controllerResource, "ResourceType",
resourceType) < 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(controllerResource, "ResourceSubType",
+ "Microsoft:Hyper-V:Synthetic Disk Drive")
< 0)
+ return -1;
+
+ if (hypervMsvmVSMSAddResourceSettings(domain, &controllerResource,
+ Msvm_ResourceAllocationSettingData_WmiInfo,
+ response) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+hypervDomainAddVirtualHardDisk(virDomainPtr domain,
+ virDomainDiskDefPtr disk,
+ const char *hostname,
+ char *parentInstanceID)
+{
+ g_autoptr(GHashTable) volumeResource = NULL;
+ g_autofree char *vhdInstanceIdEscaped = NULL;
+ g_autofree char *vhd__PATH = NULL;
+ g_autofree char *resourceType = NULL;
+
+ resourceType = g_strdup_printf("%d", MSVM_RASD_RESOURCETYPE_LOGICAL_DISK);
+
+ volumeResource =
hypervCreateEmbeddedParam(Msvm_ResourceAllocationSettingData_WmiInfo);
+ if (!volumeResource)
+ return -1;
+
+ vhdInstanceIdEscaped = virStringReplace(parentInstanceID, "\\",
"\\\\");
+ vhd__PATH = g_strdup_printf("\\\\%s\\Root\\Virtualization\\V2:"
+
"Msvm_ResourceAllocationSettingData.InstanceID=\"%s\"",
+ hostname, vhdInstanceIdEscaped);
+
+ if (!vhd__PATH)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(volumeResource, "Parent", vhd__PATH) < 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(volumeResource, "HostResource",
disk->src->path) < 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(volumeResource, "ResourceType", resourceType)
< 0)
+ return -1;
+
+ if (hypervSetEmbeddedProperty(volumeResource, "ResourceSubType",
+ "Microsoft:Hyper-V:Virtual Hard Disk") <
0)
+ return -1;
+
+ if (hypervMsvmVSMSAddResourceSettings(domain, &volumeResource,
+ Msvm_ResourceAllocationSettingData_WmiInfo,
+ NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+hypervDomainAttachVirtualDisk(virDomainPtr domain,
+ virDomainDiskDefPtr disk,
+ Msvm_ResourceAllocationSettingData *controller,
+ const char *hostname)
+{
+ int result = -1;
+ g_autofree char *parentInstanceID = NULL;
+ WsXmlDocH response = NULL;
+
+ VIR_DEBUG("Now attaching disk image '%s' with address %d to bus %d of
type %d",
+ disk->src->path, disk->info.addr.drive.unit,
disk->info.addr.drive.controller, disk->bus);
+
+ if (hypervDomainAddVirtualDiskParent(domain, disk, controller, hostname,
&response) < 0)
+ return -1;
+
+ if (!response) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add
virtual disk parent"));
+ return -1;
+ }
+
+ parentInstanceID = hypervGetInstanceIDFromXMLResponse(response);
+ if (!parentInstanceID)
+ goto cleanup;
+
+ if (hypervDomainAddVirtualHardDisk(domain, disk, hostname, parentInstanceID) < 0)
+ goto cleanup;
+
+ result = 0;
+
+ cleanup:
+ ws_xml_destroy_doc(response);
+
+ return result;
+}
+
+
+static int
+hypervDomainAttachStorageVolume(virDomainPtr domain,
+ virDomainDiskDefPtr disk,
+ Msvm_ResourceAllocationSettingData *controller,
+ const char *hostname)
+{
+ switch (disk->device) {
+ case VIR_DOMAIN_DISK_DEVICE_DISK:
+ if (disk->src->type == VIR_STORAGE_TYPE_FILE)
+ return hypervDomainAttachVirtualDisk(domain, disk, controller, hostname);
+ else
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported
disk type"));
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported disk
bus"));
+ break;
+ }
+
+ return -1;
+}
+
+
+static int
+hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def, const char
*hostname)
+{
+ int result = -1;
+ hypervPrivate *priv = domain->conn->privateData;
size_t i = 0;
+ char uuid_string[VIR_UUID_STRING_BUFLEN];
+ int num_scsi_controllers = 0;
+ int ctrlr_idx = -1;
+ Msvm_VirtualSystemSettingData *vssd = NULL;
+ Msvm_ResourceAllocationSettingData *rasd = NULL;
+ Msvm_ResourceAllocationSettingData *entry = NULL;
+ Msvm_ResourceAllocationSettingData *ideChannels[HYPERV_MAX_IDE_CHANNELS];
+ Msvm_ResourceAllocationSettingData *scsiControllers[HYPERV_MAX_SCSI_CONTROLLERS];
+ /* start with attaching scsi controllers */
for (i = 0; i < def->ncontrollers; i++) {
if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
continue;
@@ -371,7 +560,55 @@ hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def)
return -1;
}
- return 0;
+ virUUIDFormat(domain->uuid, uuid_string);
+
+ /* filter through all the rasd entries and isolate our controllers */
+ if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) <
0)
+ goto cleanup;
+
+ if (hypervGetResourceAllocationSD(priv, vssd->data->InstanceID, &rasd) <
0)
+ goto cleanup;
+
+ entry = rasd;
+ while (entry) {
+ if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER)
+ ideChannels[entry->data->Address[0] - '0'] = entry;
+ else if (entry->data->ResourceType ==
MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA)
+ scsiControllers[num_scsi_controllers++] = entry;
+
+ entry = entry->next;
+ }
+
+ /* now we loop through and attach all the disks */
+ for (i = 0; i < def->ndisks; i++) {
+ switch (def->disks[i]->bus) {
+ case VIR_DOMAIN_DISK_BUS_IDE:
+ ctrlr_idx = def->disks[i]->info.addr.drive.bus;
+ if (hypervDomainAttachStorageVolume(domain, def->disks[i],
+ ideChannels[ctrlr_idx], hostname) < 0)
{
+ goto cleanup;
+ }
+ break;
+ case VIR_DOMAIN_DISK_BUS_SCSI:
+ ctrlr_idx = def->disks[i]->info.addr.drive.controller;
+ if (hypervDomainAttachStorageVolume(domain, def->disks[i],
+ scsiControllers[ctrlr_idx], hostname)
< 0) {
+ goto cleanup;
+ }
+ break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported
controller type"));
+ goto cleanup;
+ }
+ }
+
+ result = 0;
+
+ cleanup:
+ hypervFreeObject(priv, (hypervObject *)rasd);
+ hypervFreeObject(priv, (hypervObject *)vssd);
+
+ return result;
}
@@ -1991,6 +2228,7 @@ static virDomainPtr
hypervDomainDefineXML(virConnectPtr conn, const char *xml)
{
hypervPrivate *priv = conn->privateData;
+ g_autofree char *hostname = hypervConnectGetHostname(conn);
g_autoptr(virDomainDef) def = NULL;
virDomainPtr domain = NULL;
g_autoptr(hypervInvokeParamsList) params = NULL;
@@ -2051,7 +2289,7 @@ hypervDomainDefineXML(virConnectPtr conn, const char *xml)
goto error;
/* attach all storage */
- if (hypervDomainAttachStorage(domain, def) < 0)
+ if (hypervDomainAttachStorage(domain, def, hostname) < 0)
goto error;
return domain;
diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h
index 36c0e60c2a..2c03ca3745 100644
--- a/src/hyperv/hyperv_wmi_classes.h
+++ b/src/hyperv/hyperv_wmi_classes.h
@@ -113,6 +113,7 @@ enum _Msvm_ResourceAllocationSettingData_ResourceType {
MSVM_RASD_RESOURCETYPE_DVD_DRIVE = 16,
MSVM_RASD_RESOURCETYPE_DISK_DRIVE = 17,
MSVM_RASD_RESOURCETYPE_STORAGE_EXTENT = 19,
+ MSVM_RASD_RESOURCETYPE_LOGICAL_DISK = 31,
};
--
2.27.0