vmutils: Allows updating and disabling instance RemoteFX

When resizing an instance, if it was imported, its resources
needs to be updated according to the new flavor. If a flavor
has different RemoteFX requirements, os_win should allow updates
to the instance's RemoteFX configuration.

Change-Id: Ib83bbc5c7fd07b55888f58d3407e1dd1a50e9b7e
Partial-Bug: #1663238
(cherry picked from commit ac07fcd78b)
This commit is contained in:
Claudiu Belu 2017-02-15 19:01:41 +02:00
parent e0e92d0099
commit 3c7d3b732d
4 changed files with 166 additions and 49 deletions

View File

@ -1210,12 +1210,51 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
self._vmutils._validate_remotefx_params,
1, '1024x700')
@ddt.data(True, False)
@mock.patch.object(vmutils.VMUtils, '_set_remotefx_vram')
@mock.patch.object(vmutils.VMUtils, '_get_new_resource_setting_data')
def test_set_remotefx_display_controller(self, new_obj, mock_get_new_rsd,
mock_set_remotefx_vram):
if new_obj:
remotefx_ctrl_res = None
expected_res = mock_get_new_rsd.return_value
else:
remotefx_ctrl_res = mock.MagicMock()
expected_res = remotefx_ctrl_res
self._vmutils._set_remotefx_display_controller(
mock.sentinel.fake_vm, remotefx_ctrl_res,
mock.sentinel.monitor_count, mock.sentinel.max_resolution,
mock.sentinel.vram_bytes)
self.assertEqual(mock.sentinel.monitor_count,
expected_res.MaximumMonitors)
self.assertEqual(mock.sentinel.max_resolution,
expected_res.MaximumScreenResolution)
mock_set_remotefx_vram.assert_called_once_with(
expected_res, mock.sentinel.vram_bytes)
if new_obj:
mock_get_new_rsd.assert_called_once_with(
self._vmutils._REMOTEFX_DISP_CTRL_RES_SUB_TYPE,
self._vmutils._REMOTEFX_DISP_ALLOCATION_SETTING_DATA_CLASS)
self._vmutils._jobutils.add_virt_resource.assert_called_once_with(
expected_res, mock.sentinel.fake_vm)
else:
self.assertFalse(mock_get_new_rsd.called)
modify_virt_res = self._vmutils._jobutils.modify_virt_resource
modify_virt_res.assert_called_once_with(expected_res)
def test_set_remotefx_vram(self):
self._vmutils._set_remotefx_vram(mock.sentinel.remotefx_ctrl_res,
mock.sentinel.vram_bytes)
@mock.patch.object(_wqlutils, 'get_element_associated_class')
@mock.patch.object(vmutils.VMUtils, '_add_3d_display_controller')
@mock.patch.object(vmutils.VMUtils, '_set_remotefx_display_controller')
@mock.patch.object(vmutils.VMUtils, '_vm_has_s3_controller')
def test_enable_remotefx_video_adapter(self,
mock_vm_has_s3_controller,
mock_add_3d_ctrl,
mock_set_remotefx_ctrl,
mock_get_element_associated_class):
mock_vm = self._lookup_vm()
@ -1235,12 +1274,12 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
mock_get_element_associated_class.assert_called_once_with(
self._vmutils._conn,
self._vmutils._CIM_RES_ALLOC_SETTING_DATA_CLASS,
element_uuid=mock_vm.Name)
element_instance_id=mock_vm.InstanceID)
self._vmutils._jobutils.remove_virt_resource.assert_called_once_with(
mock_r1)
mock_add_3d_ctrl.assert_called_once_with(
mock_vm, self._FAKE_MONITOR_COUNT,
mock_set_remotefx_ctrl.assert_called_once_with(
mock_vm, None, self._FAKE_MONITOR_COUNT,
self._vmutils._remote_fx_res_map[
constants.REMOTEFX_MAX_RES_1024x768],
None)
@ -1250,24 +1289,53 @@ class VMUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(self._vmutils._DISP_CTRL_ADDRESS_DX_11,
mock_r2.Address)
@mock.patch.object(vmutils.VMUtils, '_vm_has_s3_controller')
@mock.patch.object(vmutils.VMUtils, '_get_new_resource_setting_data')
@mock.patch.object(_wqlutils, 'get_element_associated_class')
def test_enable_remotefx_video_adapter_already_configured(
self, mock_get_element_associated_class):
def test_disable_remotefx_video_adapter(self,
mock_get_element_associated_class,
mock_get_new_rsd,
mock_vm_has_s3_controller):
mock_vm = self._lookup_vm()
mock_r1 = mock.MagicMock(
ResourceSubType=self._vmutils._REMOTEFX_DISP_CTRL_RES_SUB_TYPE)
mock_r2 = mock.MagicMock(
ResourceSubType=self._vmutils._S3_DISP_CTRL_RES_SUB_TYPE)
mock_r = mock.MagicMock()
mock_r.ResourceSubType = self._vmutils._SYNTH_3D_DISP_CTRL_RES_SUB_TYPE
mock_get_element_associated_class.return_value = [mock_r1, mock_r2]
mock_get_element_associated_class.return_value = [mock_r]
self._vmutils.disable_remotefx_video_adapter(
mock.sentinel.fake_vm_name)
self.assertRaises(exceptions.HyperVRemoteFXException,
self._vmutils.enable_remotefx_video_adapter,
mock.sentinel.fake_vm_name, self._FAKE_MONITOR_COUNT,
constants.REMOTEFX_MAX_RES_1024x768)
mock_get_element_associated_class.assert_called_once_with(
self._vmutils._conn,
self._vmutils._CIM_RES_ALLOC_SETTING_DATA_CLASS,
element_uuid=mock_vm.Name)
element_instance_id=mock_vm.InstanceID)
self._vmutils._jobutils.remove_virt_resource.assert_called_once_with(
mock_r1)
mock_get_new_rsd.assert_called_once_with(
self._vmutils._SYNTH_DISP_CTRL_RES_SUB_TYPE,
self._vmutils._SYNTH_DISP_ALLOCATION_SETTING_DATA_CLASS)
self._vmutils._jobutils.add_virt_resource.assert_called_once_with(
mock_get_new_rsd.return_value, mock_vm)
self._vmutils._jobutils.modify_virt_resource.assert_called_once_with(
mock_r2)
self.assertEqual(self._vmutils._DISP_CTRL_ADDRESS, mock_r2.Address)
@mock.patch.object(_wqlutils, 'get_element_associated_class')
def test_disable_remotefx_video_adapter_not_found(
self, mock_get_element_associated_class):
mock_vm = self._lookup_vm()
mock_get_element_associated_class.return_value = []
self._vmutils.disable_remotefx_video_adapter(
mock.sentinel.fake_vm_name)
mock_get_element_associated_class.assert_called_once_with(
self._vmutils._conn,
self._vmutils._CIM_RES_ALLOC_SETTING_DATA_CLASS,
element_instance_id=mock_vm.InstanceID)
self.assertFalse(self._vmutils._jobutils.remove_virt_resource.called)
@mock.patch.object(vmutils.VMUtils, 'get_vm_generation')
def test_vm_has_s3_controller(self, mock_get_vm_generation):

