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:
Claudiu Belu 2015-08-10 11:50:34 +03:00
parent 8cc9505f09
commit dc2edc2882
28 changed files with 282 additions and 423 deletions

View File

@ -15,9 +15,9 @@
# under the License. # under the License.
import mock import mock
from os_win import utilsfactory
from nova import test from nova import test
from nova.virt.hyperv import utilsfactory
class HyperVBaseTestCase(test.NoDBTestCase): class HyperVBaseTestCase(test.NoDBTestCase):
@ -28,14 +28,12 @@ class HyperVBaseTestCase(test.NoDBTestCase):
wmi_patcher = mock.patch('__builtin__.wmi', create=True, wmi_patcher = mock.patch('__builtin__.wmi', create=True,
new=self._mock_wmi) new=self._mock_wmi)
platform_patcher = mock.patch('sys.platform', 'win32') 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() platform_patcher.start()
wmi_patcher.start() wmi_patcher.start()
patched_hostutils = hostutils_patcher.start() utilsfactory_patcher.start()
patched_hostutils.check_min_windows_version.return_value = False
self.addCleanup(wmi_patcher.stop) self.addCleanup(wmi_patcher.stop)
self.addCleanup(platform_patcher.stop) self.addCleanup(platform_patcher.stop)
self.addCleanup(hostutils_patcher.stop) self.addCleanup(utilsfactory_patcher.stop)

View File

@ -20,10 +20,12 @@ Unit tests for the Hyper-V Driver.
import platform import platform
import mock import mock
from os_win import exceptions as os_win_exc
from nova import exception from nova import exception
from nova.tests.unit import fake_instance from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base from nova.tests.unit.virt.hyperv import test_base
from nova import utils
from nova.virt import driver as base_driver from nova.virt import driver as base_driver
from nova.virt.hyperv import driver from nova.virt.hyperv import driver
@ -46,16 +48,45 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
self.driver._migrationops = mock.MagicMock() self.driver._migrationops = mock.MagicMock()
self.driver._rdpconsoleops = mock.MagicMock() self.driver._rdpconsoleops = mock.MagicMock()
@mock.patch.object(driver.hostutils.HostUtils, 'check_min_windows_version') @mock.patch.object(driver.utilsfactory, 'get_hostutils')
def test_check_minimum_windows_version(self, mock_check_min_win_version): def test_check_minimum_windows_version(self, mock_get_hostutils):
mock_check_min_win_version.return_value = False mock_hostutils = mock_get_hostutils.return_value
mock_hostutils.check_min_windows_version.return_value = False
self.assertRaises(exception.HypervisorTooOld, self.assertRaises(exception.HypervisorTooOld,
self.driver._check_minimum_windows_version) self.driver._check_minimum_windows_version)
def test_public_api_signatures(self): def test_public_api_signatures(self):
self.assertPublicAPISignatures(base_driver.ComputeDriver(None), # NOTE(claudiub): wrapped functions do not keep the same signature in
self.driver) # 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') @mock.patch.object(driver.eventhandler, 'InstanceEventHandler')
def test_init_host(self, mock_InstanceEventHandler): def test_init_host(self, mock_InstanceEventHandler):

View File

@ -15,13 +15,13 @@
import eventlet import eventlet
import mock 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.tests.unit.virt.hyperv import test_base
from nova import utils from nova import utils
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import eventhandler from nova.virt.hyperv import eventhandler
from nova.virt.hyperv import utilsfactory
class EventHandlerTestCase(test_base.HyperVBaseTestCase): class EventHandlerTestCase(test_base.HyperVBaseTestCase):
@ -123,7 +123,8 @@ class EventHandlerTestCase(test_base.HyperVBaseTestCase):
side_effect = (mock.sentinel.instance_uuid side_effect = (mock.sentinel.instance_uuid
if not missing_uuid else None, ) if not missing_uuid else None, )
else: 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 = self._event_handler._vmutils.get_instance_uuid
mock_get_uuid.side_effect = side_effect mock_get_uuid.side_effect = side_effect

View File

