resync: "Adds RemoteFX support to the Hyper-V driver"

(cherry-picked from commit a39710244a8f26b0d9d80bffa41c04c84b133f17)

Change-Id: I873053f7e16941ad7b272693ece8b69e49fc7c18
This commit is contained in:
Claudiu Belu
2016-07-05 19:19:54 +03:00
parent 9d4a327cca
commit aaa7b676cb
5 changed files with 183 additions and 183 deletions

View File

@@ -69,15 +69,6 @@ IMAGE_PROP_VM_GEN_2 = "hyperv-gen2"
VM_GEN_1 = 1 VM_GEN_1 = 1
VM_GEN_2 = 2 VM_GEN_2 = 2
REMOTEFX_MAX_RES_1024x768 = "1024x768"
REMOTEFX_MAX_RES_1280x1024 = "1280x1024"
REMOTEFX_MAX_RES_1600x1200 = "1600x1200"
REMOTEFX_MAX_RES_1920x1200 = "1920x1200"
REMOTEFX_MAX_RES_2560x1600 = "2560x1600"
REMOTEFX_MAX_RES_3840x2160 = "3840x2160"
FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY = "hyperv:remotefx"
IMAGE_PROP_INTERACTIVE_SERIAL_PORT = "interactive_serial_port" IMAGE_PROP_INTERACTIVE_SERIAL_PORT = "interactive_serial_port"
IMAGE_PROP_LOGGING_SERIAL_PORT = "logging_serial_port" IMAGE_PROP_LOGGING_SERIAL_PORT = "logging_serial_port"
@@ -94,6 +85,10 @@ SERIAL_PORT_TYPES = {
# logging and interactive sessions. # logging and interactive sessions.
DEFAULT_SERIAL_CONSOLE_PORT = 1 DEFAULT_SERIAL_CONSOLE_PORT = 1
FLAVOR_ESPEC_REMOTEFX_RES = 'os:resolution'
FLAVOR_ESPEC_REMOTEFX_MONITORS = 'os:monitors'
FLAVOR_ESPEC_REMOTEFX_VRAM = 'os:vram'
SERIAL_CONSOLE_BUFFER_SIZE = 4 * units.Ki SERIAL_CONSOLE_BUFFER_SIZE = 4 * units.Ki
MAX_CONSOLE_LOG_FILE_SIZE = units.Mi // 2 MAX_CONSOLE_LOG_FILE_SIZE = units.Mi // 2

View File

@@ -138,20 +138,20 @@ class HostOps(object):
return objects.NUMATopology(cells=cells) return objects.NUMATopology(cells=cells)
def _get_remotefx_gpu_info(self): def _get_remotefx_gpu_info(self):
remotefx_total_video_ram = 0 total_video_ram = 0
remotefx_available_video_ram = 0 available_video_ram = 0
if CONF.hyperv.enable_remotefx: if CONF.hyperv.enable_remotefx:
gpus = self._hostutils.get_remotefx_gpu_info() gpus = self._hostutils.get_remotefx_gpu_info()
for gpu in gpus: for gpu in gpus:
remotefx_total_video_ram += int(gpu['total_video_ram']) total_video_ram += int(gpu['total_video_ram'])
remotefx_available_video_ram += int(gpu['available_video_ram']) available_video_ram += int(gpu['available_video_ram'])
else: else:
gpus = [] gpus = []
return {'remotefx_total_video_ram': remotefx_total_video_ram, return {'total_video_ram': total_video_ram,
'remotefx_available_video_ram': remotefx_available_video_ram, 'used_video_ram': total_video_ram - available_video_ram,
'remotefx_gpu_info': jsonutils.dumps(gpus)} 'gpu_info': jsonutils.dumps(gpus)}
def get_available_resource(self): def get_available_resource(self):
"""Retrieve resource info. """Retrieve resource info.
@@ -178,8 +178,6 @@ class HostOps(object):
cpu_topology['cores'] * cpu_topology['cores'] *
cpu_topology['threads']) cpu_topology['threads'])
gpu_info = self._get_remotefx_gpu_info()
dic = {'vcpus': vcpus, dic = {'vcpus': vcpus,
'memory_mb': total_mem_mb, 'memory_mb': total_mem_mb,
'memory_mb_used': used_mem_mb, 'memory_mb_used': used_mem_mb,
@@ -194,6 +192,8 @@ class HostOps(object):
[(arch.I686, hv_type.HYPERV, vm_mode.HVM), [(arch.I686, hv_type.HYPERV, vm_mode.HVM),
(arch.X86_64, hv_type.HYPERV, vm_mode.HVM)], (arch.X86_64, hv_type.HYPERV, vm_mode.HVM)],
} }
gpu_info = self._get_remotefx_gpu_info()
dic.update(gpu_info) dic.update(gpu_info)
numa_topology = self._get_host_numa_topology() numa_topology = self._get_host_numa_topology()