View File

@ -14,6 +14,7 @@
import ddt
import mock
import six
from os_win import constants
from os_win import exceptions
@ -118,6 +119,18 @@ class VMUtils10TestCase(test_base.OsWinBaseTestCase):
1, constants.REMOTEFX_MAX_RES_1024x768,
vram_bytes=10000)
def test_validate_remotefx(self):
self._vmutils._validate_remotefx_params(
1, constants.REMOTEFX_MAX_RES_1024x768)
def test_set_remotefx_vram(self):
remotefx_ctrl_res = mock.MagicMock()
vram_bytes = 512
self._vmutils._set_remotefx_vram(remotefx_ctrl_res, vram_bytes)
self.assertEqual(six.text_type(vram_bytes),
remotefx_ctrl_res.VRAMSizeBytes)
@mock.patch.object(vmutils10.VMUtils10, 'get_vm_generation')
def _test_vm_has_s3_controller(self, vm_gen, mock_get_vm_gen):
mock_get_vm_gen.return_value = vm_gen

View File

@ -75,9 +75,11 @@ class VMUtils(baseutils.BaseUtilsVirt):
_S3_DISP_CTRL_RES_SUB_TYPE = 'Microsoft:Hyper-V:S3 Display Controller'
_SYNTH_DISP_CTRL_RES_SUB_TYPE = ('Microsoft:Hyper-V:Synthetic Display '
'Controller')
_SYNTH_3D_DISP_CTRL_RES_SUB_TYPE = ('Microsoft:Hyper-V:Synthetic 3D '
_REMOTEFX_DISP_CTRL_RES_SUB_TYPE = ('Microsoft:Hyper-V:Synthetic 3D '
'Display Controller')
_SYNTH_3D_DISP_ALLOCATION_SETTING_DATA_CLASS = (
_SYNTH_DISP_ALLOCATION_SETTING_DATA_CLASS = (
'Msvm_SyntheticDisplayControllerSettingData')
_REMOTEFX_DISP_ALLOCATION_SETTING_DATA_CLASS = (
'Msvm_Synthetic3DDisplayControllerSettingData')
_VIRTUAL_SYSTEM_SUBTYPE = 'VirtualSystemSubType'
@ -112,6 +114,7 @@ class VMUtils(baseutils.BaseUtilsVirt):
}
_DISP_CTRL_ADDRESS_DX_11 = "02C1,00000000,01"
_DISP_CTRL_ADDRESS = "5353,00000000,00"
_vm_power_states_map = {constants.HYPERV_VM_STATE_ENABLED: 2,
constants.HYPERV_VM_STATE_DISABLED: 3,
@ -1067,44 +1070,86 @@ class VMUtils(baseutils.BaseUtilsVirt):
'max_monitors':
self._remotefx_max_monitors_map[max_resolution]})
def _add_3d_display_controller(self, vm, monitor_count,
max_resolution, vram_bytes=None):
synth_3d_disp_ctrl_res = self._get_new_resource_setting_data(
self._SYNTH_3D_DISP_CTRL_RES_SUB_TYPE,
self._SYNTH_3D_DISP_ALLOCATION_SETTING_DATA_CLASS)
def _set_remotefx_display_controller(self, vm, remotefx_disp_ctrl_res,
monitor_count, max_resolution,
vram_bytes=None):
new_wmi_obj = False
if not remotefx_disp_ctrl_res:
new_wmi_obj = True
remotefx_disp_ctrl_res = self._get_new_resource_setting_data(
self._REMOTEFX_DISP_CTRL_RES_SUB_TYPE,
self._REMOTEFX_DISP_ALLOCATION_SETTING_DATA_CLASS)
synth_3d_disp_ctrl_res.MaximumMonitors = monitor_count
synth_3d_disp_ctrl_res.MaximumScreenResolution = max_resolution
remotefx_disp_ctrl_res.MaximumMonitors = monitor_count
remotefx_disp_ctrl_res.MaximumScreenResolution = max_resolution
self._set_remotefx_vram(remotefx_disp_ctrl_res, vram_bytes)
self._jobutils.add_virt_resource(synth_3d_disp_ctrl_res, vm)
if new_wmi_obj:
self._jobutils.add_virt_resource(remotefx_disp_ctrl_res, vm)
else:
self._jobutils.modify_virt_resource(remotefx_disp_ctrl_res)
def _set_remotefx_vram(self, remotefx_disp_ctrl_res, vram_bytes):
pass
def enable_remotefx_video_adapter(self, vm_name, monitor_count,
max_resolution, vram_bytes=None):
vm = self._lookup_vm_check(vm_name, as_vssd=False)
self._validate_remotefx_params(monitor_count, max_resolution,
vram_bytes=vram_bytes)
vm = self._lookup_vm_check(vm_name)
rasds = _wqlutils.get_element_associated_class(
self._compat_conn, self._CIM_RES_ALLOC_SETTING_DATA_CLASS,
element_uuid=vm.Name)
if [r for r in rasds if r.ResourceSubType ==
self._SYNTH_3D_DISP_CTRL_RES_SUB_TYPE]:
raise exceptions.HyperVRemoteFXException(
_("RemoteFX is already configured for this VM"))
element_instance_id=vm.InstanceID)
synth_disp_ctrl_res_list = [r for r in rasds if r.ResourceSubType ==
self._SYNTH_DISP_CTRL_RES_SUB_TYPE]
if synth_disp_ctrl_res_list:
# we need to remove the generic display controller first.
self._jobutils.remove_virt_resource(synth_disp_ctrl_res_list[0])
remotefx_disp_ctrl_res = [r for r in rasds if r.ResourceSubType ==
self._REMOTEFX_DISP_CTRL_RES_SUB_TYPE]
remotefx_disp_ctrl_res = (remotefx_disp_ctrl_res[0]
if remotefx_disp_ctrl_res else None)
max_res_value = self._remote_fx_res_map.get(max_resolution)
self._add_3d_display_controller(vm, monitor_count, max_res_value,
vram_bytes)
if self._vm_has_s3_controller(vm.ElementName):
self._set_remotefx_display_controller(
vm, remotefx_disp_ctrl_res, monitor_count, max_res_value,
vram_bytes)
if self._vm_has_s3_controller(vm_name):
s3_disp_ctrl_res = [r for r in rasds if r.ResourceSubType ==
self._S3_DISP_CTRL_RES_SUB_TYPE][0]
s3_disp_ctrl_res.Address = self._DISP_CTRL_ADDRESS_DX_11
if s3_disp_ctrl_res.Address != self._DISP_CTRL_ADDRESS_DX_11:
s3_disp_ctrl_res.Address = self._DISP_CTRL_ADDRESS_DX_11
self._jobutils.modify_virt_resource(s3_disp_ctrl_res)
def disable_remotefx_video_adapter(self, vm_name):
vm = self._lookup_vm_check(vm_name)
rasds = _wqlutils.get_element_associated_class(
self._compat_conn, self._CIM_RES_ALLOC_SETTING_DATA_CLASS,
element_instance_id=vm.InstanceID)
remotefx_disp_ctrl_res = [r for r in rasds if r.ResourceSubType ==
self._REMOTEFX_DISP_CTRL_RES_SUB_TYPE]
if not remotefx_disp_ctrl_res:
# VM does not have RemoteFX configured.
return
# we need to remove the RemoteFX display controller first.
self._jobutils.remove_virt_resource(remotefx_disp_ctrl_res[0])
synth_disp_ctrl_res = self._get_new_resource_setting_data(
self._SYNTH_DISP_CTRL_RES_SUB_TYPE,
self._SYNTH_DISP_ALLOCATION_SETTING_DATA_CLASS)
self._jobutils.add_virt_resource(synth_disp_ctrl_res, vm)
if self._vm_has_s3_controller(vm_name):
s3_disp_ctrl_res = [r for r in rasds if r.ResourceSubType ==
self._S3_DISP_CTRL_RES_SUB_TYPE][0]
s3_disp_ctrl_res.Address = self._DISP_CTRL_ADDRESS
self._jobutils.modify_virt_resource(s3_disp_ctrl_res)
def _vm_has_s3_controller(self, vm_name):