@ -48,16 +48,12 @@ class ImageCacheTestCase(test.NoDBTestCase):
# in order to return the proper Utils Class, so it must be mocked. # in order to return the proper Utils Class, so it must be mocked.
patched_get_hostutils = mock.patch.object(imagecache.utilsfactory, patched_get_hostutils = mock.patch.object(imagecache.utilsfactory,
"get_hostutils") "get_hostutils")
patched_get_pathutils = mock.patch.object(imagecache.utilsfactory,
"get_pathutils")
patched_get_vhdutils = mock.patch.object(imagecache.utilsfactory, patched_get_vhdutils = mock.patch.object(imagecache.utilsfactory,
"get_vhdutils") "get_vhdutils")
patched_get_hostutils.start() patched_get_hostutils.start()
patched_get_pathutils.start()
patched_get_vhdutils.start() patched_get_vhdutils.start()
self.addCleanup(patched_get_hostutils.stop) self.addCleanup(patched_get_hostutils.stop)
self.addCleanup(patched_get_pathutils.stop)
self.addCleanup(patched_get_vhdutils.stop) self.addCleanup(patched_get_vhdutils.stop)
self.imagecache = imagecache.ImageCache() self.imagecache = imagecache.ImageCache()
@ -82,8 +78,8 @@ class ImageCacheTestCase(test.NoDBTestCase):
@mock.patch.object(imagecache.ImageCache, '_get_root_vhd_size_gb') @mock.patch.object(imagecache.ImageCache, '_get_root_vhd_size_gb')
def test_resize_and_cache_vhd_smaller(self, mock_get_vhd_size_gb): def test_resize_and_cache_vhd_smaller(self, mock_get_vhd_size_gb):
self.imagecache._vhdutils.get_vhd_info.return_value = { self.imagecache._vhdutils.get_vhd_size.return_value = {
'MaxInternalSize': (self.FAKE_VHD_SIZE_GB + 1) * units.Gi 'VirtualSize': (self.FAKE_VHD_SIZE_GB + 1) * units.Gi
} }
mock_get_vhd_size_gb.return_value = self.FAKE_VHD_SIZE_GB mock_get_vhd_size_gb.return_value = self.FAKE_VHD_SIZE_GB
mock_internal_vhd_size = ( mock_internal_vhd_size = (
@ -95,7 +91,7 @@ class ImageCacheTestCase(test.NoDBTestCase):
mock.sentinel.instance, mock.sentinel.instance,
mock.sentinel.vhd_path) 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.sentinel.vhd_path)
mock_get_vhd_size_gb.assert_called_once_with(mock.sentinel.instance) mock_get_vhd_size_gb.assert_called_once_with(mock.sentinel.instance)
mock_internal_vhd_size.assert_called_once_with( mock_internal_vhd_size.assert_called_once_with(

View File

@ -14,12 +14,12 @@
# under the License. # under the License.
import mock import mock
from os_win import exceptions as os_win_exc
from oslo_config import cfg from oslo_config import cfg
from nova.tests.unit import fake_instance from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import livemigrationops from nova.virt.hyperv import livemigrationops
from nova.virt.hyperv import vmutils
CONF = cfg.CONF CONF = cfg.CONF
@ -44,8 +44,8 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
fake_dest = mock.sentinel.DESTINATION fake_dest = mock.sentinel.DESTINATION
self._livemigrops._livemigrutils.live_migrate_vm.side_effect = [ self._livemigrops._livemigrutils.live_migrate_vm.side_effect = [
side_effect] side_effect]
if side_effect is vmutils.HyperVException: if side_effect is os_win_exc.HyperVException:
self.assertRaises(vmutils.HyperVException, self.assertRaises(os_win_exc.HyperVException,
self._livemigrops.live_migration, self._livemigrops.live_migration,
self.context, mock_instance, fake_dest, self.context, mock_instance, fake_dest,
mock_post, mock_recover, False, None) mock_post, mock_recover, False, None)
@ -70,7 +70,7 @@ class LiveMigrationOpsTestCase(test_base.HyperVBaseTestCase):
self._test_live_migration(side_effect=None) self._test_live_migration(side_effect=None)
def test_live_migration_exception(self): 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): def test_live_migration_wrong_os_version(self):
self._livemigrops._livemigrutils = None self._livemigrops._livemigrutils = None

View File

@ -15,6 +15,7 @@
import os import os
import mock import mock
from os_win import exceptions as os_win_exc
from oslo_utils import units from oslo_utils import units
from nova import exception from nova import exception
@ -23,7 +24,6 @@ from nova import test
from nova.tests.unit import fake_instance from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import migrationops from nova.virt.hyperv import migrationops
from nova.virt.hyperv import vmutils
class MigrationOpsTestCase(test_base.HyperVBaseTestCase): 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, recon_parent_vhd.assert_called_once_with(fake_diff_vhd_path,
base_vhd_copy_path) base_vhd_copy_path)
self._migrationops._vhdutils.merge_vhd.assert_called_once_with( 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( self._migrationops._pathutils.rename.assert_called_once_with(
base_vhd_copy_path, fake_diff_vhd_path) base_vhd_copy_path, fake_diff_vhd_path)
@ -300,10 +300,10 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
os.path.basename(fake_base_vhd_path)) os.path.basename(fake_base_vhd_path))
self._migrationops._vhdutils.reconnect_parent_vhd.side_effect = ( self._migrationops._vhdutils.reconnect_parent_vhd.side_effect = (
vmutils.HyperVException) os_win_exc.HyperVException)
self._migrationops._pathutils.exists.return_value = True self._migrationops._pathutils.exists.return_value = True
self.assertRaises(vmutils.HyperVException, self.assertRaises(os_win_exc.HyperVException,
self._migrationops._merge_base_vhd, self._migrationops._merge_base_vhd,
fake_diff_vhd_path, fake_base_vhd_path) fake_diff_vhd_path, fake_base_vhd_path)
self._migrationops._pathutils.exists.assert_called_once_with( self._migrationops._pathutils.exists.assert_called_once_with(
@ -314,7 +314,7 @@ class MigrationOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch.object(migrationops.MigrationOps, '_resize_vhd') @mock.patch.object(migrationops.MigrationOps, '_resize_vhd')
def test_check_resize_vhd(self, mock_resize_vhd): def test_check_resize_vhd(self, mock_resize_vhd):
self._migrationops._check_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) new_size=2)
mock_resize_vhd.assert_called_once_with(mock.sentinel.vhd_path, 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.assertRaises(exception.CannotResizeDisk,
self._migrationops._check_resize_vhd, self._migrationops._check_resize_vhd,
mock.sentinel.vhd_path, mock.sentinel.vhd_path,
{'MaxInternalSize': 1}, 0) {'VirtualSize': 1}, 0)
@mock.patch.object(migrationops.MigrationOps, '_merge_base_vhd') @mock.patch.object(migrationops.MigrationOps, '_merge_base_vhd')
def test_resize_vhd(self, mock_merge_base_vhd): def test_resize_vhd(self, mock_merge_base_vhd):

View File

@ -20,7 +20,6 @@ from nova import exception
from nova.tests.unit.virt.hyperv import test_base from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import pathutils from nova.virt.hyperv import pathutils
from nova.virt.hyperv import vmutils
class PathUtilsTestCase(test_base.HyperVBaseTestCase): class PathUtilsTestCase(test_base.HyperVBaseTestCase):
@ -33,44 +32,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
self._pathutils = pathutils.PathUtils() 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): def _mock_lookup_configdrive_path(self, ext):
self._pathutils.get_instance_dir = mock.MagicMock( self._pathutils.get_instance_dir = mock.MagicMock(
return_value=self.fake_instance_dir) return_value=self.fake_instance_dir)
@ -98,83 +59,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
self.fake_instance_name) self.fake_instance_name)
self.assertIsNone(configdrive_path) 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') @mock.patch('os.path.join')
def test_get_instances_sub_dir(self, fake_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_dir_name = "fake_dir_name"
fake_windows_error = WindowsError 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)) side_effect=WindowsError(pathutils.ERROR_INVALID_NAME))
with mock.patch('__builtin__.WindowsError', with mock.patch('__builtin__.WindowsError',
fake_windows_error, create=True): fake_windows_error, create=True):

View File

@ -16,8 +16,10 @@
import os import os
import mock import mock
from os_win import exceptions as os_win_exc
from nova.compute import task_states from nova.compute import task_states
from nova import exception
from nova.tests.unit import fake_instance from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import snapshotops from nova.virt.hyperv import snapshotops
@ -96,7 +98,7 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
mock_reconnect.assert_called_once_with(dest_vhd_path, mock_reconnect.assert_called_once_with(dest_vhd_path,
base_dest_disk_path) base_dest_disk_path)
self._snapshotops._vhdutils.merge_vhd.assert_called_once_with( 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( mock_save_glance_image.assert_called_once_with(
self.context, mock.sentinel.IMAGE_ID, base_dest_disk_path) self.context, mock.sentinel.IMAGE_ID, base_dest_disk_path)
else: else:
@ -119,3 +121,18 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
def test_snapshot_no_base_disk(self): def test_snapshot_no_base_disk(self):
self._test_snapshot(base_disk_path=None) 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)