View File

@@ -393,11 +393,7 @@ class VMOps(object):
CONF.hyperv.limit_cpu_features, CONF.hyperv.limit_cpu_features,
dynamic_memory_ratio) dynamic_memory_ratio)
flavor_extra_specs = instance.flavor.extra_specs self._configure_remotefx(instance, vm_gen)
remote_fx_config = flavor_extra_specs.get(
constants.FLAVOR_REMOTE_FX_EXTRA_SPEC_KEY)
if remote_fx_config:
self._configure_remotefx(instance, vm_gen, remote_fx_config)
self._vmutils.create_scsi_controller(instance_name) self._vmutils.create_scsi_controller(instance_name)
@@ -430,6 +426,45 @@ class VMOps(object):
self._configure_secure_vm(context, instance, image_meta, self._configure_secure_vm(context, instance, image_meta,
secure_boot_enabled) secure_boot_enabled)
def _configure_remotefx(self, instance, vm_gen):
extra_specs = instance.flavor.extra_specs
remotefx_max_resolution = extra_specs.get(
constants.FLAVOR_ESPEC_REMOTEFX_RES)
if not remotefx_max_resolution:
# RemoteFX not required.
return
if not CONF.hyperv.enable_remotefx:
raise exception.InstanceUnacceptable(
_("enable_remotefx configuration option needs to be set to "
"True in order to use RemoteFX."))
if not self._hostutils.check_server_feature(
self._hostutils.FEATURE_RDS_VIRTUALIZATION):
raise exception.InstanceUnacceptable(
_("The RDS-Virtualization feature must be installed in order "
"to use RemoteFX."))
if not self._vmutils.vm_gen_supports_remotefx(vm_gen):
raise exception.InstanceUnacceptable(
_("RemoteFX is not supported on generation %s virtual "
"machines on this version of Windows.") % vm_gen)
instance_name = instance.name
LOG.debug('Configuring RemoteFX for instance: %s', instance_name)
remotefx_monitor_count = int(extra_specs.get(
constants.FLAVOR_ESPEC_REMOTEFX_MONITORS) or 1)
remotefx_vram = extra_specs.get(
constants.FLAVOR_ESPEC_REMOTEFX_VRAM)
vram_bytes = int(remotefx_vram) * units.Mi if remotefx_vram else None
self._vmutils.enable_remotefx_video_adapter(
instance_name,
remotefx_monitor_count,
remotefx_max_resolution,
vram_bytes)
def _attach_root_device(self, instance_name, root_dev_info): def _attach_root_device(self, instance_name, root_dev_info):
if root_dev_info['type'] == constants.VOLUME: if root_dev_info['type'] == constants.VOLUME:
self._volumeops.attach_volume(root_dev_info['connection_info'], self._volumeops.attach_volume(root_dev_info['connection_info'],
@@ -570,40 +605,6 @@ 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, vm_gen, config):
if not CONF.hyperv.enable_remotefx:
reason = _("enable_remotefx configuration option needs to be set "
"to True in order to use RemoteFX")
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
reason=reason)
if not self._hostutils.check_server_feature(
self._hostutils.FEATURE_RDS_VIRTUALIZATION):
reason = _("The RDS-Virtualization feature must be installed in "
"order to use RemoteFX")
raise exception.InstanceUnacceptable(instance_id=instance.uuid,
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
LOG.debug('Configuring RemoteFX for instance: %s', instance_name)
remotefx_args = config.split(',')
remotefx_max_resolution = remotefx_args[0]
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(
instance_name,
remotefx_monitor_count,
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):]
# Do the attach here and if there is a certain file format that isn't # Do the attach here and if there is a certain file format that isn't

