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

View File

@ -20,10 +20,12 @@ Unit tests for the Hyper-V Driver.
import platform
import mock
from os_win import exceptions as os_win_exc
from nova import exception
from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base
from nova import utils
from nova.virt import driver as base_driver
from nova.virt.hyperv import driver
@ -46,16 +48,45 @@ class HyperVDriverTestCase(test_base.HyperVBaseTestCase):
self.driver._migrationops = mock.MagicMock()
self.driver._rdpconsoleops = mock.MagicMock()
@mock.patch.object(driver.hostutils.HostUtils, 'check_min_windows_version')
def test_check_minimum_windows_version(self, mock_check_min_win_version):
mock_check_min_win_version.return_value = False
@mock.patch.object(driver.utilsfactory, 'get_hostutils')
def test_check_minimum_windows_version(self, mock_get_hostutils):
mock_hostutils = mock_get_hostutils.return_value
mock_hostutils.check_min_windows_version.return_value = False
self.assertRaises(exception.HypervisorTooOld,
self.driver._check_minimum_windows_version)
def test_public_api_signatures(self):
self.assertPublicAPISignatures(base_driver.ComputeDriver(None),
self.driver)
# NOTE(claudiub): wrapped functions do not keep the same signature in
# Python 2.7, which causes this test to fail. Instead, we should
# compare the public API signatures of the unwrapped methods.
for attr in driver.HyperVDriver.__dict__:
class_member = getattr(driver.HyperVDriver, attr)
if callable(class_member):
mocked_method = mock.patch.object(
driver.HyperVDriver, attr,
utils.get_wrapped_function(class_member))
mocked_method.start()
self.addCleanup(mocked_method.stop)
self.assertPublicAPISignatures(base_driver.ComputeDriver,
driver.HyperVDriver)
def test_converted_exception(self):
self.driver._vmops.get_info.side_effect = (
os_win_exc.OSWinException)
self.assertRaises(exception.NovaException,
self.driver.get_info, mock.sentinel.instance)
self.driver._vmops.get_info.side_effect = os_win_exc.HyperVException
self.assertRaises(exception.NovaException,
self.driver.get_info, mock.sentinel.instance)
self.driver._vmops.get_info.side_effect = (
os_win_exc.HyperVVMNotFoundException(vm_name='foofoo'))
self.assertRaises(exception.InstanceNotFound,
self.driver.get_info, mock.sentinel.instance)
@mock.patch.object(driver.eventhandler, 'InstanceEventHandler')
def test_init_host(self, mock_InstanceEventHandler):

View File

@ -15,13 +15,13 @@
import eventlet
import mock
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from nova import exception
from nova.tests.unit.virt.hyperv import test_base
from nova import utils
from nova.virt.hyperv import constants
from nova.virt.hyperv import eventhandler
from nova.virt.hyperv import utilsfactory
class EventHandlerTestCase(test_base.HyperVBaseTestCase):
@ -123,7 +123,8 @@ class EventHandlerTestCase(test_base.HyperVBaseTestCase):
side_effect = (mock.sentinel.instance_uuid
if not missing_uuid else None, )
else:
side_effect = exception.InstanceNotFound('fake_instance_uuid')
side_effect = os_win_exc.HyperVVMNotFoundException(
vm_name=mock.sentinel.instance_name)
mock_get_uuid = self._event_handler._vmutils.get_instance_uuid
mock_get_uuid.side_effect = side_effect

View File

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

View File

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

View File

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

View File