View File

@ -21,7 +21,6 @@ import mock
from oslo_config import cfg from oslo_config import cfg
from nova import test from nova import test
from nova.virt.hyperv import hostutils
from nova.virt.hyperv import utilsfactory from nova.virt.hyperv import utilsfactory
from nova.virt.hyperv import volumeutils from nova.virt.hyperv import volumeutils
from nova.virt.hyperv import volumeutilsv2 from nova.virt.hyperv import volumeutilsv2
@ -31,18 +30,25 @@ CONF = cfg.CONF
class TestHyperVUtilsFactory(test.NoDBTestCase): class TestHyperVUtilsFactory(test.NoDBTestCase):
def test_get_volumeutils_v2(self): 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): 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): 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): @mock.patch.object(utilsfactory, 'CONF')
CONF.set_override('force_volumeutils_v1', force_v1, 'hyperv') 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( with mock.patch.object(
hostutils.HostUtils, utilsfactory.utils,
'check_min_windows_version') as mock_check_min_windows_version: 'check_min_windows_version') as mock_check_min_windows_version:
mock_check_min_windows_version.return_value = os_supports_v2 mock_check_min_windows_version.return_value = os_supports_v2

View 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)

View File

@ -16,6 +16,7 @@ import os
from eventlet import timeout as etimeout from eventlet import timeout as etimeout
import mock import mock
from os_win import exceptions as os_win_exc
from oslo_concurrency import processutils from oslo_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import units 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.tests.unit.virt.hyperv import test_base
from nova.virt import hardware from nova.virt import hardware
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import ioutils
from nova.virt.hyperv import vmops from nova.virt.hyperv import vmops
from nova.virt.hyperv import vmutils
CONF = cfg.CONF CONF = cfg.CONF
@ -126,7 +125,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)
mock_instance.root_gb = self.FAKE_SIZE mock_instance.root_gb = self.FAKE_SIZE
self.flags(use_cow_images=use_cow_images) 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} vhd_size * units.Gi}
self._vmops._vhdutils.get_vhd_format.return_value = vhd_format self._vmops._vhdutils.get_vhd_format.return_value = vhd_format
root_vhd_internal_size = mock_instance.root_gb * units.Gi 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( self._vmops._pathutils.get_ephemeral_vhd_path.assert_called_with(
mock_instance.name, mock.sentinel.FAKE_FORMAT) mock_instance.name, mock.sentinel.FAKE_FORMAT)
self._vmops._vhdutils.create_dynamic_vhd.assert_called_with( self._vmops._vhdutils.create_dynamic_vhd.assert_called_with(
mock.sentinel.FAKE_PATH, mock_instance.ephemeral_gb * units.Gi, mock.sentinel.FAKE_PATH, mock_instance.ephemeral_gb * units.Gi)
mock.sentinel.FAKE_FORMAT)
self.assertEqual(mock.sentinel.FAKE_PATH, response) self.assertEqual(mock.sentinel.FAKE_PATH, response)
@mock.patch('nova.virt.hyperv.vmops.VMOps.destroy') @mock.patch('nova.virt.hyperv.vmops.VMOps.destroy')
@ -301,8 +299,8 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
self.context, mock_instance, mock_image_meta, self.context, mock_instance, mock_image_meta,
[mock.sentinel.FILE], mock.sentinel.PASSWORD, [mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.INFO, mock.sentinel.DEV_INFO) mock.sentinel.INFO, mock.sentinel.DEV_INFO)
elif fail is vmutils.HyperVException: elif fail is os_win_exc.HyperVException:
self.assertRaises(vmutils.HyperVException, self._vmops.spawn, self.assertRaises(os_win_exc.HyperVException, self._vmops.spawn,
self.context, mock_instance, mock_image_meta, self.context, mock_instance, mock_image_meta,
[mock.sentinel.FILE], mock.sentinel.PASSWORD, [mock.sentinel.FILE], mock.sentinel.PASSWORD,
mock.sentinel.INFO, mock.sentinel.DEV_INFO) mock.sentinel.INFO, mock.sentinel.DEV_INFO)
@ -347,7 +345,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
def test_spawn_create_instance_exception(self): def test_spawn_create_instance_exception(self):
self._test_spawn(exists=False, boot_from_volume=False, self._test_spawn(exists=False, boot_from_volume=False,
configdrive_required=True, configdrive_required=True,
fail=vmutils.HyperVException) fail=os_win_exc.HyperVException)
def test_spawn_not_required(self): def test_spawn_not_required(self):
self._test_spawn(exists=False, boot_from_volume=False, 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): def test_spawn_no_admin_permissions(self):
self._vmops._vmutils.check_admin_permissions.side_effect = ( self._vmops._vmutils.check_admin_permissions.side_effect = (
vmutils.HyperVException) os_win_exc.HyperVException)
self.assertRaises(vmutils.HyperVException, self.assertRaises(os_win_exc.HyperVException,
self._vmops.spawn, self._vmops.spawn,
self.context, mock.DEFAULT, mock.DEFAULT, self.context, mock.DEFAULT, mock.DEFAULT,
[mock.sentinel.FILE], mock.sentinel.PASSWORD, [mock.sentinel.FILE], mock.sentinel.PASSWORD,
@ -663,10 +661,11 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch('nova.virt.hyperv.vmops.VMOps.power_off') @mock.patch('nova.virt.hyperv.vmops.VMOps.power_off')
def test_destroy_exception(self, mock_power_off): def test_destroy_exception(self, mock_power_off):
mock_instance = fake_instance.fake_instance_obj(self.context) 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._vmops._vmutils.vm_exists.return_value = True
self.assertRaises(vmutils.HyperVException, self.assertRaises(os_win_exc.HyperVException,
self._vmops.destroy, mock_instance) self._vmops.destroy, mock_instance)
def test_reboot_hard(self): def test_reboot_hard(self):
@ -689,10 +688,11 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch("nova.virt.hyperv.vmops.VMOps._soft_shutdown") @mock.patch("nova.virt.hyperv.vmops.VMOps._soft_shutdown")
def test_reboot_soft_exception(self, mock_soft_shutdown, mock_power_on): def test_reboot_soft_exception(self, mock_soft_shutdown, mock_power_on):
mock_soft_shutdown.return_value = True 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) 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) instance, {}, vmops.REBOOT_TYPE_SOFT)
mock_soft_shutdown.assert_called_once_with(instance) 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) instance = fake_instance.fake_instance_obj(self.context)
mock_shutdown_vm = self._vmops._vmutils.soft_shutdown_vm 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.") "Expected failure.")
result = self._vmops._soft_shutdown(instance, self._FAKE_TIMEOUT) 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") @mock.patch("nova.virt.hyperv.vmops.VMOps._soft_shutdown")
def test_power_off_unexisting_instance(self, mock_soft_shutdown): def test_power_off_unexisting_instance(self, mock_soft_shutdown):
mock_soft_shutdown.side_effect = ( mock_soft_shutdown.side_effect = os_win_exc.HyperVVMNotFoundException(
exception.InstanceNotFound('fake_instance_uuid')) vm_name=mock.sentinel.vm_name)
self._test_power_off(timeout=1, set_state_expected=False) self._test_power_off(timeout=1, set_state_expected=False)
@mock.patch('nova.virt.hyperv.vmops.VMOps._set_vm_state') @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): def test_set_vm_state_exception(self):
mock_instance = fake_instance.fake_instance_obj(self.context) mock_instance = fake_instance.fake_instance_obj(self.context)
self._vmops._vmutils.set_vm_state.side_effect = vmutils.HyperVException self._vmops._vmutils.set_vm_state.side_effect = (
self.assertRaises(vmutils.HyperVException, self._vmops._set_vm_state, os_win_exc.HyperVException)
self.assertRaises(os_win_exc.HyperVException,
self._vmops._set_vm_state,
mock_instance, mock.sentinel.STATE) mock_instance, mock.sentinel.STATE)
def test_get_vm_state(self): def test_get_vm_state(self):
@ -904,7 +906,7 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
mock.sentinel.FAKE_VM_NAME, vmops.SHUTDOWN_TIME_INCREMENT) mock.sentinel.FAKE_VM_NAME, vmops.SHUTDOWN_TIME_INCREMENT)
self.assertFalse(result) self.assertFalse(result)
@mock.patch.object(ioutils, 'IOThread') @mock.patch.object(vmops.ioutils, 'IOThread')
def _test_log_vm_serial_output(self, mock_io_thread, def _test_log_vm_serial_output(self, mock_io_thread,
worker_running=False, worker_running=False,
worker_exists=False): worker_exists=False):
@ -1005,7 +1007,6 @@ class VMOpsTestCase(test_base.HyperVBaseTestCase):
@mock.patch("os.path.exists") @mock.patch("os.path.exists")
def test_get_console_output_exception(self, fake_path_exists, fake_open): def test_get_console_output_exception(self, fake_path_exists, fake_open):
fake_vm = mock.MagicMock() fake_vm = mock.MagicMock()
fake_open.side_effect = IOError fake_open.side_effect = IOError
fake_path_exists.return_value = True fake_path_exists.return_value = True
self._vmops._pathutils.get_vm_console_log_paths.return_value = ( 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') @mock.patch.object(vmops.VMOps, '_check_hotplug_available')
def test_detach_interface_missing_instance(self, mock_check_hotplug): 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.assertRaises(exception.InterfaceDetachFailed,
self._vmops.detach_interface, self._vmops.detach_interface,
mock.MagicMock(), mock.sentinel.fake_vif) mock.MagicMock(), mock.sentinel.fake_vif)

