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:
parent
84bddb030c
commit
6847a0ef92
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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_()
|
||||
|
|
Loading…
Reference in New Issue