Fixes get_vm_storage_paths issue for Hyper-V V2 API

Add get_vm_storage_paths function to vmutilsv2.py

get_vm_storage_paths implementation on Hyper-V V2 API changed
compared to previous V1 API. In previous V1 APIs, using
Msvm_ResourceAllocationSettingData class can get storage
paths, but in V2 API, only using Msvm_StorageAllocationSettingData
class can get the storage paths.

Closes-Bug: #1248463

Change-Id: Ica73221524f162a6ffcd9dc64ee33c85fb5ad31d
This commit is contained in:
jufeng 2013-11-07 14:12:36 +08:00 committed by Feng Ju
parent 84bddb030c
commit 6847a0ef92
4 changed files with 117 additions and 33 deletions

View File

@ -28,6 +28,8 @@ class VMUtilsTestCase(test.NoDBTestCase):
_FAKE_VM_NAME = 'fake_vm'
_FAKE_MEMORY_MB = 2
_FAKE_VM_PATH = "fake_vm_path"
_FAKE_VHD_PATH = "fake_vhd_path"
_FAKE_VOLUME_DRIVE_PATH = "fake_volume_drive_path"
def setUp(self):
self._vmutils = vmutils.VMUtils()
@ -75,3 +77,29 @@ class VMUtilsTestCase(test.NoDBTestCase):
self.assertTrue(mock_s.DynamicMemoryEnabled)
else:
self.assertFalse(mock_s.DynamicMemoryEnabled)
def test_get_vm_storage_paths(self):
mock_vm = self._lookup_vm()
mock_vmsettings = [mock.MagicMock()]
mock_vm.associators.return_value = mock_vmsettings
mock_rasds = []
mock_rasd1 = mock.MagicMock()
mock_rasd1.ResourceSubType = self._vmutils._IDE_DISK_RES_SUB_TYPE
mock_rasd1.Connection = [self._FAKE_VHD_PATH]
mock_rasd2 = mock.MagicMock()
mock_rasd2.ResourceSubType = self._vmutils._PHYS_DISK_RES_SUB_TYPE
mock_rasd2.HostResource = [self._FAKE_VOLUME_DRIVE_PATH]
mock_rasds.append(mock_rasd1)
mock_rasds.append(mock_rasd2)
mock_vmsettings[0].associators.return_value = mock_rasds
storage = self._vmutils.get_vm_storage_paths(self._FAKE_VM_NAME)
(disk_files, volume_drives) = storage
mock_vm.associators.assert_called_with(
wmi_result_class='Msvm_VirtualSystemSettingData')
mock_vmsettings[0].associators.assert_called_with(
wmi_result_class='Msvm_ResourceAllocationSettingData')
self.assertEqual([self._FAKE_VHD_PATH], disk_files)
self.assertEqual([self._FAKE_VOLUME_DRIVE_PATH], volume_drives)

View File

@ -39,6 +39,8 @@ class VMUtilsV2TestCase(test.NoDBTestCase):
_FAKE_RES_DATA = "fake_res_data"
_FAKE_RES_PATH = "fake_res_path"
_FAKE_DYNAMIC_MEMORY_RATIO = 1.0
_FAKE_VHD_PATH = "fake_vhd_path"
_FAKE_VOLUME_DRIVE_PATH = "fake_volume_drive_path"
def setUp(self):
self._vmutils = vmutilsv2.VMUtilsV2()
@ -115,6 +117,32 @@ class VMUtilsV2TestCase(test.NoDBTestCase):
self.assertTrue(self._vmutils._add_virt_resource.called)
def test_get_vm_storage_paths(self):
mock_vm = self._lookup_vm()
mock_vmsettings = [mock.MagicMock()]
mock_vm.associators.return_value = mock_vmsettings
mock_sasds = []
mock_sasd1 = mock.MagicMock()
mock_sasd1.ResourceSubType = self._vmutils._IDE_DISK_RES_SUB_TYPE
mock_sasd1.HostResource = [self._FAKE_VHD_PATH]
mock_sasd2 = mock.MagicMock()
mock_sasd2.ResourceSubType = self._vmutils._PHYS_DISK_RES_SUB_TYPE
mock_sasd2.HostResource = [self._FAKE_VOLUME_DRIVE_PATH]
mock_sasds.append(mock_sasd1)
mock_sasds.append(mock_sasd2)
mock_vmsettings[0].associators.return_value = mock_sasds
storage = self._vmutils.get_vm_storage_paths(self._FAKE_VM_NAME)
(disk_files, volume_drives) = storage
mock_vm.associators.assert_called_with(
wmi_result_class='Msvm_VirtualSystemSettingData')
mock_vmsettings[0].associators.assert_called_with(
wmi_result_class='Msvm_StorageAllocationSettingData')
self.assertEqual([self._FAKE_VHD_PATH], disk_files)
self.assertEqual([self._FAKE_VOLUME_DRIVE_PATH], volume_drives)
def test_destroy(self):
self._lookup_vm()