View File

@ -17,14 +17,13 @@
import os import os
import mock import mock
from os_win import exceptions as os_win_exc
from oslo_config import cfg from oslo_config import cfg
from nova import exception from nova import exception
from nova import test from nova import test
from nova.tests.unit import fake_block_device from nova.tests.unit import fake_block_device
from nova.tests.unit.virt.hyperv import test_base 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 from nova.virt.hyperv import volumeops
CONF = cfg.CONF CONF = cfg.CONF
@ -120,16 +119,15 @@ class VolumeOpsTestCase(test_base.HyperVBaseTestCase):
fake_volume_driver.disconnect_volumes.assert_called_once_with( fake_volume_driver.disconnect_volumes.assert_called_once_with(
block_device_mapping) 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() block_device_info = get_fake_block_dev_info()
response = self._volumeops.ebs_root_in_block_devices(block_device_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._volumeops._default_root_device, block_device_info)
self.assertEqual( self.assertEqual(mock_vol_in_mapping.return_value, response)
self._volumeops._volutils.volume_in_mapping.return_value,
response)
def test_get_volume_connector(self): def test_get_volume_connector(self):
mock_instance = mock.DEFAULT mock_instance = mock.DEFAULT
@ -239,9 +237,9 @@ class ISCSIVolumeDriverTestCase(test_base.HyperVBaseTestCase):
mock_logout_storage_target, mock_logout_storage_target,
mock_get_mounted_disk): mock_get_mounted_disk):
connection_info = get_fake_connection_info() 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, self._volume_driver.attach_volume, connection_info,
mock.sentinel.instance_name) mock.sentinel.instance_name)
mock_logout_storage_target.assert_called_with(mock.sentinel.fake_iqn) mock_logout_storage_target.assert_called_with(mock.sentinel.fake_iqn)
@ -418,6 +416,8 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
super(SMBFSVolumeDriverTestCase, self).setUp() super(SMBFSVolumeDriverTestCase, self).setUp()
self._volume_driver = volumeops.SMBFSVolumeDriver() self._volume_driver = volumeops.SMBFSVolumeDriver()
self._volume_driver._vmutils = mock.MagicMock() 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, 'ensure_share_mounted')
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path') @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, def test_attach_non_existing_image(self, mock_get_disk_path,
mock_ensure_share_mounted): mock_ensure_share_mounted):
self._volume_driver._vmutils.attach_drive.side_effect = ( self._volume_driver._vmutils.attach_drive.side_effect = (
vmutils.HyperVException()) os_win_exc.HyperVException)
self.assertRaises(exception.VolumeAttachFailed, self.assertRaises(exception.VolumeAttachFailed,
self._volume_driver.attach_volume, self._volume_driver.attach_volume,
self._FAKE_CONNECTION_INFO, self._FAKE_CONNECTION_INFO,
mock.sentinel.instance_name) mock.sentinel.instance_name)
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path') @mock.patch.object(volumeops.SMBFSVolumeDriver, '_get_disk_path')
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share') def test_detach_volume(self, mock_get_disk_path):
def test_detach_volume(self, mock_unmount_smb_share, mock_get_disk_path):
mock_get_disk_path.return_value = ( mock_get_disk_path.return_value = (
mock.sentinel.disk_path) mock.sentinel.disk_path)
@ -510,12 +509,10 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
self.assertEqual(expected, disk_path) self.assertEqual(expected, disk_path)
@mock.patch.object(volumeops.SMBFSVolumeDriver, '_parse_credentials') @mock.patch.object(volumeops.SMBFSVolumeDriver, '_parse_credentials')
@mock.patch.object(pathutils.PathUtils, 'check_smb_mapping') def _test_ensure_mounted(self, mock_parse_credentials, is_mounted=False):
@mock.patch.object(pathutils.PathUtils, 'mount_smb_share') mock_mount_smb_share = self._volume_driver._pathutils.mount_smb_share
def _test_ensure_mounted(self, mock_mount_smb_share, self._volume_driver._pathutils.check_smb_mapping.return_value = (
mock_check_smb_mapping, mock_parse_credentials, is_mounted)
is_mounted=False):
mock_check_smb_mapping.return_value = is_mounted
mock_parse_credentials.return_value = ( mock_parse_credentials.return_value = (
self._FAKE_USERNAME, self._FAKE_PASSWORD) self._FAKE_USERNAME, self._FAKE_PASSWORD)
@ -537,10 +534,10 @@ class SMBFSVolumeDriverTestCase(test_base.HyperVBaseTestCase):
def test_ensure_already_mounted(self): def test_ensure_already_mounted(self):
self._test_ensure_mounted(is_mounted=True) self._test_ensure_mounted(is_mounted=True)
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share') def test_disconnect_volumes(self):
def test_disconnect_volumes(self, mock_unmount_smb_share):
block_device_mapping = [ block_device_mapping = [
{'connection_info': self._FAKE_CONNECTION_INFO}] {'connection_info': self._FAKE_CONNECTION_INFO}]
self._volume_driver.disconnect_volumes(block_device_mapping) 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) self._FAKE_SHARE_NORMALIZED)