@ -20,7 +20,6 @@ from nova import exception
from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import constants
from nova.virt.hyperv import pathutils
from nova.virt.hyperv import vmutils
class PathUtilsTestCase(test_base.HyperVBaseTestCase):
@ -33,44 +32,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
self._pathutils = pathutils.PathUtils()
def _test_smb_conn(self, smb_available=True):
self._mock_wmi.x_wmi = Exception
self._mock_wmi.WMI.side_effect = None if smb_available else Exception
self._pathutils._set_smb_conn()
if smb_available:
expected_conn = self._mock_wmi.WMI.return_value
self.assertEqual(expected_conn, self._pathutils._smb_conn)
else:
self.assertRaises(vmutils.HyperVException,
getattr,
self._pathutils, '_smb_conn')
def test_smb_conn_available(self):
self._test_smb_conn()
def test_smb_conn_unavailable(self):
self._test_smb_conn(smb_available=False)
@mock.patch.object(pathutils.PathUtils, 'rename')
@mock.patch.object(os.path, 'isfile')
@mock.patch.object(os, 'listdir')
def test_move_folder_files(self, mock_listdir, mock_isfile, mock_rename):
src_dir = 'src'
dest_dir = 'dest'
fname = 'tmp_file.txt'
subdir = 'tmp_folder'
src_fname = os.path.join(src_dir, fname)
dest_fname = os.path.join(dest_dir, fname)
# making sure src_subdir is not moved.
mock_listdir.return_value = [fname, subdir]
mock_isfile.side_effect = [True, False]
self._pathutils.move_folder_files(src_dir, dest_dir)
mock_rename.assert_called_once_with(src_fname, dest_fname)
def _mock_lookup_configdrive_path(self, ext):
self._pathutils.get_instance_dir = mock.MagicMock(
return_value=self.fake_instance_dir)
@ -98,83 +59,6 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
self.fake_instance_name)
self.assertIsNone(configdrive_path)
@mock.patch.object(pathutils.PathUtils, 'unmount_smb_share')
@mock.patch('os.path.exists')
def _test_check_smb_mapping(self, mock_exists, mock_unmount_smb_share,
existing_mappings=True, share_available=False):
mock_exists.return_value = share_available
fake_mappings = (
[mock.sentinel.smb_mapping] if existing_mappings else [])
self._pathutils._smb_conn.Msft_SmbMapping.return_value = (
fake_mappings)
ret_val = self._pathutils.check_smb_mapping(
mock.sentinel.share_path)
self.assertEqual(existing_mappings and share_available, ret_val)
if existing_mappings and not share_available:
mock_unmount_smb_share.assert_called_once_with(
mock.sentinel.share_path, force=True)
def test_check_mapping(self):
self._test_check_smb_mapping()
def test_remake_unavailable_mapping(self):
self._test_check_smb_mapping(existing_mappings=True,
share_available=False)
def test_available_mapping(self):
self._test_check_smb_mapping(existing_mappings=True,
share_available=True)
def test_mount_smb_share(self):
fake_create = self._pathutils._smb_conn.Msft_SmbMapping.Create
self._pathutils.mount_smb_share(mock.sentinel.share_path,
mock.sentinel.username,
mock.sentinel.password)
fake_create.assert_called_once_with(
RemotePath=mock.sentinel.share_path,
UserName=mock.sentinel.username,
Password=mock.sentinel.password)
def _test_unmount_smb_share(self, force=False):
fake_mapping = mock.Mock()
smb_mapping_class = self._pathutils._smb_conn.Msft_SmbMapping
smb_mapping_class.return_value = [fake_mapping]
self._pathutils.unmount_smb_share(mock.sentinel.share_path,
force)
smb_mapping_class.assert_called_once_with(
RemotePath=mock.sentinel.share_path)
fake_mapping.Remove.assert_called_once_with(Force=force)
def test_soft_unmount_smb_share(self):
self._test_unmount_smb_share()
def test_force_unmount_smb_share(self):
self._test_unmount_smb_share(force=True)
@mock.patch('time.sleep')
@mock.patch('shutil.rmtree')
def test_rmtree(self, mock_rmtree, mock_sleep):
class WindowsError(Exception):
def __init__(self, winerror=None):
self.winerror = winerror
mock_rmtree.side_effect = [WindowsError(
pathutils.ERROR_DIR_IS_NOT_EMPTY), True]
fake_windows_error = WindowsError
with mock.patch('__builtin__.WindowsError',
fake_windows_error, create=True):
self._pathutils.rmtree(mock.sentinel.FAKE_PATH)
mock_rmtree.assert_has_calls([mock.call(mock.sentinel.FAKE_PATH),
mock.call(mock.sentinel.FAKE_PATH)])
mock_sleep.assert_called_once_with(1)
@mock.patch('os.path.join')
def test_get_instances_sub_dir(self, fake_path_join):
@ -184,7 +68,7 @@ class PathUtilsTestCase(test_base.HyperVBaseTestCase):
fake_dir_name = "fake_dir_name"
fake_windows_error = WindowsError
self._pathutils._check_create_dir = mock.MagicMock(
self._pathutils.check_create_dir = mock.MagicMock(
side_effect=WindowsError(pathutils.ERROR_INVALID_NAME))
with mock.patch('__builtin__.WindowsError',
fake_windows_error, create=True):

View File

@ -16,8 +16,10 @@
import os
import mock
from os_win import exceptions as os_win_exc
from nova.compute import task_states
from nova import exception
from nova.tests.unit import fake_instance
from nova.tests.unit.virt.hyperv import test_base
from nova.virt.hyperv import snapshotops
@ -96,7 +98,7 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
mock_reconnect.assert_called_once_with(dest_vhd_path,
base_dest_disk_path)
self._snapshotops._vhdutils.merge_vhd.assert_called_once_with(
dest_vhd_path, base_dest_disk_path)
dest_vhd_path)
mock_save_glance_image.assert_called_once_with(
self.context, mock.sentinel.IMAGE_ID, base_dest_disk_path)
else:
@ -119,3 +121,18 @@ class SnapshotOpsTestCase(test_base.HyperVBaseTestCase):
def test_snapshot_no_base_disk(self):
self._test_snapshot(base_disk_path=None)
@mock.patch.object(snapshotops.SnapshotOps, '_snapshot')
def test_snapshot_instance_not_found(self, mock_snapshot):
mock_instance = fake_instance.fake_instance_obj(self.context)
mock_snapshot.side_effect = os_win_exc.HyperVVMNotFoundException(
vm_name=mock_instance.name)
self.assertRaises(exception.InstanceNotFound,
self._snapshotops.snapshot,
self.context, mock_instance, mock.sentinel.image_id,
mock.sentinel.update_task_state)
mock_snapshot.assert_called_once_with(self.context, mock_instance,
mock.sentinel.image_id,
mock.sentinel.update_task_state)