View File

@ -67,6 +67,16 @@ class VMUtils(object):
_IDE_CTRL_RES_SUB_TYPE = 'Microsoft Emulated IDE Controller'
_SCSI_CTRL_RES_SUB_TYPE = 'Microsoft Synthetic SCSI Controller'
_SETTINGS_DEFINE_STATE_CLASS = 'Msvm_SettingsDefineState'
_VIRTUAL_SYSTEM_SETTING_DATA_CLASS = 'Msvm_VirtualSystemSettingData'
_RESOURCE_ALLOC_SETTING_DATA_CLASS = 'Msvm_ResourceAllocationSettingData'
_PROCESSOR_SETTING_DATA_CLASS = 'Msvm_ProcessorSettingData'
_MEMORY_SETTING_DATA_CLASS = 'Msvm_MemorySettingData'
_STORAGE_ALLOC_SETTING_DATA_CLASS = _RESOURCE_ALLOC_SETTING_DATA_CLASS
_SYNTHETIC_ETHERNET_PORT_SETTING_DATA_CLASS = \
'Msvm_SyntheticEthernetPortSettingData'
_AFFECTED_JOB_ELEMENT_CLASS = "Msvm_AffectedJobElement"
_vm_power_states_map = {constants.HYPERV_VM_STATE_ENABLED: 2,
constants.HYPERV_VM_STATE_DISABLED: 3,
constants.HYPERV_VM_STATE_REBOOT: 10,
@ -95,8 +105,8 @@ class VMUtils(object):
vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0]
vmsettings = vm.associators(
wmi_association_class='Msvm_SettingsDefineState',
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_association_class=self._SETTINGS_DEFINE_STATE_CLASS,
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
settings_paths = [v.path_() for v in vmsettings]
#See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx
(ret_val, summary_info) = vs_man_svc.GetSummaryInformation(
@ -146,13 +156,13 @@ class VMUtils(object):
def _get_vm_setting_data(self, vm):
vmsettings = vm.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
# Avoid snapshots
return [s for s in vmsettings if s.SettingType == 3][0]
def _set_vm_memory(self, vm, vmsetting, memory_mb, dynamic_memory_ratio):
mem_settings = vmsetting.associators(
wmi_result_class='Msvm_MemorySettingData')[0]
wmi_result_class=self._MEMORY_SETTING_DATA_CLASS)[0]
max_mem = long(memory_mb)
mem_settings.Limit = max_mem
@ -175,7 +185,7 @@ class VMUtils(object):
def _set_vm_vcpus(self, vm, vmsetting, vcpus_num, limit_cpu_features):
procsetting = vmsetting.associators(
wmi_result_class='Msvm_ProcessorSettingData')[0]
wmi_result_class=self._PROCESSOR_SETTING_DATA_CLASS)[0]
vcpus = long(vcpus_num)
procsetting.VirtualQuantity = vcpus
procsetting.Reservation = vcpus
@ -229,18 +239,18 @@ class VMUtils(object):
vm = self._lookup_vm_check(vm_name)
vmsettings = vm.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
rasds = vmsettings[0].associators(
wmi_result_class='MSVM_ResourceAllocationSettingData')
wmi_result_class=self._RESOURCE_ALLOC_SETTING_DATA_CLASS)
res = [r for r in rasds
if r.ResourceSubType == self._SCSI_CTRL_RES_SUB_TYPE][0]
return res.path_()
def _get_vm_ide_controller(self, vm, ctrller_addr):
vmsettings = vm.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
rasds = vmsettings[0].associators(
wmi_result_class='MSVM_ResourceAllocationSettingData')
wmi_result_class=self._RESOURCE_ALLOC_SETTING_DATA_CLASS)
return [r for r in rasds
if r.ResourceSubType == self._IDE_CTRL_RES_SUB_TYPE
and r.Address == str(ctrller_addr)][0].path_()
@ -250,12 +260,13 @@ class VMUtils(object):
return self._get_vm_ide_controller(vm, ctrller_addr)
def get_attached_disks_count(self, scsi_controller_path):
volumes = self._conn.query("SELECT * FROM "
"Msvm_ResourceAllocationSettingData "
volumes = self._conn.query("SELECT * FROM %(class_name)s "
"WHERE ResourceSubType = "
"'%(res_sub_type)s' AND "
"Parent = '%(parent)s'" %
{'res_sub_type':
{"class_name":
self._RESOURCE_ALLOC_SETTING_DATA_CLASS,
'res_sub_type':
self._PHYS_DISK_RES_SUB_TYPE,
'parent':
scsi_controller_path.replace("'", "''")})
@ -265,9 +276,10 @@ class VMUtils(object):
return self._conn.query("SELECT * FROM %s WHERE InstanceID "
"LIKE '%%\\Default'" % class_name)[0]
def _get_new_resource_setting_data(
self, resource_sub_type,
class_name='Msvm_ResourceAllocationSettingData'):
def _get_new_resource_setting_data(self, resource_sub_type,
class_name=None):
if class_name is None:
class_name = self._RESOURCE_ALLOC_SETTING_DATA_CLASS
return self._conn.query("SELECT * FROM %(class_name)s "
"WHERE ResourceSubType = "
"'%(res_sub_type)s' AND "
@ -349,7 +361,7 @@ class VMUtils(object):
"""Create a (synthetic) nic and attach it to the vm."""
#Create a new nic
new_nic_data = self._get_new_setting_data(
'Msvm_SyntheticEthernetPortSettingData')
self._SYNTHETIC_ETHERNET_PORT_SETTING_DATA_CLASS)
#Configure the nic
new_nic_data.ElementName = nic_name
@ -374,13 +386,16 @@ class VMUtils(object):
"to %(req_state)s"),
{'vm_name': vm_name, 'req_state': req_state})
def _get_disk_resource_disk_path(self, disk_resource):
return disk_resource.Connection
def get_vm_storage_paths(self, vm_name):
vm = self._lookup_vm_check(vm_name)
vmsettings = vm.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
rasds = vmsettings[0].associators(
wmi_result_class='Msvm_ResourceAllocationSettingData')
wmi_result_class=self._STORAGE_ALLOC_SETTING_DATA_CLASS)
disk_resources = [r for r in rasds
if r.ResourceSubType ==
self._IDE_DISK_RES_SUB_TYPE]
@ -395,7 +410,8 @@ class VMUtils(object):
disk_files = []
for disk_resource in disk_resources:
disk_files.extend([c for c in disk_resource.Connection])
disk_files.extend(
[c for c in self._get_disk_resource_disk_path(disk_resource)])
return (disk_files, volume_drives)
@ -511,7 +527,7 @@ class VMUtils(object):
job_wmi_path = job_path.replace('\\', '/')
job = wmi.WMI(moniker=job_wmi_path)
snp_setting_data = job.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')[0]
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)[0]
return snp_setting_data.path_()
def remove_vm_snapshot(self, snapshot_path):
@ -528,10 +544,12 @@ class VMUtils(object):
self._remove_virt_resource(physical_disk, vm.path_())
def _get_mounted_disk_resource_from_path(self, disk_path):
physical_disks = self._conn.query("SELECT * FROM "
"Msvm_ResourceAllocationSettingData"
" WHERE ResourceSubType = '%s'" %
self._PHYS_DISK_RES_SUB_TYPE)
physical_disks = self._conn.query("SELECT * FROM %(class_name)s "
"WHERE ResourceSubType = '%(res_sub_type)s'" %
{"class_name":
self._RESOURCE_ALLOC_SETTING_DATA_CLASS,
'res_sub_type':
self._PHYS_DISK_RES_SUB_TYPE})
for physical_disk in physical_disks:
if physical_disk.HostResource:
if physical_disk.HostResource[0].lower() == disk_path.lower():
@ -545,12 +563,15 @@ class VMUtils(object):
return mounted_disks[0].path_()
def get_controller_volume_paths(self, controller_path):
disks = self._conn.query("SELECT * FROM "
"Msvm_ResourceAllocationSettingData "
disks = self._conn.query("SELECT * FROM %(class_name)s "
"WHERE ResourceSubType = '%(res_sub_type)s' "
"AND Parent='%(parent)s'" %
{"res_sub_type": self._PHYS_DISK_RES_SUB_TYPE,
"parent": controller_path})
{"class_name":
self._RESOURCE_ALLOC_SETTING_DATA_CLASS,
"res_sub_type":
self._PHYS_DISK_RES_SUB_TYPE,
"parent":
controller_path})
disk_data = {}
for disk in disks:
if disk.HostResource:

View File

@ -58,6 +58,10 @@ class VMUtilsV2(vmutils.VMUtils):
_METRIC_ENABLED = 2
_STORAGE_ALLOC_SETTING_DATA_CLASS = 'Msvm_StorageAllocationSettingData'
_ETHERNET_PORT_ALLOCATION_SETTING_DATA_CLASS = \
'Msvm_EthernetPortAllocationSettingData'
_vm_power_states_map = {constants.HYPERV_VM_STATE_ENABLED: 2,
constants.HYPERV_VM_STATE_DISABLED: 3,
constants.HYPERV_VM_STATE_REBOOT: 11,
@ -81,12 +85,12 @@ class VMUtilsV2(vmutils.VMUtils):
SystemSettings=vs_data.GetText_(1))
job = self.check_ret_val(ret_val, job_path)
if not vm_path and job:
vm_path = job.associators("Msvm_AffectedJobElement")[0]
vm_path = job.associators(self._AFFECTED_JOB_ELEMENT_CLASS)[0]
return self._get_wmi_obj(vm_path)
def _get_vm_setting_data(self, vm):
vmsettings = vm.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)
# Avoid snapshots
return [s for s in vmsettings if
s.VirtualSystemType == self._VIRTUAL_SYSTEM_TYPE_REALIZED][0]
@ -120,7 +124,7 @@ class VMUtilsV2(vmutils.VMUtils):
res_sub_type = self._IDE_DVD_RES_SUB_TYPE
res = self._get_new_resource_setting_data(
res_sub_type, 'Msvm_StorageAllocationSettingData')
res_sub_type, self._STORAGE_ALLOC_SETTING_DATA_CLASS)
res.Parent = drive_path
res.HostResource = [path]
@ -152,6 +156,9 @@ class VMUtilsV2(vmutils.VMUtils):
vm = self._lookup_vm_check(vm_name)
self._add_virt_resource(scsicontrl, vm.path_())
def _get_disk_resource_disk_path(self, disk_resource):
return disk_resource.HostResource
def destroy_vm(self, vm_name):
vm = self._lookup_vm_check(vm_name)
@ -202,7 +209,7 @@ class VMUtilsV2(vmutils.VMUtils):
job_wmi_path = job_path.replace('\\', '/')
job = wmi.WMI(moniker=job_wmi_path)
snp_setting_data = job.associators(
wmi_result_class='Msvm_VirtualSystemSettingData')[0]
wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA_CLASS)[0]
return snp_setting_data.path_()
@ -215,7 +222,7 @@ class VMUtilsV2(vmutils.VMUtils):
nic_data = self._get_nic_data_by_name(nic_name)
eth_port_data = self._get_new_setting_data(
'Msvm_EthernetPortAllocationSettingData')
self._ETHERNET_PORT_ALLOCATION_SETTING_DATA_CLASS)
eth_port_data.HostResource = [vswitch_conn_data]
eth_port_data.Parent = nic_data.path_()