View File

@ -17,9 +17,13 @@
A Hyper-V Nova Compute driver. A Hyper-V Nova Compute driver.
""" """
import functools
import platform import platform
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from oslo_log import log as logging from oslo_log import log as logging
import six
from nova import exception from nova import exception
from nova.i18n import _, _LE from nova.i18n import _, _LE
@ -27,7 +31,6 @@ from nova import objects
from nova.virt import driver from nova.virt import driver
from nova.virt.hyperv import eventhandler from nova.virt.hyperv import eventhandler
from nova.virt.hyperv import hostops from nova.virt.hyperv import hostops
from nova.virt.hyperv import hostutils
from nova.virt.hyperv import livemigrationops from nova.virt.hyperv import livemigrationops
from nova.virt.hyperv import migrationops from nova.virt.hyperv import migrationops
from nova.virt.hyperv import rdpconsoleops from nova.virt.hyperv import rdpconsoleops
@ -38,6 +41,49 @@ from nova.virt.hyperv import volumeops
LOG = logging.getLogger(__name__) 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): class HyperVDriver(driver.ComputeDriver):
capabilities = { capabilities = {
"has_imagecache": False, "has_imagecache": False,
@ -61,7 +107,7 @@ class HyperVDriver(driver.ComputeDriver):
self._rdpconsoleops = rdpconsoleops.RDPConsoleOps() self._rdpconsoleops = rdpconsoleops.RDPConsoleOps()
def _check_minimum_windows_version(self): 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. # the version is of Windows is older than Windows Server 2012 R2.
# Log an error, lettingusers know that this version is not # Log an error, lettingusers know that this version is not
# supported any longer. # supported any longer.

View File

@ -20,15 +20,15 @@ import sys
if sys.platform == 'win32': if sys.platform == 'win32':
import wmi import wmi
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from nova import exception
from nova.i18n import _LW from nova.i18n import _LW
from nova import utils from nova import utils
from nova.virt import event as virtevent from nova.virt import event as virtevent
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import utilsfactory
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -117,7 +117,7 @@ class InstanceEventHandler(object):
"will be ignored."), "will be ignored."),
instance_name) instance_name)
return instance_uuid return instance_uuid
except exception.InstanceNotFound: except os_win_exc.HyperVVMNotFoundException:
# The instance has been deleted. # The instance has been deleted.
pass pass

View File

@ -21,6 +21,7 @@ import os
import platform import platform
import time import time
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
@ -31,7 +32,7 @@ from nova.compute import hv_type
from nova.compute import vm_mode from nova.compute import vm_mode
from nova.i18n import _ from nova.i18n import _
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import utilsfactory from nova.virt.hyperv import pathutils
CONF = cfg.CONF CONF = cfg.CONF
CONF.import_opt('my_ip', 'nova.netconf') CONF.import_opt('my_ip', 'nova.netconf')
@ -41,7 +42,7 @@ LOG = logging.getLogger(__name__)
class HostOps(object): class HostOps(object):
def __init__(self): def __init__(self):
self._hostutils = utilsfactory.get_hostutils() self._hostutils = utilsfactory.get_hostutils()
self._pathutils = utilsfactory.get_pathutils() self._pathutils = pathutils.PathUtils()
def _get_cpu_info(self): def _get_cpu_info(self):
"""Get the CPU information. """Get the CPU information.

View File

@ -17,6 +17,7 @@ Image caching and management.
""" """
import os import os
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
@ -24,7 +25,7 @@ from oslo_utils import units
from nova import exception from nova import exception
from nova import utils from nova import utils
from nova.virt.hyperv import utilsfactory from nova.virt.hyperv import pathutils
from nova.virt import images from nova.virt import images
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -35,7 +36,7 @@ CONF.import_opt('use_cow_images', 'nova.virt.driver')
class ImageCache(object): class ImageCache(object):
def __init__(self): def __init__(self):
self._pathutils = utilsfactory.get_pathutils() self._pathutils = pathutils.PathUtils()
self._vhdutils = utilsfactory.get_vhdutils() self._vhdutils = utilsfactory.get_vhdutils()
def _get_root_vhd_size_gb(self, instance): def _get_root_vhd_size_gb(self, instance):
@ -45,8 +46,7 @@ class ImageCache(object):
return instance.root_gb return instance.root_gb
def _resize_and_cache_vhd(self, instance, vhd_path): def _resize_and_cache_vhd(self, instance, vhd_path):
vhd_info = self._vhdutils.get_vhd_info(vhd_path) vhd_size = self._vhdutils.get_vhd_size(vhd_path)['VirtualSize']
vhd_size = vhd_info['MaxInternalSize']
root_vhd_size_gb = self._get_root_vhd_size_gb(instance) root_vhd_size_gb = self._get_root_vhd_size_gb(instance)
root_vhd_size = root_vhd_size_gb * units.Gi root_vhd_size = root_vhd_size_gb * units.Gi

