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.
|
# 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)
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
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
|
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)
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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. "
|
||||||
|
@ -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)
|
|
||||||
|
@ -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__)
|
||||||
|
|
||||||
|
@ -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 "
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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.",
|
||||||
|
@ -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})
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user