Hyper-V: adds os-win library
Adds os-win to requirements.txt. Replaces the current usage of *Utils classes in the Hyper-V Driver with the equivalent *Utils classes from os-win. Adds decorators to the HyperVDriver methods that prevent os-win specific exceptions to leak outside the driver. Depends-On: Id5cd1dce195b38611f4f8c74857087620048b13f Co-Authored-By: Lucian Petrut <lpetrut@cloudbasesolutions.com> Partially Implements: blueprint add-os-win-library Change-Id: I04509843210dcedf98a0cd9e08fa07865c8a76de
This commit is contained in:
parent
8cc9505f09
commit
dc2edc2882
@ -15,9 +15,9 @@
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from os_win import utilsfactory
|
||||
|
||||
from nova import test
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
|
||||
|
||||
class HyperVBaseTestCase(test.NoDBTestCase):
|
||||
@ -28,14 +28,12 @@ class HyperVBaseTestCase(test.NoDBTestCase):
|
||||
wmi_patcher = mock.patch('__builtin__.wmi', create=True,
|
||||
new=self._mock_wmi)
|
||||
platform_patcher = mock.patch('sys.platform', 'win32')
|
||||
hostutils_patcher = mock.patch.object(utilsfactory, 'utils')
|
||||
utilsfactory_patcher = mock.patch.object(utilsfactory, '_get_class')
|
||||
|
||||
platform_patcher.start()
|
||||
wmi_patcher.start()
|
||||
patched_hostutils = hostutils_patcher.start()
|
||||
|
||||
patched_hostutils.check_min_windows_version.return_value = False
|
||||
utilsfactory_patcher.start()
|
||||
|
||||
self.addCleanup(wmi_patcher.stop)
|
||||
self.addCleanup(platform_patcher.stop)
|
||||
self.addCleanup(hostutils_patcher.stop)
|
||||
self.addCleanup(utilsfactory_patcher.stop)
|
||||
|
@ -20,10 +20,12 @@ Unit tests for the Hyper-V Driver.
|
||||
import platform
|
||||
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
|
||||
from nova import exception
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova import utils
|
||||
from nova.virt import driver as base_driver
|
||||
from nova.virt.hyperv import driver
|
||||
|
||||
@ -46,16 +48,45 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
self.driver._migrationops = mock.MagicMock()
|
||||
self.driver._rdpconsoleops = mock.MagicMock()
|
||||
|
||||
@mock.patch.object(driver.hostutils.HostUtils, 'check_min_windows_version')
|
||||
def test_check_minimum_windows_version(self, mock_check_min_win_version):
|
||||
mock_check_min_win_version.return_value = False
|
||||
@mock.patch.object(driver.utilsfactory, 'get_hostutils')
|
||||
def test_check_minimum_windows_version(self, mock_get_hostutils):
|
||||
mock_hostutils = mock_get_hostutils.return_value
|
||||
mock_hostutils.check_min_windows_version.return_value = False
|
||||
|
||||
self.assertRaises(exception.HypervisorTooOld,
|
||||
self.driver._check_minimum_windows_version)
|
||||
|
||||
def test_public_api_signatures(self):
|
||||
self.assertPublicAPISignatures(base_driver.ComputeDriver(None),
|
||||
self.driver)
|
||||
# NOTE(claudiub): wrapped functions do not keep the same signature in
|
||||
# Python 2.7, which causes this test to fail. Instead, we should
|
||||
# compare the public API signatures of the unwrapped methods.
|
||||
|
||||
for attr in driver.HyperVDriver.__dict__:
|
||||
class_member = getattr(driver.HyperVDriver, attr)
|
||||
if callable(class_member):
|
||||
mocked_method = mock.patch.object(
|
||||
driver.HyperVDriver, attr,
|
||||
utils.get_wrapped_function(class_member))
|
||||
mocked_method.start()
|
||||
self.addCleanup(mocked_method.stop)
|
||||
|
||||
self.assertPublicAPISignatures(base_driver.ComputeDriver,
|
||||
driver.HyperVDriver)
|
||||
|
||||
def test_converted_exception(self):
|
||||
self.driver._vmops.get_info.side_effect = (
|
||||
os_win_exc.OSWinException)
|
||||
self.assertRaises(exception.NovaException,
|
||||
self.driver.get_info, mock.sentinel.instance)
|
||||
|
||||
self.driver._vmops.get_info.side_effect = os_win_exc.HyperVException
|
||||
self.assertRaises(exception.NovaException,
|
||||
self.driver.get_info, mock.sentinel.instance)
|
||||
|
||||
self.driver._vmops.get_info.side_effect = (
|
||||
os_win_exc.HyperVVMNotFoundException(vm_name='foofoo'))
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
self.driver.get_info, mock.sentinel.instance)
|
||||
|
||||
@mock.patch.object(driver.eventhandler, 'InstanceEventHandler')
|
||||
def test_init_host(self, mock_InstanceEventHandler):
|
||||
|
@ -15,13 +15,13 @@
|
||||
|
||||
import eventlet
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win import utilsfactory
|
||||
|
||||
from nova import exception
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova import utils
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import eventhandler
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
|
||||
|
||||
class EventHandlerTestCase(test_base.HyperVBaseTestCase):
|
||||
@ -123,7 +123,8 @@ class EventHandlerTestCase(test_base.HyperVBaseTestCase):
|
||||
side_effect = (mock.sentinel.instance_uuid
|
||||
if not missing_uuid else None, )
|
||||
else:
|
||||
side_effect = exception.InstanceNotFound('fake_instance_uuid')
|
||||
side_effect = os_win_exc.HyperVVMNotFoundException(
|
||||
vm_name=mock.sentinel.instance_name)
|
||||
mock_get_uuid = self._event_handler._vmutils.get_instance_uuid
|
||||
mock_get_uuid.side_effect = side_effect
|
||||
|
||||
|
@ -48,16 +48,12 @@ class ImageCacheTestCase(test.NoDBTestCase):
|
||||
# in order to return the proper Utils Class, so it must be mocked.
|
||||
patched_get_hostutils = mock.patch.object(imagecache.utilsfactory,
|
||||
"get_hostutils")
|
||||
patched_get_pathutils = mock.patch.object(imagecache.utilsfactory,
|
||||
"get_pathutils")
|
||||
patched_get_vhdutils = mock.patch.object(imagecache.utilsfactory,
|
||||
"get_vhdutils")
|
||||
patched_get_hostutils.start()
|
||||
patched_get_pathutils.start()
|
||||
patched_get_vhdutils.start()
|
||||
|
||||
self.addCleanup(patched_get_hostutils.stop)
|
||||
self.addCleanup(patched_get_pathutils.stop)
|
||||
self.addCleanup(patched_get_vhdutils.stop)
|
||||
|
||||
self.imagecache = imagecache.ImageCache()
|
||||
@ -82,8 +78,8 @@ class ImageCacheTestCase(test.NoDBTestCase):
|
||||
|
||||
@mock.patch.object(imagecache.ImageCache, '_get_root_vhd_size_gb')
|
||||
def test_resize_and_cache_vhd_smaller(self, mock_get_vhd_size_gb):
|
||||
self.imagecache._vhdutils.get_vhd_info.return_value = {
|
||||
'MaxInternalSize': (self.FAKE_VHD_SIZE_GB + 1) * units.Gi
|
||||
self.imagecache._vhdutils.get_vhd_size.return_value = {
|
||||
'VirtualSize': (self.FAKE_VHD_SIZE_GB + 1) * units.Gi
|
||||
}
|
||||
mock_get_vhd_size_gb.return_value = self.FAKE_VHD_SIZE_GB
|
||||
mock_internal_vhd_size = (
|
||||
@ -95,7 +91,7 @@ class ImageCacheTestCase(test.NoDBTestCase):
|
||||
mock.sentinel.instance,
|
||||
mock.sentinel.vhd_path)
|
||||
|
||||
self.imagecache._vhdutils.get_vhd_info.assert_called_once_with(
|
||||
self.imagecache._vhdutils.get_vhd_size.assert_called_once_with(
|
||||
mock.sentinel.vhd_path)
|
||||
mock_get_vhd_size_gb.assert_called_once_with(mock.sentinel.instance)
|
||||
mock_internal_vhd_size.assert_called_once_with(
|
||||
|
@ -14,12 +14,12 @@
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import livemigrationops
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
@ -44,8 +44,8 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
fake_dest = mock.sentinel.DESTINATION
|
||||
self._livemigrops._livemigrutils.live_migrate_vm.side_effect = [
|
||||
side_effect]
|
||||
if side_effect is vmutils.HyperVException:
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
if side_effect is os_win_exc.HyperVException:
|
||||
self.assertRaises(os_win_exc.HyperVException,
|
||||
self._livemigrops.live_migration,
|
||||
self.context, mock_instance, fake_dest,
|
||||
mock_post, mock_recover, False, None)
|
||||
@ -70,7 +70,7 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
self._test_live_migration(side_effect=None)
|
||||
|
||||
def test_live_migration_exception(self):
|
||||
self._test_live_migration(side_effect=vmutils.HyperVException)
|
||||
self._test_live_migration(side_effect=os_win_exc.HyperVException)
|
||||
|
||||
def test_live_migration_wrong_os_version(self):
|
||||
self._livemigrops._livemigrutils = None
|
||||
|
@ -15,6 +15,7 @@
|
||||
import os
|
||||
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
from oslo_utils import units
|
||||
|
||||
from nova import exception
|
||||
@ -23,7 +24,6 @@ from nova import test
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import migrationops
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
|
||||
class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
@ -288,7 +288,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
recon_parent_vhd.assert_called_once_with(fake_diff_vhd_path,
|
||||
base_vhd_copy_path)
|
||||
self._migrationops._vhdutils.merge_vhd.assert_called_once_with(
|
||||
fake_diff_vhd_path, base_vhd_copy_path)
|
||||
fake_diff_vhd_path)
|
||||
self._migrationops._pathutils.rename.assert_called_once_with(
|
||||
base_vhd_copy_path, fake_diff_vhd_path)
|
||||
|
||||
@ -300,10 +300,10 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
os.path.basename(fake_base_vhd_path))
|
||||
|
||||
self._migrationops._vhdutils.reconnect_parent_vhd.side_effect = (
|
||||
vmutils.HyperVException)
|
||||
os_win_exc.HyperVException)
|
||||
self._migrationops._pathutils.exists.return_value = True
|
||||
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
self.assertRaises(os_win_exc.HyperVException,
|
||||
self._migrationops._merge_base_vhd,
|
||||
fake_diff_vhd_path, fake_base_vhd_path)
|
||||
self._migrationops._pathutils.exists.assert_called_once_with(
|
||||
@ -314,7 +314,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
@mock.patch.object(migrationops.MigrationOps, '_resize_vhd')
|
||||
def test_check_resize_vhd(self, mock_resize_vhd):
|
||||
self._migrationops._check_resize_vhd(
|
||||
vhd_path=mock.sentinel.vhd_path, vhd_info={'MaxInternalSize': 1},
|
||||
vhd_path=mock.sentinel.vhd_path, vhd_info={'VirtualSize': 1},
|
||||
new_size=2)
|
||||
mock_resize_vhd.assert_called_once_with(mock.sentinel.vhd_path, 2)
|
||||
|
||||
@ -322,7 +322,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
self.assertRaises(exception.CannotResizeDisk,
|
||||
self._migrationops._check_resize_vhd,
|
||||
mock.sentinel.vhd_path,
|
||||
{'MaxInternalSize': 1}, 0)
|
||||
{'VirtualSize': 1}, 0)
|
||||
|
||||
@mock.patch.object(migrationops.MigrationOps, '_merge_base_vhd')
|
||||
def test_resize_vhd(self, mock_merge_base_vhd):
|
||||
|
@ -20,7 +20,6 @@ from nova import exception
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
|
||||
class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
||||
@ -33,44 +32,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
|
||||
def _test_smb_conn(self, smb_available=True):
|
||||
self._mock_wmi.x_wmi = Exception
|
||||
self._mock_wmi.WMI.side_effect = None if smb_available else Exception
|
||||
|
||||
self._pathutils._set_smb_conn()
|
||||
|
||||
if smb_available:
|
||||
expected_conn = self._mock_wmi.WMI.return_value
|
||||
self.assertEqual(expected_conn, self._pathutils._smb_conn)
|
||||
else:
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
getattr,
|
||||
self._pathutils, '_smb_conn')
|
||||
|
||||
def test_smb_conn_available(self):
|
||||
self._test_smb_conn()
|
||||
|
||||
def test_smb_conn_unavailable(self):
|
||||
self._test_smb_conn(smb_available=False)
|
||||
|
||||
@mock.patch.object(pathutils.PathUtils, 'rename')
|
||||
@mock.patch.object(os.path, 'isfile')
|
||||
@mock.patch.object(os, 'listdir')
|
||||
def test_move_folder_files(self, mock_listdir, mock_isfile, mock_rename):
|
||||
src_dir = 'src'
|
||||
dest_dir = 'dest'
|
||||
fname = 'tmp_file.txt'
|
||||
subdir = 'tmp_folder'
|
||||
src_fname = os.path.join(src_dir, fname)
|
||||
dest_fname = os.path.join(dest_dir, fname)
|
||||
|
||||
# making sure src_subdir is not moved.
|
||||
mock_listdir.return_value = [fname, subdir]
|
||||
mock_isfile.side_effect = [True, False]
|
||||
|
||||
self._pathutils.move_folder_files(src_dir, dest_dir)
|
||||
mock_rename.assert_called_once_with(src_fname, dest_fname)
|
||||
|
||||
def _mock_lookup_configdrive_path(self, ext):
|
||||
self._pathutils.get_instance_dir = mock.MagicMock(
|
||||
return_value=self.fake_instance_dir)
|
||||
@ -98,83 +59,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
||||
self.fake_instance_name)
|
||||
self.assertIsNone(configdrive_path)
|
||||
|
||||
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share')
|
||||
@mock.patch('os.path.exists')
|
||||
def _test_check_smb_mapping(self, mock_exists, mock_unmount_smb_share,
|
||||
existing_mappings=True, share_available=False):
|
||||
mock_exists.return_value = share_available
|
||||
|
||||
fake_mappings = (
|
||||
[mock.sentinel.smb_mapping] if existing_mappings else [])
|
||||
|
||||
self._pathutils._smb_conn.Msft_SmbMapping.return_value = (
|
||||
fake_mappings)
|
||||
|
||||
ret_val = self._pathutils.check_smb_mapping(
|
||||
mock.sentinel.share_path)
|
||||
|
||||
self.assertEqual(existing_mappings and share_available, ret_val)
|
||||
if existing_mappings and not share_available:
|
||||
mock_unmount_smb_share.assert_called_once_with(
|
||||
mock.sentinel.share_path, force=True)
|
||||
|
||||
def test_check_mapping(self):
|
||||
self._test_check_smb_mapping()
|
||||
|
||||
def test_remake_unavailable_mapping(self):
|
||||
self._test_check_smb_mapping(existing_mappings=True,
|
||||
share_available=False)
|
||||
|
||||
def test_available_mapping(self):
|
||||
self._test_check_smb_mapping(existing_mappings=True,
|
||||
share_available=True)
|
||||
|
||||
def test_mount_smb_share(self):
|
||||
fake_create = self._pathutils._smb_conn.Msft_SmbMapping.Create
|
||||
self._pathutils.mount_smb_share(mock.sentinel.share_path,
|
||||
mock.sentinel.username,
|
||||
mock.sentinel.password)
|
||||
fake_create.assert_called_once_with(
|
||||
RemotePath=mock.sentinel.share_path,
|
||||
UserName=mock.sentinel.username,
|
||||
Password=mock.sentinel.password)
|
||||
|
||||
def _test_unmount_smb_share(self, force=False):
|
||||
fake_mapping = mock.Mock()
|
||||
smb_mapping_class = self._pathutils._smb_conn.Msft_SmbMapping
|
||||
smb_mapping_class.return_value = [fake_mapping]
|
||||
|
||||
self._pathutils.unmount_smb_share(mock.sentinel.share_path,
|
||||
force)
|
||||
|
||||
smb_mapping_class.assert_called_once_with(
|
||||
RemotePath=mock.sentinel.share_path)
|
||||
fake_mapping.Remove.assert_called_once_with(Force=force)
|
||||
|
||||
def test_soft_unmount_smb_share(self):
|
||||
self._test_unmount_smb_share()
|
||||
|
||||
def test_force_unmount_smb_share(self):
|
||||
self._test_unmount_smb_share(force=True)
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch('shutil.rmtree')
|
||||
def test_rmtree(self, mock_rmtree, mock_sleep):
|
||||
class WindowsError(Exception):
|
||||
def __init__(self, winerror=None):
|
||||
self.winerror = winerror
|
||||
|
||||
mock_rmtree.side_effect = [WindowsError(
|
||||
pathutils.ERROR_DIR_IS_NOT_EMPTY), True]
|
||||
fake_windows_error = WindowsError
|
||||
with mock.patch('__builtin__.WindowsError',
|
||||
fake_windows_error, create=True):
|
||||
self._pathutils.rmtree(mock.sentinel.FAKE_PATH)
|
||||
|
||||
mock_rmtree.assert_has_calls([mock.call(mock.sentinel.FAKE_PATH),
|
||||
mock.call(mock.sentinel.FAKE_PATH)])
|
||||
mock_sleep.assert_called_once_with(1)
|
||||
|
||||
@mock.patch('os.path.join')
|
||||
def test_get_instances_sub_dir(self, fake_path_join):
|
||||
|
||||
@ -184,7 +68,7 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
fake_dir_name = "fake_dir_name"
|
||||
fake_windows_error = WindowsError
|
||||
self._pathutils._check_create_dir = mock.MagicMock(
|
||||
self._pathutils.check_create_dir = mock.MagicMock(
|
||||
side_effect=WindowsError(pathutils.ERROR_INVALID_NAME))
|
||||
with mock.patch('__builtin__.WindowsError',
|
||||
fake_windows_error, create=True):
|
||||
|
@ -16,8 +16,10 @@
|
||||
import os
|
||||
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
|
||||
from nova.compute import task_states
|
||||
from nova import exception
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import snapshotops
|
||||
@ -96,7 +98,7 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
mock_reconnect.assert_called_once_with(dest_vhd_path,
|
||||
base_dest_disk_path)
|
||||
self._snapshotops._vhdutils.merge_vhd.assert_called_once_with(
|
||||
dest_vhd_path, base_dest_disk_path)
|
||||
dest_vhd_path)
|
||||
mock_save_glance_image.assert_called_once_with(
|
||||
self.context, mock.sentinel.IMAGE_ID, base_dest_disk_path)
|
||||
else:
|
||||
@ -119,3 +121,18 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
def test_snapshot_no_base_disk(self):
|
||||
self._test_snapshot(base_disk_path=None)
|
||||
|
||||
@mock.patch.object(snapshotops.SnapshotOps, '_snapshot')
|
||||
def test_snapshot_instance_not_found(self, mock_snapshot):
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
mock_snapshot.side_effect = os_win_exc.HyperVVMNotFoundException(
|
||||
vm_name=mock_instance.name)
|
||||
|
||||
self.assertRaises(exception.InstanceNotFound,
|
||||
self._snapshotops.snapshot,
|
||||
self.context, mock_instance, mock.sentinel.image_id,
|
||||
mock.sentinel.update_task_state)
|
||||
|
||||
mock_snapshot.assert_called_once_with(self.context, mock_instance,
|
||||
mock.sentinel.image_id,
|
||||
mock.sentinel.update_task_state)
|
||||
|
@ -21,7 +21,6 @@ import mock
|
||||
from oslo_config import cfg
|
||||
|
||||
from nova import test
|
||||
from nova.virt.hyperv import hostutils
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import volumeutils
|
||||
from nova.virt.hyperv import volumeutilsv2
|
||||
@ -31,18 +30,25 @@ CONF = cfg.CONF
|
||||
|
||||
class TestHyperVUtilsFactory(test.NoDBTestCase):
|
||||
def test_get_volumeutils_v2(self):
|
||||
self._test_returned_class(volumeutilsv2.VolumeUtilsV2, False, True)
|
||||
self._test_returned_class(expected_class=volumeutilsv2.VolumeUtilsV2,
|
||||
os_supports_v2=True)
|
||||
|
||||
def test_get_volumeutils_v1(self):
|
||||
self._test_returned_class(volumeutils.VolumeUtils, False, False)
|
||||
self._test_returned_class(expected_class=volumeutils.VolumeUtils)
|
||||
|
||||
def test_get_volumeutils_force_v1_and_not_min_version(self):
|
||||
self._test_returned_class(volumeutils.VolumeUtils, True, False)
|
||||
self._test_returned_class(expected_class=volumeutils.VolumeUtils,
|
||||
force_v1=True)
|
||||
|
||||
def _test_returned_class(self, expected_class, force_v1, os_supports_v2):
|
||||
CONF.set_override('force_volumeutils_v1', force_v1, 'hyperv')
|
||||
@mock.patch.object(utilsfactory, 'CONF')
|
||||
def _test_returned_class(self, mock_CONF, expected_class, force_v1=False,
|
||||
os_supports_v2=False):
|
||||
# NOTE(claudiub): temporary change, in order for unit tests to pass.
|
||||
# force_hyperv_utils_v1 CONF flag does not exist anymore.
|
||||
# utilsfactory and its test cases will be removed next commit.
|
||||
mock_CONF.hyperv.force_volumeutils_v1 = force_v1
|
||||
with mock.patch.object(
|
||||
hostutils.HostUtils,
|
||||
utilsfactory.utils,
|
||||
'check_min_windows_version') as mock_check_min_windows_version:
|
||||
mock_check_min_windows_version.return_value = os_supports_v2
|
||||
|
||||
|
35
nova/tests/unit/virt/hyperv/test_vif.py
Normal file
35
nova/tests/unit/virt/hyperv/test_vif.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Copyright 2015 Cloudbase Solutions Srl
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 mock
|
||||
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import vif
|
||||
|
||||
|
||||
class HyperVNovaNetworkVIFDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
def setUp(self):
|
||||
super(HyperVNovaNetworkVIFDriverTestCase, self).setUp()
|
||||
self.vif_driver = vif.HyperVNovaNetworkVIFDriver()
|
||||
|
||||
def test_plug(self):
|
||||
self.flags(vswitch_name=mock.sentinel.vswitch_name, group='hyperv')
|
||||
fake_vif = {'id': mock.sentinel.fake_id}
|
||||
|
||||
self.vif_driver.plug(mock.sentinel.instance, fake_vif)
|
||||
netutils = self.vif_driver._netutils
|
||||
netutils.connect_vnic_to_vswitch.assert_called_once_with(
|
||||
mock.sentinel.vswitch_name, mock.sentinel.fake_id)
|
@ -16,6 +16,7 @@ import os
|
||||
|
||||
from eventlet import timeout as etimeout
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
@ -28,9 +29,7 @@ from nova.tests.unit.objects import test_virtual_interface
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt import hardware
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import ioutils
|
||||
from nova.virt.hyperv import vmops
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
@ -126,7 +125,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
mock_instance.root_gb = self.FAKE_SIZE
|
||||
self.flags(use_cow_images=use_cow_images)
|
||||
self._vmops._vhdutils.get_vhd_info.return_value = {'MaxInternalSize':
|
||||
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.root_gb * units.Gi
|
||||
@ -259,8 +258,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
self._vmops._pathutils.get_ephemeral_vhd_path.assert_called_with(
|
||||
mock_instance.name, mock.sentinel.FAKE_FORMAT)
|
||||
self._vmops._vhdutils.create_dynamic_vhd.assert_called_with(
|
||||
mock.sentinel.FAKE_PATH, mock_instance.ephemeral_gb * units.Gi,
|
||||
mock.sentinel.FAKE_FORMAT)
|
||||
mock.sentinel.FAKE_PATH, mock_instance.ephemeral_gb * units.Gi)
|
||||
self.assertEqual(mock.sentinel.FAKE_PATH, response)
|
||||
|
||||
@mock.patch('nova.virt.hyperv.vmops.VMOps.destroy')
|
||||
@ -301,8 +299,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
self.context, mock_instance, mock_image_meta,
|
||||
[mock.sentinel.FILE], mock.sentinel.PASSWORD,
|
||||
mock.sentinel.INFO, mock.sentinel.DEV_INFO)
|
||||
elif fail is vmutils.HyperVException:
|
||||
self.assertRaises(vmutils.HyperVException, self._vmops.spawn,
|
||||
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.INFO, mock.sentinel.DEV_INFO)
|
||||
@ -347,7 +345,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
def test_spawn_create_instance_exception(self):
|
||||
self._test_spawn(exists=False, boot_from_volume=False,
|
||||
configdrive_required=True,
|
||||
fail=vmutils.HyperVException)
|
||||
fail=os_win_exc.HyperVException)
|
||||
|
||||
def test_spawn_not_required(self):
|
||||
self._test_spawn(exists=False, boot_from_volume=False,
|
||||
@ -359,8 +357,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
def test_spawn_no_admin_permissions(self):
|
||||
self._vmops._vmutils.check_admin_permissions.side_effect = (
|
||||
vmutils.HyperVException)
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
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,
|
||||
@ -663,10 +661,11 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
@mock.patch('nova.virt.hyperv.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 = vmutils.HyperVException
|
||||
self._vmops._vmutils.destroy_vm.side_effect = (
|
||||
os_win_exc.HyperVException)
|
||||
self._vmops._vmutils.vm_exists.return_value = True
|
||||
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
self.assertRaises(os_win_exc.HyperVException,
|
||||
self._vmops.destroy, mock_instance)
|
||||
|
||||
def test_reboot_hard(self):
|
||||
@ -689,10 +688,11 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
@mock.patch("nova.virt.hyperv.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 = vmutils.HyperVException("Expected failure")
|
||||
mock_power_on.side_effect = os_win_exc.HyperVException(
|
||||
"Expected failure")
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
|
||||
self.assertRaises(vmutils.HyperVException, self._vmops.reboot,
|
||||
self.assertRaises(os_win_exc.HyperVException, self._vmops.reboot,
|
||||
instance, {}, vmops.REBOOT_TYPE_SOFT)
|
||||
|
||||
mock_soft_shutdown.assert_called_once_with(instance)
|
||||
@ -723,7 +723,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
|
||||
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm
|
||||
mock_shutdown_vm.side_effect = vmutils.HyperVException(
|
||||
mock_shutdown_vm.side_effect = os_win_exc.HyperVException(
|
||||
"Expected failure.")
|
||||
|
||||
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT)
|
||||
@ -820,8 +820,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
@mock.patch("nova.virt.hyperv.vmops.VMOps._soft_shutdown")
|
||||
def test_power_off_unexisting_instance(self, mock_soft_shutdown):
|
||||
mock_soft_shutdown.side_effect = (
|
||||
exception.InstanceNotFound('fake_instance_uuid'))
|
||||
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('nova.virt.hyperv.vmops.VMOps._set_vm_state')
|
||||
@ -875,8 +875,10 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
def test_set_vm_state_exception(self):
|
||||
mock_instance = fake_instance.fake_instance_obj(self.context)
|
||||
self._vmops._vmutils.set_vm_state.side_effect = vmutils.HyperVException
|
||||
self.assertRaises(vmutils.HyperVException, self._vmops._set_vm_state,
|
||||
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):
|
||||
@ -904,7 +906,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
mock.sentinel.FAKE_VM_NAME, vmops.SHUTDOWN_TIME_INCREMENT)
|
||||
self.assertFalse(result)
|
||||
|
||||
@mock.patch.object(ioutils, 'IOThread')
|
||||
@mock.patch.object(vmops.ioutils, 'IOThread')
|
||||
def _test_log_vm_serial_output(self, mock_io_thread,
|
||||
worker_running=False,
|
||||
worker_exists=False):
|
||||
@ -1005,7 +1007,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
@mock.patch("os.path.exists")
|
||||
def test_get_console_output_exception(self, fake_path_exists, fake_open):
|
||||
fake_vm = mock.MagicMock()
|
||||
|
||||
fake_open.side_effect = IOError
|
||||
fake_path_exists.return_value = True
|
||||
self._vmops._pathutils.get_vm_console_log_paths.return_value = (
|
||||
@ -1179,7 +1180,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
|
||||
@mock.patch.object(vmops.VMOps, '_check_hotplug_available')
|
||||
def test_detach_interface_missing_instance(self, mock_check_hotplug):
|
||||
mock_check_hotplug.side_effect = exception.NotFound
|
||||
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)
|
||||
|
@ -17,14 +17,13 @@
|
||||
import os
|
||||
|
||||
import mock
|
||||
from os_win import exceptions as os_win_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from nova import exception
|
||||
from nova import test
|
||||
from nova.tests.unit import fake_block_device
|
||||
from nova.tests.unit.virt.hyperv import test_base
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt.hyperv import vmutils
|
||||
from nova.virt.hyperv import volumeops
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -120,16 +119,15 @@ class VolumeOpsTestCase(test_base.HyperVBaseTestCase):
|
||||
fake_volume_driver.disconnect_volumes.assert_called_once_with(
|
||||
block_device_mapping)
|
||||
|
||||
def test_ebs_root_in_block_devices(self):
|
||||
@mock.patch('nova.block_device.volume_in_mapping')
|
||||
def test_ebs_root_in_block_devices(self, mock_vol_in_mapping):
|
||||
block_device_info = get_fake_block_dev_info()
|
||||
|
||||
response = self._volumeops.ebs_root_in_block_devices(block_device_info)
|
||||
|
||||
self._volumeops._volutils.volume_in_mapping.assert_called_once_with(
|
||||
mock_vol_in_mapping.assert_called_once_with(
|
||||
self._volumeops._default_root_device, block_device_info)
|
||||
self.assertEqual(
|
||||
self._volumeops._volutils.volume_in_mapping.return_value,
|
||||
response)
|
||||
self.assertEqual(mock_vol_in_mapping.return_value, response)
|
||||
|
||||
def test_get_volume_connector(self):
|
||||
mock_instance = mock.DEFAULT
|
||||
@ -239,9 +237,9 @@ class ISCSIVolumeDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
mock_logout_storage_target,
|
||||
mock_get_mounted_disk):
|
||||
connection_info = get_fake_connection_info()
|
||||
mock_get_mounted_disk.side_effect = vmutils.HyperVException
|
||||
mock_get_mounted_disk.side_effect = os_win_exc.HyperVException
|
||||
|
||||
self.assertRaises(vmutils.HyperVException,
|
||||
self.assertRaises(os_win_exc.HyperVException,
|
||||
self._volume_driver.attach_volume, connection_info,
|
||||
mock.sentinel.instance_name)
|
||||
mock_logout_storage_target.assert_called_with(mock.sentinel.fake_iqn)
|
||||
@ -418,6 +416,8 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
super(SMBFSVolumeDriverTestCase, self).setUp()
|
||||
self._volume_driver = volumeops.SMBFSVolumeDriver()
|
||||
self._volume_driver._vmutils = mock.MagicMock()
|
||||
self._volume_driver._pathutils = mock.MagicMock()
|
||||
self._volume_driver._volutils = mock.MagicMock()
|
||||
|
||||
@mock.patch.object(volumeops.SMBFSVolumeDriver, 'ensure_share_mounted')
|
||||
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path')
|
||||
@ -468,15 +468,14 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
def test_attach_non_existing_image(self, mock_get_disk_path,
|
||||
mock_ensure_share_mounted):
|
||||
self._volume_driver._vmutils.attach_drive.side_effect = (
|
||||
vmutils.HyperVException())
|
||||
os_win_exc.HyperVException)
|
||||
self.assertRaises(exception.VolumeAttachFailed,
|
||||
self._volume_driver.attach_volume,
|
||||
self._FAKE_CONNECTION_INFO,
|
||||
mock.sentinel.instance_name)
|
||||
|
||||
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path')
|
||||
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share')
|
||||
def test_detach_volume(self, mock_unmount_smb_share, mock_get_disk_path):
|
||||
def test_detach_volume(self, mock_get_disk_path):
|
||||
mock_get_disk_path.return_value = (
|
||||
mock.sentinel.disk_path)
|
||||
|
||||
@ -510,12 +509,10 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
self.assertEqual(expected, disk_path)
|
||||
|
||||
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_parse_credentials')
|
||||
@mock.patch.object(pathutils.PathUtils, 'check_smb_mapping')
|
||||
@mock.patch.object(pathutils.PathUtils, 'mount_smb_share')
|
||||
def _test_ensure_mounted(self, mock_mount_smb_share,
|
||||
mock_check_smb_mapping, mock_parse_credentials,
|
||||
is_mounted=False):
|
||||
mock_check_smb_mapping.return_value = is_mounted
|
||||
def _test_ensure_mounted(self, mock_parse_credentials, is_mounted=False):
|
||||
mock_mount_smb_share = self._volume_driver._pathutils.mount_smb_share
|
||||
self._volume_driver._pathutils.check_smb_mapping.return_value = (
|
||||
is_mounted)
|
||||
mock_parse_credentials.return_value = (
|
||||
self._FAKE_USERNAME, self._FAKE_PASSWORD)
|
||||
|
||||
@ -537,10 +534,10 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
|
||||
def test_ensure_already_mounted(self):
|
||||
self._test_ensure_mounted(is_mounted=True)
|
||||
|
||||
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share')
|
||||
def test_disconnect_volumes(self, mock_unmount_smb_share):
|
||||
def test_disconnect_volumes(self):
|
||||
block_device_mapping = [
|
||||
{'connection_info': self._FAKE_CONNECTION_INFO}]
|
||||
self._volume_driver.disconnect_volumes(block_device_mapping)
|
||||
mock_unmount_smb_share.assert_called_once_with(
|
||||
mock_unmount_share = self._volume_driver._pathutils.unmount_smb_share
|
||||
mock_unmount_share.assert_called_once_with(
|
||||
self._FAKE_SHARE_NORMALIZED)
|
||||
|
@ -17,9 +17,13 @@
|
||||
A Hyper-V Nova Compute driver.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import platform
|
||||
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win import utilsfactory
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _, _LE
|
||||
@ -27,7 +31,6 @@ from nova import objects
|
||||
from nova.virt import driver
|
||||
from nova.virt.hyperv import eventhandler
|
||||
from nova.virt.hyperv import hostops
|
||||
from nova.virt.hyperv import hostutils
|
||||
from nova.virt.hyperv import livemigrationops
|
||||
from nova.virt.hyperv import migrationops
|
||||
from nova.virt.hyperv import rdpconsoleops
|
||||
@ -38,6 +41,49 @@ from nova.virt.hyperv import volumeops
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def convert_exceptions(function, exception_map):
|
||||
expected_exceptions = tuple(exception_map.keys())
|
||||
|
||||
@functools.wraps(function)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return function(*args, **kwargs)
|
||||
except expected_exceptions as ex:
|
||||
raised_exception = exception_map.get(type(ex))
|
||||
if not raised_exception:
|
||||
# exception might be a subclass of an expected exception.
|
||||
for expected in expected_exceptions:
|
||||
if isinstance(ex, expected):
|
||||
raised_exception = exception_map[expected]
|
||||
break
|
||||
|
||||
raise raised_exception(six.text_type(ex))
|
||||
return wrapper
|
||||
|
||||
|
||||
def decorate_all_methods(decorator, *args, **kwargs):
|
||||
def decorate(cls):
|
||||
for attr in cls.__dict__:
|
||||
class_member = getattr(cls, attr)
|
||||
if callable(class_member):
|
||||
setattr(cls, attr, decorator(class_member, *args, **kwargs))
|
||||
return cls
|
||||
|
||||
return decorate
|
||||
|
||||
|
||||
exception_conversion_map = {
|
||||
# expected_exception: converted_exception
|
||||
os_win_exc.OSWinException: exception.NovaException,
|
||||
os_win_exc.HyperVVMNotFoundException: exception.InstanceNotFound,
|
||||
}
|
||||
|
||||
# NOTE(claudiub): the purpose of the decorator below is to prevent any
|
||||
# os_win exceptions (subclasses of OSWinException) to leak outside of the
|
||||
# HyperVDriver.
|
||||
|
||||
|
||||
@decorate_all_methods(convert_exceptions, exception_conversion_map)
|
||||
class HyperVDriver(driver.ComputeDriver):
|
||||
capabilities = {
|
||||
"has_imagecache": False,
|
||||
@ -61,7 +107,7 @@ class HyperVDriver(driver.ComputeDriver):
|
||||
self._rdpconsoleops = rdpconsoleops.RDPConsoleOps()
|
||||
|
||||
def _check_minimum_windows_version(self):
|
||||
if not hostutils.HostUtils().check_min_windows_version(6, 2):
|
||||
if not utilsfactory.get_hostutils().check_min_windows_version(6, 2):
|
||||
# the version is of Windows is older than Windows Server 2012 R2.
|
||||
# Log an error, lettingusers know that this version is not
|
||||
# supported any longer.
|
||||
|
@ -20,15 +20,15 @@ import sys
|
||||
if sys.platform == 'win32':
|
||||
import wmi
|
||||
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _LW
|
||||
from nova import utils
|
||||
from nova.virt import event as virtevent
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -117,7 +117,7 @@ class InstanceEventHandler(object):
|
||||
"will be ignored."),
|
||||
instance_name)
|
||||
return instance_uuid
|
||||
except exception.InstanceNotFound:
|
||||
except os_win_exc.HyperVVMNotFoundException:
|
||||
# The instance has been deleted.
|
||||
pass
|
||||
|
||||
|
@ -21,6 +21,7 @@ import os
|
||||
import platform
|
||||
import time
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
@ -31,7 +32,7 @@ from nova.compute import hv_type
|
||||
from nova.compute import vm_mode
|
||||
from nova.i18n import _
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import pathutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('my_ip', 'nova.netconf')
|
||||
@ -41,7 +42,7 @@ LOG = logging.getLogger(__name__)
|
||||
class HostOps(object):
|
||||
def __init__(self):
|
||||
self._hostutils = utilsfactory.get_hostutils()
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
|
||||
def _get_cpu_info(self):
|
||||
"""Get the CPU information.
|
||||
|
@ -17,6 +17,7 @@ Image caching and management.
|
||||
"""
|
||||
import os
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
@ -24,7 +25,7 @@ from oslo_utils import units
|
||||
|
||||
from nova import exception
|
||||
from nova import utils
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt import images
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -35,7 +36,7 @@ CONF.import_opt('use_cow_images', 'nova.virt.driver')
|
||||
|
||||
class ImageCache(object):
|
||||
def __init__(self):
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
self._vhdutils = utilsfactory.get_vhdutils()
|
||||
|
||||
def _get_root_vhd_size_gb(self, instance):
|
||||
@ -45,8 +46,7 @@ class ImageCache(object):
|
||||
return instance.root_gb
|
||||
|
||||
def _resize_and_cache_vhd(self, instance, vhd_path):
|
||||
vhd_info = self._vhdutils.get_vhd_info(vhd_path)
|
||||
vhd_size = vhd_info['MaxInternalSize']
|
||||
vhd_size = self._vhdutils.get_vhd_size(vhd_path)['VirtualSize']
|
||||
|
||||
root_vhd_size_gb = self._get_root_vhd_size_gb(instance)
|
||||
root_vhd_size = root_vhd_size_gb * units.Gi
|
||||
|
@ -18,15 +18,15 @@ Management class for live migration VM operations.
|
||||
"""
|
||||
import functools
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from nova.i18n import _
|
||||
from nova.virt.hyperv import imagecache
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt.hyperv import vmops
|
||||
from nova.virt.hyperv import vmutilsv2
|
||||
from nova.virt.hyperv import volumeops
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -53,11 +53,11 @@ class LiveMigrationOps(object):
|
||||
else:
|
||||
self._livemigrutils = None
|
||||
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
self._vmops = vmops.VMOps()
|
||||
self._volumeops = volumeops.VolumeOps()
|
||||
self._imagecache = imagecache.ImageCache()
|
||||
self._vmutils = vmutilsv2.VMUtilsV2()
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
|
||||
@check_os_version_requirement
|
||||
def live_migration(self, context, instance_ref, dest, post_method,
|
||||
|
@ -18,6 +18,7 @@ Management class for migration / resize operations.
|
||||
"""
|
||||
import os
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import units
|
||||
@ -27,7 +28,7 @@ from nova.i18n import _, _LE
|
||||
from nova import objects
|
||||
from nova.virt import configdrive
|
||||
from nova.virt.hyperv import imagecache
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt.hyperv import vmops
|
||||
from nova.virt.hyperv import volumeops
|
||||
|
||||
@ -39,7 +40,7 @@ class MigrationOps(object):
|
||||
self._hostutils = utilsfactory.get_hostutils()
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._vhdutils = utilsfactory.get_vhdutils()
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
self._volumeops = volumeops.VolumeOps()
|
||||
self._vmops = vmops.VMOps()
|
||||
self._imagecache = imagecache.ImageCache()
|
||||
@ -201,11 +202,9 @@ class MigrationOps(object):
|
||||
self._vhdutils.reconnect_parent_vhd(diff_vhd_path,
|
||||
base_vhd_copy_path)
|
||||
|
||||
LOG.debug("Merging base disk %(base_vhd_copy_path)s and "
|
||||
"diff disk %(diff_vhd_path)s",
|
||||
{'base_vhd_copy_path': base_vhd_copy_path,
|
||||
'diff_vhd_path': diff_vhd_path})
|
||||
self._vhdutils.merge_vhd(diff_vhd_path, base_vhd_copy_path)
|
||||
LOG.debug("Merging differential disk %s into its parent.",
|
||||
diff_vhd_path)
|
||||
self._vhdutils.merge_vhd(diff_vhd_path)
|
||||
|
||||
# Replace the differential VHD with the merged one
|
||||
self._pathutils.rename(base_vhd_copy_path, diff_vhd_path)
|
||||
@ -215,7 +214,7 @@ class MigrationOps(object):
|
||||
self._pathutils.remove(base_vhd_copy_path)
|
||||
|
||||
def _check_resize_vhd(self, vhd_path, vhd_info, new_size):
|
||||
curr_size = vhd_info['MaxInternalSize']
|
||||
curr_size = vhd_info['VirtualSize']
|
||||
if new_size < curr_size:
|
||||
raise exception.CannotResizeDisk(
|
||||
reason=_("Cannot resize the root disk to a smaller size. "
|
||||
|
@ -14,21 +14,14 @@
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
if sys.platform == 'win32':
|
||||
import wmi
|
||||
|
||||
from os_win.utils import pathutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import utils
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -47,89 +40,14 @@ CONF.register_opts(hyperv_opts, 'hyperv')
|
||||
CONF.import_opt('instances_path', 'nova.compute.manager')
|
||||
|
||||
ERROR_INVALID_NAME = 123
|
||||
ERROR_DIR_IS_NOT_EMPTY = 145
|
||||
|
||||
# NOTE(claudiub): part of the pre-existing PathUtils is nova-specific and
|
||||
# it does not belong in the os-win library. In order to ensure the same
|
||||
# functionality with the least amount of changes necessary, adding as a mixin
|
||||
# the os_win.pathutils.PathUtils class into this PathUtils.
|
||||
|
||||
|
||||
class PathUtils(object):
|
||||
def __init__(self):
|
||||
self._set_smb_conn()
|
||||
|
||||
@property
|
||||
def _smb_conn(self):
|
||||
if self._smb_conn_attr:
|
||||
return self._smb_conn_attr
|
||||
raise vmutils.HyperVException(_("The SMB WMI namespace is not "
|
||||
"available on this OS version."))
|
||||
|
||||
def _set_smb_conn(self):
|
||||
# The following namespace is not available prior to Windows
|
||||
# Server 2012. utilsfactory is not used in order to avoid a
|
||||
# circular dependency.
|
||||
try:
|
||||
self._smb_conn_attr = wmi.WMI(
|
||||
moniker=r"root\Microsoft\Windows\SMB")
|
||||
except wmi.x_wmi:
|
||||
self._smb_conn_attr = None
|
||||
|
||||
def open(self, path, mode):
|
||||
"""Wrapper on __builtin__.open used to simplify unit testing."""
|
||||
import __builtin__
|
||||
return __builtin__.open(path, mode)
|
||||
|
||||
def exists(self, path):
|
||||
return os.path.exists(path)
|
||||
|
||||
def makedirs(self, path):
|
||||
os.makedirs(path)
|
||||
|
||||
def remove(self, path):
|
||||
os.remove(path)
|
||||
|
||||
def rename(self, src, dest):
|
||||
os.rename(src, dest)
|
||||
|
||||
def copyfile(self, src, dest):
|
||||
self.copy(src, dest)
|
||||
|
||||
def copy(self, src, dest):
|
||||
# With large files this is 2x-3x faster than shutil.copy(src, dest),
|
||||
# especially when copying to a UNC target.
|
||||
# shutil.copyfileobj(...) with a proper buffer is better than
|
||||
# shutil.copy(...) but still 20% slower than a shell copy.
|
||||
# It can be replaced with Win32 API calls to avoid the process
|
||||
# spawning overhead.
|
||||
LOG.debug('Copying file from %s to %s', src, dest)
|
||||
output, ret = utils.execute('cmd.exe', '/C', 'copy', '/Y', src, dest)
|
||||
if ret:
|
||||
raise IOError(_('The file copy from %(src)s to %(dest)s failed')
|
||||
% {'src': src, 'dest': dest})
|
||||
|
||||
def move_folder_files(self, src_dir, dest_dir):
|
||||
"""Moves the files of the given src_dir to dest_dir.
|
||||
It will ignore any nested folders.
|
||||
|
||||
:param src_dir: Given folder from which to move files.
|
||||
:param dest_dir: Folder to which to move files.
|
||||
"""
|
||||
|
||||
for fname in os.listdir(src_dir):
|
||||
src = os.path.join(src_dir, fname)
|
||||
# ignore subdirs.
|
||||
if os.path.isfile(src):
|
||||
self.rename(src, os.path.join(dest_dir, fname))
|
||||
|
||||
def rmtree(self, path):
|
||||
# This will be removed once support for Windows Server 2008R2 is
|
||||
# stopped
|
||||
for i in range(5):
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
return
|
||||
except WindowsError as e:
|
||||
if e.winerror == ERROR_DIR_IS_NOT_EMPTY:
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise e
|
||||
class PathUtils(pathutils.PathUtils):
|
||||
|
||||
def get_instances_dir(self, remote_server=None):
|
||||
local_instance_path = os.path.normpath(CONF.instances_path)
|
||||
@ -145,25 +63,15 @@ class PathUtils(object):
|
||||
else:
|
||||
return local_instance_path
|
||||
|
||||
def _check_create_dir(self, path):
|
||||
if not self.exists(path):
|
||||
LOG.debug('Creating directory: %s', path)
|
||||
self.makedirs(path)
|
||||
|
||||
def _check_remove_dir(self, path):
|
||||
if self.exists(path):
|
||||
LOG.debug('Removing directory: %s', path)
|
||||
self.rmtree(path)
|
||||
|
||||
def _get_instances_sub_dir(self, dir_name, remote_server=None,
|
||||
create_dir=True, remove_dir=False):
|
||||
instances_path = self.get_instances_dir(remote_server)
|
||||
path = os.path.join(instances_path, dir_name)
|
||||
try:
|
||||
if remove_dir:
|
||||
self._check_remove_dir(path)
|
||||
self.check_remove_dir(path)
|
||||
if create_dir:
|
||||
self._check_create_dir(path)
|
||||
self.check_create_dir(path)
|
||||
return path
|
||||
except WindowsError as ex:
|
||||
if ex.winerror == ERROR_INVALID_NAME:
|
||||
@ -238,52 +146,3 @@ class PathUtils(object):
|
||||
remote_server)
|
||||
console_log_path = os.path.join(instance_dir, 'console.log')
|
||||
return console_log_path, console_log_path + '.1'
|
||||
|
||||
def check_smb_mapping(self, smbfs_share):
|
||||
mappings = self._smb_conn.Msft_SmbMapping(RemotePath=smbfs_share)
|
||||
|
||||
if not mappings:
|
||||
return False
|
||||
|
||||
if os.path.exists(smbfs_share):
|
||||
LOG.debug('Share already mounted: %s', smbfs_share)
|
||||
return True
|
||||
else:
|
||||
LOG.debug('Share exists but is unavailable: %s ', smbfs_share)
|
||||
self.unmount_smb_share(smbfs_share, force=True)
|
||||
return False
|
||||
|
||||
def mount_smb_share(self, smbfs_share, username=None, password=None):
|
||||
try:
|
||||
LOG.debug('Mounting share: %s', smbfs_share)
|
||||
self._smb_conn.Msft_SmbMapping.Create(RemotePath=smbfs_share,
|
||||
UserName=username,
|
||||
Password=password)
|
||||
except wmi.x_wmi as exc:
|
||||
err_msg = (_(
|
||||
'Unable to mount SMBFS share: %(smbfs_share)s '
|
||||
'WMI exception: %(wmi_exc)s') % {'smbfs_share': smbfs_share,
|
||||
'wmi_exc': exc})
|
||||
raise vmutils.HyperVException(err_msg)
|
||||
|
||||
def unmount_smb_share(self, smbfs_share, force=False):
|
||||
mappings = self._smb_conn.Msft_SmbMapping(RemotePath=smbfs_share)
|
||||
if not mappings:
|
||||
LOG.debug('Share %s is not mounted. Skipping unmount.',
|
||||
smbfs_share)
|
||||
|
||||
for mapping in mappings:
|
||||
# Due to a bug in the WMI module, getting the output of
|
||||
# methods returning None will raise an AttributeError
|
||||
try:
|
||||
mapping.Remove(Force=force)
|
||||
except AttributeError:
|
||||
pass
|
||||
except wmi.x_wmi:
|
||||
# If this fails, a 'Generic Failure' exception is raised.
|
||||
# This happens even if we unforcefully unmount an in-use
|
||||
# share, for which reason we'll simply ignore it in this
|
||||
# case.
|
||||
if force:
|
||||
raise vmutils.HyperVException(
|
||||
_("Could not unmount share: %s") % smbfs_share)
|
||||
|
@ -13,11 +13,11 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.console import type as ctype
|
||||
from nova.virt.hyperv import hostops
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -18,14 +18,17 @@ Management class for VM snapshot operations.
|
||||
"""
|
||||
import os
|
||||
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.compute import task_states
|
||||
from nova import exception
|
||||
from nova.i18n import _LW
|
||||
from nova.image import glance
|
||||
from nova import utils
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import pathutils
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -33,7 +36,7 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class SnapshotOps(object):
|
||||
def __init__(self):
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._vhdutils = utilsfactory.get_vhdutils()
|
||||
|
||||
@ -54,7 +57,11 @@ class SnapshotOps(object):
|
||||
def instance_synchronized_snapshot():
|
||||
self._snapshot(context, instance, image_id, update_task_state)
|
||||
|
||||
instance_synchronized_snapshot()
|
||||
try:
|
||||
instance_synchronized_snapshot()
|
||||
except os_win_exc.HyperVVMNotFoundException:
|
||||
# the instance might dissapear before starting the operation.
|
||||
raise exception.InstanceNotFound(instance_id=instance.uuid)
|
||||
|
||||
def _snapshot(self, context, instance, image_id, update_task_state):
|
||||
"""Create snapshot from a running VM instance."""
|
||||
@ -103,11 +110,9 @@ class SnapshotOps(object):
|
||||
self._vhdutils.reconnect_parent_vhd(dest_vhd_path,
|
||||
dest_base_disk_path)
|
||||
|
||||
LOG.debug("Merging base disk %(dest_base_disk_path)s and "
|
||||
"diff disk %(dest_vhd_path)s",
|
||||
{'dest_base_disk_path': dest_base_disk_path,
|
||||
'dest_vhd_path': dest_vhd_path})
|
||||
self._vhdutils.merge_vhd(dest_vhd_path, dest_base_disk_path)
|
||||
LOG.debug("Merging diff disk %s into its parent.",
|
||||
dest_vhd_path)
|
||||
self._vhdutils.merge_vhd(dest_vhd_path)
|
||||
image_vhd_path = dest_base_disk_path
|
||||
|
||||
LOG.debug("Updating Glance image %(image_id)s with content from "
|
||||
|
@ -27,16 +27,10 @@ from nova.virt.hyperv import vmutilsv2
|
||||
from nova.virt.hyperv import volumeutils
|
||||
from nova.virt.hyperv import volumeutilsv2
|
||||
|
||||
hyper_opts = [
|
||||
cfg.BoolOpt('force_volumeutils_v1',
|
||||
default=False,
|
||||
help='Force V1 volume utility class'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(hyper_opts, 'hyperv')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF.import_group('hyperv', 'os_win.utilsfactory')
|
||||
|
||||
utils = hostutils.HostUtils()
|
||||
|
||||
|
@ -16,11 +16,10 @@
|
||||
|
||||
import abc
|
||||
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
|
||||
hyperv_opts = [
|
||||
cfg.StrOpt('vswitch_name',
|
||||
help='External virtual switch Name, '
|
||||
@ -60,22 +59,11 @@ class HyperVNovaNetworkVIFDriver(HyperVBaseVIFDriver):
|
||||
"""Nova network VIF driver."""
|
||||
|
||||
def __init__(self):
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._netutils = utilsfactory.get_networkutils()
|
||||
|
||||
def plug(self, instance, vif):
|
||||
vswitch_path = self._netutils.get_external_vswitch(
|
||||
CONF.hyperv.vswitch_name)
|
||||
|
||||
vm_name = instance.name
|
||||
LOG.debug('Creating vswitch port for instance: %s', vm_name)
|
||||
if self._netutils.vswitch_port_needed():
|
||||
vswitch_data = self._netutils.create_vswitch_port(vswitch_path,
|
||||
vm_name)
|
||||
else:
|
||||
vswitch_data = vswitch_path
|
||||
|
||||
self._vmutils.set_nic_connection(vm_name, vif['id'], vswitch_data)
|
||||
self._netutils.connect_vnic_to_vswitch(CONF.hyperv.vswitch_name,
|
||||
vif['id'])
|
||||
|
||||
def unplug(self, instance, vif):
|
||||
# TODO(alepilotti) Not implemented
|
||||
|
@ -22,6 +22,9 @@ import os
|
||||
import time
|
||||
|
||||
from eventlet import timeout as etimeout
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win.utils.io import ioutils
|
||||
from os_win import utilsfactory
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
@ -41,9 +44,7 @@ from nova.virt import configdrive
|
||||
from nova.virt import hardware
|
||||
from nova.virt.hyperv import constants
|
||||
from nova.virt.hyperv import imagecache
|
||||
from nova.virt.hyperv import ioutils
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import vmutils
|
||||
from nova.virt.hyperv import pathutils
|
||||
from nova.virt.hyperv import volumeops
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -130,8 +131,8 @@ class VMOps(object):
|
||||
def __init__(self):
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._vhdutils = utilsfactory.get_vhdutils()
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._hostutils = utilsfactory.get_hostutils()
|
||||
self._pathutils = pathutils.PathUtils()
|
||||
self._volumeops = volumeops.VolumeOps()
|
||||
self._imagecache = imagecache.ImageCache()
|
||||
self._vif_driver = None
|
||||
@ -180,7 +181,7 @@ class VMOps(object):
|
||||
def _create_root_vhd(self, context, instance):
|
||||
base_vhd_path = self._imagecache.get_cached_image(context, instance)
|
||||
base_vhd_info = self._vhdutils.get_vhd_info(base_vhd_path)
|
||||
base_vhd_size = base_vhd_info['MaxInternalSize']
|
||||
base_vhd_size = base_vhd_info['VirtualSize']
|
||||
format_ext = base_vhd_path.split('.')[-1]
|
||||
root_vhd_path = self._pathutils.get_root_vhd_path(instance.name,
|
||||
format_ext)
|
||||
@ -246,8 +247,7 @@ class VMOps(object):
|
||||
|
||||
eph_vhd_path = self._pathutils.get_ephemeral_vhd_path(
|
||||
instance.name, vhd_format)
|
||||
self._vhdutils.create_dynamic_vhd(eph_vhd_path, eph_vhd_size,
|
||||
vhd_format)
|
||||
self._vhdutils.create_dynamic_vhd(eph_vhd_path, eph_vhd_size)
|
||||
return eph_vhd_path
|
||||
|
||||
@check_admin_permissions
|
||||
@ -495,7 +495,7 @@ class VMOps(object):
|
||||
LOG.info(_LI("Soft shutdown succeeded."),
|
||||
instance=instance)
|
||||
return True
|
||||
except vmutils.HyperVException as e:
|
||||
except os_win_exc.HyperVException as e:
|
||||
# Exception is raised when trying to shutdown the instance
|
||||
# while it is still booting.
|
||||
LOG.debug("Soft shutdown failed: %s", e, instance=instance)
|
||||
@ -545,7 +545,7 @@ class VMOps(object):
|
||||
|
||||
self._set_vm_state(instance,
|
||||
constants.HYPERV_VM_STATE_DISABLED)
|
||||
except exception.InstanceNotFound:
|
||||
except os_win_exc.HyperVVMNotFoundException:
|
||||
# The manager can call the stop API after receiving instance
|
||||
# power off events. If this is triggered when the instance
|
||||
# is being deleted, it might attempt to power off an unexisting
|
||||
@ -761,7 +761,7 @@ class VMOps(object):
|
||||
LOG.debug('Detaching vif: %s', vif['id'], instance=instance)
|
||||
self._vif_driver.unplug(instance, vif)
|
||||
self._vmutils.destroy_nic(instance.name, vif['id'])
|
||||
except exception.NotFound:
|
||||
except os_win_exc.HyperVVMNotFoundException:
|
||||
# TODO(claudiub): add set log level to error after string freeze.
|
||||
LOG.debug("Instance not found during detach interface. It "
|
||||
"might have been destroyed beforehand.",
|
||||
|
@ -22,17 +22,18 @@ import os
|
||||
import re
|
||||
import time
|
||||
|
||||
from os_win import exceptions as os_win_exc
|
||||
from os_win import utilsfactory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from six.moves import range
|
||||
|
||||
from nova import block_device
|
||||
from nova import exception
|
||||
from nova.i18n import _, _LE, _LW
|
||||
from nova import utils
|
||||
from nova.virt import driver
|
||||
from nova.virt.hyperv import utilsfactory
|
||||
from nova.virt.hyperv import vmutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -65,7 +66,7 @@ class VolumeOps(object):
|
||||
|
||||
def __init__(self):
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._volutils = utilsfactory.get_volumeutils()
|
||||
self._volutils = utilsfactory.get_iscsi_initiator_utils()
|
||||
self._initiator = None
|
||||
self._default_root_device = 'vda'
|
||||
self.volume_drivers = {'smbfs': SMBFSVolumeDriver(),
|
||||
@ -111,8 +112,8 @@ class VolumeOps(object):
|
||||
root_device = block_device_info.get('root_device_name')
|
||||
if not root_device:
|
||||
root_device = self._default_root_device
|
||||
return self._volutils.volume_in_mapping(root_device,
|
||||
block_device_info)
|
||||
return block_device.volume_in_mapping(root_device,
|
||||
block_device_info)
|
||||
|
||||
def fix_instance_volume_disk_paths(self, instance_name, block_device_info):
|
||||
mapping = driver.block_device_info_get_mapping(block_device_info)
|
||||
@ -161,7 +162,7 @@ class VolumeOps(object):
|
||||
class ISCSIVolumeDriver(object):
|
||||
def __init__(self):
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._volutils = utilsfactory.get_volumeutils()
|
||||
self._volutils = utilsfactory.get_iscsi_initiator_utils()
|
||||
|
||||
def login_storage_target(self, connection_info):
|
||||
data = connection_info['data']
|
||||
@ -358,7 +359,6 @@ class SMBFSVolumeDriver(object):
|
||||
def __init__(self):
|
||||
self._pathutils = utilsfactory.get_pathutils()
|
||||
self._vmutils = utilsfactory.get_vmutils()
|
||||
self._volutils = utilsfactory.get_volumeutils()
|
||||
self._username_regex = re.compile(r'user(?:name)?=([^, ]+)')
|
||||
self._password_regex = re.compile(r'pass(?:word)?=([^, ]+)')
|
||||
|
||||
@ -382,7 +382,7 @@ class SMBFSVolumeDriver(object):
|
||||
disk_path,
|
||||
ctrller_path,
|
||||
slot)
|
||||
except vmutils.HyperVException as exn:
|
||||
except os_win_exc.HyperVException as exn:
|
||||
LOG.exception(_LE('Attach volume failed to %(instance_name)s: '
|
||||
'%(exn)s'), {'instance_name': instance_name,
|
||||
'exn': exn})
|
||||
|
@ -20,7 +20,6 @@ import nova.virt.driver
|
||||
import nova.virt.firewall
|
||||
import nova.virt.hardware
|
||||
import nova.virt.hyperv.pathutils
|
||||
import nova.virt.hyperv.utilsfactory
|
||||
import nova.virt.hyperv.vif
|
||||
import nova.virt.hyperv.vmops
|
||||
import nova.virt.hyperv.volumeops
|
||||
@ -70,7 +69,6 @@ def list_opts():
|
||||
('hyperv',
|
||||
itertools.chain(
|
||||
nova.virt.hyperv.pathutils.hyperv_opts,
|
||||
nova.virt.hyperv.utilsfactory.hyper_opts,
|
||||
nova.virt.hyperv.vif.hyperv_opts,
|
||||
nova.virt.hyperv.vmops.hyperv_opts,
|
||||
nova.virt.hyperv.volumeops.hyper_volumeops_opts,
|
||||
|
@ -52,3 +52,4 @@ psutil<2.0.0,>=1.1.1
|
||||
oslo.versionedobjects>=0.9.0
|
||||
alembic>=0.8.0
|
||||
os-brick>=0.4.0 # Apache-2.0
|
||||
os-win>=0.0.6 # Apache-2.0
|
||||
|
@ -255,6 +255,7 @@ nova.tests.unit.virt.hyperv.test_snapshotops.SnapshotOpsTestCase
|
||||
nova.tests.unit.virt.hyperv.test_utilsfactory.TestHyperVUtilsFactory
|
||||
nova.tests.unit.virt.hyperv.test_vhdutils.VHDUtilsTestCase
|
||||
nova.tests.unit.virt.hyperv.test_vhdutilsv2.VHDUtilsV2TestCase
|
||||
nova.tests.unit.virt.hyperv.test_vif.HyperVNovaNetworkVIFDriverTestCase
|
||||
nova.tests.unit.virt.hyperv.test_vmops.VMOpsTestCase
|
||||
nova.tests.unit.virt.hyperv.test_vmutils.VMUtilsTestCase
|
||||
nova.tests.unit.virt.hyperv.test_vmutilsv2.VMUtilsV2TestCase
|
||||
|
Loading…
x
Reference in New Issue
Block a user