View File

@ -18,15 +18,15 @@ Management class for live migration VM operations.
""" """
import functools import functools
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from nova.i18n import _ from nova.i18n import _
from nova.virt.hyperv import imagecache 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 vmops
from nova.virt.hyperv import vmutilsv2
from nova.virt.hyperv import volumeops from nova.virt.hyperv import volumeops
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -53,11 +53,11 @@ class LiveMigrationOps(object):
else: else:
self._livemigrutils = None self._livemigrutils = None
self._pathutils = utilsfactory.get_pathutils() self._pathutils = pathutils.PathUtils()
self._vmops = vmops.VMOps() self._vmops = vmops.VMOps()
self._volumeops = volumeops.VolumeOps() self._volumeops = volumeops.VolumeOps()
self._imagecache = imagecache.ImageCache() self._imagecache = imagecache.ImageCache()
self._vmutils = vmutilsv2.VMUtilsV2() self._vmutils = utilsfactory.get_vmutils()
@check_os_version_requirement @check_os_version_requirement
def live_migration(self, context, instance_ref, dest, post_method, def live_migration(self, context, instance_ref, dest, post_method,

View File

@ -18,6 +18,7 @@ Management class for migration / resize operations.
""" """
import os import os
from os_win import utilsfactory
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import units from oslo_utils import units
@ -27,7 +28,7 @@ from nova.i18n import _, _LE
from nova import objects from nova import objects
from nova.virt import configdrive from nova.virt import configdrive
from nova.virt.hyperv import imagecache 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 vmops
from nova.virt.hyperv import volumeops from nova.virt.hyperv import volumeops
@ -39,7 +40,7 @@ class MigrationOps(object):
self._hostutils = utilsfactory.get_hostutils() self._hostutils = utilsfactory.get_hostutils()
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._vhdutils = utilsfactory.get_vhdutils() self._vhdutils = utilsfactory.get_vhdutils()
self._pathutils = utilsfactory.get_pathutils() self._pathutils = pathutils.PathUtils()
self._volumeops = volumeops.VolumeOps() self._volumeops = volumeops.VolumeOps()
self._vmops = vmops.VMOps() self._vmops = vmops.VMOps()
self._imagecache = imagecache.ImageCache() self._imagecache = imagecache.ImageCache()
@ -201,11 +202,9 @@ class MigrationOps(object):
self._vhdutils.reconnect_parent_vhd(diff_vhd_path, self._vhdutils.reconnect_parent_vhd(diff_vhd_path,
base_vhd_copy_path) base_vhd_copy_path)
LOG.debug("Merging base disk %(base_vhd_copy_path)s and " LOG.debug("Merging differential disk %s into its parent.",
"diff disk %(diff_vhd_path)s", diff_vhd_path)
{'base_vhd_copy_path': base_vhd_copy_path, self._vhdutils.merge_vhd(diff_vhd_path)
'diff_vhd_path': diff_vhd_path})
self._vhdutils.merge_vhd(diff_vhd_path, base_vhd_copy_path)
# Replace the differential VHD with the merged one # Replace the differential VHD with the merged one
self._pathutils.rename(base_vhd_copy_path, diff_vhd_path) self._pathutils.rename(base_vhd_copy_path, diff_vhd_path)
@ -215,7 +214,7 @@ class MigrationOps(object):
self._pathutils.remove(base_vhd_copy_path) self._pathutils.remove(base_vhd_copy_path)
def _check_resize_vhd(self, vhd_path, vhd_info, new_size): 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: if new_size < curr_size:
raise exception.CannotResizeDisk( raise exception.CannotResizeDisk(
reason=_("Cannot resize the root disk to a smaller size. " reason=_("Cannot resize the root disk to a smaller size. "

View File

@ -14,21 +14,14 @@
# under the License. # under the License.
import os 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_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import utils
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import vmutils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -47,89 +40,14 @@ CONF.register_opts(hyperv_opts, 'hyperv')
CONF.import_opt('instances_path', 'nova.compute.manager') CONF.import_opt('instances_path', 'nova.compute.manager')
ERROR_INVALID_NAME = 123 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): class PathUtils(pathutils.PathUtils):
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
def get_instances_dir(self, remote_server=None): def get_instances_dir(self, remote_server=None):
local_instance_path = os.path.normpath(CONF.instances_path) local_instance_path = os.path.normpath(CONF.instances_path)
@ -145,25 +63,15 @@ class PathUtils(object):
else: else:
return local_instance_path 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, def _get_instances_sub_dir(self, dir_name, remote_server=None,
create_dir=True, remove_dir=False): create_dir=True, remove_dir=False):
instances_path = self.get_instances_dir(remote_server) instances_path = self.get_instances_dir(remote_server)
path = os.path.join(instances_path, dir_name) path = os.path.join(instances_path, dir_name)
try: try:
if remove_dir: if remove_dir:
self._check_remove_dir(path) self.check_remove_dir(path)
if create_dir: if create_dir:
self._check_create_dir(path) self.check_create_dir(path)
return path return path
except WindowsError as ex: except WindowsError as ex:
if ex.winerror == ERROR_INVALID_NAME: if ex.winerror == ERROR_INVALID_NAME:
@ -238,52 +146,3 @@ class PathUtils(object):
remote_server) remote_server)
console_log_path = os.path.join(instance_dir, 'console.log') console_log_path = os.path.join(instance_dir, 'console.log')
return console_log_path, console_log_path + '.1' 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)

View File

@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from os_win import utilsfactory
from oslo_log import log as logging from oslo_log import log as logging
from nova.console import type as ctype from nova.console import type as ctype
from nova.virt.hyperv import hostops from nova.virt.hyperv import hostops
from nova.virt.hyperv import utilsfactory
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)

View File