View File

@@ -135,6 +135,28 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
mock_NUMATopology.assert_called_once_with( mock_NUMATopology.assert_called_once_with(
cells=[mock_NUMACell.return_value]) cells=[mock_NUMACell.return_value])
def test_get_remotefx_gpu_info(self):
self.flags(enable_remotefx=True, group='hyperv')
fake_gpus = [{'total_video_ram': '2048',
'available_video_ram': '1024'},
{'total_video_ram': '1024',
'available_video_ram': '1024'}]
self._hostops._hostutils.get_remotefx_gpu_info.return_value = fake_gpus
ret_val = self._hostops._get_remotefx_gpu_info()
self.assertEqual(3072, ret_val['total_video_ram'])
self.assertEqual(1024, ret_val['used_video_ram'])
def test_get_remotefx_gpu_info_disabled(self):
self.flags(enable_remotefx=False, group='hyperv')
ret_val = self._hostops._get_remotefx_gpu_info()
self.assertEqual(0, ret_val['total_video_ram'])
self.assertEqual(0, ret_val['used_video_ram'])
self._hostops._hostutils.get_remotefx_gpu_info.assert_not_called()
@mock.patch.object(hostops.HostOps, '_get_host_numa_topology') @mock.patch.object(hostops.HostOps, '_get_host_numa_topology')
@mock.patch.object(hostops.HostOps, '_get_remotefx_gpu_info') @mock.patch.object(hostops.HostOps, '_get_remotefx_gpu_info')
@mock.patch.object(hostops.HostOps, '_get_cpu_info') @mock.patch.object(hostops.HostOps, '_get_cpu_info')
@@ -185,7 +207,7 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
'numa_topology': mock.sentinel.numa_topology_json, 'numa_topology': mock.sentinel.numa_topology_json,
'remotefx_available_video_ram': 2048, 'remotefx_available_video_ram': 2048,
'remotefx_gpu_info': mock.sentinel.FAKE_GPU_INFO, 'remotefx_gpu_info': mock.sentinel.FAKE_GPU_INFO,
'remotefx_total_video_ram': 4096 'remotefx_total_video_ram': 4096,
} }
self.assertEqual(expected, response) self.assertEqual(expected, response)
@@ -227,18 +249,6 @@ class HostOpsTestCase(test_base.HyperVBaseTestCase):
self.assertEqual(expected, response) self.assertEqual(expected, response)
def test_get_remotefx_gpu_info(self):
self.flags(enable_remotefx=True, group='hyperv')
fake_gpus = [{'total_video_ram': '2048',
'available_video_ram': '1024'},
{'total_video_ram': '1024',
'available_video_ram': '1024'}]
self._hostops._hostutils.get_remotefx_gpu_info.return_value = fake_gpus
ret_val = self._hostops._get_remotefx_gpu_info()
self.assertEqual(3072, ret_val['remotefx_total_video_ram'])
self.assertEqual(2048, ret_val['remotefx_available_video_ram'])
@mock.patch.object(hostops.HostOps, '_wait_for_instance_pending_task') @mock.patch.object(hostops.HostOps, '_wait_for_instance_pending_task')
@mock.patch.object(hostops.HostOps, '_set_service_state') @mock.patch.object(hostops.HostOps, '_set_service_state')
@mock.patch.object(hostops.HostOps, '_migrate_vm') @mock.patch.object(hostops.HostOps, '_migrate_vm')

