Merge "Add support for Windows Server 2016 RemoteFx features"
This commit is contained in:
commit
11825f0474
|
@ -74,6 +74,8 @@ REMOTEFX_MAX_RES_1280x1024 = "1280x1024"
|
||||||
REMOTEFX_MAX_RES_1600x1200 = "1600x1200"
|
REMOTEFX_MAX_RES_1600x1200 = "1600x1200"
|
||||||
REMOTEFX_MAX_RES_1920x1200 = "1920x1200"
|
REMOTEFX_MAX_RES_1920x1200 = "1920x1200"
|
||||||
REMOTEFX_MAX_RES_2560x1600 = "2560x1600"
|
REMOTEFX_MAX_RES_2560x1600 = "2560x1600"
|
||||||
|
REMOTEFX_MAX_RES_3840x2160 = "3840x2160"
|
||||||
|
|
||||||
|
|
||||||
FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY = "hyperv:remotefx"
|
FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY = "hyperv:remotefx"
|
||||||
|
|
||||||
|
|
|
@ -393,13 +393,7 @@ class VMOps(object):
|
||||||
remote_fx_config = flavor_extra_specs.get(
|
remote_fx_config = flavor_extra_specs.get(
|
||||||
constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY)
|
constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY)
|
||||||
if remote_fx_config:
|
if remote_fx_config:
|
||||||
if vm_gen == constants.VM_GEN_2:
|
self._configure_remotefx(instance, vm_gen, remote_fx_config)
|
||||||
reason = _("RemoteFX is not supported on generation 2 virtual "
|
|
||||||
"machines.")
|
|
||||||
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
|
|
||||||
reason=reason)
|
|
||||||
else:
|
|
||||||
self._configure_remotefx(instance, remote_fx_config)
|
|
||||||
|
|
||||||
self._vmutils.create_scsi_controller(instance_name)
|
self._vmutils.create_scsi_controller(instance_name)
|
||||||
|
|
||||||
|
@ -570,7 +564,7 @@ class VMOps(object):
|
||||||
|
|
||||||
return memory_per_numa_node, cpus_per_numa_node
|
return memory_per_numa_node, cpus_per_numa_node
|
||||||
|
|
||||||
def _configure_remotefx(self, instance, config):
|
def _configure_remotefx(self, instance, vm_gen, config):
|
||||||
if not CONF.hyperv.enable_remotefx:
|
if not CONF.hyperv.enable_remotefx:
|
||||||
reason = _("enable_remotefx configuration option needs to be set "
|
reason = _("enable_remotefx configuration option needs to be set "
|
||||||
"to True in order to use RemoteFX")
|
"to True in order to use RemoteFX")
|
||||||
|
@ -584,16 +578,25 @@ class VMOps(object):
|
||||||
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
|
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
|
||||||
reason=reason)
|
reason=reason)
|
||||||
|
|
||||||
|
if not self._vmutils.vm_gen_supports_remotefx(vm_gen):
|
||||||
|
reason = _("RemoteFX is not supported on generation %s virtual "
|
||||||
|
"machines on this version of Windows.") % vm_gen
|
||||||
|
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
|
||||||
|
reason=reason)
|
||||||
|
|
||||||
instance_name = instance.name
|
instance_name = instance.name
|
||||||
LOG.debug('Configuring RemoteFX for instance: %s', instance_name)
|
LOG.debug('Configuring RemoteFX for instance: %s', instance_name)
|
||||||
|
remotefx_args = config.split(',')
|
||||||
(remotefx_max_resolution, remotefx_monitor_count) = config.split(',')
|
remotefx_max_resolution = remotefx_args[0]
|
||||||
remotefx_monitor_count = int(remotefx_monitor_count)
|
remotefx_monitor_count = int(remotefx_args[1])
|
||||||
|
remotefx_vram = remotefx_args[2] if len(remotefx_args) == 3 else None
|
||||||
|
vram_bytes = int(remotefx_vram) * units.Mi if remotefx_vram else None
|
||||||
|
|
||||||
self._vmutils.enable_remotefx_video_adapter(
|
self._vmutils.enable_remotefx_video_adapter(
|
||||||
instance_name,
|
instance_name,
|
||||||
remotefx_monitor_count,
|
remotefx_monitor_count,
|
||||||
remotefx_max_resolution)
|
remotefx_max_resolution,
|
||||||
|
vram_bytes)
|
||||||
|
|
||||||
def attach_config_drive(self, instance, configdrive_path, vm_gen):
|
def attach_config_drive(self, instance, configdrive_path, vm_gen):
|
||||||
configdrive_ext = configdrive_path[(configdrive_path.rfind('.') + 1):]
|
configdrive_ext = configdrive_path[(configdrive_path.rfind('.') + 1):]
|
||||||
|
|
|
@ -553,6 +553,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||||
if remotefx is True:
|
if remotefx is True:
|
||||||
mock_configure_remotefx.assert_called_once_with(
|
mock_configure_remotefx.assert_called_once_with(
|
||||||
mock_instance,
|
mock_instance,
|
||||||
|
vm_gen,
|
||||||
flavor.extra_specs['hyperv:remotefx'])
|
flavor.extra_specs['hyperv:remotefx'])
|
||||||
|
|
||||||
self._vmops._vmutils.create_vm.assert_called_once_with(
|
self._vmops._vmutils.create_vm.assert_called_once_with(
|
||||||
|
@ -1440,34 +1441,45 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||||
def test_get_instance_vnuma_config_no_topology(self):
|
def test_get_instance_vnuma_config_no_topology(self):
|
||||||
self._check_get_instance_vnuma_config()
|
self._check_get_instance_vnuma_config()
|
||||||
|
|
||||||
def _test_configure_remotefx(self, fail=False):
|
def _test_configure_remotefx(self, fail=True, enable_remotefx=True):
|
||||||
self.flags(enable_remotefx=True, group='hyperv')
|
self.flags(enable_remotefx=enable_remotefx, group='hyperv')
|
||||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||||
|
|
||||||
fake_resolution = "1920x1200"
|
fake_resolution = "1920x1200"
|
||||||
fake_monitor_count = 3
|
fake_monitor_count = 3
|
||||||
fake_config = "%s,%s" % (fake_resolution, fake_monitor_count)
|
fake_vram_mb = 64
|
||||||
|
fake_config = "%s,%s,%s" % (
|
||||||
|
fake_resolution, fake_monitor_count, fake_vram_mb)
|
||||||
|
|
||||||
self._vmops._vmutils.enable_remotefx_video_adapter = mock.MagicMock()
|
|
||||||
enable_remotefx = self._vmops._vmutils.enable_remotefx_video_adapter
|
enable_remotefx = self._vmops._vmutils.enable_remotefx_video_adapter
|
||||||
self._vmops._hostutils.check_server_feature = mock.MagicMock()
|
|
||||||
|
|
||||||
if fail:
|
if fail:
|
||||||
self._vmops._hostutils.check_server_feature.return_value = False
|
|
||||||
self.assertRaises(exception.InstanceUnacceptable,
|
self.assertRaises(exception.InstanceUnacceptable,
|
||||||
self._vmops._configure_remotefx,
|
self._vmops._configure_remotefx,
|
||||||
mock_instance, fake_config)
|
mock_instance, mock.sentinel.vm_gen, fake_config)
|
||||||
else:
|
else:
|
||||||
self._vmops._configure_remotefx(mock_instance, fake_config)
|
self._vmops._configure_remotefx(
|
||||||
|
mock_instance, mock.sentinel.vm_gen, fake_config)
|
||||||
enable_remotefx.assert_called_once_with(mock_instance.name,
|
enable_remotefx.assert_called_once_with(mock_instance.name,
|
||||||
fake_monitor_count,
|
fake_monitor_count,
|
||||||
fake_resolution)
|
fake_resolution,
|
||||||
|
fake_vram_mb * units.Mi)
|
||||||
|
|
||||||
def test_configure_remotefx_exception(self):
|
def test_configure_remotefx_disabled(self):
|
||||||
self._test_configure_remotefx(fail=True)
|
self._test_configure_remotefx(enable_remotefx=False)
|
||||||
|
|
||||||
|
def test_configure_remotefx_no_server_feature(self):
|
||||||
|
self._vmops._hostutils.check_server_feature.return_value = False
|
||||||
|
self._test_configure_remotefx()
|
||||||
|
self._vmops._hostutils.check_server_feature.assert_called_once_with(
|
||||||
|
self._vmops._hostutils.FEATURE_RDS_VIRTUALIZATION)
|
||||||
|
|
||||||
|
def test_configure_remotefx_unsupported_vm_gen(self):
|
||||||
|
self._vmops._vmutils.vm_gen_supports_remotefx.return_value = False
|
||||||
|
self._test_configure_remotefx()
|
||||||
|
|
||||||
def test_configure_remotefx(self):
|
def test_configure_remotefx(self):
|
||||||
self._test_configure_remotefx()
|
self._test_configure_remotefx(fail=False)
|
||||||
|
|
||||||
@mock.patch.object(vmops.VMOps, '_get_vm_state')
|
@mock.patch.object(vmops.VMOps, '_get_vm_state')
|
||||||
def _test_check_hotplug_is_available(self, mock_get_vm_state, vm_gen,
|
def _test_check_hotplug_is_available(self, mock_get_vm_state, vm_gen,
|
||||||
|
|
Loading…
Reference in New Issue