View File

@ -21,7 +21,6 @@ import mock
from oslo_config import cfg
from nova import test
from nova.virt.hyperv import hostutils
from nova.virt.hyperv import utilsfactory
from nova.virt.hyperv import volumeutils
from nova.virt.hyperv import volumeutilsv2
@ -31,18 +30,25 @@ CONF = cfg.CONF
class TestHyperVUtilsFactory(test.NoDBTestCase):
def test_get_volumeutils_v2(self):
self._test_returned_class(volumeutilsv2.VolumeUtilsV2, False, True)
self._test_returned_class(expected_class=volumeutilsv2.VolumeUtilsV2,
os_supports_v2=True)
def test_get_volumeutils_v1(self):
self._test_returned_class(volumeutils.VolumeUtils, False, False)
self._test_returned_class(expected_class=volumeutils.VolumeUtils)
def test_get_volumeutils_force_v1_and_not_min_version(self):
self._test_returned_class(volumeutils.VolumeUtils, True, False)
self._test_returned_class(expected_class=volumeutils.VolumeUtils,
force_v1=True)
def _test_returned_class(self, expected_class, force_v1, os_supports_v2):
CONF.set_override('force_volumeutils_v1', force_v1, 'hyperv')
@mock.patch.object(utilsfactory, 'CONF')
def _test_returned_class(self, mock_CONF, expected_class, force_v1=False,
os_supports_v2=False):
# NOTE(claudiub): temporary change, in order for unit tests to pass.
# force_hyperv_utils_v1 CONF flag does not exist anymore.
# utilsfactory and its test cases will be removed next commit.
mock_CONF.hyperv.force_volumeutils_v1 = force_v1
with mock.patch.object(
hostutils.HostUtils,
utilsfactory.utils,
'check_min_windows_version') as mock_check_min_windows_version:
mock_check_min_windows_version.return_value = os_supports_v2

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