View File

@@ -557,7 +557,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_configure_secure_vm, mock_configure_secure_vm,
enable_instance_metrics, enable_instance_metrics,
vm_gen=constants.VM_GEN_1, vnuma_enabled=False, vm_gen=constants.VM_GEN_1, vnuma_enabled=False,
requires_sec_boot=True, remotefx=False): requires_sec_boot=True):
mock_vif_driver = mock_get_vif_driver() mock_vif_driver = mock_get_vif_driver()
self.flags(dynamic_memory_ratio=2.0, group='hyperv') self.flags(dynamic_memory_ratio=2.0, group='hyperv')
self.flags(enable_instance_metrics_collection=enable_instance_metrics, self.flags(enable_instance_metrics_collection=enable_instance_metrics,
@@ -582,77 +582,61 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
dynamic_memory_ratio = CONF.hyperv.dynamic_memory_ratio dynamic_memory_ratio = CONF.hyperv.dynamic_memory_ratio
flavor = flavor_obj.Flavor(**test_flavor.fake_flavor) flavor = flavor_obj.Flavor(**test_flavor.fake_flavor)
if remotefx is True:
flavor.extra_specs['hyperv:remotefx'] = "1920x1200,2"
mock_instance.flavor = flavor mock_instance.flavor = flavor
if remotefx is True and vm_gen == constants.VM_GEN_2: self._vmops.create_instance(
self.assertRaises(os_win_exc.HyperVException, context=self.context,
self._vmops.create_instance, instance=mock_instance,
context=self.context, network_info=[fake_network_info],
instance=mock_instance, block_device_info=block_device_info,
network_info=[fake_network_info], root_device=root_device_info,
block_device_info=block_device_info, vm_gen=vm_gen,
root_device=root_device_info, image_meta=mock.sentinel.image_meta)
vm_gen=vm_gen,
image_meta=mock.sentinel.image_meta)
else:
self._vmops.create_instance(
context=self.context,
instance=mock_instance,
network_info=[fake_network_info],
block_device_info=block_device_info,
root_device=root_device_info,
vm_gen=vm_gen,
image_meta=mock.sentinel.image_meta)
if remotefx is True:
mock_configure_remotefx.assert_called_once_with(
mock_instance,
vm_gen,
flavor.extra_specs['hyperv:remotefx'])
self._vmops._vmutils.create_vm.assert_called_once_with( mock_configure_remotefx.assert_called_once_with(mock_instance, vm_gen)
mock_instance.name, vnuma_enabled, vm_gen,
instance_path, [mock_instance.uuid])
self._vmops._vmutils.update_vm.assert_called_once_with(
mock_instance.name, mock_instance.memory_mb, mem_per_numa,
mock_instance.vcpus, cpus_per_numa,
CONF.hyperv.limit_cpu_features, dynamic_memory_ratio)
mock_create_scsi_ctrl = self._vmops._vmutils.create_scsi_controller self._vmops._vmutils.create_vm.assert_called_once_with(
mock_create_scsi_ctrl.assert_called_once_with(mock_instance.name) mock_instance.name, vnuma_enabled, vm_gen,
instance_path, [mock_instance.uuid])
self._vmops._vmutils.update_vm.assert_called_once_with(
mock_instance.name, mock_instance.memory_mb, mem_per_numa,
mock_instance.vcpus, cpus_per_numa,
CONF.hyperv.limit_cpu_features, dynamic_memory_ratio)
mock_attach_root_device.assert_called_once_with(mock_instance.name, mock_create_scsi_ctrl = self._vmops._vmutils.create_scsi_controller
root_device_info) mock_create_scsi_ctrl.assert_called_once_with(mock_instance.name)
mock_attach_ephemerals.assert_called_once_with(mock_instance.name,
block_device_info['ephemerals'])
mock_attach_volumes.assert_called_once_with(
block_device_info['block_device_mapping'], mock_instance.name)
mock_get_port_settings.assert_called_with(mock.sentinel.image_meta) mock_attach_root_device.assert_called_once_with(mock_instance.name,
mock_create_pipes.assert_called_once_with( root_device_info)
mock_instance, mock_get_port_settings.return_value) mock_attach_ephemerals.assert_called_once_with(mock_instance.name,
block_device_info['ephemerals'])
mock_attach_volumes.assert_called_once_with(
block_device_info['block_device_mapping'], mock_instance.name)
self._vmops._vmutils.create_nic.assert_called_once_with( mock_get_port_settings.assert_called_with(mock.sentinel.image_meta)
mock_instance.name, mock.sentinel.ID, mock.sentinel.ADDRESS) mock_create_pipes.assert_called_once_with(
mock_vif_driver.plug.assert_called_once_with(mock_instance, mock_instance, mock_get_port_settings.return_value)
fake_network_info)
mock_enable = ( self._vmops._vmutils.create_nic.assert_called_once_with(
self._vmops._metricsutils.enable_vm_metrics_collection) mock_instance.name, mock.sentinel.ID, mock.sentinel.ADDRESS)
if enable_instance_metrics: mock_vif_driver.plug.assert_called_once_with(mock_instance,
mock_enable.assert_called_once_with(mock_instance.name) fake_network_info)
mock_set_qos_specs.assert_called_once_with(mock_instance) mock_enable = (
if requires_sec_boot: self._vmops._metricsutils.enable_vm_metrics_collection)
mock_requires_secure_boot.assert_called_once_with( if enable_instance_metrics:
mock_instance, mock.sentinel.image_meta, vm_gen) mock_enable.assert_called_once_with(mock_instance.name)
mock_requires_certificate.assert_called_once_with( mock_set_qos_specs.assert_called_once_with(mock_instance)
mock_instance.uuid, if requires_sec_boot:
mock.sentinel.image_meta) mock_requires_secure_boot.assert_called_once_with(
enable_secure_boot = self._vmops._vmutils.enable_secure_boot mock_instance, mock.sentinel.image_meta, vm_gen)
enable_secure_boot.assert_called_once_with( mock_requires_certificate.assert_called_once_with(
mock_instance.name, mock_requires_certificate.return_value) mock_instance.uuid,
mock_configure_secure_vm.assert_called_once_with(self.context, mock.sentinel.image_meta)
mock_instance, mock.sentinel.image_meta, requires_sec_boot) enable_secure_boot = self._vmops._vmutils.enable_secure_boot
enable_secure_boot.assert_called_once_with(
mock_instance.name, mock_requires_certificate.return_value)
mock_configure_secure_vm.assert_called_once_with(self.context,
mock_instance, mock.sentinel.image_meta, requires_sec_boot)
def test_create_instance(self): def test_create_instance(self):
self._test_create_instance(enable_instance_metrics=True) self._test_create_instance(enable_instance_metrics=True)
@@ -670,14 +654,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self._test_create_instance(enable_instance_metrics=False, self._test_create_instance(enable_instance_metrics=False,
vm_gen=constants.VM_GEN_2) vm_gen=constants.VM_GEN_2)
def test_create_instance_with_remote_fx(self):
self._test_create_instance(enable_instance_metrics=False,
remotefx=True)
def test_create_instance_with_remote_fx_gen2(self):
self._test_create_instance(enable_instance_metrics=False,
remotefx=True)
@mock.patch.object(vmops.volumeops.VolumeOps, 'attach_volume') @mock.patch.object(vmops.volumeops.VolumeOps, 'attach_volume')
def test_attach_root_device_volume(self, mock_attach_volume): def test_attach_root_device_volume(self, mock_attach_volume):
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)
@@ -1292,6 +1268,64 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock.call(mock.sentinel.FAKE_DVD_PATH2, mock.call(mock.sentinel.FAKE_DVD_PATH2,
mock.sentinel.FAKE_DEST_PATH)) mock.sentinel.FAKE_DEST_PATH))
def _setup_remotefx_mocks(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.extra_specs = {
'os:resolution': os_win_const.REMOTEFX_MAX_RES_1920x1200,
'os:monitors': '2',
'os:vram': '256'}
return mock_instance
def test_configure_remotefx_not_required(self):
self.flags(enable_remotefx=False, group='hyperv')
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._configure_remotefx(mock_instance, mock.sentinel.VM_GEN)
def test_configure_remotefx_exception_enable_config(self):
self.flags(enable_remotefx=False, group='hyperv')
mock_instance = self._setup_remotefx_mocks()
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._configure_remotefx,
mock_instance, mock.sentinel.VM_GEN)
def test_configure_remotefx_exception_server_feature(self):
self.flags(enable_remotefx=True, group='hyperv')
mock_instance = self._setup_remotefx_mocks()
self._vmops._hostutils.check_server_feature.return_value = False
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._configure_remotefx,
mock_instance, mock.sentinel.VM_GEN)
def test_configure_remotefx_exception_vm_gen(self):
self.flags(enable_remotefx=True, group='hyperv')
mock_instance = self._setup_remotefx_mocks()
self._vmops._hostutils.check_server_feature.return_value = True
self._vmops._vmutils.vm_gen_supports_remotefx.return_value = False
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._configure_remotefx,
mock_instance, mock.sentinel.VM_GEN)
def test_configure_remotefx(self):
self.flags(enable_remotefx=True, group='hyperv')
mock_instance = self._setup_remotefx_mocks()
self._vmops._hostutils.check_server_feature.return_value = True
self._vmops._vmutils.vm_gen_supports_remotefx.return_value = True
extra_specs = mock_instance.flavor.extra_specs
self._vmops._configure_remotefx(mock_instance,
constants.VM_GEN_1)
mock_enable_remotefx = (
self._vmops._vmutils.enable_remotefx_video_adapter)
mock_enable_remotefx.assert_called_once_with(
mock_instance.name, int(extra_specs['os:monitors']),
extra_specs['os:resolution'],
int(extra_specs['os:vram']) * units.Mi)
@mock.patch('nova.virt.configdrive.required_by') @mock.patch('nova.virt.configdrive.required_by')
@mock.patch.object(vmops.VMOps, '_create_root_vhd') @mock.patch.object(vmops.VMOps, '_create_root_vhd')
@mock.patch.object(vmops.VMOps, 'get_image_vm_generation') @mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
@@ -1506,46 +1540,6 @@ 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=True, enable_remotefx=True):
self.flags(enable_remotefx=enable_remotefx, group='hyperv')
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_resolution = "1920x1200"
fake_monitor_count = 3
fake_vram_mb = 64
fake_config = "%s,%s,%s" % (
fake_resolution, fake_monitor_count, fake_vram_mb)
enable_remotefx = self._vmops._vmutils.enable_remotefx_video_adapter
if fail:
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._configure_remotefx,
mock_instance, mock.sentinel.vm_gen, fake_config)
else:
self._vmops._configure_remotefx(
mock_instance, mock.sentinel.vm_gen, fake_config)
enable_remotefx.assert_called_once_with(mock_instance.name,
fake_monitor_count,
fake_resolution,
fake_vram_mb * units.Mi)
def test_configure_remotefx_disabled(self):
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):
self._test_configure_remotefx(fail=False)
@mock.patch.object(vmops.VMOps, '_get_vif_driver') @mock.patch.object(vmops.VMOps, '_get_vif_driver')
def test_unplug_vifs(self, mock_get_vif_driver): def test_unplug_vifs(self, mock_get_vif_driver):
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)