@ -18,14 +18,17 @@ Management class for VM snapshot operations.
""" """
import os import os
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from nova.compute import task_states from nova.compute import task_states
from nova import exception
from nova.i18n import _LW from nova.i18n import _LW
from nova.image import glance from nova.image import glance
from nova import utils from nova import utils
from nova.virt.hyperv import utilsfactory from nova.virt.hyperv import pathutils
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -33,7 +36,7 @@ LOG = logging.getLogger(__name__)
class SnapshotOps(object): class SnapshotOps(object):
def __init__(self): def __init__(self):
self._pathutils = utilsfactory.get_pathutils() self._pathutils = pathutils.PathUtils()
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._vhdutils = utilsfactory.get_vhdutils() self._vhdutils = utilsfactory.get_vhdutils()
@ -54,7 +57,11 @@ class SnapshotOps(object):
def instance_synchronized_snapshot(): def instance_synchronized_snapshot():
self._snapshot(context, instance, image_id, update_task_state) 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): def _snapshot(self, context, instance, image_id, update_task_state):
"""Create snapshot from a running VM instance.""" """Create snapshot from a running VM instance."""
@ -103,11 +110,9 @@ class SnapshotOps(object):
self._vhdutils.reconnect_parent_vhd(dest_vhd_path, self._vhdutils.reconnect_parent_vhd(dest_vhd_path,
dest_base_disk_path) dest_base_disk_path)
LOG.debug("Merging base disk %(dest_base_disk_path)s and " LOG.debug("Merging diff disk %s into its parent.",
"diff disk %(dest_vhd_path)s", dest_vhd_path)
{'dest_base_disk_path': dest_base_disk_path, self._vhdutils.merge_vhd(dest_vhd_path)
'dest_vhd_path': dest_vhd_path})
self._vhdutils.merge_vhd(dest_vhd_path, dest_base_disk_path)
image_vhd_path = dest_base_disk_path image_vhd_path = dest_base_disk_path
LOG.debug("Updating Glance image %(image_id)s with content from " LOG.debug("Updating Glance image %(image_id)s with content from "

View File

@ -27,16 +27,10 @@ from nova.virt.hyperv import vmutilsv2
from nova.virt.hyperv import volumeutils from nova.virt.hyperv import volumeutils
from nova.virt.hyperv import volumeutilsv2 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 = cfg.CONF
CONF.register_opts(hyper_opts, 'hyperv')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONF.import_group('hyperv', 'os_win.utilsfactory')
utils = hostutils.HostUtils() utils = hostutils.HostUtils()

View File

@ -16,11 +16,10 @@
import abc import abc
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from nova.virt.hyperv import utilsfactory
hyperv_opts = [ hyperv_opts = [
cfg.StrOpt('vswitch_name', cfg.StrOpt('vswitch_name',
help='External virtual switch Name, ' help='External virtual switch Name, '
@ -60,22 +59,11 @@ class HyperVNovaNetworkVIFDriver(HyperVBaseVIFDriver):
"""Nova network VIF driver.""" """Nova network VIF driver."""
def __init__(self): def __init__(self):
self._vmutils = utilsfactory.get_vmutils()
self._netutils = utilsfactory.get_networkutils() self._netutils = utilsfactory.get_networkutils()
def plug(self, instance, vif): def plug(self, instance, vif):
vswitch_path = self._netutils.get_external_vswitch( self._netutils.connect_vnic_to_vswitch(CONF.hyperv.vswitch_name,
CONF.hyperv.vswitch_name) vif['id'])
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)
def unplug(self, instance, vif): def unplug(self, instance, vif):
# TODO(alepilotti) Not implemented # TODO(alepilotti) Not implemented

View File

@ -22,6 +22,9 @@ import os
import time import time
from eventlet import timeout as etimeout 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_concurrency import processutils
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
@ -41,9 +44,7 @@ from nova.virt import configdrive
from nova.virt import hardware from nova.virt import hardware
from nova.virt.hyperv import constants from nova.virt.hyperv import constants
from nova.virt.hyperv import imagecache from nova.virt.hyperv import imagecache
from nova.virt.hyperv import ioutils from nova.virt.hyperv import pathutils
from nova.virt.hyperv import utilsfactory
from nova.virt.hyperv import vmutils
from nova.virt.hyperv import volumeops from nova.virt.hyperv import volumeops
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -130,8 +131,8 @@ class VMOps(object):
def __init__(self): def __init__(self):
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._vhdutils = utilsfactory.get_vhdutils() self._vhdutils = utilsfactory.get_vhdutils()
self._pathutils = utilsfactory.get_pathutils()
self._hostutils = utilsfactory.get_hostutils() self._hostutils = utilsfactory.get_hostutils()
self._pathutils = pathutils.PathUtils()
self._volumeops = volumeops.VolumeOps() self._volumeops = volumeops.VolumeOps()
self._imagecache = imagecache.ImageCache() self._imagecache = imagecache.ImageCache()
self._vif_driver = None self._vif_driver = None
@ -180,7 +181,7 @@ class VMOps(object):
def _create_root_vhd(self, context, instance): def _create_root_vhd(self, context, instance):
base_vhd_path = self._imagecache.get_cached_image(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_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] format_ext = base_vhd_path.split('.')[-1]
root_vhd_path = self._pathutils.get_root_vhd_path(instance.name, root_vhd_path = self._pathutils.get_root_vhd_path(instance.name,
format_ext) format_ext)
@ -246,8 +247,7 @@ class VMOps(object):
eph_vhd_path = self._pathutils.get_ephemeral_vhd_path( eph_vhd_path = self._pathutils.get_ephemeral_vhd_path(
instance.name, vhd_format) instance.name, vhd_format)
self._vhdutils.create_dynamic_vhd(eph_vhd_path, eph_vhd_size, self._vhdutils.create_dynamic_vhd(eph_vhd_path, eph_vhd_size)
vhd_format)
return eph_vhd_path return eph_vhd_path
@check_admin_permissions @check_admin_permissions
@ -495,7 +495,7 @@ class VMOps(object):
LOG.info(_LI("Soft shutdown succeeded."), LOG.info(_LI("Soft shutdown succeeded."),
instance=instance) instance=instance)
return True return True
except vmutils.HyperVException as e: except os_win_exc.HyperVException as e:
# Exception is raised when trying to shutdown the instance # Exception is raised when trying to shutdown the instance
# while it is still booting. # while it is still booting.
LOG.debug("Soft shutdown failed: %s", e, instance=instance) LOG.debug("Soft shutdown failed: %s", e, instance=instance)
@ -545,7 +545,7 @@ class VMOps(object):
self._set_vm_state(instance, self._set_vm_state(instance,
constants.HYPERV_VM_STATE_DISABLED) constants.HYPERV_VM_STATE_DISABLED)
except exception.InstanceNotFound: except os_win_exc.HyperVVMNotFoundException:
# The manager can call the stop API after receiving instance # The manager can call the stop API after receiving instance
# power off events. If this is triggered when the instance # power off events. If this is triggered when the instance
# is being deleted, it might attempt to power off an unexisting # 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) LOG.debug('Detaching vif: %s', vif['id'], instance=instance)
self._vif_driver.unplug(instance, vif) self._vif_driver.unplug(instance, vif)
self._vmutils.destroy_nic(instance.name, vif['id']) 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. # TODO(claudiub): add set log level to error after string freeze.
LOG.debug("Instance not found during detach interface. It " LOG.debug("Instance not found during detach interface. It "
"might have been destroyed beforehand.", "might have been destroyed beforehand.",

View File

@ -22,17 +22,18 @@ import os
import re import re
import time import time
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from six.moves import range from six.moves import range
from nova import block_device
from nova import exception from nova import exception
from nova.i18n import _, _LE, _LW from nova.i18n import _, _LE, _LW
from nova import utils from nova import utils
from nova.virt import driver from nova.virt import driver
from nova.virt.hyperv import utilsfactory
from nova.virt.hyperv import vmutils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -65,7 +66,7 @@ class VolumeOps(object):
def __init__(self): def __init__(self):
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._volutils = utilsfactory.get_volumeutils() self._volutils = utilsfactory.get_iscsi_initiator_utils()
self._initiator = None self._initiator = None
self._default_root_device = 'vda' self._default_root_device = 'vda'
self.volume_drivers = {'smbfs': SMBFSVolumeDriver(), self.volume_drivers = {'smbfs': SMBFSVolumeDriver(),
@ -111,8 +112,8 @@ class VolumeOps(object):
root_device = block_device_info.get('root_device_name') root_device = block_device_info.get('root_device_name')
if not root_device: if not root_device:
root_device = self._default_root_device root_device = self._default_root_device
return self._volutils.volume_in_mapping(root_device, return block_device.volume_in_mapping(root_device,
block_device_info) block_device_info)
def fix_instance_volume_disk_paths(self, instance_name, 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) mapping = driver.block_device_info_get_mapping(block_device_info)
@ -161,7 +162,7 @@ class VolumeOps(object):
class ISCSIVolumeDriver(object): class ISCSIVolumeDriver(object):
def __init__(self): def __init__(self):
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._volutils = utilsfactory.get_volumeutils() self._volutils = utilsfactory.get_iscsi_initiator_utils()
def login_storage_target(self, connection_info): def login_storage_target(self, connection_info):
data = connection_info['data'] data = connection_info['data']
@ -358,7 +359,6 @@ class SMBFSVolumeDriver(object):
def __init__(self): def __init__(self):
self._pathutils = utilsfactory.get_pathutils() self._pathutils = utilsfactory.get_pathutils()
self._vmutils = utilsfactory.get_vmutils() self._vmutils = utilsfactory.get_vmutils()
self._volutils = utilsfactory.get_volumeutils()
self._username_regex = re.compile(r'user(?:name)?=([^, ]+)') self._username_regex = re.compile(r'user(?:name)?=([^, ]+)')
self._password_regex = re.compile(r'pass(?:word)?=([^, ]+)') self._password_regex = re.compile(r'pass(?:word)?=([^, ]+)')
@ -382,7 +382,7 @@ class SMBFSVolumeDriver(object):
disk_path, disk_path,
ctrller_path, ctrller_path,
slot) slot)
except vmutils.HyperVException as exn: except os_win_exc.HyperVException as exn:
LOG.exception(_LE('Attach volume failed to %(instance_name)s: ' LOG.exception(_LE('Attach volume failed to %(instance_name)s: '
'%(exn)s'), {'instance_name': instance_name, '%(exn)s'), {'instance_name': instance_name,
'exn': exn}) 'exn': exn})

View File

@ -20,7 +20,6 @@ import nova.virt.driver
import nova.virt.firewall import nova.virt.firewall
import nova.virt.hardware import nova.virt.hardware
import nova.virt.hyperv.pathutils import nova.virt.hyperv.pathutils
import nova.virt.hyperv.utilsfactory
import nova.virt.hyperv.vif import nova.virt.hyperv.vif
import nova.virt.hyperv.vmops import nova.virt.hyperv.vmops
import nova.virt.hyperv.volumeops import nova.virt.hyperv.volumeops
@ -70,7 +69,6 @@ def list_opts():
('hyperv', ('hyperv',
itertools.chain( itertools.chain(
nova.virt.hyperv.pathutils.hyperv_opts, nova.virt.hyperv.pathutils.hyperv_opts,
nova.virt.hyperv.utilsfactory.hyper_opts,
nova.virt.hyperv.vif.hyperv_opts, nova.virt.hyperv.vif.hyperv_opts,
nova.virt.hyperv.vmops.hyperv_opts, nova.virt.hyperv.vmops.hyperv_opts,
nova.virt.hyperv.volumeops.hyper_volumeops_opts, nova.virt.hyperv.volumeops.hyper_volumeops_opts,

View File

@ -52,3 +52,4 @@ psutil<2.0.0,>=1.1.1
oslo.versionedobjects>=0.9.0 oslo.versionedobjects>=0.9.0
alembic>=0.8.0 alembic>=0.8.0
os-brick>=0.4.0 # Apache-2.0 os-brick>=0.4.0 # Apache-2.0
os-win>=0.0.6 # Apache-2.0

View File

@ -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_utilsfactory.TestHyperVUtilsFactory
nova.tests.unit.virt.hyperv.test_vhdutils.VHDUtilsTestCase nova.tests.unit.virt.hyperv.test_vhdutils.VHDUtilsTestCase
nova.tests.unit.virt.hyperv.test_vhdutilsv2.VHDUtilsV2TestCase 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_vmops.VMOpsTestCase
nova.tests.unit.virt.hyperv.test_vmutils.VMUtilsTestCase nova.tests.unit.virt.hyperv.test_vmutils.VMUtilsTestCase
nova.tests.unit.virt.hyperv.test_vmutilsv2.VMUtilsV2TestCase nova.tests.unit.virt.hyperv.test_vmutilsv2.VMUtilsV2TestCase