View File

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

View File

@ -17,9 +17,13 @@
A Hyper-V Nova Compute driver.
"""
import functools
import platform
from os_win import exceptions as os_win_exc
from os_win import utilsfactory
from oslo_log import log as logging
import six
from nova import exception
from nova.i18n import _, _LE
@ -27,7 +31,6 @@ from nova import objects
from nova.virt import driver
from nova.virt.hyperv import eventhandler
from nova.virt.hyperv import hostops
from nova.virt.hyperv import hostutils
from nova.virt.hyperv import livemigrationops
from nova.virt.hyperv import migrationops
from nova.virt.hyperv import rdpconsoleops
@ -38,6 +41,49 @@ from nova.virt.hyperv import volumeops
LOG = logging.getLogger(__name__)
def convert_exceptions(function, exception_map):
expected_exceptions = tuple(exception_map.keys())
@functools.wraps(function)
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except expected_exceptions as ex:
raised_exception = exception_map.get(type(ex))
if not raised_exception:
# exception might be a subclass of an expected exception.
for expected in expected_exceptions:
if isinstance(ex, expected):
raised_exception = exception_map[expected]
break
raise raised_exception(six.text_type(ex))
return wrapper
def decorate_all_methods(decorator, *args, **kwargs):
def decorate(cls):
for attr in cls.__dict__:
class_member = getattr(cls, attr)
if callable(class_member):
setattr(cls, attr, decorator(class_member, *args, **kwargs))
return cls
return decorate
exception_conversion_map = {
# expected_exception: converted_exception
os_win_exc.OSWinException: exception.NovaException,
os_win_exc.HyperVVMNotFoundException: exception.InstanceNotFound,
}
# NOTE(claudiub): the purpose of the decorator below is to prevent any
# os_win exceptions (subclasses of OSWinException) to leak outside of the
# HyperVDriver.
@decorate_all_methods(convert_exceptions, exception_conversion_map)
class HyperVDriver(driver.ComputeDriver):
capabilities = {
"has_imagecache": False,
@ -61,7 +107,7 @@ class HyperVDriver(driver.ComputeDriver):
self._rdpconsoleops = rdpconsoleops.RDPConsoleOps()
def _check_minimum_windows_version(self):
if not hostutils.HostUtils().check_min_windows_version(6, 2):
if not utilsfactory.get_hostutils().check_min_windows_version(6, 2):
# the version is of Windows is older than Windows Server 2012 R2.
# Log an error, lettingusers know that this version is not
# supported any longer.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,21 +14,14 @@
# under the License.
import os
import shutil
import sys
import time
if sys.platform == 'win32':
import wmi
from os_win.utils import pathutils
from oslo_config import cfg
from oslo_log import log as logging
from nova import exception
from nova.i18n import _
from nova import utils
from nova.virt.hyperv import constants
from nova.virt.hyperv import vmutils
LOG = logging.getLogger(__name__)
@ -47,89 +40,14 @@ CONF.register_opts(hyperv_opts, 'hyperv')
CONF.import_opt('instances_path', 'nova.compute.manager')
ERROR_INVALID_NAME = 123
ERROR_DIR_IS_NOT_EMPTY = 145
# NOTE(claudiub): part of the pre-existing PathUtils is nova-specific and
# it does not belong in the os-win library. In order to ensure the same
# functionality with the least amount of changes necessary, adding as a mixin
# the os_win.pathutils.PathUtils class into this PathUtils.
class PathUtils(object):
def __init__(self):
self._set_smb_conn()
@property
def _smb_conn(self):
if self._smb_conn_attr:
return self._smb_conn_attr
raise vmutils.HyperVException(_("The SMB WMI namespace is not "
"available on this OS version."))
def _set_smb_conn(self):
# The following namespace is not available prior to Windows
# Server 2012. utilsfactory is not used in order to avoid a
# circular dependency.
try:
self._smb_conn_attr = wmi.WMI(
moniker=r"root\Microsoft\Windows\SMB")
except wmi.x_wmi:
self._smb_conn_attr = None
def open(self, path, mode):
"""Wrapper on __builtin__.open used to simplify unit testing."""
import __builtin__
return __builtin__.open(path, mode)
def exists(self, path):
return os.path.exists(path)
def makedirs(self, path):
os.makedirs(path)
def remove(self, path):
os.remove(path)
def rename(self, src, dest):
os.rename(src, dest)
def copyfile(self, src, dest):
self.copy(src, dest)
def copy(self, src, dest):
# With large files this is 2x-3x faster than shutil.copy(src, dest),
# especially when copying to a UNC target.
# shutil.copyfileobj(...) with a proper buffer is better than
# shutil.copy(...) but still 20% slower than a shell copy.
# It can be replaced with Win32 API calls to avoid the process
# spawning overhead.
LOG.debug('Copying file from %s to %s', src, dest)
output, ret = utils.execute('cmd.exe', '/C', 'copy', '/Y', src, dest)
if ret:
raise IOError(_('The file copy from %(src)s to %(dest)s failed')
% {'src': src, 'dest': dest})
def move_folder_files(self, src_dir, dest_dir):
"""Moves the files of the given src_dir to dest_dir.
It will ignore any nested folders.
:param src_dir: Given folder from which to move files.
:param dest_dir: Folder to which to move files.
"""
for fname in os.listdir(src_dir):
src = os.path.join(src_dir, fname)
# ignore subdirs.
if os.path.isfile(src):
self.rename(src, os.path.join(dest_dir, fname))
def rmtree(self, path):
# This will be removed once support for Windows Server 2008R2 is
# stopped
for i in range(5):
try:
shutil.rmtree(path)
return
except WindowsError as e:
if e.winerror == ERROR_DIR_IS_NOT_EMPTY:
time.sleep(1)
else:
raise e
class PathUtils(pathutils.PathUtils):
def get_instances_dir(self, remote_server=None):
local_instance_path = os.path.normpath(CONF.instances_path)
@ -145,25 +63,15 @@ class PathUtils(object):
else:
return local_instance_path
def _check_create_dir(self, path):
if not self.exists(path):
LOG.debug('Creating directory: %s', path)
self.makedirs(path)
def _check_remove_dir(self, path):
if self.exists(path):
LOG.debug('Removing directory: %s', path)
self.rmtree(path)
def _get_instances_sub_dir(self, dir_name, remote_server=None,
create_dir=True, remove_dir=False):
instances_path = self.get_instances_dir(remote_server)
path = os.path.join(instances_path, dir_name)
try:
if remove_dir:
self._check_remove_dir(path)
self.check_remove_dir(path)
if create_dir:
self._check_create_dir(path)
self.check_create_dir(path)
return path
except WindowsError as ex:
if ex.winerror == ERROR_INVALID_NAME:
@ -238,52 +146,3 @@ class PathUtils(object):
remote_server)
console_log_path = os.path.join(instance_dir, 'console.log')
return console_log_path, console_log_path + '.1'
def check_smb_mapping(self, smbfs_share):
mappings = self._smb_conn.Msft_SmbMapping(RemotePath=smbfs_share)
if not mappings:
return False
if os.path.exists(smbfs_share):
LOG.debug('Share already mounted: %s', smbfs_share)
return True
else:
LOG.debug('Share exists but is unavailable: %s ', smbfs_share)
self.unmount_smb_share(smbfs_share, force=True)
return False
def mount_smb_share(self, smbfs_share, username=None, password=None):
try:
LOG.debug('Mounting share: %s', smbfs_share)
self._smb_conn.Msft_SmbMapping.Create(RemotePath=smbfs_share,
UserName=username,
Password=password)
except wmi.x_wmi as exc:
err_msg = (_(
'Unable to mount SMBFS share: %(smbfs_share)s '
'WMI exception: %(wmi_exc)s') % {'smbfs_share': smbfs_share,
'wmi_exc': exc})
raise vmutils.HyperVException(err_msg)
def unmount_smb_share(self, smbfs_share, force=False):
mappings = self._smb_conn.Msft_SmbMapping(RemotePath=smbfs_share)
if not mappings:
LOG.debug('Share %s is not mounted. Skipping unmount.',
smbfs_share)
for mapping in mappings:
# Due to a bug in the WMI module, getting the output of
# methods returning None will raise an AttributeError
try:
mapping.Remove(Force=force)
except AttributeError:
pass
except wmi.x_wmi:
# If this fails, a 'Generic Failure' exception is raised.
# This happens even if we unforcefully unmount an in-use
# share, for which reason we'll simply ignore it in this
# case.
if force:
raise vmutils.HyperVException(
_("Could not unmount share: %s") % smbfs_share)

View File

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

View File

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

View File

@ -27,16 +27,10 @@ from nova.virt.hyperv import vmutilsv2
from nova.virt.hyperv import volumeutils
from nova.virt.hyperv import volumeutilsv2
hyper_opts = [
cfg.BoolOpt('force_volumeutils_v1',
default=False,
help='Force V1 volume utility class'),
]
CONF = cfg.CONF
CONF.register_opts(hyper_opts, 'hyperv')
LOG = logging.getLogger(__name__)
CONF.import_group('hyperv', 'os_win.utilsfactory')
utils = hostutils.HostUtils()

View File

@ -16,11 +16,10 @@
import abc
from os_win import utilsfactory
from oslo_config import cfg
from oslo_log import log as logging
from nova.virt.hyperv import utilsfactory
hyperv_opts = [
cfg.StrOpt('vswitch_name',
help='External virtual switch Name, '
@ -60,22 +59,11 @@ class HyperVNovaNetworkVIFDriver(HyperVBaseVIFDriver):
"""Nova network VIF driver."""
def __init__(self):
self._vmutils = utilsfactory.get_vmutils()
self._netutils = utilsfactory.get_networkutils()
def plug(self, instance, vif):
vswitch_path = self._netutils.get_external_vswitch(
CONF.hyperv.vswitch_name)
vm_name = instance.name
LOG.debug('Creating vswitch port for instance: %s', vm_name)
if self._netutils.vswitch_port_needed():
vswitch_data = self._netutils.create_vswitch_port(vswitch_path,
vm_name)
else:
vswitch_data = vswitch_path
self._vmutils.set_nic_connection(vm_name, vif['id'], vswitch_data)
self._netutils.connect_vnic_to_vswitch(CONF.hyperv.vswitch_name,
vif['id'])
def unplug(self, instance, vif):
# TODO(alepilotti) Not implemented

View File

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

View File

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

View File

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

View File

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

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_vhdutils.VHDUtilsTestCase
nova.tests.unit.virt.hyperv.test_vhdutilsv2.VHDUtilsV2TestCase
nova.tests.unit.virt.hyperv.test_vif.HyperVNovaNetworkVIFDriverTestCase
nova.tests.unit.virt.hyperv.test_vmops.VMOpsTestCase
nova.tests.unit.virt.hyperv.test_vmutils.VMUtilsTestCase
nova.tests.unit.virt.hyperv.test_vmutilsv2.VMUtilsV2TestCase