View File

@ -16,6 +16,7 @@
import re
from oslo_log import log as logging
import six
from os_win._i18n import _
from os_win import constants
@ -112,26 +113,16 @@ class VMUtils10(vmutils.VMUtils):
vram_bytes=None):
super(VMUtils10, self)._validate_remotefx_params(monitor_count,
max_resolution)
if vram_bytes not in self._remotefx_vram_vals:
if vram_bytes and vram_bytes not in self._remotefx_vram_vals:
raise exceptions.HyperVRemoteFXException(
_("Unsuported RemoteFX VRAM value: %(requested_value)s."
"The supported VRAM values are: %(supported_values)s") %
{'requested_value': vram_bytes,
'supported_values': self._remotefx_vram_vals})
def _add_3d_display_controller(self, vm, monitor_count,
max_resolution, vram_bytes=None):
synth_3d_disp_ctrl_res = self._get_new_resource_setting_data(
self._SYNTH_3D_DISP_CTRL_RES_SUB_TYPE,
self._SYNTH_3D_DISP_ALLOCATION_SETTING_DATA_CLASS)
synth_3d_disp_ctrl_res.MaximumMonitors = monitor_count
synth_3d_disp_ctrl_res.MaximumScreenResolution = max_resolution
def _set_remotefx_vram(self, remotefx_disp_ctrl_res, vram_bytes):
if vram_bytes:
synth_3d_disp_ctrl_res.VRAMSizeBytes = unicode(vram_bytes)
self._jobutils.add_virt_resource(synth_3d_disp_ctrl_res, vm)
remotefx_disp_ctrl_res.VRAMSizeBytes = six.text_type(vram_bytes)
def _vm_has_s3_controller(self, vm_name):
return self.get_vm_generation(vm_name) == constants.VM_GEN_1