compute-hyperv/compute_hyperv/tests/unit/test_vmops.py

2423 lines
111 KiB
Python

# Copyright 2014 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import ddt
from eventlet import timeout as etimeout
import mock
from nova.compute import vm_states
from nova import exception
from nova import objects
from nova.objects import fields
from nova.tests.unit.objects import test_virtual_interface
from nova.virt import hardware
from os_win import constants as os_win_const
from os_win import exceptions as os_win_exc
from oslo_concurrency import processutils
from oslo_utils import fileutils
from oslo_utils import units
import compute_hyperv.nova.conf
from compute_hyperv.nova import constants
from compute_hyperv.nova import vmops
from compute_hyperv.tests import fake_instance
from compute_hyperv.tests.unit import test_base
CONF = compute_hyperv.nova.conf.CONF
@ddt.ddt
class VMOpsTestCase(test_base.HyperVBaseTestCase):
"""Unit tests for the Hyper-V VMOps class."""
_autospec_classes = [
vmops.pathutils.PathUtils,
vmops.volumeops.VolumeOps,
vmops.imagecache.ImageCache,
vmops.serialconsoleops.SerialConsoleOps,
vmops.block_device_manager.BlockDeviceInfoManager,
vmops.vif_utils.HyperVVIFDriver,
vmops.pdk.PDK,
]
_FAKE_TIMEOUT = 2
FAKE_SIZE = 10
FAKE_DIR = 'fake_dir'
FAKE_ROOT_PATH = 'C:\\path\\to\\fake.%s'
FAKE_CONFIG_DRIVE_ISO = 'configdrive.iso'
FAKE_CONFIG_DRIVE_VHD = 'configdrive.vhd'
FAKE_UUID = '4f54fb69-d3a2-45b7-bb9b-b6e6b3d893b3'
FAKE_LOG = 'fake_log'
_FAKE_PDK_FILE_PATH = 'C:\\path\\to\\fakepdk.pdk'
_FAKE_FSK_FILE_PATH = 'C:\\path\\to\\fakefsk.fsk'
_WIN_VERSION_6_3 = '6.3.0'
_WIN_VERSION_10 = '10.0'
ISO9660 = 'iso9660'
VFAT = 'vfat'
_FAKE_CONFIGDRIVE_PATH = 'C:/fake_instance_dir/configdrive.vhd'
def setUp(self):
super(VMOpsTestCase, self).setUp()
self.context = 'fake-context'
self._vmops = vmops.VMOps(virtapi=mock.MagicMock())
self._pathutils = self._vmops._pathutils
self._vmutils = self._vmops._vmutils
self._metricsutils = self._vmops._metricsutils
self._vif_driver = self._vmops._vif_driver
def test_list_instances(self):
mock_instance = mock.MagicMock()
self._vmops._vmutils.list_instances.return_value = [mock_instance]
response = self._vmops.list_instances()
self._vmops._vmutils.list_instances.assert_called_once_with()
self.assertEqual(response, [mock_instance])
@ddt.data(True, False)
def test_estimate_instance_overhead(self, instance_automatic_shutdown):
self.flags(instance_automatic_shutdown=instance_automatic_shutdown,
group='hyperv')
instance_info = {'memory_mb': 512}
expected_disk_overhead = 0 if instance_automatic_shutdown else 1
overhead = self._vmops.estimate_instance_overhead(instance_info)
self.assertEqual(0, overhead['memory_mb'])
self.assertEqual(expected_disk_overhead, overhead['disk_gb'])
instance_info = {'memory_mb': 500}
overhead = self._vmops.estimate_instance_overhead(instance_info)
self.assertEqual(0, overhead['disk_gb'])
def _test_get_info(self, vm_exists):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_info = mock.MagicMock(spec_set=dict)
fake_info = {'EnabledState': 2,
'MemoryUsage': mock.sentinel.FAKE_MEM_KB,
'NumberOfProcessors': mock.sentinel.FAKE_NUM_CPU,
'UpTime': mock.sentinel.FAKE_CPU_NS}
def getitem(key):
return fake_info[key]
mock_info.__getitem__.side_effect = getitem
expected = hardware.InstanceInfo(state=constants.HYPERV_POWER_STATE[2])
self._vmops._vmutils.vm_exists.return_value = vm_exists
self._vmops._vmutils.get_vm_summary_info.return_value = mock_info
if not vm_exists:
self.assertRaises(exception.InstanceNotFound,
self._vmops.get_info, mock_instance)
else:
response = self._vmops.get_info(mock_instance)
self._vmops._vmutils.vm_exists.assert_called_once_with(
mock_instance.name)
self._vmops._vmutils.get_vm_summary_info.assert_called_once_with(
mock_instance.name)
self.assertEqual(response, expected)
def test_get_info(self):
self._test_get_info(vm_exists=True)
def test_get_info_exception(self):
self._test_get_info(vm_exists=False)
@mock.patch.object(vmops.VMOps, 'check_vm_image_type')
@mock.patch.object(vmops.VMOps, '_create_root_vhd')
def test_create_root_device_type_disk(self, mock_create_root_device,
mock_check_vm_image_type):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_root_disk_info = {'type': constants.DISK}
self._vmops._create_root_device(self.context, mock_instance,
mock_root_disk_info,
mock.sentinel.VM_GEN_1)
mock_create_root_device.assert_called_once_with(
self.context, mock_instance)
mock_check_vm_image_type.assert_called_once_with(
mock_instance.uuid, mock.sentinel.VM_GEN_1,
mock_create_root_device.return_value)
@mock.patch.object(vmops.VMOps, '_create_root_iso')
def test_create_root_device_type_iso(self, mock_create_root_iso):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_root_disk_info = {'type': constants.DVD}
self._vmops._create_root_device(self.context, mock_instance,
mock_root_disk_info,
mock.sentinel.VM_GEN_1)
mock_create_root_iso.assert_called_once_with(self.context,
mock_instance)
@mock.patch('os.path.exists')
def _test_create_root_iso(self, mock_os_path_exists,
iso_already_exists=False):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_get_root_vhd_path = self._vmops._pathutils.get_root_vhd_path
mock_get_root_vhd_path.return_value = mock.sentinel.ROOT_ISO_PATH
mock_get_cached_image = self._vmops._imagecache.get_cached_image
mock_get_cached_image.return_value = mock.sentinel.CACHED_ISO_PATH
mock_os_path_exists.return_value = iso_already_exists
self._vmops._create_root_iso(self.context, mock_instance)
mock_get_cached_image.assert_called_once_with(self.context,
mock_instance)
mock_get_root_vhd_path.assert_called_once_with(mock_instance.name,
'iso')
if not iso_already_exists:
self._vmops._pathutils.copyfile.assert_called_once_with(
mock.sentinel.CACHED_ISO_PATH, mock.sentinel.ROOT_ISO_PATH)
else:
self._vmops._pathutils.copyfile.assert_not_called()
def test_create_root_iso(self):
self._test_create_root_iso()
def test_create_root_iso_already_existing_image(self):
self._test_create_root_iso(iso_already_exists=True)
def _prepare_create_root_device_mocks(self, use_cow_images, vhd_format,
vhd_size):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.root_gb = self.FAKE_SIZE
self.flags(use_cow_images=use_cow_images)
self._vmops._vhdutils.get_vhd_info.return_value = {'VirtualSize':
vhd_size * units.Gi}
self._vmops._vhdutils.get_vhd_format.return_value = vhd_format
root_vhd_internal_size = mock_instance.flavor.root_gb * units.Gi
get_size = self._vmops._vhdutils.get_internal_vhd_size_by_file_size
get_size.return_value = root_vhd_internal_size
self._vmops._pathutils.exists.return_value = True
return mock_instance
@mock.patch('os.path.exists')
def _test_create_root_vhd_exception(self, mock_os_path_exists, vhd_format):
mock_instance = self._prepare_create_root_device_mocks(
use_cow_images=False, vhd_format=vhd_format,
vhd_size=(self.FAKE_SIZE + 1))
fake_vhd_path = self.FAKE_ROOT_PATH % vhd_format
self._vmops._imagecache.get_cached_image.return_value = fake_vhd_path
fake_root_path = self._vmops._pathutils.get_root_vhd_path.return_value
mock_os_path_exists.return_value = False
self.assertRaises(exception.FlavorDiskSmallerThanImage,
self._vmops._create_root_vhd, self.context,
mock_instance)
self.assertFalse(self._vmops._vhdutils.resize_vhd.called)
self._vmops._pathutils.exists.assert_called_once_with(
fake_root_path)
self._vmops._pathutils.remove.assert_called_once_with(
fake_root_path)
@mock.patch('os.path.exists')
def _test_create_root_vhd_qcow(self, mock_os_path_exists, vhd_format,
vhd_already_exists=False):
mock_instance = self._prepare_create_root_device_mocks(
use_cow_images=True, vhd_format=vhd_format,
vhd_size=(self.FAKE_SIZE - 1))
fake_vhd_path = self.FAKE_ROOT_PATH % vhd_format
self._vmops._imagecache.get_cached_image.return_value = fake_vhd_path
mock_os_path_exists.return_value = vhd_already_exists
fake_root_path = self._vmops._pathutils.get_root_vhd_path.return_value
root_vhd_internal_size = mock_instance.flavor.root_gb * units.Gi
get_size = self._vmops._vhdutils.get_internal_vhd_size_by_file_size
response = self._vmops._create_root_vhd(context=self.context,
instance=mock_instance)
self.assertEqual(fake_root_path, response)
self._vmops._pathutils.get_root_vhd_path.assert_called_with(
mock_instance.name, vhd_format, False)
differencing_vhd = self._vmops._vhdutils.create_differencing_vhd
if not vhd_already_exists:
differencing_vhd.assert_called_with(fake_root_path, fake_vhd_path)
self._vmops._vhdutils.get_vhd_info.assert_called_once_with(
fake_vhd_path)
if vhd_format is constants.DISK_FORMAT_VHD:
self.assertFalse(get_size.called)
self.assertFalse(self._vmops._vhdutils.resize_vhd.called)
else:
get_size.assert_called_once_with(fake_vhd_path,
root_vhd_internal_size)
self._vmops._vhdutils.resize_vhd.assert_called_once_with(
fake_root_path, root_vhd_internal_size,
is_file_max_size=False)
else:
differencing_vhd.assert_not_called()
self._vmops._vhdutils.resize_vhd.assert_not_called()
@mock.patch('os.path.exists')
def _test_create_root_vhd(self, mock_os_path_exists,
vhd_format, is_rescue_vhd=False,
vhd_already_exists=False):
mock_instance = self._prepare_create_root_device_mocks(
use_cow_images=False, vhd_format=vhd_format,
vhd_size=(self.FAKE_SIZE - 1))
fake_vhd_path = self.FAKE_ROOT_PATH % vhd_format
mock_get_cached_image = self._vmops._imagecache.get_cached_image
mock_get_cached_image.return_value = fake_vhd_path
rescue_image_id = (
mock.sentinel.rescue_image_id if is_rescue_vhd else None)
fake_root_path = self._vmops._pathutils.get_root_vhd_path.return_value
root_vhd_internal_size = mock_instance.flavor.root_gb * units.Gi
get_size = self._vmops._vhdutils.get_internal_vhd_size_by_file_size
mock_os_path_exists.return_value = vhd_already_exists
response = self._vmops._create_root_vhd(
context=self.context,
instance=mock_instance,
rescue_image_id=rescue_image_id)
self.assertEqual(fake_root_path, response)
mock_get_cached_image.assert_called_once_with(self.context,
mock_instance,
rescue_image_id)
self._vmops._pathutils.get_root_vhd_path.assert_called_with(
mock_instance.name, vhd_format, is_rescue_vhd)
if not vhd_already_exists:
self._vmops._pathutils.copyfile.assert_called_once_with(
fake_vhd_path, fake_root_path)
get_size.assert_called_once_with(fake_vhd_path,
root_vhd_internal_size)
if is_rescue_vhd:
self.assertFalse(self._vmops._vhdutils.resize_vhd.called)
else:
self._vmops._vhdutils.resize_vhd.assert_called_once_with(
fake_root_path, root_vhd_internal_size,
is_file_max_size=False)
else:
self._vmops._pathutils.copyfile.assert_not_called()
def test_create_root_vhd(self):
self._test_create_root_vhd(vhd_format=constants.DISK_FORMAT_VHD)
def test_create_root_vhdx(self):
self._test_create_root_vhd(vhd_format=constants.DISK_FORMAT_VHDX)
def test_create_root_vhd_existing_disk(self):
self._test_create_root_vhd(vhd_format=constants.DISK_FORMAT_VHD,
vhd_already_exists=True)
def test_create_root_vhdx_existing_disk(self):
self._test_create_root_vhd(vhd_format=constants.DISK_FORMAT_VHDX,
vhd_already_exists=True)
def test_create_root_vhd_use_cow_images_true(self):
self._test_create_root_vhd_qcow(vhd_format=constants.DISK_FORMAT_VHD)
def test_create_root_vhdx_use_cow_images_true(self):
self._test_create_root_vhd_qcow(vhd_format=constants.DISK_FORMAT_VHDX)
def test_create_root_vhd_use_already_existing_cow_images(self):
self._test_create_root_vhd_qcow(vhd_format=constants.DISK_FORMAT_VHD,
vhd_already_exists=True)
def test_create_root_vhdx_use_already_existing_cow_images(self):
self._test_create_root_vhd_qcow(vhd_format=constants.DISK_FORMAT_VHDX,
vhd_already_exists=True)
def test_create_rescue_vhd(self):
self._test_create_root_vhd(vhd_format=constants.DISK_FORMAT_VHD,
is_rescue_vhd=True)
def test_create_root_vhdx_size_less_than_internal(self):
self._test_create_root_vhd_exception(
vhd_format=constants.DISK_FORMAT_VHD)
def test_is_resize_needed_exception(self):
inst = mock.MagicMock()
self.assertRaises(
exception.FlavorDiskSmallerThanImage,
self._vmops._is_resize_needed,
mock.sentinel.FAKE_PATH, self.FAKE_SIZE, self.FAKE_SIZE - 1, inst)
def test_is_resize_needed_true(self):
inst = mock.MagicMock()
self.assertTrue(self._vmops._is_resize_needed(
mock.sentinel.FAKE_PATH, self.FAKE_SIZE, self.FAKE_SIZE + 1, inst))
def test_is_resize_needed_false(self):
inst = mock.MagicMock()
self.assertFalse(self._vmops._is_resize_needed(
mock.sentinel.FAKE_PATH, self.FAKE_SIZE, self.FAKE_SIZE, inst))
@mock.patch.object(vmops.VMOps, 'create_ephemeral_disk')
def test_create_ephemerals(self, mock_create_ephemeral_disk):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_ephemerals = [dict(), dict()]
self._vmops._vhdutils.get_best_supported_vhd_format.return_value = (
mock.sentinel.format)
self._vmops._pathutils.get_ephemeral_vhd_path.side_effect = [
mock.sentinel.FAKE_PATH0, mock.sentinel.FAKE_PATH1]
self._vmops._create_ephemerals(mock_instance, fake_ephemerals)
self._vmops._pathutils.get_ephemeral_vhd_path.assert_has_calls(
[mock.call(mock_instance.name, mock.sentinel.format, 'eph0'),
mock.call(mock_instance.name, mock.sentinel.format, 'eph1')])
mock_create_ephemeral_disk.assert_has_calls(
[mock.call(mock_instance.name, fake_ephemerals[0]),
mock.call(mock_instance.name, fake_ephemerals[1])])
def test_create_ephemeral_disk(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_ephemeral_info = {'path': 'fake_eph_path',
'size': 10}
self._vmops.create_ephemeral_disk(mock_instance.name,
mock_ephemeral_info)
mock_create_dynamic_vhd = self._vmops._vhdutils.create_dynamic_vhd
mock_create_dynamic_vhd.assert_called_once_with('fake_eph_path',
10 * units.Gi)
def test_get_attached_ephemeral_disks(self):
ephemeral_disks = [os.path.join('image_dir', img_name)
for img_name in ['eph0.vhdx', 'eph1.vhdx']]
image_disks = ephemeral_disks + [
os.path.join('image_dir', 'root.vhdx')]
self._vmutils.get_vm_storage_paths.return_value = (
image_disks, mock.sentinel.passthrough_disks)
ret_val = self._vmops.get_attached_ephemeral_disks(
mock.sentinel.instance_name)
self.assertEqual(ephemeral_disks, ret_val)
self._vmutils.get_vm_storage_paths.assert_called_once_with(
mock.sentinel.instance_name)
@mock.patch.object(vmops.objects, 'PCIDeviceBus')
@mock.patch.object(vmops.objects, 'NetworkInterfaceMetadata')
@mock.patch.object(vmops.objects.VirtualInterfaceList,
'get_by_instance_uuid')
def test_get_vif_metadata(self, mock_get_by_inst_uuid,
mock_NetworkInterfaceMetadata, mock_PCIDevBus):
mock_vif = mock.MagicMock(tag='taggy')
mock_vif.__contains__.side_effect = (
lambda attr: getattr(mock_vif, attr, None) is not None)
mock_get_by_inst_uuid.return_value = [mock_vif,
mock.MagicMock(tag=None)]
vif_metadata = self._vmops._get_vif_metadata(self.context,
mock.sentinel.instance_id)
mock_get_by_inst_uuid.assert_called_once_with(
self.context, mock.sentinel.instance_id)
mock_NetworkInterfaceMetadata.assert_called_once_with(
mac=mock_vif.address,
bus=mock_PCIDevBus.return_value,
tags=[mock_vif.tag])
self.assertEqual([mock_NetworkInterfaceMetadata.return_value],
vif_metadata)
@mock.patch.object(vmops.objects, 'InstanceDeviceMetadata')
@mock.patch.object(vmops.VMOps, '_get_vif_metadata')
def test_update_device_metadata(self, mock_get_vif_metadata,
mock_InstanceDeviceMetadata):
mock_instance = mock.MagicMock()
mock_get_vif_metadata.return_value = [mock.sentinel.vif_metadata]
self._vmops._block_dev_man.get_bdm_metadata.return_value = [
mock.sentinel.bdm_metadata]
self._vmops.update_device_metadata(self.context, mock_instance)
mock_get_vif_metadata.assert_called_once_with(self.context,
mock_instance.uuid)
self._vmops._block_dev_man.get_bdm_metadata.assert_called_once_with(
self.context, mock_instance)
expected_metadata = [mock.sentinel.vif_metadata,
mock.sentinel.bdm_metadata]
mock_InstanceDeviceMetadata.assert_called_once_with(
devices=expected_metadata)
self.assertEqual(mock_InstanceDeviceMetadata.return_value,
mock_instance.device_metadata)
def test_set_boot_order(self):
self._vmops.set_boot_order(mock.sentinel.instance_name,
mock.sentinel.vm_gen,
mock.sentinel.bdi)
mock_get_boot_order = self._vmops._block_dev_man.get_boot_order
mock_get_boot_order.assert_called_once_with(
mock.sentinel.vm_gen, mock.sentinel.bdi)
self._vmops._vmutils.set_boot_order.assert_called_once_with(
mock.sentinel.instance_name, mock_get_boot_order.return_value)
@mock.patch.object(vmops.VMOps, 'plug_vifs')
@mock.patch('compute_hyperv.nova.vmops.VMOps.destroy')
@mock.patch('compute_hyperv.nova.vmops.VMOps.power_on')
@mock.patch.object(vmops.VMOps, 'set_boot_order')
@mock.patch('compute_hyperv.nova.vmops.VMOps.attach_config_drive')
@mock.patch('compute_hyperv.nova.vmops.VMOps._create_config_drive')
@mock.patch('nova.virt.configdrive.required_by')
@mock.patch('compute_hyperv.nova.vmops.VMOps.update_device_metadata')
@mock.patch('compute_hyperv.nova.vmops.VMOps.create_instance')
@mock.patch('compute_hyperv.nova.vmops.VMOps.get_image_vm_generation')
@mock.patch('compute_hyperv.nova.vmops.VMOps._create_ephemerals')
@mock.patch('compute_hyperv.nova.vmops.VMOps._create_root_device')
@mock.patch('compute_hyperv.nova.vmops.VMOps._delete_disk_files')
@mock.patch('compute_hyperv.nova.vmops.VMOps._get_neutron_events',
return_value=[])
def _test_spawn(self, mock_get_neutron_events,
mock_delete_disk_files,
mock_create_root_device,
mock_create_ephemerals, mock_get_image_vm_gen,
mock_create_instance, mock_update_device_metadata,
mock_configdrive_required,
mock_create_config_drive, mock_attach_config_drive,
mock_set_boot_order,
mock_power_on, mock_destroy, mock_plug_vifs,
exists, configdrive_required, fail,
fake_vm_gen=constants.VM_GEN_2):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_image_meta = mock.MagicMock()
root_device_info = mock.sentinel.ROOT_DEV_INFO
mock_get_image_vm_gen.return_value = fake_vm_gen
fake_config_drive_path = mock_create_config_drive.return_value
block_device_info = {'ephemerals': [], 'root_disk': root_device_info}
self._vmops._pathutils.get_instance_dir.return_value = (
'fake-instance-dir')
self._vmops._vmutils.vm_exists.return_value = exists
mock_configdrive_required.return_value = configdrive_required
mock_create_instance.side_effect = fail
if exists:
self.assertRaises(exception.InstanceExists, self._vmops.spawn,
self.context, mock_instance, mock_image_meta,
[mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.network_info, block_device_info)
elif fail is os_win_exc.HyperVException:
self.assertRaises(os_win_exc.HyperVException, self._vmops.spawn,
self.context, mock_instance, mock_image_meta,
[mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.network_info, block_device_info)
mock_destroy.assert_called_once_with(mock_instance,
mock.sentinel.network_info,
block_device_info)
else:
self._vmops.spawn(self.context, mock_instance, mock_image_meta,
[mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.network_info, block_device_info)
self._vmops._vmutils.vm_exists.assert_called_once_with(
mock_instance.name)
self._vmops._pathutils.get_instance_dir.assert_called_once_with(
mock_instance.name, create_dir=False)
mock_validate_and_update_bdi = (
self._vmops._block_dev_man.validate_and_update_bdi)
mock_validate_and_update_bdi.assert_called_once_with(
mock_instance, mock_image_meta, fake_vm_gen, block_device_info)
mock_create_root_device.assert_called_once_with(self.context,
mock_instance,
root_device_info,
fake_vm_gen)
mock_create_ephemerals.assert_called_once_with(
mock_instance, block_device_info['ephemerals'])
mock_get_neutron_events.assert_called_once_with(
mock.sentinel.network_info)
mock_get_image_vm_gen.assert_called_once_with(mock_instance.uuid,
mock_image_meta)
mock_create_instance.assert_called_once_with(
self.context, mock_instance, mock.sentinel.network_info,
block_device_info, fake_vm_gen, mock_image_meta)
mock_plug_vifs.assert_called_once_with(mock_instance,
mock.sentinel.network_info)
mock_update_device_metadata.assert_called_once_with(
self.context, mock_instance)
mock_configdrive_required.assert_called_once_with(mock_instance)
if configdrive_required:
mock_create_config_drive.assert_called_once_with(
self.context, mock_instance, [mock.sentinel.FILE],
mock.sentinel.PASSWORD,
mock.sentinel.network_info)
mock_attach_config_drive.assert_called_once_with(
mock_instance, fake_config_drive_path, fake_vm_gen)
mock_set_boot_order.assert_called_once_with(
mock_instance.name, fake_vm_gen, block_device_info)
mock_power_on.assert_called_once_with(
mock_instance,
network_info=mock.sentinel.network_info,
should_plug_vifs=False)
def test_spawn(self):
self._test_spawn(exists=False, configdrive_required=True, fail=None)
def test_spawn_instance_exists(self):
self._test_spawn(exists=True, configdrive_required=True, fail=None)
def test_spawn_create_instance_exception(self):
self._test_spawn(exists=False, configdrive_required=True,
fail=os_win_exc.HyperVException)
def test_spawn_not_required(self):
self._test_spawn(exists=False, configdrive_required=False, fail=None)
def test_spawn_no_admin_permissions(self):
self._vmops._vmutils.check_admin_permissions.side_effect = (
os_win_exc.HyperVException)
self.assertRaises(os_win_exc.HyperVException,
self._vmops.spawn,
self.context, mock.DEFAULT, mock.DEFAULT,
[mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.INFO, mock.sentinel.DEV_INFO)
@mock.patch.object(vmops.VMOps, '_get_neutron_events')
def test_wait_vif_plug_events(self, mock_get_events):
self._vmops._virtapi.wait_for_instance_event.side_effect = (
etimeout.Timeout)
self.flags(vif_plugging_timeout=1)
self.flags(vif_plugging_is_fatal=True)
def _context_user():
with self._vmops.wait_vif_plug_events(mock.sentinel.instance,
mock.sentinel.network_info):
pass
self.assertRaises(exception.VirtualInterfaceCreateException,
_context_user)
mock_get_events.assert_called_once_with(mock.sentinel.network_info)
self._vmops._virtapi.wait_for_instance_event.assert_called_once_with(
mock.sentinel.instance, mock_get_events.return_value,
deadline=CONF.vif_plugging_timeout,
error_callback=self._vmops._neutron_failed_callback)
@mock.patch.object(vmops.VMOps, '_get_neutron_events')
def test_wait_vif_plug_events_port_binding_failed(self, mock_get_events):
mock_get_events.side_effect = exception.PortBindingFailed(
port_id='fake_id')
def _context_user():
with self._vmops.wait_vif_plug_events(mock.sentinel.instance,
mock.sentinel.network_info):
pass
self.assertRaises(exception.PortBindingFailed, _context_user)
def test_neutron_failed_callback(self):
self.flags(vif_plugging_is_fatal=True)
self.assertRaises(exception.VirtualInterfaceCreateException,
self._vmops._neutron_failed_callback,
mock.sentinel.event_name, mock.sentinel.instance)
@mock.patch.object(vmops.utils, 'is_neutron')
def test_get_neutron_events(self, mock_is_neutron):
network_info = [{'id': mock.sentinel.vif_id1, 'active': True},
{'id': mock.sentinel.vif_id2, 'active': False},
{'id': mock.sentinel.vif_id3}]
events = self._vmops._get_neutron_events(network_info)
self.assertEqual([('network-vif-plugged', mock.sentinel.vif_id2)],
events)
mock_is_neutron.assert_called_once_with()
@mock.patch.object(vmops.utils, 'is_neutron')
def test_get_neutron_events_no_timeout(self, mock_is_neutron):
self.flags(vif_plugging_timeout=0)
network_info = [{'id': mock.sentinel.vif_id1, 'active': True}]
events = self._vmops._get_neutron_events(network_info)
self.assertEqual([], events)
mock_is_neutron.assert_called_once_with()
@mock.patch.object(vmops.VMOps, 'configure_instance_metrics')
@mock.patch.object(vmops.VMOps, 'update_vm_resources')
@mock.patch.object(vmops.VMOps, '_configure_secure_vm')
@mock.patch.object(vmops.VMOps, '_requires_secure_boot')
@mock.patch.object(vmops.VMOps, '_requires_certificate')
@mock.patch.object(vmops.VMOps, '_get_instance_vnuma_config')
@mock.patch.object(vmops.VMOps, '_attach_root_device')
@mock.patch.object(vmops.VMOps, 'configure_remotefx')
@mock.patch.object(vmops.VMOps, '_get_image_serial_port_settings')
@mock.patch.object(vmops.VMOps, '_create_vm_com_port_pipes')
@mock.patch.object(vmops.VMOps, 'attach_ephemerals')
def test_create_instance(self, mock_attach_ephemerals,
mock_create_pipes,
mock_get_port_settings,
mock_configure_remotefx,
mock_attach_root_device,
mock_get_vnuma_config,
mock_requires_certificate,
mock_requires_secure_boot,
mock_configure_secure_vm,
mock_update_vm_resources,
mock_configure_metrics):
root_device_info = mock.sentinel.ROOT_DEV_INFO
block_device_info = {'root_disk': root_device_info, 'ephemerals': [],
'block_device_mapping': []}
fake_network_info = {'id': mock.sentinel.ID,
'address': mock.sentinel.ADDRESS}
mock_instance = fake_instance.fake_instance_obj(self.context)
instance_path = os.path.join(CONF.instances_path, mock_instance.name)
mock_get_vnuma_config.return_value = (mock.sentinel.mem_per_numa_node,
mock.sentinel.vnuma_cpus)
self._vmops.create_instance(context=self.context,
instance=mock_instance,
network_info=[fake_network_info],
block_device_info=block_device_info,
vm_gen=mock.sentinel.vm_gen,
image_meta=mock.sentinel.image_meta)
mock_get_vnuma_config.assert_called_once_with(mock_instance,
mock.sentinel.image_meta)
self._vmops._vmutils.create_vm.assert_called_once_with(
mock_instance.name, True, mock.sentinel.vm_gen,
instance_path, [mock_instance.uuid])
mock_configure_remotefx.assert_called_once_with(
mock_instance, mock.sentinel.vm_gen)
mock_create_scsi_ctrl = self._vmops._vmutils.create_scsi_controller
mock_create_scsi_ctrl.assert_called_once_with(mock_instance.name)
mock_attach_root_device.assert_called_once_with(
self.context, mock_instance, root_device_info)
mock_attach_ephemerals.assert_called_once_with(mock_instance.name,
block_device_info['ephemerals'])
self._vmops._volumeops.attach_volumes.assert_called_once_with(
self.context, block_device_info['block_device_mapping'],
mock_instance)
mock_get_port_settings.assert_called_with(mock.sentinel.image_meta)
mock_create_pipes.assert_called_once_with(
mock_instance, mock_get_port_settings.return_value)
self._vmops._vmutils.create_nic.assert_called_once_with(
mock_instance.name, mock.sentinel.ID, mock.sentinel.ADDRESS)
mock_configure_metrics.assert_called_once_with(mock_instance.name)
mock_requires_secure_boot.assert_called_once_with(
mock_instance, mock.sentinel.image_meta, mock.sentinel.vm_gen)
mock_requires_certificate.assert_called_once_with(
mock.sentinel.image_meta)
enable_secure_boot = self._vmops._vmutils.enable_secure_boot
enable_secure_boot.assert_called_once_with(
mock_instance.name,
msft_ca_required=mock_requires_certificate.return_value)
mock_configure_secure_vm.assert_called_once_with(self.context,
mock_instance, mock.sentinel.image_meta,
mock_requires_secure_boot.return_value)
mock_update_vm_resources.assert_called_once_with(
mock_instance, mock.sentinel.vm_gen, mock.sentinel.image_meta)
@mock.patch.object(vmops.VMOps, '_attach_pci_devices')
@mock.patch.object(vmops.VMOps, '_set_instance_disk_qos_specs')
@mock.patch.object(vmops.VMOps, '_get_instance_dynamic_memory_ratio')
@mock.patch.object(vmops.VMOps, '_requires_nested_virt')
@mock.patch.object(vmops.VMOps, '_get_instance_vnuma_config')
def _check_update_vm_resources(self, mock_get_vnuma_config,
mock_requires_nested_virt,
mock_get_dynamic_memory_ratio,
mock_set_qos_specs,
mock_attach_pci_devices,
pci_requests=None,
instance_automatic_shutdown=False):
self.flags(instance_automatic_shutdown=instance_automatic_shutdown,
group='hyperv')
mock_get_vnuma_config.return_value = (mock.sentinel.mem_per_numa_node,
mock.sentinel.vnuma_cpus)
dynamic_memory_ratio = mock_get_dynamic_memory_ratio.return_value
mock_instance = fake_instance.fake_instance_obj(self.context)
instance_pci_requests = objects.InstancePCIRequests(
requests=pci_requests or [], instance_uuid=mock_instance.uuid)
mock_instance.pci_requests = instance_pci_requests
host_shutdown_action = (os_win_const.HOST_SHUTDOWN_ACTION_SHUTDOWN
if pci_requests or
instance_automatic_shutdown
else None)
self._vmops.update_vm_resources(mock_instance, mock.sentinel.vm_gen,
mock.sentinel.image_meta,
mock.sentinel.instance_path,
mock.sentinel.is_resize)
mock_get_vnuma_config.assert_called_once_with(mock_instance,
mock.sentinel.image_meta)
mock_requires_nested_virt.assert_called_once_with(
mock_instance, mock.sentinel.image_meta)
mock_get_dynamic_memory_ratio.assert_called_once_with(
mock_instance, True, mock_requires_nested_virt.return_value)
self._vmops._vmutils.update_vm.assert_called_once_with(
mock_instance.name, mock_instance.flavor.memory_mb,
mock.sentinel.mem_per_numa_node, mock_instance.flavor.vcpus,
mock.sentinel.vnuma_cpus, CONF.hyperv.limit_cpu_features,
dynamic_memory_ratio,
configuration_root_dir=mock.sentinel.instance_path,
host_shutdown_action=host_shutdown_action,
vnuma_enabled=True)
mock_set_qos_specs.assert_called_once_with(mock_instance,
mock.sentinel.is_resize)
mock_attach_pci_devices.assert_called_once_with(
mock_instance, mock.sentinel.is_resize)
self._vmops._vmutils.set_nested_virtualization(
mock_instance.name, state=mock_requires_nested_virt.return_value)
def test_update_vm_resources(self):
self._check_update_vm_resources()
def test_update_vm_resources_pci_requested(self):
vendor_id = 'fake_vendor_id'
product_id = 'fake_product_id'
spec = {'vendor_id': vendor_id, 'product_id': product_id}
request = objects.InstancePCIRequest(count=1, spec=[spec])
self._check_update_vm_resources(pci_requests=[request])
def test_create_instance_automatic_shutdown(self):
self._check_update_vm_resources(instance_automatic_shutdown=True)
def test_attach_pci_devices(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
vendor_id = 'fake_vendor_id'
product_id = 'fake_product_id'
spec = {'vendor_id': vendor_id, 'product_id': product_id}
request = objects.InstancePCIRequest(count=2, spec=[spec])
instance_pci_requests = objects.InstancePCIRequests(
requests=[request], instance_uuid=mock_instance.uuid)
mock_instance.pci_requests = instance_pci_requests
self._vmops._attach_pci_devices(mock_instance, True)
self._vmops._vmutils.remove_all_pci_devices.assert_called_once_with(
mock_instance.name)
self._vmops._vmutils.add_pci_device.assert_has_calls(
[mock.call(mock_instance.name, vendor_id, product_id)] * 2)
@mock.patch.object(vmops.hardware, 'numa_get_constraints')
@mock.patch.object(vmops.objects.ImageMeta, 'from_dict')
def _check_get_instance_vnuma_config_exception(self, mock_from_dict,
mock_get_numa, numa_cells):
flavor = {'extra_specs': {}}
mock_instance = mock.MagicMock(flavor=flavor)
image_meta = mock.MagicMock(properties={})
mock_get_numa.return_value.cells = numa_cells
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._get_instance_vnuma_config,
mock_instance, image_meta)
def test_get_instance_vnuma_config_bad_cpuset(self):
cell1 = mock.MagicMock(cpuset=set([0]), memory=1024)
cell2 = mock.MagicMock(cpuset=set([1, 2]), memory=1024)
self._check_get_instance_vnuma_config_exception(
numa_cells=[cell1, cell2])
def test_get_instance_vnuma_config_bad_memory(self):
cell1 = mock.MagicMock(cpuset=set([0]), memory=1024)
cell2 = mock.MagicMock(cpuset=set([1]), memory=2048)
self._check_get_instance_vnuma_config_exception(
numa_cells=[cell1, cell2])
@mock.patch.object(vmops.hardware, 'numa_get_constraints')
@mock.patch.object(vmops.objects.ImageMeta, 'from_dict')
def _check_get_instance_vnuma_config(
self, mock_from_dict, mock_get_numa, numa_topology=None,
expected_mem_per_numa=None, expected_cpus_per_numa=None):
mock_instance = mock.MagicMock()
image_meta = mock.MagicMock()
mock_get_numa.return_value = numa_topology
result_memory_per_numa, result_cpus_per_numa = (
self._vmops._get_instance_vnuma_config(mock_instance, image_meta))
self.assertEqual(expected_cpus_per_numa, result_cpus_per_numa)
self.assertEqual(expected_mem_per_numa, result_memory_per_numa)
def test_get_instance_vnuma_config(self):
cell1 = mock.MagicMock(cpuset=set([0]), memory=2048, cpu_pinning=None)
cell2 = mock.MagicMock(cpuset=set([1]), memory=2048, cpu_pinning=None)
mock_topology = mock.MagicMock(cells=[cell1, cell2])
self._check_get_instance_vnuma_config(numa_topology=mock_topology,
expected_cpus_per_numa=1,
expected_mem_per_numa=2048)
def test_get_instance_vnuma_config_no_topology(self):
self._check_get_instance_vnuma_config()
@ddt.data((True, False),
(False, True),
(False, False))
@ddt.unpack
def test_get_instance_dynamic_memory_ratio(self, vnuma_enabled,
nested_virt_enabled):
mock_instance = fake_instance.fake_instance_obj(self.context)
expected_dyn_memory_ratio = 2.0
self.flags(dynamic_memory_ratio=expected_dyn_memory_ratio,
group='hyperv')
if vnuma_enabled or nested_virt_enabled:
expected_dyn_memory_ratio = 1.0
response = self._vmops._get_instance_dynamic_memory_ratio(
mock_instance, vnuma_enabled, nested_virt_enabled)
self.assertEqual(expected_dyn_memory_ratio, response)
def test_attach_root_device_volume(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
root_device_info = {'type': constants.VOLUME,
'connection_info': mock.sentinel.CONN_INFO,
'disk_bus': constants.CTRL_TYPE_IDE}
self._vmops._attach_root_device(self.context,
mock_instance, root_device_info)
self._vmops._volumeops.attach_volume.assert_called_once_with(
self.context,
root_device_info['connection_info'], mock_instance,
disk_bus=root_device_info['disk_bus'])
@mock.patch.object(vmops.VMOps, '_attach_drive')
def test_attach_root_device_disk(self, mock_attach_drive):
mock_instance = fake_instance.fake_instance_obj(self.context)
root_device_info = {'type': constants.DISK,
'boot_index': 0,
'disk_bus': constants.CTRL_TYPE_IDE,
'path': 'fake_path',
'drive_addr': 0,
'ctrl_disk_addr': 1}
self._vmops._attach_root_device(
self.context, mock_instance, root_device_info)
mock_attach_drive.assert_called_once_with(
mock_instance.name, root_device_info['path'],
root_device_info['drive_addr'], root_device_info['ctrl_disk_addr'],
root_device_info['disk_bus'], root_device_info['type'])
@mock.patch.object(vmops.VMOps, '_attach_drive')
def test_attach_ephemerals(self, mock_attach_drive):
mock_instance = fake_instance.fake_instance_obj(self.context)
class FakeBDM(dict):
_bdm_obj = mock.sentinel.bdm_obj
ephemerals = [{'path': os.path.join('eph_dir', 'eph0_path'),
'boot_index': 1,
'disk_bus': constants.CTRL_TYPE_IDE,
'device_type': 'disk',
'drive_addr': 0,
'ctrl_disk_addr': 1},
{'path': os.path.join('eph_dir', 'eph1_path'),
'boot_index': 2,
'disk_bus': constants.CTRL_TYPE_SCSI,
'device_type': 'disk',
'drive_addr': 0,
'ctrl_disk_addr': 0},
{'path': None}]
ephemerals = [FakeBDM(ephemerals[0]),
ephemerals[1],
FakeBDM(ephemerals[2])]
self._vmops.attach_ephemerals(mock_instance.name, ephemerals)
mock_attach_drive.assert_has_calls(
[mock.call(mock_instance.name, ephemerals[0]['path'], 0,
1, constants.CTRL_TYPE_IDE, constants.DISK),
mock.call(mock_instance.name, ephemerals[1]['path'], 0,
0, constants.CTRL_TYPE_SCSI, constants.DISK)
])
mock_update_conn = (
self._vmops._block_dev_man.update_bdm_connection_info)
mock_update_conn.assert_called_once_with(
mock.sentinel.bdm_obj,
eph_filename=os.path.basename(ephemerals[0]['path']))
def test_attach_drive_vm_to_scsi(self):
self._vmops._attach_drive(
mock.sentinel.FAKE_VM_NAME, mock.sentinel.FAKE_PATH,
mock.sentinel.FAKE_DRIVE_ADDR, mock.sentinel.FAKE_CTRL_DISK_ADDR,
constants.CTRL_TYPE_SCSI)
self._vmops._vmutils.attach_scsi_drive.assert_called_once_with(
mock.sentinel.FAKE_VM_NAME, mock.sentinel.FAKE_PATH,
constants.DISK)
def test_attach_drive_vm_to_ide(self):
self._vmops._attach_drive(
mock.sentinel.FAKE_VM_NAME, mock.sentinel.FAKE_PATH,
mock.sentinel.FAKE_DRIVE_ADDR, mock.sentinel.FAKE_CTRL_DISK_ADDR,
constants.CTRL_TYPE_IDE)
self._vmops._vmutils.attach_ide_drive.assert_called_once_with(
mock.sentinel.FAKE_VM_NAME, mock.sentinel.FAKE_PATH,
mock.sentinel.FAKE_DRIVE_ADDR, mock.sentinel.FAKE_CTRL_DISK_ADDR,
constants.DISK)
def test_get_image_vm_generation_default(self):
image_meta = {"properties": {}}
self._vmops._hostutils.get_default_vm_generation.return_value = (
constants.IMAGE_PROP_VM_GEN_1)
self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
response = self._vmops.get_image_vm_generation(
mock.sentinel.instance_id, image_meta)
self.assertEqual(constants.VM_GEN_1, response)
def test_get_image_vm_generation_gen2(self):
image_meta = {"properties": {
constants.IMAGE_PROP_VM_GEN: constants.IMAGE_PROP_VM_GEN_2}}
self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
response = self._vmops.get_image_vm_generation(
mock.sentinel.instance_id, image_meta)
self.assertEqual(constants.VM_GEN_2, response)
def test_get_image_vm_generation_bad_prop(self):
image_meta = {"properties":
{constants.IMAGE_PROP_VM_GEN: mock.sentinel.bad_prop}}
self._vmops._hostutils.get_supported_vm_types.return_value = [
constants.IMAGE_PROP_VM_GEN_1, constants.IMAGE_PROP_VM_GEN_2]
self.assertRaises(exception.InstanceUnacceptable,
self._vmops.get_image_vm_generation,
mock.sentinel.instance_id,
image_meta)
def test_check_vm_image_type_exception(self):
self._vmops._vhdutils.get_vhd_format.return_value = (
constants.DISK_FORMAT_VHD)
self.assertRaises(exception.InstanceUnacceptable,
self._vmops.check_vm_image_type,
mock.sentinel.instance_id, constants.VM_GEN_2,
mock.sentinel.FAKE_PATH)
def _check_requires_certificate(self, os_type):
mock_image_meta = {'properties': {'os_type': os_type}}
expected_result = os_type == fields.OSType.LINUX
result = self._vmops._requires_certificate(mock_image_meta)
self.assertEqual(expected_result, result)
def test_requires_certificate_windows(self):
self._check_requires_certificate(os_type=fields.OSType.WINDOWS)
def test_requires_certificate_linux(self):
self._check_requires_certificate(os_type=fields.OSType.LINUX)
def _check_requires_secure_boot(
self, image_prop_os_type=fields.OSType.LINUX,
image_prop_secure_boot=fields.SecureBoot.REQUIRED,
flavor_secure_boot=fields.SecureBoot.REQUIRED,
vm_gen=constants.VM_GEN_2, expected_exception=True):
mock_instance = fake_instance.fake_instance_obj(self.context)
if flavor_secure_boot:
mock_instance.flavor.extra_specs = {
constants.FLAVOR_SPEC_SECURE_BOOT: flavor_secure_boot}
mock_image_meta = {'properties': {'os_type': image_prop_os_type}}
if image_prop_secure_boot:
mock_image_meta['properties']['os_secure_boot'] = (
image_prop_secure_boot)
if expected_exception:
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._requires_secure_boot,
mock_instance, mock_image_meta, vm_gen)
else:
result = self._vmops._requires_secure_boot(mock_instance,
mock_image_meta,
vm_gen)
requires_sb = fields.SecureBoot.REQUIRED in [
flavor_secure_boot, image_prop_secure_boot]
self.assertEqual(requires_sb, result)
def test_requires_secure_boot_ok(self):
self._check_requires_secure_boot(
expected_exception=False)
def test_requires_secure_boot_image_img_prop_none(self):
self._check_requires_secure_boot(
image_prop_secure_boot=None,
expected_exception=False)
def test_requires_secure_boot_image_extra_spec_none(self):
self._check_requires_secure_boot(
flavor_secure_boot=None,
expected_exception=False)
def test_requires_secure_boot_flavor_no_os_type(self):
self._check_requires_secure_boot(
image_prop_os_type=None)
def test_requires_secure_boot_flavor_no_os_type_no_exc(self):
self._check_requires_secure_boot(
image_prop_os_type=None,
image_prop_secure_boot=fields.SecureBoot.DISABLED,
flavor_secure_boot=fields.SecureBoot.DISABLED,
expected_exception=False)
def test_requires_secure_boot_flavor_disabled(self):
self._check_requires_secure_boot(
flavor_secure_boot=fields.SecureBoot.DISABLED)
def test_requires_secure_boot_image_disabled(self):
self._check_requires_secure_boot(
image_prop_secure_boot=fields.SecureBoot.DISABLED)
def test_requires_secure_boot_generation_1(self):
self._check_requires_secure_boot(vm_gen=constants.VM_GEN_1)
def _check_requires_nested_virt(self, extra_spec='', img_prop=None,
expected=True):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.extra_specs['hw:cpu_features'] = extra_spec
image_meta = {"properties": {'hw_cpu_features': img_prop or ''}}
requires_nested = self._vmops._requires_nested_virt(mock_instance,
image_meta)
self.assertEqual(expected, requires_nested)
def test_requires_nested_virt_flavor(self):
self._check_requires_nested_virt(extra_spec='vmx')
def test_requires_nested_virt_image(self):
self._check_requires_nested_virt(img_prop='vmx')
def test_requires_nested_virt_False(self):
self._check_requires_nested_virt(expected=False)
def test_requires_nested_virt_unsupported(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.extra_specs['hw:cpu_features'] = 'vmx'
mock_image_meta = mock.MagicMock()
self._vmops._hostutils.supports_nested_virtualization.return_value = (
False)
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._requires_nested_virt,
mock_instance, mock_image_meta)
@mock.patch('nova.api.metadata.base.InstanceMetadata')
@mock.patch('nova.virt.configdrive.ConfigDriveBuilder')
@mock.patch('nova.utils.execute')
def _test_create_config_drive(self, mock_execute, mock_ConfigDriveBuilder,
mock_InstanceMetadata, config_drive_format,
config_drive_cdrom, side_effect,
rescue=False):
mock_instance = fake_instance.fake_instance_obj(self.context)
self.flags(config_drive_format=config_drive_format)
self.flags(config_drive_cdrom=config_drive_cdrom, group='hyperv')
self.flags(config_drive_inject_password=True, group='hyperv')
mock_ConfigDriveBuilder().__enter__().make_drive.side_effect = [
side_effect]
path_iso = os.path.join(self.FAKE_DIR, self.FAKE_CONFIG_DRIVE_ISO)
path_vhd = os.path.join(self.FAKE_DIR, self.FAKE_CONFIG_DRIVE_VHD)
def fake_get_configdrive_path(instance_name, disk_format,
rescue=False):
return (path_iso
if disk_format == constants.DVD_FORMAT else path_vhd)
mock_get_configdrive_path = self._vmops._pathutils.get_configdrive_path
mock_get_configdrive_path.side_effect = fake_get_configdrive_path
expected_get_configdrive_path_calls = [mock.call(mock_instance.name,
constants.DVD_FORMAT,
rescue=rescue)]
if not config_drive_cdrom:
expected_call = mock.call(mock_instance.name,
constants.DISK_FORMAT_VHD,
rescue=rescue)
expected_get_configdrive_path_calls.append(expected_call)
if config_drive_format != self.ISO9660:
self.assertRaises(exception.ConfigDriveUnsupportedFormat,
self._vmops._create_config_drive,
self.context,
mock_instance,
[mock.sentinel.FILE],
mock.sentinel.PASSWORD,
mock.sentinel.NET_INFO,
rescue)
elif side_effect is processutils.ProcessExecutionError:
self.assertRaises(processutils.ProcessExecutionError,
self._vmops._create_config_drive,
self.context,
mock_instance,
[mock.sentinel.FILE],
mock.sentinel.PASSWORD,
mock.sentinel.NET_INFO,
rescue)
else:
path = self._vmops._create_config_drive(self.context,
mock_instance,
[mock.sentinel.FILE],
mock.sentinel.PASSWORD,
mock.sentinel.NET_INFO,
rescue)
mock_InstanceMetadata.assert_called_once_with(
mock_instance, content=[mock.sentinel.FILE],
extra_md={'admin_pass': mock.sentinel.PASSWORD},
network_info=mock.sentinel.NET_INFO,
request_context=self.context)
mock_get_configdrive_path.assert_has_calls(
expected_get_configdrive_path_calls)
mock_ConfigDriveBuilder.assert_called_with(
instance_md=mock_InstanceMetadata.return_value)
mock_make_drive = mock_ConfigDriveBuilder().__enter__().make_drive
mock_make_drive.assert_called_once_with(path_iso)
if not CONF.hyperv.config_drive_cdrom:
expected = path_vhd
mock_execute.assert_called_once_with(
CONF.hyperv.qemu_img_cmd,
'convert', '-f', 'raw', '-O', 'vpc',
path_iso, path_vhd, attempts=1)
self._vmops._pathutils.remove.assert_called_once_with(
os.path.join(self.FAKE_DIR, self.FAKE_CONFIG_DRIVE_ISO))
else:
expected = path_iso
self.assertEqual(expected, path)
def test_create_config_drive_cdrom(self):
self._test_create_config_drive(config_drive_format=self.ISO9660,
config_drive_cdrom=True,
side_effect=None)
def test_create_config_drive_vhd(self):
self._test_create_config_drive(config_drive_format=self.ISO9660,
config_drive_cdrom=False,
side_effect=None)
def test_create_rescue_config_drive_vhd(self):
self._test_create_config_drive(config_drive_format=self.ISO9660,
config_drive_cdrom=False,
side_effect=None,
rescue=True)
def test_create_config_drive_other_drive_format(self):
self._test_create_config_drive(config_drive_format=self.VFAT,
config_drive_cdrom=False,
side_effect=None)
def test_create_config_drive_execution_error(self):
self._test_create_config_drive(
config_drive_format=self.ISO9660,
config_drive_cdrom=False,
side_effect=processutils.ProcessExecutionError)
def test_attach_config_drive_exception(self):
instance = fake_instance.fake_instance_obj(self.context)
self.assertRaises(exception.InvalidDiskFormat,
self._vmops.attach_config_drive,
instance, 'C:/fake_instance_dir/configdrive.xxx',
constants.VM_GEN_1)
@mock.patch.object(vmops.VMOps, '_attach_drive')
def test_attach_config_drive(self, mock_attach_drive):
instance = fake_instance.fake_instance_obj(self.context)
self._vmops.attach_config_drive(instance,
self._FAKE_CONFIGDRIVE_PATH,
constants.VM_GEN_1)
mock_attach_drive.assert_called_once_with(
instance.name, self._FAKE_CONFIGDRIVE_PATH,
1, 0, constants.CTRL_TYPE_IDE, constants.DISK)
@mock.patch.object(vmops.VMOps, '_attach_drive')
def test_attach_config_drive_gen2(self, mock_attach_drive):
instance = fake_instance.fake_instance_obj(self.context)
self._vmops.attach_config_drive(instance,
self._FAKE_CONFIGDRIVE_PATH,
constants.VM_GEN_2)
mock_attach_drive.assert_called_once_with(
instance.name, self._FAKE_CONFIGDRIVE_PATH,
1, 0, constants.CTRL_TYPE_SCSI, constants.DISK)
def test_detach_config_drive(self):
is_rescue_configdrive = True
mock_lookup_configdrive = (
self._vmops._pathutils.lookup_configdrive_path)
mock_lookup_configdrive.return_value = mock.sentinel.configdrive_path
self._vmops._detach_config_drive(mock.sentinel.instance_name,
rescue=is_rescue_configdrive,
delete=True)
mock_lookup_configdrive.assert_called_once_with(
mock.sentinel.instance_name,
rescue=is_rescue_configdrive)
self._vmops._vmutils.detach_vm_disk.assert_called_once_with(
mock.sentinel.instance_name, mock.sentinel.configdrive_path,
is_physical=False)
self._vmops._pathutils.remove.assert_called_once_with(
mock.sentinel.configdrive_path)
@ddt.data({'passed_instance_path': True},
{'cleanup_migr_files': True})
@ddt.unpack
def test_delete_disk_files(self, passed_instance_path=None,
cleanup_migr_files=False):
mock_instance = mock.Mock(
system_metadata=dict(
backup_location=mock.sentinel.backup_location))
self._vmops._delete_disk_files(mock_instance,
passed_instance_path,
cleanup_migr_files)
stop_console_handler = (
self._vmops._serial_console_ops.stop_console_handler_unsync)
stop_console_handler.assert_called_once_with(mock_instance.name)
if passed_instance_path:
self.assertFalse(self._vmops._pathutils.get_instance_dir.called)
else:
self._pathutils.get_instance_dir.assert_called_once_with(
mock_instance.name)
exp_inst_path = (passed_instance_path or
self._pathutils.get_instance_dir.return_value)
exp_check_remove_dir_calls = [mock.call(exp_inst_path)]
mock_get_migr_dir = self._pathutils.get_instance_migr_revert_dir
if cleanup_migr_files:
mock_get_migr_dir.assert_called_once_with(
exp_inst_path, remove_dir=True)
exp_check_remove_dir_calls.append(
mock.call(mock.sentinel.backup_location))
self._pathutils.check_remove_dir.assert_has_calls(
exp_check_remove_dir_calls)
@ddt.data({"force_destroy": True},
{'vm_exists': False, 'planned_vm_exists': False},
{'vm_exists': False, 'planned_vm_exists': True})
@ddt.unpack
@mock.patch('compute_hyperv.nova.vmops.VMOps._delete_disk_files')
@mock.patch('compute_hyperv.nova.vmops.VMOps.power_off')
@mock.patch('compute_hyperv.nova.vmops.VMOps.unplug_vifs')
def test_destroy(self, mock_unplug_vifs, mock_power_off,
mock_delete_disk_files, vm_exists=True,
planned_vm_exists=False,
force_destroy=False):
self.flags(force_destroy_instances=force_destroy, group="hyperv")
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._vmutils.vm_exists.return_value = vm_exists
self._vmops._migrutils.planned_vm_exists.return_value = (
planned_vm_exists)
self._vmops.destroy(
instance=mock_instance,
block_device_info=mock.sentinel.FAKE_BD_INFO,
network_info=mock.sentinel.fake_network_info,
cleanup_migration_files=mock.sentinel.cleanup_migr_files)
self._vmops._vmutils.vm_exists.assert_called_with(
mock_instance.name)
if vm_exists:
self._vmops._vmutils.stop_vm_jobs.assert_called_once_with(
mock_instance.name)
mock_power_off.assert_called_once_with(mock_instance)
self._vmops._vmutils.destroy_vm.assert_called_once_with(
mock_instance.name)
elif planned_vm_exists:
self._vmops._migrutils.planned_vm_exists.assert_called_once_with(
mock_instance.name)
destroy_planned_vm = (
self._vmops._migrutils.destroy_existing_planned_vm)
destroy_planned_vm.assert_called_once_with(
mock_instance.name)
self.assertFalse(self._vmops._vmutils.destroy_vm.called)
else:
self.assertFalse(
self._vmops._migrutils.destroy_existing_planned_vm.called)
mock_unplug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
self._vmops._volumeops.disconnect_volumes.assert_called_once_with(
mock.sentinel.FAKE_BD_INFO)
mock_delete_disk_files.assert_called_once_with(
mock_instance,
self._pathutils.get_instance_dir.return_value,
mock.sentinel.cleanup_migr_files)
@mock.patch('compute_hyperv.nova.vmops.VMOps.power_off')
def test_destroy_exception(self, mock_power_off):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._vmutils.destroy_vm.side_effect = (
os_win_exc.HyperVException)
self._vmops._vmutils.vm_exists.return_value = True
self.assertRaises(os_win_exc.HyperVException,
self._vmops.destroy, mock_instance,
mock.sentinel.network_info,
mock.sentinel.block_device_info)
def test_reboot_hard(self):
self._test_reboot(vmops.REBOOT_TYPE_HARD,
os_win_const.HYPERV_VM_STATE_REBOOT)
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_reboot_soft(self, mock_soft_shutdown):
mock_soft_shutdown.return_value = True
self._test_reboot(vmops.REBOOT_TYPE_SOFT,
os_win_const.HYPERV_VM_STATE_ENABLED)
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_reboot_soft_failed(self, mock_soft_shutdown):
mock_soft_shutdown.return_value = False
self._test_reboot(vmops.REBOOT_TYPE_SOFT,
os_win_const.HYPERV_VM_STATE_REBOOT)
@mock.patch("compute_hyperv.nova.vmops.VMOps.power_on")
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_reboot_soft_exception(self, mock_soft_shutdown, mock_power_on):
mock_soft_shutdown.return_value = True
mock_power_on.side_effect = os_win_exc.HyperVException(
"Expected failure")
instance = fake_instance.fake_instance_obj(self.context)
self.assertRaises(os_win_exc.HyperVException, self._vmops.reboot,
instance, {}, vmops.REBOOT_TYPE_SOFT)
mock_soft_shutdown.assert_called_once_with(instance)
mock_power_on.assert_called_once_with(instance, network_info={})
def _test_reboot(self, reboot_type, vm_state):
instance = fake_instance.fake_instance_obj(self.context)
with mock.patch.object(self._vmops, '_set_vm_state') as mock_set_state:
self._vmops.reboot(instance, {}, reboot_type)
mock_set_state.assert_called_once_with(instance, vm_state)
@mock.patch("compute_hyperv.nova.vmops.VMOps._wait_for_power_off")
def test_soft_shutdown(self, mock_wait_for_power_off):
instance = fake_instance.fake_instance_obj(self.context)
mock_wait_for_power_off.return_value = True
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT)
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm
mock_shutdown_vm.assert_called_once_with(instance.name)
mock_wait_for_power_off.assert_called_once_with(
instance.name, self._FAKE_TIMEOUT)
self.assertTrue(result)
@mock.patch("time.sleep")
def test_soft_shutdown_failed(self, mock_sleep):
instance = fake_instance.fake_instance_obj(self.context)
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm
mock_shutdown_vm.side_effect = os_win_exc.HyperVException(
"Expected failure.")
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT)
mock_shutdown_vm.assert_called_once_with(instance.name)
self.assertFalse(result)
@mock.patch("compute_hyperv.nova.vmops.VMOps._wait_for_power_off")
def test_soft_shutdown_wait(self, mock_wait_for_power_off):
instance = fake_instance.fake_instance_obj(self.context)
mock_wait_for_power_off.side_effect = [False, True]
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT, 1)
calls = [mock.call(instance.name, 1),
mock.call(instance.name, self._FAKE_TIMEOUT - 1)]
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm
mock_shutdown_vm.assert_called_with(instance.name)
mock_wait_for_power_off.assert_has_calls(calls)
self.assertTrue(result)
@mock.patch("compute_hyperv.nova.vmops.VMOps._wait_for_power_off")
def test_soft_shutdown_wait_timeout(self, mock_wait_for_power_off):
instance = fake_instance.fake_instance_obj(self.context)
mock_wait_for_power_off.return_value = False
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT, 1.5)
calls = [mock.call(instance.name, 1.5),
mock.call(instance.name, self._FAKE_TIMEOUT - 1.5)]
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm
mock_shutdown_vm.assert_called_with(instance.name)
mock_wait_for_power_off.assert_has_calls(calls)
self.assertFalse(result)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_pause(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.pause(instance=mock_instance)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_PAUSED)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_unpause(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.unpause(instance=mock_instance)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_ENABLED)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_suspend(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.suspend(instance=mock_instance)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_SUSPENDED)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_resume(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.resume(instance=mock_instance)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_ENABLED)
def _test_power_off(self, timeout, set_state_expected=True):
instance = fake_instance.fake_instance_obj(self.context)
with mock.patch.object(self._vmops, '_set_vm_state') as mock_set_state:
self._vmops.power_off(instance, timeout)
serialops = self._vmops._serial_console_ops
serialops.stop_console_handler.assert_called_once_with(
instance.name)
if set_state_expected:
mock_set_state.assert_called_once_with(
instance, os_win_const.HYPERV_VM_STATE_DISABLED)
def test_power_off_hard(self):
self._test_power_off(timeout=0)
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_power_off_exception(self, mock_soft_shutdown):
mock_soft_shutdown.return_value = False
self._test_power_off(timeout=1)
@mock.patch("compute_hyperv.nova.vmops.VMOps._set_vm_state")
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_power_off_soft(self, mock_soft_shutdown, mock_set_state):
instance = fake_instance.fake_instance_obj(self.context)
mock_soft_shutdown.return_value = True
self._vmops.power_off(instance, 1, 0)
serialops = self._vmops._serial_console_ops
serialops.stop_console_handler.assert_called_once_with(
instance.name)
mock_soft_shutdown.assert_called_once_with(
instance, 1, vmops.SHUTDOWN_TIME_INCREMENT)
self.assertFalse(mock_set_state.called)
@mock.patch("compute_hyperv.nova.vmops.VMOps._soft_shutdown")
def test_power_off_unexisting_instance(self, mock_soft_shutdown):
mock_soft_shutdown.side_effect = os_win_exc.HyperVVMNotFoundException(
vm_name=mock.sentinel.vm_name)
self._test_power_off(timeout=1, set_state_expected=False)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_power_on(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.power_on(mock_instance)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_ENABLED)
@mock.patch('compute_hyperv.nova.vmops.VMOps._set_vm_state')
def test_power_on_having_block_devices(self, mock_set_vm_state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.power_on(mock_instance, mock.sentinel.block_device_info)
mock_fix_instance_vol_paths = (
self._vmops._volumeops.fix_instance_volume_disk_paths)
mock_fix_instance_vol_paths.assert_called_once_with(
mock_instance.name, mock.sentinel.block_device_info)
mock_set_vm_state.assert_called_once_with(
mock_instance, os_win_const.HYPERV_VM_STATE_ENABLED)
@mock.patch.object(vmops.VMOps, 'plug_vifs')
def test_power_on_with_network_info(self, mock_plug_vifs):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.power_on(mock_instance,
network_info=mock.sentinel.fake_network_info)
mock_plug_vifs.assert_called_once_with(
mock_instance, mock.sentinel.fake_network_info)
@mock.patch.object(vmops.VMOps, 'plug_vifs')
def test_power_on_vifs_already_plugged(self, mock_plug_vifs):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops.power_on(mock_instance,
should_plug_vifs=False)
self.assertFalse(mock_plug_vifs.called)
def _test_set_vm_state(self, state):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._set_vm_state(mock_instance, state)
self._vmops._vmutils.set_vm_state.assert_called_once_with(
mock_instance.name, state)
def test_set_vm_state_disabled(self):
self._test_set_vm_state(state=os_win_const.HYPERV_VM_STATE_DISABLED)
def test_set_vm_state_enabled(self):
self._test_set_vm_state(state=os_win_const.HYPERV_VM_STATE_ENABLED)
def test_set_vm_state_reboot(self):
self._test_set_vm_state(state=os_win_const.HYPERV_VM_STATE_REBOOT)
def test_set_vm_state_exception(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._vmutils.set_vm_state.side_effect = (
os_win_exc.HyperVException)
self.assertRaises(os_win_exc.HyperVException,
self._vmops._set_vm_state,
mock_instance, mock.sentinel.STATE)
def test_get_vm_state(self):
summary_info = {'EnabledState': os_win_const.HYPERV_VM_STATE_DISABLED}
with mock.patch.object(self._vmops._vmutils,
'get_vm_summary_info') as mock_get_summary_info:
mock_get_summary_info.return_value = summary_info
response = self._vmops._get_vm_state(mock.sentinel.FAKE_VM_NAME)
self.assertEqual(response, os_win_const.HYPERV_VM_STATE_DISABLED)
@mock.patch.object(vmops.VMOps, '_get_vm_state')
def test_wait_for_power_off_true(self, mock_get_state):
mock_get_state.return_value = os_win_const.HYPERV_VM_STATE_DISABLED
result = self._vmops._wait_for_power_off(
mock.sentinel.FAKE_VM_NAME, vmops.SHUTDOWN_TIME_INCREMENT)
mock_get_state.assert_called_with(mock.sentinel.FAKE_VM_NAME)
self.assertTrue(result)
@mock.patch.object(vmops.etimeout, "with_timeout")
def test_wait_for_power_off_false(self, mock_with_timeout):
mock_with_timeout.side_effect = etimeout.Timeout()
result = self._vmops._wait_for_power_off(
mock.sentinel.FAKE_VM_NAME, vmops.SHUTDOWN_TIME_INCREMENT)
self.assertFalse(result)
def test_create_vm_com_port_pipes(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_serial_ports = {
1: constants.SERIAL_PORT_TYPE_RO,
2: constants.SERIAL_PORT_TYPE_RW
}
self._vmops._create_vm_com_port_pipes(mock_instance,
mock_serial_ports)
expected_calls = []
for port_number, port_type in mock_serial_ports.items():
expected_pipe = r'\\.\pipe\%s_%s' % (mock_instance.uuid,
port_type)
expected_calls.append(mock.call(mock_instance.name,
port_number,
expected_pipe))
mock_set_conn = self._vmops._vmutils.set_vm_serial_port_connection
mock_set_conn.assert_has_calls(expected_calls)
def test_list_instance_uuids(self):
fake_uuid = '4f54fb69-d3a2-45b7-bb9b-b6e6b3d893b3'
with mock.patch.object(self._vmops._vmutils,
'list_instance_notes') as mock_list_notes:
mock_list_notes.return_value = [('fake_name', [fake_uuid])]
response = self._vmops.list_instance_uuids()
mock_list_notes.assert_called_once_with()
self.assertEqual(response, [fake_uuid])
def test_copy_vm_dvd_disks(self):
fake_paths = [mock.sentinel.FAKE_DVD_PATH1,
mock.sentinel.FAKE_DVD_PATH2]
mock_copy = self._vmops._pathutils.copyfile
mock_get_dvd_disk_paths = self._vmops._vmutils.get_vm_dvd_disk_paths
mock_get_dvd_disk_paths.return_value = fake_paths
self._vmops._pathutils.get_instance_dir.return_value = (
mock.sentinel.FAKE_DEST_PATH)
self._vmops.copy_vm_dvd_disks(mock.sentinel.FAKE_VM_NAME,
mock.sentinel.FAKE_DEST_HOST)
mock_get_dvd_disk_paths.assert_called_with(mock.sentinel.FAKE_VM_NAME)
self._vmops._pathutils.get_instance_dir.assert_called_once_with(
mock.sentinel.FAKE_VM_NAME,
remote_server=mock.sentinel.FAKE_DEST_HOST)
mock_copy.has_calls(mock.call(mock.sentinel.FAKE_DVD_PATH1,
mock.sentinel.FAKE_DEST_PATH),
mock.call(mock.sentinel.FAKE_DVD_PATH2,
mock.sentinel.FAKE_DEST_PATH))
def test_plug_vifs(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.plug_vifs(mock_instance,
network_info=mock_network_info)
self._vmops._vif_driver.plug.assert_has_calls(calls)
def test_plug_vifs_failed(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
mock_network_info = [fake_vif1]
self._vmops._vif_driver.plug.side_effect = exception.NovaException
self.assertRaises(exception.VirtualInterfacePlugException,
self._vmops.plug_vifs,
mock_instance, mock_network_info)
def test_unplug_vifs(self):
mock_instance = fake_instance.fake_instance_obj(self.context)
fake_vif1 = {'id': mock.sentinel.ID1,
'type': mock.sentinel.vif_type1}
fake_vif2 = {'id': mock.sentinel.ID2,
'type': mock.sentinel.vif_type2}
mock_network_info = [fake_vif1, fake_vif2]
calls = [mock.call(mock_instance, fake_vif1),
mock.call(mock_instance, fake_vif2)]
self._vmops.unplug_vifs(mock_instance,
network_info=mock_network_info)
self._vmops._vif_driver.unplug.assert_has_calls(calls)
@ddt.data({},
{'metrics_enabled': False},
{'enable_network_metrics': False})
@ddt.unpack
def test_configure_instance_metrics(self, metrics_enabled=True,
enable_network_metrics=True):
port_names = ['port1', 'port2']
enable_vm_metrics = self._metricsutils.enable_vm_metrics_collection
self._vmutils.get_vm_nic_names.return_value = port_names
self.flags(enable_instance_metrics_collection=metrics_enabled,
group='hyperv')
self._vmops.configure_instance_metrics(
mock.sentinel.instance_name,
enable_network_metrics=enable_network_metrics)
if metrics_enabled:
enable_vm_metrics.assert_called_once_with(
mock.sentinel.instance_name)
if enable_network_metrics:
self._vmutils.get_vm_nic_names.assert_called_once_with(
mock.sentinel.instance_name)
self._vif_driver.enable_metrics.assert_has_calls(
[mock.call(mock.sentinel.instance_name, port_name)
for port_name in port_names])
else:
enable_vm_metrics.assert_not_called()
if not (metrics_enabled and enable_network_metrics):
self._vif_driver.enable_metrics.assert_not_called()
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)
mock_instance.old_flavor.extra_specs['os:resolution'] = (
os_win_const.REMOTEFX_MAX_RES_1920x1200)
self._vmops.configure_remotefx(mock_instance, mock.sentinel.VM_GEN,
True)
disable_remotefx = self._vmops._vmutils.disable_remotefx_video_adapter
disable_remotefx.assert_called_once_with(mock_instance.name)
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.object(vmops.VMOps, '_get_vm_state')
def test_check_hotplug_available_vm_disabled(self, mock_get_vm_state):
fake_vm = fake_instance.fake_instance_obj(self.context)
mock_get_vm_state.return_value = os_win_const.HYPERV_VM_STATE_DISABLED
result = self._vmops._check_hotplug_available(fake_vm)
self.assertTrue(result)
mock_get_vm_state.assert_called_once_with(fake_vm.name)
self.assertFalse(
self._vmops._hostutils.check_min_windows_version.called)
self.assertFalse(self._vmops._vmutils.get_vm_generation.called)
@mock.patch.object(vmops.VMOps, '_get_vm_state')
def _test_check_hotplug_available(
self, mock_get_vm_state, expected_result=False,
vm_gen=constants.VM_GEN_2, windows_version=_WIN_VERSION_10):
fake_vm = fake_instance.fake_instance_obj(self.context)
mock_get_vm_state.return_value = os_win_const.HYPERV_VM_STATE_ENABLED
self._vmops._vmutils.get_vm_generation.return_value = vm_gen
fake_check_win_vers = self._vmops._hostutils.check_min_windows_version
fake_check_win_vers.return_value = (
windows_version == self._WIN_VERSION_10)
result = self._vmops._check_hotplug_available(fake_vm)
self.assertEqual(expected_result, result)
mock_get_vm_state.assert_called_once_with(fake_vm.name)
fake_check_win_vers.assert_called_once_with(10, 0)
def test_check_if_hotplug_available(self):
self._test_check_hotplug_available(expected_result=True)
def test_check_if_hotplug_available_gen1(self):
self._test_check_hotplug_available(
expected_result=False, vm_gen=constants.VM_GEN_1)
def test_check_if_hotplug_available_win_6_3(self):
self._test_check_hotplug_available(
expected_result=False, windows_version=self._WIN_VERSION_6_3)
@mock.patch.object(vmops.VMOps, 'update_device_metadata')
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_attach_interface(self, mock_check_hotplug_available,
mock_update_dev_meta):
mock_check_hotplug_available.return_value = True
fake_vm = fake_instance.fake_instance_obj(self.context)
fake_vif = test_virtual_interface.fake_vif
self._vmops.attach_interface(
mock.sentinel.context, fake_vm, fake_vif)
mock_check_hotplug_available.assert_called_once_with(fake_vm)
self._vmops._vif_driver.plug.assert_called_once_with(
fake_vm, fake_vif)
self._vmops._vmutils.create_nic.assert_called_once_with(
fake_vm.name, fake_vif['id'], fake_vif['address'])
mock_update_dev_meta.assert_called_once_with(
mock.sentinel.context, fake_vm)
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_attach_interface_failed(self, mock_check_hotplug_available):
mock_check_hotplug_available.return_value = False
self.assertRaises(exception.InterfaceAttachFailed,
self._vmops.attach_interface,
mock.sentinel.context,
mock.MagicMock(), mock.sentinel.fake_vif)
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_detach_interface(self, mock_check_hotplug_available):
mock_check_hotplug_available.return_value = True
fake_vm = fake_instance.fake_instance_obj(self.context)
fake_vif = test_virtual_interface.fake_vif
self._vmops.detach_interface(fake_vm, fake_vif)
mock_check_hotplug_available.assert_called_once_with(fake_vm)
self._vmops._vif_driver.unplug.assert_called_once_with(
fake_vm, fake_vif)
self._vmops._vmutils.destroy_nic.assert_called_once_with(
fake_vm.name, fake_vif['id'])
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_detach_interface_failed(self, mock_check_hotplug_available):
mock_check_hotplug_available.return_value = False
self.assertRaises(exception.InterfaceDetachFailed,
self._vmops.detach_interface,
mock.MagicMock(), mock.sentinel.fake_vif)
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_detach_interface_missing_instance(self, mock_check_hotplug):
mock_check_hotplug.side_effect = os_win_exc.HyperVVMNotFoundException(
vm_name='fake_vm')
self.assertRaises(exception.InterfaceDetachFailed,
self._vmops.detach_interface,
mock.MagicMock(), mock.sentinel.fake_vif)
@mock.patch('nova.virt.configdrive.required_by')
@mock.patch.object(vmops.VMOps, '_create_root_vhd')
@mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
@mock.patch.object(vmops.VMOps, '_attach_drive')
@mock.patch.object(vmops.VMOps, '_create_config_drive')
@mock.patch.object(vmops.VMOps, 'attach_config_drive')
@mock.patch.object(vmops.VMOps, '_detach_config_drive')
@mock.patch.object(vmops.VMOps, 'power_on')
def test_rescue_instance(self, mock_power_on,
mock_detach_config_drive,
mock_attach_config_drive,
mock_create_config_drive,
mock_attach_drive,
mock_get_image_vm_gen,
mock_create_root_vhd,
mock_configdrive_required):
mock_image_meta = mock.MagicMock()
mock_vm_gen = constants.VM_GEN_2
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_configdrive_required.return_value = True
mock_create_root_vhd.return_value = mock.sentinel.rescue_vhd_path
mock_get_image_vm_gen.return_value = mock_vm_gen
self._vmops._vmutils.get_vm_generation.return_value = mock_vm_gen
self._vmops._pathutils.lookup_root_vhd_path.return_value = (
mock.sentinel.root_vhd_path)
mock_create_config_drive.return_value = (
mock.sentinel.rescue_configdrive_path)
self._vmops.rescue_instance(self.context,
mock_instance,
mock.sentinel.network_info,
mock_image_meta,
mock.sentinel.rescue_password)
mock_get_image_vm_gen.assert_called_once_with(
mock_instance.uuid, mock_image_meta)
self._vmops._vmutils.detach_vm_disk.assert_called_once_with(
mock_instance.name, mock.sentinel.root_vhd_path,
is_physical=False)
mock_attach_drive.assert_called_once_with(
mock_instance.name, mock.sentinel.rescue_vhd_path, 0,
self._vmops._ROOT_DISK_CTRL_ADDR,
vmops.VM_GENERATIONS_CONTROLLER_TYPES[mock_vm_gen])
self._vmops._vmutils.attach_scsi_drive.assert_called_once_with(
mock_instance.name, mock.sentinel.root_vhd_path,
drive_type=constants.DISK)
mock_detach_config_drive.assert_called_once_with(mock_instance.name)
mock_create_config_drive.assert_called_once_with(
self.context, mock_instance,
injected_files=None,
admin_password=mock.sentinel.rescue_password,
network_info=mock.sentinel.network_info,
rescue=True)
mock_attach_config_drive.assert_called_once_with(
mock_instance, mock.sentinel.rescue_configdrive_path,
mock_vm_gen)
@mock.patch.object(vmops.VMOps, '_create_root_vhd')
@mock.patch.object(vmops.VMOps, 'get_image_vm_generation')
@mock.patch.object(vmops.VMOps, 'unrescue_instance')
def _test_rescue_instance_exception(self, mock_unrescue,
mock_get_image_vm_gen,
mock_create_root_vhd,
wrong_vm_gen=False,
boot_from_volume=False,
expected_exc=None):
mock_vm_gen = constants.VM_GEN_1
image_vm_gen = (mock_vm_gen
if not wrong_vm_gen else constants.VM_GEN_2)
mock_image_meta = mock.MagicMock()
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_get_image_vm_gen.return_value = image_vm_gen
self._vmops._vmutils.get_vm_generation.return_value = mock_vm_gen
self._vmops._pathutils.lookup_root_vhd_path.return_value = (
mock.sentinel.root_vhd_path if not boot_from_volume else None)
self.assertRaises(expected_exc,
self._vmops.rescue_instance,
self.context, mock_instance,
mock.sentinel.network_info,
mock_image_meta,
mock.sentinel.rescue_password)
mock_unrescue.assert_called_once_with(mock_instance)
def test_rescue_instance_wrong_vm_gen(self):
# Test the case when the rescue image requires a different
# vm generation than the actual rescued instance.
self._test_rescue_instance_exception(
wrong_vm_gen=True,
expected_exc=exception.ImageUnacceptable)
def test_rescue_instance_boot_from_volume(self):
# Rescuing instances booted from volume is not supported.
self._test_rescue_instance_exception(
boot_from_volume=True,
expected_exc=exception.InstanceNotRescuable)
@mock.patch.object(fileutils, 'delete_if_exists')
@mock.patch.object(vmops.VMOps, '_attach_drive')
@mock.patch.object(vmops.VMOps, 'attach_config_drive')
@mock.patch.object(vmops.VMOps, '_detach_config_drive')
@mock.patch.object(vmops.VMOps, 'power_on')
@mock.patch.object(vmops.VMOps, 'power_off')
def test_unrescue_instance(self, mock_power_on, mock_power_off,
mock_detach_config_drive,
mock_attach_configdrive,
mock_attach_drive,
mock_delete_if_exists):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_vm_gen = constants.VM_GEN_2
self._vmops._vmutils.get_vm_generation.return_value = mock_vm_gen
self._vmops._vmutils.is_disk_attached.return_value = False
self._vmops._pathutils.lookup_root_vhd_path.side_effect = (
mock.sentinel.root_vhd_path, mock.sentinel.rescue_vhd_path)
self._vmops._pathutils.lookup_configdrive_path.return_value = (
mock.sentinel.configdrive_path)
self._vmops.unrescue_instance(mock_instance)
self._vmops._pathutils.lookup_root_vhd_path.assert_has_calls(
[mock.call(mock_instance.name),
mock.call(mock_instance.name, rescue=True)])
self._vmops._vmutils.detach_vm_disk.assert_has_calls(
[mock.call(mock_instance.name,
mock.sentinel.root_vhd_path,
is_physical=False),
mock.call(mock_instance.name,
mock.sentinel.rescue_vhd_path,
is_physical=False)])
mock_attach_drive.assert_called_once_with(
mock_instance.name, mock.sentinel.root_vhd_path, 0,
self._vmops._ROOT_DISK_CTRL_ADDR,
vmops.VM_GENERATIONS_CONTROLLER_TYPES[mock_vm_gen])
mock_detach_config_drive.assert_called_once_with(mock_instance.name,
rescue=True,
delete=True)
mock_delete_if_exists.assert_called_once_with(
mock.sentinel.rescue_vhd_path)
self._vmops._vmutils.is_disk_attached.assert_called_once_with(
mock.sentinel.configdrive_path,
is_physical=False)
mock_attach_configdrive.assert_called_once_with(
mock_instance, mock.sentinel.configdrive_path, mock_vm_gen)
mock_power_on.assert_called_once_with(mock_instance)
@mock.patch.object(vmops.VMOps, 'power_off')
def test_unrescue_instance_missing_root_image(self, mock_power_off):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.vm_state = vm_states.RESCUED
self._vmops._pathutils.lookup_root_vhd_path.return_value = None
self.assertRaises(exception.InstanceNotRescuable,
self._vmops.unrescue_instance,
mock_instance)
@ddt.data((1, True),
(0, True),
(0, False))
@ddt.unpack
@mock.patch.object(vmops.VMOps, '_get_scoped_flavor_extra_specs')
@mock.patch.object(vmops.VMOps, '_get_instance_local_disks')
def test_set_instance_disk_qos_specs(self, total_iops_sec, is_resize,
mock_get_local_disks,
mock_get_scoped_specs):
fake_total_bytes_sec = 8
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_local_disks = [mock.sentinel.root_vhd_path,
mock.sentinel.eph_vhd_path]
mock_get_local_disks.return_value = mock_local_disks
mock_set_qos_specs = self._vmops._vmutils.set_disk_qos_specs
mock_get_scoped_specs.return_value = dict(
disk_total_bytes_sec=fake_total_bytes_sec)
mock_bytes_per_sec_to_iops = (
self._vmops._volumeops.bytes_per_sec_to_iops)
mock_bytes_per_sec_to_iops.return_value = total_iops_sec
self._vmops._set_instance_disk_qos_specs(mock_instance, is_resize)
mock_bytes_per_sec_to_iops.assert_called_once_with(
fake_total_bytes_sec)
if total_iops_sec or is_resize:
mock_get_local_disks.assert_called_once_with(mock_instance.name)
expected_calls = [mock.call(disk_path, total_iops_sec)
for disk_path in mock_local_disks]
mock_set_qos_specs.assert_has_calls(expected_calls)
else:
self.assertFalse(mock_get_local_disks.called)
self.assertFalse(mock_set_qos_specs.called)
def test_get_instance_local_disks(self):
fake_instance_dir = 'fake_instance_dir'
fake_local_disks = [os.path.join(fake_instance_dir, disk_name)
for disk_name in ['root.vhd', 'configdrive.iso']]
fake_instance_disks = ['fake_remote_disk'] + fake_local_disks
mock_get_storage_paths = self._vmops._vmutils.get_vm_storage_paths
mock_get_storage_paths.return_value = [fake_instance_disks, []]
mock_get_instance_dir = self._vmops._pathutils.get_instance_dir
mock_get_instance_dir.return_value = fake_instance_dir
ret_val = self._vmops._get_instance_local_disks(
mock.sentinel.instance_name)
self.assertEqual(fake_local_disks, ret_val)
def test_get_scoped_flavor_extra_specs(self):
# The flavor extra spect dict contains only string values.
fake_total_bytes_sec = '8'
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.flavor.extra_specs = {
'spec_key': 'spec_value',
'quota:total_bytes_sec': fake_total_bytes_sec}
ret_val = self._vmops._get_scoped_flavor_extra_specs(
mock_instance, scope='quota')
expected_specs = {
'total_bytes_sec': fake_total_bytes_sec
}
self.assertEqual(expected_specs, ret_val)
def _mock_get_port_settings(self, logging_port, interactive_port):
mock_image_port_settings = {
constants.IMAGE_PROP_LOGGING_SERIAL_PORT: logging_port,
constants.IMAGE_PROP_INTERACTIVE_SERIAL_PORT: interactive_port
}
mock_image_meta = {'properties': mock_image_port_settings}
acceptable_ports = [1, 2]
expected_exception = not (logging_port in acceptable_ports and
interactive_port in acceptable_ports)
if expected_exception:
self.assertRaises(exception.ImageSerialPortNumberInvalid,
self._vmops._get_image_serial_port_settings,
mock_image_meta)
else:
return self._vmops._get_image_serial_port_settings(
mock_image_meta)
def test_get_image_serial_port_settings(self):
logging_port = 1
interactive_port = 2
ret_val = self._mock_get_port_settings(logging_port, interactive_port)
expected_serial_ports = {
logging_port: constants.SERIAL_PORT_TYPE_RO,
interactive_port: constants.SERIAL_PORT_TYPE_RW,
}
self.assertEqual(expected_serial_ports, ret_val)
def test_get_image_serial_port_settings_exception(self):
self._mock_get_port_settings(1, 3)
def test_get_image_serial_port_settings_single_port(self):
interactive_port = 1
ret_val = self._mock_get_port_settings(interactive_port,
interactive_port)
expected_serial_ports = {
interactive_port: constants.SERIAL_PORT_TYPE_RW
}
self.assertEqual(expected_serial_ports, ret_val)
@mock.patch.object(vmops.VMOps, '_check_vtpm_requirements')
@mock.patch.object(vmops.VMOps, '_feature_requested')
@mock.patch.object(vmops.VMOps, '_create_fsk')
def _test_configure_secure_vm(self, mock_create_fsk,
mock_feature_requested,
mock_check_vtpm_requirements,
requires_shielded, requires_encryption):
instance = mock.MagicMock()
mock_tmp_file = self._vmops._pathutils.temporary_file
mock_tmp_file.return_value.__enter__.side_effect = [
self._FAKE_FSK_FILE_PATH, self._FAKE_PDK_FILE_PATH]
mock_feature_requested.side_effect = [requires_shielded,
requires_encryption]
self._vmops._configure_secure_vm(mock.sentinel.context, instance,
mock.sentinel.image_meta,
mock.sentinel.secure_boot_enabled)
expected_calls = [mock.call(instance,
mock.sentinel.image_meta,
constants.IMAGE_PROP_VTPM_SHIELDED)]
if not requires_shielded:
expected_calls.append(mock.call(instance,
mock.sentinel.image_meta,
constants.IMAGE_PROP_VTPM))
mock_feature_requested.has_calls(expected_calls)
mock_check_vtpm_requirements.assert_called_with(instance,
mock.sentinel.image_meta, mock.sentinel.secure_boot_enabled)
self._vmops._vmutils.add_vtpm.assert_called_once_with(
instance.name, self._FAKE_PDK_FILE_PATH,
shielded=requires_shielded)
self._vmops._vmutils.provision_vm.assert_called_once_with(
instance.name, self._FAKE_FSK_FILE_PATH, self._FAKE_PDK_FILE_PATH)
def test_configure_secure_vm_shielded(self):
self._test_configure_secure_vm(requires_shielded=True,
requires_encryption=True)
def test_configure_secure_vm_encryption(self):
self._test_configure_secure_vm(requires_shielded=False,
requires_encryption=True)
@mock.patch.object(vmops.VMOps, '_check_vtpm_requirements')
@mock.patch.object(vmops.VMOps, '_feature_requested')
def test_configure_regular_vm(self, mock_feature_requested,
mock_check_vtpm_requirements):
mock_feature_requested.side_effect = [False, False]
self._vmops._configure_secure_vm(mock.sentinel.context,
mock.MagicMock(),
mock.sentinel.image_meta,
mock.sentinel.secure_boot_enabled)
self.assertFalse(mock_check_vtpm_requirements.called)
def _test_feature_requested(self, image_prop, image_prop_required):
mock_instance = mock.MagicMock()
mock_image_meta = {'properties': {image_prop: image_prop_required}}
feature_requested = image_prop_required == constants.REQUIRED
result = self._vmops._feature_requested(mock_instance,
mock_image_meta,
image_prop)
self.assertEqual(feature_requested, result)
def test_vtpm_image_required(self):
self._test_feature_requested(
image_prop=constants.IMAGE_PROP_VTPM_SHIELDED,
image_prop_required=constants.REQUIRED)
def test_vtpm_image_disabled(self):
self._test_feature_requested(
image_prop=constants.IMAGE_PROP_VTPM_SHIELDED,
image_prop_required=constants.DISABLED)
def _test_check_vtpm_requirements(self, os_type='windows',
secure_boot_enabled=True,
guarded_host=True):
mock_instance = mock.MagicMock()
mock_image_meta = {'properties': {'os_type': os_type}}
guarded_host = self._vmops._hostutils.is_host_guarded.return_value
if (not secure_boot_enabled or not guarded_host or
os_type not in os_win_const.VTPM_SUPPORTED_OS):
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._check_vtpm_requirements,
mock_instance,
mock_image_meta,
secure_boot_enabled)
else:
self._vmops._check_vtpm_requirements(mock_instance,
mock_image_meta,
secure_boot_enabled)
def test_vtpm_requirements_all_satisfied(self):
self._test_check_vtpm_requirements()
def test_vtpm_requirement_no_secureboot(self):
self._test_check_vtpm_requirements(secure_boot_enabled=False)
def test_vtpm_requirement_not_supported_os(self):
self._test_check_vtpm_requirements(
os_type=mock.sentinel.unsupported_os)
def test_vtpm_requirement_host_not_guarded(self):
self._test_check_vtpm_requirements(guarded_host=False)
@mock.patch.object(vmops.VMOps, '_get_fsk_data')
def test_create_fsk(self, mock_get_fsk_data):
mock_instance = mock.MagicMock()
fsk_pairs = mock_get_fsk_data.return_value
self._vmops._create_fsk(mock_instance, mock.sentinel.fsk_filename)
mock_get_fsk_data.assert_called_once_with(mock_instance)
self._vmops._vmutils.populate_fsk.assert_called_once_with(
mock.sentinel.fsk_filename, fsk_pairs)
def _test_get_fsk_data(self, metadata, instance_name,
expected_fsk_pairs=None):
mock_instance = mock.MagicMock()
mock_instance.metadata = metadata
mock_instance.hostname = instance_name
result = self._vmops._get_fsk_data(mock_instance)
self.assertEqual(expected_fsk_pairs, result)
def test_get_fsk_data_no_computername(self):
metadata = {'TimeZone': mock.sentinel.timezone}
expected_fsk_pairs = {'@@ComputerName@@': mock.sentinel.instance_name}
self._test_get_fsk_data(metadata,
mock.sentinel.instance_name,
expected_fsk_pairs)
def test_get_fsk_data_with_computername(self):
metadata = {'fsk:ComputerName': mock.sentinel.instance_name,
'fsk:TimeZone': mock.sentinel.timezone}
expected_fsk_pairs = {'@@ComputerName@@': mock.sentinel.instance_name,
'@@TimeZone@@': mock.sentinel.timezone}
self._test_get_fsk_data(metadata,
mock.sentinel.instance_name,
expected_fsk_pairs)
def test_get_fsk_data_computername_exception(self):
mock_instance = mock.MagicMock()
mock_instance.metadata = {
'fsk:ComputerName': mock.sentinel.computer_name,
'fsk:TimeZone': mock.sentinel.timezone}
mock_instance.hostname = mock.sentinel.instance_name
self.assertRaises(exception.InstanceUnacceptable,
self._vmops._get_fsk_data,
mock_instance)
@ddt.data({'vm_state': os_win_const.HYPERV_VM_STATE_DISABLED},
{'vm_state': os_win_const.HYPERV_VM_STATE_SUSPENDED},
{'vm_state': os_win_const.HYPERV_VM_STATE_SUSPENDED,
'allow_paused': True},
{'vm_state': os_win_const.HYPERV_VM_STATE_PAUSED},
{'vm_state': os_win_const.HYPERV_VM_STATE_PAUSED,
'allow_paused': True},
{'allow_paused': True})
@ddt.unpack
@mock.patch.object(vmops.VMOps, 'pause')
@mock.patch.object(vmops.VMOps, 'suspend')
@mock.patch.object(vmops.VMOps, '_set_vm_state')
def test_prepare_for_volume_snapshot(
self, mock_set_state, mock_suspend, mock_pause,
vm_state=os_win_const.HYPERV_VM_STATE_ENABLED,
allow_paused=False):
self._vmops._vmutils.get_vm_state.return_value = vm_state
expect_instance_suspend = not allow_paused and vm_state not in [
os_win_const.HYPERV_VM_STATE_DISABLED,
os_win_const.HYPERV_VM_STATE_SUSPENDED]
expect_instance_pause = allow_paused and vm_state == (
os_win_const.HYPERV_VM_STATE_ENABLED)
with self._vmops.prepare_for_volume_snapshot(
mock.sentinel.instance, allow_paused):
self._vmutils.get_vm_state.assert_called_once_with(
mock.sentinel.instance.name)
if expect_instance_suspend:
mock_suspend.assert_called_once_with(mock.sentinel.instance)
else:
mock_suspend.assert_not_called()
if expect_instance_pause:
mock_pause.assert_called_once_with(mock.sentinel.instance)
else:
mock_pause.assert_not_called()
# We expect the previous instance state to be restored.
if expect_instance_suspend or expect_instance_pause:
mock_set_state.assert_called_once_with(mock.sentinel.instance,
vm_state)
else:
mock_set_state.assert_not_called()
@ddt.data({},
{'instance_found': False},
{'uuid_found': True})
def test_get_instance_uuid(self, instance_found=True, uuid_found=True):
if instance_found:
side_effect = (mock.sentinel.instance_uuid
if uuid_found else None, )
else:
side_effect = os_win_exc.HyperVVMNotFoundException(
vm_name=mock.sentinel.instance_name)
self._vmutils.get_instance_uuid.side_effect = side_effect
instance_uuid = self._vmops.get_instance_uuid(
mock.sentinel.instance_name)
self._vmutils.get_instance_uuid.assert_called_once_with(
mock.sentinel.instance_name)
expected_uuid = (mock.sentinel.instance_uuid
if instance_found and uuid_found else None)
self.assertEqual(expected_uuid, instance_uuid)
def test_get_instance_uuid_missing_but_expected(self):
self._vmutils.get_instance_uuid.side_effect = (
os_win_exc.HyperVVMNotFoundException(
vm_name=mock.sentinel.instance_name))
self.assertRaises(os_win_exc.HyperVVMNotFoundException,
self._vmops.get_instance_uuid,
mock.sentinel.instance_name,
expect_existing=True)