From 106bf560e291b9b8a0690680170db575086e04b3 Mon Sep 17 00:00:00 2001 From: Pedro Navarro Perez Date: Mon, 26 Aug 2013 13:09:41 +0200 Subject: [PATCH] Add support for Havana missing features in Windows driver The following features were added: -copy_volume_to_image (Havana) -copy_image_to_volume (Havana) -get_volume_stats (Havana) -extend_volume (Icehouse) The test mocking based on binary pickled files were replaced by mox. Change-Id: I92c681280d6f7b85bcba7a5e3513f2bdb6c13f1d Implements: blueprint windows-storage-driver-extended --- cinder/image/image_utils.py | 50 +- cinder/tests/test_drivers_compatibility.py | 2 +- cinder/tests/test_windows.py | 430 ++++++++++++------ cinder/tests/windows/basetestcase.py | 103 ----- cinder/tests/windows/db_fakes.py | 30 +- cinder/tests/windows/mockproxy.py | 241 ---------- cinder/tests/windows/stubs/README.rst | 2 - ...river.test_check_for_setup_errors_wmi.p.gz | Bin 473 -> 0 bytes ...stWindowsDriver.test_create_export_os.p.gz | Bin 439 -> 0 bytes ...tWindowsDriver.test_create_export_wmi.p.gz | Bin 1455 -> 0 bytes ...WindowsDriver.test_create_snapshot_os.p.gz | Bin 441 -> 0 bytes ...indowsDriver.test_create_snapshot_wmi.p.gz | Bin 1476 -> 0 bytes ...r.test_create_volume_from_snapshot_os.p.gz | Bin 500 -> 0 bytes ....test_create_volume_from_snapshot_wmi.p.gz | Bin 1840 -> 0 bytes ...stWindowsDriver.test_create_volume_os.p.gz | Bin 439 -> 0 bytes ...tWindowsDriver.test_create_volume_wmi.p.gz | Bin 1057 -> 0 bytes ...WindowsDriver.test_delete_snapshot_os.p.gz | Bin 441 -> 0 bytes ...indowsDriver.test_delete_snapshot_wmi.p.gz | Bin 1504 -> 0 bytes ...stWindowsDriver.test_delete_volume_os.p.gz | Bin 472 -> 0 bytes ...tWindowsDriver.test_delete_volume_wmi.p.gz | Bin 1040 -> 0 bytes ...stWindowsDriver.test_ensure_export_os.p.gz | Bin 439 -> 0 bytes ...tWindowsDriver.test_ensure_export_wmi.p.gz | Bin 1453 -> 0 bytes ...sDriver.test_initialize_connection_os.p.gz | Bin 447 -> 0 bytes ...Driver.test_initialize_connection_wmi.p.gz | Bin 1982 -> 0 bytes ...stWindowsDriver.test_remove_export_os.p.gz | Bin 439 -> 0 bytes ...tWindowsDriver.test_remove_export_wmi.p.gz | Bin 1462 -> 0 bytes cinder/tests/windows/windowsutils.py | 145 ------ cinder/volume/drivers/windows.py | 245 ---------- cinder/volume/drivers/windows/__init__.py | 13 + cinder/volume/drivers/windows/windows.py | 227 +++++++++ .../volume/drivers/windows/windows_utils.py | 297 ++++++++++++ cinder/volume/manager.py | 4 +- etc/cinder/cinder.conf.sample | 2 +- 33 files changed, 895 insertions(+), 896 deletions(-) delete mode 100644 cinder/tests/windows/basetestcase.py delete mode 100644 cinder/tests/windows/mockproxy.py delete mode 100644 cinder/tests/windows/stubs/README.rst delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz delete mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz delete mode 100644 cinder/tests/windows/windowsutils.py delete mode 100644 cinder/volume/drivers/windows.py create mode 100644 cinder/volume/drivers/windows/__init__.py create mode 100644 cinder/volume/drivers/windows/windows.py create mode 100644 cinder/volume/drivers/windows/windows_utils.py diff --git a/cinder/image/image_utils.py b/cinder/image/image_utils.py index 2f638ae64..032919595 100644 --- a/cinder/image/image_utils.py +++ b/cinder/image/image_utils.py @@ -183,9 +183,10 @@ class QemuImgInfo(object): def qemu_img_info(path): """Return a object containing the parsed output from qemu-img info.""" - out, err = utils.execute('env', 'LC_ALL=C', 'LANG=C', - 'qemu-img', 'info', path, - run_as_root=True) + cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) + if os.name == 'nt': + cmd = cmd[3:] + out, err = utils.execute(*cmd, run_as_root=True) return QemuImgInfo(out) @@ -232,9 +233,23 @@ def fetch_verify_image(context, image_service, image_id, dest, {'fmt': fmt, 'backing_file': backing_file})) +def fetch_to_vhd(context, image_service, + image_id, dest, + user_id=None, project_id=None): + fetch_to_volume_format(context, image_service, image_id, dest, 'vpc', + user_id, project_id) + + def fetch_to_raw(context, image_service, image_id, dest, user_id=None, project_id=None): + fetch_to_volume_format(context, image_service, image_id, dest, 'raw', + user_id, project_id) + + +def fetch_to_volume_format(context, image_service, + image_id, dest, volume_format, + user_id=None, project_id=None): if (CONF.image_conversion_dir and not os.path.exists(CONF.image_conversion_dir)): os.makedirs(CONF.image_conversion_dir) @@ -273,22 +288,29 @@ def fetch_to_raw(context, image_service, # check via 'qemu-img info' that what we copied was in fact a raw # image and not a different format with a backing file, which may be # malicious. - LOG.debug("%s was %s, converting to raw" % (image_id, fmt)) - convert_image(tmp, dest, 'raw') + LOG.debug("%s was %s, converting to %s " % (image_id, fmt, + volume_format)) + convert_image(tmp, dest, volume_format) data = qemu_img_info(dest) - if data.file_format != "raw": + if data.file_format != volume_format: raise exception.ImageUnacceptable( image_id=image_id, - reason=_("Converted to raw, but format is now %s") % - data.file_format) + reason=_("Converted to %(vol_format)s, but format is " + "now %(file_format)s") % {'vol_format': volume_format, + 'file_format': data. + file_format}) -def upload_volume(context, image_service, image_meta, volume_path): +def upload_volume(context, image_service, image_meta, volume_path, + volume_format='raw'): image_id = image_meta['id'] - if (image_meta['disk_format'] == 'raw'): - LOG.debug("%s was raw, no need to convert to %s" % - (image_id, image_meta['disk_format'])) + if (image_meta['disk_format'] == volume_format): + LOG.debug("%s was %s, no need to convert to %s" % + (image_id, volume_format, image_meta['disk_format'])) + if os.name == 'nt': + with fileutils.file_open(volume_path) as image_file: + image_service.update(context, image_id, {}, image_file) with utils.temporary_chown(volume_path): with fileutils.file_open(volume_path) as image_file: image_service.update(context, image_id, {}, image_file) @@ -301,8 +323,8 @@ def upload_volume(context, image_service, image_meta, volume_path): fd, tmp = tempfile.mkstemp(dir=CONF.image_conversion_dir) os.close(fd) with fileutils.remove_path_on_error(tmp): - LOG.debug("%s was raw, converting to %s" % - (image_id, image_meta['disk_format'])) + LOG.debug("%s was %s, converting to %s" % + (image_id, volume_format, image_meta['disk_format'])) convert_image(volume_path, tmp, image_meta['disk_format']) data = qemu_img_info(tmp) diff --git a/cinder/tests/test_drivers_compatibility.py b/cinder/tests/test_drivers_compatibility.py index d9c6cd9dd..1082fe7e0 100644 --- a/cinder/tests/test_drivers_compatibility.py +++ b/cinder/tests/test_drivers_compatibility.py @@ -32,7 +32,7 @@ LEFTHAND_MODULE = "cinder.volume.drivers.san.hp_lefthand.HpSanISCSIDriver" NFS_MODULE = "cinder.volume.drivers.nfs.NfsDriver" SOLIDFIRE_MODULE = "cinder.volume.drivers.solidfire.SolidFireDriver" STORWIZE_SVC_MODULE = "cinder.volume.drivers.storwize_svc.StorwizeSVCDriver" -WINDOWS_MODULE = "cinder.volume.drivers.windows.WindowsDriver" +WINDOWS_MODULE = "cinder.volume.drivers.windows.windows.WindowsDriver" XIV_DS8K_MODULE = "cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver" ZADARA_MODULE = "cinder.volume.drivers.zadara.ZadaraVPSAISCSIDriver" NETAPP_MODULE = "cinder.volume.drivers.netapp.common.Deprecated" diff --git a/cinder/tests/test_windows.py b/cinder/tests/test_windows.py index 05b1907ae..af9697395 100644 --- a/cinder/tests/test_windows.py +++ b/cinder/tests/test_windows.py @@ -20,205 +20,365 @@ Unit tests for Windows Server 2012 OpenStack Cinder volume driver """ -import sys +import os from oslo.config import cfg -from cinder.tests.windows import basetestcase +import mox as mox_lib +from mox import IgnoreArg +from mox import stubout + +from cinder import test + +from cinder.image import image_utils + from cinder.tests.windows import db_fakes -from cinder.tests.windows import windowsutils -from cinder.volume.drivers import windows +from cinder.volume import configuration as conf +from cinder.volume.drivers.windows import windows +from cinder.volume.drivers.windows import windows_utils CONF = cfg.CONF -class TestWindowsDriver(basetestcase.BaseTestCase): +class TestWindowsDriver(test.TestCase): def __init__(self, method): super(TestWindowsDriver, self).__init__(method) def setUp(self): super(TestWindowsDriver, self).setUp() + self._mox = mox_lib.Mox() + self.stubs = stubout.StubOutForTesting() self.flags( windows_iscsi_lun_path='C:\iSCSIVirtualDisks', ) - self._volume_data = None - self._volume_data_2 = None - self._snapshot_data = None - self._connector_data = None - self._volume_id = '10958016-e196-42e3-9e7f-5d8927ae3099' - self._volume_id_2 = '20958016-e196-42e3-9e7f-5d8927ae3098' - self._snapshot_id = '30958016-e196-42e3-9e7f-5d8927ae3097' - self._iqn = "iqn.1991-05.com.microsoft:dell1160dsy" - self._setup_stubs() + configuration = conf.Configuration(None) + configuration.append_config_values(windows.windows_opts) + + self._driver = windows.WindowsDriver(configuration=configuration) + self._driver.do_setup({}) - self._drv = windows.WindowsDriver() - self._drv.do_setup({}) - self._wutils = windowsutils.WindowsUtils() + def tearDown(self): + self._mox.UnsetStubs() + self.stubs.UnsetAll() + super(TestWindowsDriver, self).tearDown() def _setup_stubs(self): - # Modules to mock - modules_to_mock = [ - 'wmi', - 'os', - 'subprocess', - 'multiprocessing' - ] + def fake_wutils__init__(self): + pass + windows_utils.WindowsUtils.__init__ = fake_wutils__init__ - modules_to_test = [ - windows, - windowsutils, - sys.modules[__name__] - ] + def fake_local_path(self, volume): + return os.path.join(CONF.windows_iscsi_lun_path, + str(volume['name']) + ".vhd") - self._inject_mocks_in_modules(modules_to_mock, modules_to_test) + def test_check_for_setup_errors(self): + mox = self._mox + drv = self._driver + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'check_for_setup_error') + windows_utils.WindowsUtils.check_for_setup_error() - def tearDown(self): - try: - if (self._volume_data_2 and - self._wutils.volume_exists(self._volume_data_2['name'])): - self._wutils.delete_volume(self._volume_data_2['name']) - - if (self._volume_data and - self._wutils.volume_exists( - self._volume_data['name'])): - self._wutils.delete_volume(self._volume_data['name']) - if (self._snapshot_data and - self._wutils.snapshot_exists( - self._snapshot_data['name'])): - self._wutils.delete_snapshot(self._snapshot_data['name']) - if (self._connector_data and - self._wutils.initiator_id_exists( - "%s%s" % (CONF.iscsi_target_prefix, - self._volume_data['name']), - self._connector_data['initiator'])): - target_name = "%s%s" % (CONF.iscsi_target_prefix, - self._volume_data['name']) - initiator_name = self._connector_data['initiator'] - self._wutils.delete_initiator_id(target_name, initiator_name) - if (self._volume_data and - self._wutils.export_exists("%s%s" % - (CONF.iscsi_target_prefix, - self._volume_data['name']))): - self._wutils.delete_export( - "%s%s" % (CONF.iscsi_target_prefix, - self._volume_data['name'])) - - finally: - super(TestWindowsDriver, self).tearDown() + mox.ReplayAll() - def test_check_for_setup_errors(self): - self._drv.check_for_setup_error() + drv.check_for_setup_error() + + mox.VerifyAll() def test_create_volume(self): - self._create_volume() + mox = self._mox + drv = self._driver + vol = db_fakes.get_fake_volume_info() + + self.stubs.Set(drv, 'local_path', self.fake_local_path) - wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name']) - self.assertEquals(len(wt_disks), 1) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_volume') - def _create_volume(self): - self._volume_data = db_fakes.get_fake_volume_info(self._volume_id) - self._drv.create_volume(self._volume_data) + windows_utils.WindowsUtils.create_volume(self.fake_local_path(vol), + vol['name'], vol['size']) + + mox.ReplayAll() + + drv.create_volume(vol) + + mox.VerifyAll() def test_delete_volume(self): - self._create_volume() + """delete_volume simple test case.""" + mox = self._mox + drv = self._driver + + vol = db_fakes.get_fake_volume_info() + + mox.StubOutWithMock(drv, 'local_path') + drv.local_path(vol).AndReturn(self.fake_local_path(vol)) - self._drv.delete_volume(self._volume_data) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'delete_volume') + windows_utils.WindowsUtils.delete_volume(vol['name'], + self.fake_local_path(vol)) + mox.ReplayAll() - wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name']) - self.assertEquals(len(wt_disks), 0) + drv.delete_volume(vol) + + mox.VerifyAll() def test_create_snapshot(self): - #Create a volume - self._create_volume() + mox = self._mox + drv = self._driver + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_snapshot') + volume = db_fakes.get_fake_volume_info() + snapshot = db_fakes.get_fake_snapshot_info() + + self.stubs.Set(drv, 'local_path', self.fake_local_path(snapshot)) + + windows_utils.WindowsUtils.create_snapshot(volume['name'], + snapshot['name']) - wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name']) - self.assertEquals(len(wt_disks), 1) - #Create a snapshot from the previous volume - self._create_snapshot() + mox.ReplayAll() - snapshot_name = self._snapshot_data['name'] - wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name) - self.assertEquals(len(wt_snapshots), 1) + drv.create_snapshot(snapshot) - def _create_snapshot(self): - volume_name = self._volume_data['name'] - snapshot_id = self._snapshot_id - self._snapshot_data = db_fakes.get_fake_snapshot_info(volume_name, - snapshot_id) - self._drv.create_snapshot(self._snapshot_data) + mox.VerifyAll() def test_create_volume_from_snapshot(self): - #Create a volume - self._create_volume() - #Create a snapshot from the previous volume - self._create_snapshot() + mox = self._mox + drv = self._driver + + snapshot = db_fakes.get_fake_snapshot_info() + volume = db_fakes.get_fake_volume_info() + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_volume_from_snapshot') + windows_utils.WindowsUtils.\ + create_volume_from_snapshot(volume['name'], snapshot['name']) - self._volume_data_2 = db_fakes.get_fake_volume_info(self._volume_id_2) + mox.ReplayAll() - self._drv.create_volume_from_snapshot(self._volume_data_2, - self._snapshot_data) + drv.create_volume_from_snapshot(volume, snapshot) - wt_disks = self._wutils.find_vhd_by_name(self._volume_data_2['name']) - self.assertEquals(len(wt_disks), 1) + mox.VerifyAll() def test_delete_snapshot(self): - #Create a volume - self._create_volume() - #Create a snapshot from the previous volume - self._create_snapshot() + mox = self._mox + drv = self._driver - self._drv.delete_snapshot(self._snapshot_data) + snapshot = db_fakes.get_fake_snapshot_info() - snapshot_name = self._snapshot_data['name'] - wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name) - self.assertEquals(len(wt_snapshots), 0) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'delete_snapshot') + windows_utils.WindowsUtils.delete_snapshot(snapshot['name']) + + mox.ReplayAll() + + drv.delete_snapshot(snapshot) + + mox.VerifyAll() def test_create_export(self): - #Create a volume - self._create_volume() + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + + initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) - retval = self._drv.create_export({}, self._volume_data) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_iscsi_target') + windows_utils.WindowsUtils.create_iscsi_target(initiator_name, + IgnoreArg()) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'add_disk_to_target') + windows_utils.WindowsUtils.add_disk_to_target(volume['name'], + initiator_name) - volume_name = self._volume_data['name'] - self.assertEquals( - retval, - {'provider_location': "%s%s" % (CONF.iscsi_target_prefix, - volume_name)}) + mox.ReplayAll() + + export_info = drv.create_export(None, volume) + + mox.VerifyAll() + + self.assertEquals(export_info['provider_location'], initiator_name) def test_initialize_connection(self): - #Create a volume - self._create_volume() + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) + + connector = db_fakes.get_fake_connector_info() - self._drv.create_export({}, self._volume_data) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'associate_initiator_with_iscsi_target') + windows_utils.WindowsUtils.associate_initiator_with_iscsi_target( + volume['provider_location'], initiator_name, ) - self._connector_data = db_fakes.get_fake_connector_info(self._iqn) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'get_host_information') + windows_utils.WindowsUtils.get_host_information( + volume, volume['provider_location']) - init_data = self._drv.initialize_connection(self._volume_data, - self._connector_data) - target_name = self._volume_data['provider_location'] - initiator_name = self._connector_data['initiator'] + mox.ReplayAll() - wt_initiator_ids = self._wutils.find_initiator_ids(target_name, - initiator_name) - self.assertEquals(len(wt_initiator_ids), 1) + drv.initialize_connection(volume, connector) - properties = init_data['data'] - self.assertNotEqual(properties['target_iqn'], None) + mox.VerifyAll() + + def test_terminate_connection(self): + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) + connector = db_fakes.get_fake_connector_info() + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'delete_iscsi_target') + windows_utils.WindowsUtils.delete_iscsi_target( + initiator_name, volume['provider_location']) + + mox.ReplayAll() + + drv.terminate_connection(volume, connector) + + mox.VerifyAll() def test_ensure_export(self): - #Create a volume - self._create_volume() + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + + initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_iscsi_target') + windows_utils.WindowsUtils.create_iscsi_target(initiator_name, True) + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'add_disk_to_target') + windows_utils.WindowsUtils.add_disk_to_target(volume['name'], + initiator_name) + + mox.ReplayAll() - self._drv.ensure_export({}, self._volume_data) + drv.ensure_export(None, volume) + + mox.VerifyAll() def test_remove_export(self): - #Create a volume - self._create_volume() + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + + target_name = volume['provider_location'] + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'remove_iscsi_target') + windows_utils.WindowsUtils.remove_iscsi_target(target_name) + + mox.ReplayAll() + + drv.remove_export(None, volume) + + mox.VerifyAll() + + def test_copy_image_to_volume(self): + """resize_image common case usage.""" + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + + self.stubs.Set(drv, 'local_path', self.fake_local_path) + + mox.StubOutWithMock(image_utils, 'fetch_to_vhd') + image_utils.fetch_to_vhd(None, None, None, + self.fake_local_path(volume)) + + mox.ReplayAll() + + drv.copy_image_to_volume(None, volume, None, None) + + mox.VerifyAll() + + def test_copy_volume_to_image(self): + mox = self._mox + drv = self._driver + + vol = db_fakes.get_fake_volume_info() + + image_meta = db_fakes.get_fake_image_meta() + + self.stubs.Set(drv, 'local_path', self.fake_local_path) + + mox.StubOutWithMock(image_utils, 'upload_volume') + + temp_vhd_path = os.path.join(CONF.image_conversion_dir, + str(image_meta['id']) + ".vhd") + + image_utils.upload_volume(None, None, image_meta, temp_vhd_path, 'vpc') + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'copy_vhd_disk') + + windows_utils.WindowsUtils.copy_vhd_disk(self.fake_local_path(vol), + temp_vhd_path) + + mox.ReplayAll() + + drv.copy_volume_to_image(None, vol, None, image_meta) + + mox.VerifyAll() + + def test_create_cloned_volume(self): + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + volume_cloned = db_fakes.get_fake_volume_info_cloned() + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'create_volume') + + windows_utils.WindowsUtils.create_volume(IgnoreArg(), IgnoreArg(), + IgnoreArg()) + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, + 'copy_vhd_disk') + windows_utils.WindowsUtils.copy_vhd_disk(self.fake_local_path( + volume_cloned), self.fake_local_path(volume)) + + mox.ReplayAll() + + drv.create_cloned_volume(volume, volume_cloned) + + mox.VerifyAll() + + def test_extend_volume(self): + mox = self._mox + drv = self._driver + + volume = db_fakes.get_fake_volume_info() + + TEST_VOLUME_ADDITIONAL_SIZE_MB = 1024 + TEST_VOLUME_ADDITIONAL_SIZE_GB = 1 + + self._mox.StubOutWithMock(windows_utils.WindowsUtils, 'extend') + + windows_utils.WindowsUtils.extend(volume['name'], + TEST_VOLUME_ADDITIONAL_SIZE_MB) + + new_size = volume['size'] + TEST_VOLUME_ADDITIONAL_SIZE_GB + + mox.ReplayAll() - self._drv.create_export({}, self._volume_data) + drv.extend_volume(volume, new_size) - self._drv.remove_export({}, self._volume_data) + mox.VerifyAll() diff --git a/cinder/tests/windows/basetestcase.py b/cinder/tests/windows/basetestcase.py deleted file mode 100644 index ef749f612..000000000 --- a/cinder/tests/windows/basetestcase.py +++ /dev/null @@ -1,103 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Cloudbase Solutions Srl -# -# 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. - -""" -TestCase for MockProxy based tests and related classes. -""" - -import cinder.test -import gzip -import os -import pickle - -from cinder.tests.windows import mockproxy - -gen_test_mocks_key = 'CINDER_GENERATE_TEST_MOCKS' - - -class BaseTestCase(cinder.test.TestCase): - """TestCase for MockProxy based tests.""" - - def run(self, result=None): - self._currentResult = result - super(BaseTestCase, self).run(result) - - def setUp(self): - super(BaseTestCase, self).setUp() - self._mps = {} - - def tearDown(self): - super(BaseTestCase, self).tearDown() - - # python-subunit will wrap test results with a decorator. - # Need to access the decorated member of results to get the - # actual test result when using python-subunit. - if hasattr(self._currentResult, 'decorated'): - result = self._currentResult.decorated - else: - result = self._currentResult - has_errors = len([test for (test, msgs) in result.errors - if test.id() == self.id()]) > 0 - failed = len([test for (test, msgs) in result.failures - if test.id() == self.id()]) > 0 - - if not has_errors and not failed: - self._save_mock_proxies() - - def _save_mock(self, name, mock): - path = self._get_stub_file_path(self.id(), name) - pickle.dump(mock, gzip.open(path, 'wb')) - - def _get_stub_file_path(self, test_name, mock_name): - # test naming differs between platforms - prefix = 'cinder.tests.' - if test_name.startswith(prefix): - test_name = test_name[len(prefix):] - file_name = '{0}_{1}.p.gz'.format(test_name, mock_name) - return os.path.join(os.path.dirname(mockproxy.__file__), - "stubs", file_name) - - def _load_mock(self, name): - path = self._get_stub_file_path(self.id(), name) - if os.path.exists(path): - return pickle.load(gzip.open(path, 'rb')) - else: - return None - - def _load_mock_or_create_proxy(self, module_name): - m = None - if (not gen_test_mocks_key in os.environ or - os.environ[gen_test_mocks_key].lower() - not in ['true', 'yes', '1']): - m = self._load_mock(module_name) - else: - module = __import__(module_name) - m = mockproxy.MockProxy(module) - self._mps[module_name] = m - return m - - def _inject_mocks_in_modules(self, objects_to_mock, modules_to_test): - for module_name in objects_to_mock: - mp = self._load_mock_or_create_proxy(module_name) - for mt in modules_to_test: - module_local_name = module_name.split('.')[-1] - setattr(mt, module_local_name, mp) - - def _save_mock_proxies(self): - for name, mp in self._mps.items(): - m = mp.get_mock() - if m.has_values(): - self._save_mock(name, m) diff --git a/cinder/tests/windows/db_fakes.py b/cinder/tests/windows/db_fakes.py index a93dbc6f9..45d5c07c2 100644 --- a/cinder/tests/windows/db_fakes.py +++ b/cinder/tests/windows/db_fakes.py @@ -19,18 +19,32 @@ Stubouts, mocks and fixtures for windows volume test suite """ -def get_fake_volume_info(name): - return {'name': name, +def get_fake_volume_info(): + return {'name': 'volume_name', 'size': 1, - 'provider_location': 'iqn.2010-10.org.openstack:' + name, + 'provider_location': 'iqn.2010-10.org.openstack:' + 'volume_name', 'id': 1, 'provider_auth': None} -def get_fake_snapshot_info(volume_name, snapshot_name): - return {'name': snapshot_name, - 'volume_name': volume_name, } +def get_fake_volume_info_cloned(): + return {'name': 'volume_name_cloned', + 'size': 1, + 'provider_location': 'iqn.2010-10.org.openstack:' + + 'volume_name_cloned', + 'id': 1, + 'provider_auth': None} + + +def get_fake_image_meta(): + return {'id': '10958016-e196-42e3-9e7f-5d8927ae3099' + } + + +def get_fake_snapshot_info(): + return {'name': 'snapshot_name', + 'volume_name': 'volume_name', } -def get_fake_connector_info(initiator): - return {'initiator': initiator, } +def get_fake_connector_info(): + return {'initiator': 'iqn.2010-10.org.openstack:' + 'volume_name', } diff --git a/cinder/tests/windows/mockproxy.py b/cinder/tests/windows/mockproxy.py deleted file mode 100644 index 4a48532ca..000000000 --- a/cinder/tests/windows/mockproxy.py +++ /dev/null @@ -1,241 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Cloudbase Solutions Srl -# -# 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. -# - - -""" -Classes for dynamic generation of mock objects. -""" - -import inspect - - -def serialize_obj(obj): - if isinstance(obj, float): - val = str(round(obj, 10)) - elif isinstance(obj, dict): - d = {} - for k1, v1 in obj.items(): - d[k1] = serialize_obj(v1) - val = str(d) - elif isinstance(obj, list): - l1 = [] - for i1 in obj: - l1.append(serialize_obj(i1)) - val = str(l1) - elif isinstance(obj, tuple): - l1 = () - for i1 in obj: - l1 = l1 + (serialize_obj(i1),) - val = str(l1) - else: - val = str(obj) - return val - - -def serialize_args(*args, **kwargs): - """Workaround for float string conversion issues in Python 2.6.""" - return serialize_obj((args, kwargs)) - - -class Mock(object): - def _get_next_value(self, name): - c = self._access_count.get(name) - if c is None: - c = 0 - else: - c = c + 1 - self._access_count[name] = c - return self._values[name][c] - - def _get_next_ret_value(self, name, params): - d = self._access_count.get(name) - if d is None: - d = {} - self._access_count[name] = d - c = d.get(params) - if c is None: - c = 0 - else: - c = c + 1 - d[params] = c - return self._values[name][params][c] - - def __init__(self, values): - self._values = values - self._access_count = {} - - def has_values(self): - return len(self._values) > 0 - - def __getattr__(self, name): - if name.startswith('__') and name.endswith('__'): - return object.__getattribute__(self, name) - else: - if isinstance(self._values[name], dict): - def newfunc(*args, **kwargs): - params = serialize_args(args, kwargs) - return self._get_next_ret_value(name, params) - return newfunc - else: - return self._get_next_value(name) - - def __str__(self): - return self._get_next_value('__str__') - - def __iter__(self): - return getattr(self._get_next_value('__iter__'), '__iter__')() - - def __len__(self): - return self._get_next_value('__len__') - - def __getitem__(self, key): - return self._get_next_ret_value('__getitem__', str(key)) - - def __call__(self, *args, **kwargs): - params = serialize_args(args, kwargs) - return self._get_next_ret_value('__call__', params) - - -class MockProxy(object): - def __init__(self, wrapped): - self._wrapped = wrapped - self._recorded_values = {} - - def _get_proxy_object(self, obj): - if (hasattr(obj, '__dict__') or - isinstance(obj, tuple) or - isinstance(obj, list) or - isinstance(obj, dict)): - p = MockProxy(obj) - else: - p = obj - return p - - def __getattr__(self, name): - if name in ['_wrapped']: - return object.__getattribute__(self, name) - else: - attr = getattr(self._wrapped, name) - if (inspect.isfunction(attr) or - inspect.ismethod(attr) or - inspect.isbuiltin(attr)): - def newfunc(*args, **kwargs): - result = attr(*args, **kwargs) - p = self._get_proxy_object(result) - params = serialize_args(args, kwargs) - self._add_recorded_ret_value(name, params, p) - return p - return newfunc - elif (hasattr(attr, '__dict__') or - (hasattr(attr, '__getitem__') and not - (isinstance(attr, str) or isinstance(attr, unicode)))): - p = MockProxy(attr) - else: - p = attr - self._add_recorded_value(name, p) - return p - - def __setattr__(self, name, value): - if name in ['_wrapped', '_recorded_values']: - object.__setattr__(self, name, value) - else: - setattr(self._wrapped, name, value) - - def _add_recorded_ret_value(self, name, params, val): - d = self._recorded_values.get(name) - if d is None: - d = {} - self._recorded_values[name] = d - l = d.get(params) - if l is None: - l = [] - d[params] = l - l.append(val) - - def _add_recorded_value(self, name, val): - if name not in self._recorded_values: - self._recorded_values[name] = [] - self._recorded_values[name].append(val) - - def get_mock(self): - values = {} - for k, v in self._recorded_values.items(): - if isinstance(v, dict): - d = {} - values[k] = d - for k1, v1 in v.items(): - l = [] - d[k1] = l - for i1 in v1: - if isinstance(i1, MockProxy): - l.append(i1.get_mock()) - else: - l.append(i1) - else: - l = [] - values[k] = l - for i in v: - if isinstance(i, MockProxy): - l.append(i.get_mock()) - elif isinstance(i, dict): - d = {} - for k1, v1 in v.items(): - if isinstance(v1, MockProxy): - d[k1] = v1.get_mock() - else: - d[k1] = v1 - l.append(d) - elif isinstance(i, list): - l1 = [] - for i1 in i: - if isinstance(i1, MockProxy): - l1.append(i1.get_mock()) - else: - l1.append(i1) - l.append(l1) - else: - l.append(i) - return Mock(values) - - def __str__(self): - s = str(self._wrapped) - self._add_recorded_value('__str__', s) - return s - - def __len__(self): - l = len(self._wrapped) - self._add_recorded_value('__len__', l) - return l - - def __iter__(self): - it = [] - for i in self._wrapped: - it.append(self._get_proxy_object(i)) - self._add_recorded_value('__iter__', it) - return iter(it) - - def __getitem__(self, key): - p = self._get_proxy_object(self._wrapped[key]) - self._add_recorded_ret_value('__getitem__', str(key), p) - return p - - def __call__(self, *args, **kwargs): - c = self._wrapped(*args, **kwargs) - p = self._get_proxy_object(c) - params = serialize_args(args, kwargs) - self._add_recorded_ret_value('__call__', params, p) - return p diff --git a/cinder/tests/windows/stubs/README.rst b/cinder/tests/windows/stubs/README.rst deleted file mode 100644 index 150fd3ad1..000000000 --- a/cinder/tests/windows/stubs/README.rst +++ /dev/null @@ -1,2 +0,0 @@ -Files with extension p.gz are compressed pickle files containing serialized -mocks used during unit testing diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz deleted file mode 100644 index dada5e65488544313a26c2cdbef0d70915191d59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 473 zcmV;~0Ve(*iwFq9^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt?%xV{2b#Z*pIAWps6LUuAM~Z*p^AcWr4dZ~&E(T}#6-6o&85uaMoW1L>NNZms`d zpdu=GGYDN4N?qH8CUeTzfA^ehV@|vgn$w(|n>8cYoswC#NuwmR4WTn35O zO}{on8jKG<-C<&PKJBdDxWRsY!2|ZdG0;k_woMzFUMaAvccTM14v)bJcy8hegJq@_vQw60rUM)^yW-@IUWO&Z5}-+O90fZW*6gcCwqZv)vqx PAN{1?@2ehz=>h-%(WC1R diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz deleted file mode 100644 index c425615b9262a82c16d4bf2ba89881c9a38818f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 439 zcmV;o0Z9HIiwFq9^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*Wq5FJa&%vBb1rZI%~8v0!!QuM?^lFe>_B2HDSoKe^pZn+XrL#9aTL{Y zl3K!&^Pu$KyHe6ZODLuEP=n>&+12dqSO}$0WhZOEL#Wo+t`}BypkoMyXxf$RA}ftG z(E$^6FwwITTivPS3GOfgO+b|8vTt^_Y0DDSawCNWP2t{Z1`m1);Yug42+B$bX-p|p z-`W6l>IxYctn8~@FAZY3!#FnU%C0ddC}XDyff|DvKc1FQ1C-GZaifdm2~>9k~&K^s%eplo@?2!GvgYb{ zS9RGIvx{ykvsYV{9bRwqY<{pPtID701y!8K<{&GauXOrm%`dl}g`o`_(>+=a+PflhhyQb+*?$0>V;TQX2k9x3EJTahgp8hC6=1_Xu>yAgZNzbXf zt1I_w*}WSWdinfv^jFVc&d+|UcinBdB6RI|00^5K0mZQcTO2EN^4L24_Bg*b7Io>Q zuy%I$?mA2zCT^=;z3u8|GtB%oVTKU%`cHSZIsfVL`=~y-r!prlWwFnt)SgQjh_gMH zN<=P|XZ5OVTfSVCdv7Wv-7>jK#W(Zxrk^J;uk>e_{|^NGZGp>~;aAPCkj@3&vcijz!V6M(!3r;;!i%Kv zBIhJIrOak+7uwGyM3HMLd6z&Bkuqkd^xwgO&XFO*K= zpB`yIlLmAcA2nc-1`NcVH2CCBQv8c@?S^fv-*09pKpcaZHM`}k**b5WWp(rXUvIFH zgx;uq^d|S{O#rPUdXv!Grxk38I?L4ANS#g8Sryl9^Y6QE%Sy2$7qsMpmR-;bDB7_| zKIn}gTL#I3@JbAF1u>!z1n~!=e_f|QW(Y*J=Ee1OvSpx><74@nvmXn{698l=NYNDl zk}UuvUjT^4Fg*-;AG3f7KAHxH^CbA|xITdi07l6GNLvcXdkPpg6)^28P_=m^h)20L zmIoj+gMEm^3=YirBD4&J4&=xOK#~!FWG4U_tpH^50`QI;x$w69ZA=op;WJz_hHD9~ z3TFxL`#oIm@)52g5wU@QH+*);$ld6ez`UtGK;lgeypc)wEBF5VjaE)Yz+um?An ze5_FcP9EX+vcKuOfJz zNnU3LuQQmm>8r$Nv}yPZYXa{konp*KtPLn_@>x6htgjhS zvQ#*F$=Y$&TgrMAob?`jJdul(^+=_o*C`71Wu2nP!@<8`oz4$lxpi~rUaVH3e6&19 zhcP2KC>Ty?Xb=({7~oJ(5_SjSYtTSI1I4%x(L7ThG@g18)3FB;K2s>#f8J|V_4*D! zxy^{&ZXu5PEkwoLQXn6T1X2$mO*WP|B9kZsi87HW2NFGj^Mm)dZuda5OBEjOW&d>U zU8?FPKTO{4n)T%6+4S3e*u_9 J97PWi006G8!utRK diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz deleted file mode 100644 index 5e55a96f30d141bbd10e3fce92051ca47da1b7bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 441 zcmV;q0Y?5GiwFqA^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*b8ca9b7*gLUvG0RZ~)Cw%WA_g5WMeKgk0=EVk{|ssMqw8LwjhTCxdYm z)p3$q!jki#^xwNu(n3oprSwpP<=xrU?Ce+wrB7uiYrsRO*4VBWR&}6b2!&|cmFyxb zjWy8$6Lm1rvl3g~spARmFak|Ll;yH-cD8BD64Y`dg#}IF-f9L9dJ5r6C$I?0N(gC8 zDOBIu0CegK85peWt6eV*V!6XOHtWi+F()WvrwM@?gBm}cmQds+%=MBf)SieWU}}Gz zq}is$a!#{KvY7K|zh3z@zFUgseku10oPaAMe>w`uSbWVF=6qq^7xwN8 j`|yP&*mlO!f8YnpoF6Rz8$bBP4}7CHc;MH!djkLf%Yn{s diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz deleted file mode 100644 index 4e5879f678a3144027df965ee71d1bb87090af56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1476 zcmV;#1v~m5iwFqA^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*b8ca9b7*gLUw3V3E^q+7S50r*Mi9O8R|vk?E+Tnnzc)Y+wuPWN*eL2C zxfl>=dLy%zL`J0SrbhmIXLq?vi;42lqBaalq?WU9XWq=4DT=E8G~d`ohL@sRH|=Iy zwACi7Np@5e<@(lcCarDSX7Y$P)nhYRRmFY1ss8$uUEsH@hOC&+Z?@&KE!XpTR^9w* zi#DricG=b}`=jRB(QPfVtHXI-6t-#RMYUbGhgmJ%4=QW$mxp}0wGBSg?wP^G?=NO} z3&h<6;De)U{J+M_vAez+9Xz?uRkbef?Z$n5J#yERlgY`Zs@jvsRq5_O9~`^Y*N0D^ zuMdx%NtzukYhc*|Z7(2Oc%Z-$DG0xt%oZLRAhv}E1ll2bJHJ}zb#qra@L-%7N_Ndq zKr@uOcPQ)3P#(=t=Y{i)&0C8WsPq=pz=C!bj9bn~XMsVqz^L=%yvUc!`5bL9=AZJt z{(1j)+WQ8i)qQ`%uf}JjgqHhC5<9P(>Lmzea1IrmN!jv6E8RU4j}FT@vwUY zBoZKj%Ys(~-RqUvZSRyHL-kdM3FeL__^!i*Kzt&=QW2j{_z-gNki_r?=SbMKASqgq z{t%LP7Nm$4q{MU8Tc1J7KXB|kIymyD>;WD;hblc?70E7lTil6h1*}+N2FS3M0+D<*N7%)M1y-n)6R%y(TL_TY+CFM+tfakh5bEm z@A~kazrG&)l~?Civv=jD-R4V&s2MH*VuU6j#}Nud?tm@sOWj4zv21+;D9dFpajhN3Yq1DG#Ppoz~wnWXIiCAbiWCvK+p*o z3I%wjfFKo+v;umu091=EFhJ$cMTUJpGHQ=FssL9H;Ti{*1vy4N>foXtMYxQ4C0N?E zR{>xlHYh4Hc;?JqvnV#stO^!%GHa4ql$z)T4lm^e9(n}+MU&vW1RmN1p85pdHwvgr zi+FTYrx|(9qeUpMAckZRo(v+8K_oJWo(!TVgOD$jrXT_t#E=ZalR*YD$V3L&lL5sm zxk2)8F+ln(lAVQ=MY7K#l&*Mm)UOvhdKamo5`vdP2wDh9453#;KsiiDMSH{*<}Y=0?b|@mgFX91 zDT_>>MP7-fc4=GdYl-odoD%Z=Mu!pzjXB-d>ikwUtzXE(!a@5+iDM)sp?4>dk(4Ax zQj!=+VLv0?K9~8*_Ax0xt|y3(jDbw5&0L#WzGW9dlv!MxfaF{xjO8=G$3v_xb z=>}ykFdw&e^U3YbAUxa|2@bB1VMROoW%OZFtw!gwi}^Hf^Ec(vjvnvq#*SS0M!$}_ zzVUzVHT@O`ua5hk@yU-JLr=26TQ=k^^Souj6D;wT^}KcSTZ}mBsxM7l!cq<~VJRPS ziF+>bz$Koz#CtArl@iuLgiwFqB^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*c5iHTZDn6(a&K*4b8ca9b7*gLUvG0RZ~)DdO;6k~5QgvbD-f4tB{qsb z^5I_Tg+qJjN}M7^S+5C!ZEVF3A42?hX3Q>9t8G~!4n#^~kH_!4^Tg5Gy2o}hJ>Wyz z(T8c)!A{_ENVOiujhV7weDK*lPVBwUep`L(Cj0ORKX3$&fo|LNJZ!@-wk_E8jnM%d zho8X-_~j&|8&|+8X*;cr_pP?`7!q(LEmYuf<*wV##$&9en8IY&g=?HMw6S%JL63tT zUs0BE)MbKlnS?$Hu>yP_x3d!Wn}-2SlR_0^HOA5=Nl(+JX_E7A&0p8BI$vE}4pW%B z?f1dodP+N6oSvP~;OUv33yhq^NwOeiMc#N07deB@d%y1faLF0Es$5EL#8R2+YFTV*#jDPUT&e8tdK26DUsJq}P0=SH z0|!bTTMETQeu#@8E+TRfdoJRQizqPdHCBF{2Y=sWeH0H-5f4%So5!)GNK75#A#?gm q7_}_L=13AYrvWfL0p>mq?Z~8H^XlhV=|S=O6x zvu(8~{6|@@n|6Cyw)M8yh~ls;m+SLtJ87$?Z6;U#qP}V-7j^l0v#q~=E8h5T#RiIU zHaojquG-~#HY@70f2y)AHdwrEH&pz+k;UQpMinPdX7jSFnr2qkm+SUPvC-iNQ#AgU zFZ0!9)%bfh+;jfn4{xUa5=6KL@HY-m{r^+{@icrs8y$QPe=q9w@^iHfUtf&E=kw>2 z=i9n&pI==p!}X7Yr{U?-C*OaZK6x5UVsW_I02K>wdjZ9Qfr9i%LGfz3STHp3*cJ>3 zY(VsGcCwytnoo5A4=$KNv1FO^6n-1A4Is6!Kzfn`|pb2wNYA+m2_$>jXfH>m-6M}Amty6q$s?Tl<9fT$$qGAB}`G+nv%PODdq902+JgV zHskY?~-NENJcbwYlU3GJGQh=i$L2@3IGYa2=}VXf>jE zyF=}eTNA?9Fg%mO*W~auDsgM{o!lN*O}Sle+GV}&NhaZx6`;ozI6anF(b!ey<5-+-_5NQ8^gHmEK-6A-~2Ab2kzl0!gbkAP5VuOM{V zEC^FfQGt|}JS~G{x^~4i?ReRI=1ObhyKVr&mtYUVmtZc$m_Yafnm|A(KX0omUu!yB zz@-F04{aH?)xDOo7ci$UV9sAayeG)MEX(SzdHbo4v7;BKgMZ7Dqm$|T<+iZXoq@xxOzOH+M@qD)T@Qfh@yiO$3=l5oA_H@F|eeKvGTv zIiyW8ZL)hk(?-Jo*q2CoZ=S1%5G ziFQup+euR~ZPhSsHTzgcAM5O6-TOFbOGlbknKV7jSAVwSZ=7%O->E_%yf%ppPAlgUJVwp8v{G6pq4ABjk~nDg4(`<+AL~dA4}E1nh4hp z;Ray?7n@#}qzzowHgLoZ*Q#1`vjr}C%}dZ!To2Ags^@O#Psjdrow?*s6xp9Bat%g- zKSv2ZOo_df5)>5s=|Rq-2>wUWfixMe?cuWjnFsV@HHB+D44QN9&LOtvko$A!8+6Fg zfS@01>tG^wJDepP4-*^>h$$Knb2MO>G1At(NZhk^Rt&_>LZ-1-4D^bTwoc-)wocqz zAq|=^T{e3k`cBP80RN0lPccoX2M8A@cq`0WKPeV1R5vUBq?U3afq5B#U zW|kCrUR~~qJk74u(Um&8QunUZxmm_I%RI)`<3xmJIKcA=gmDJKJOp7s1)<43H=5jY zqZ!Weh6j1WT?^XOwV=&i3wl{vq;RveN4VLzl$WfV!pXh-pLNsngYjs=-Z)!eOg3V2 z8I$WVg)yh|1xwBCz6k5QonKVFBbNWJCtf(j7{sLBE++M+S~u;y{QTnAUDSn_8_aI# zG#`m#s9w(K{i!XPan+S{x4UUvZgfk@)Dnd%9N+e8= z(-y;g@pOc@;=vaI9+>L#IInV$Bk`rY)zOB_6V+D}2>`AB8RByijk4C0o+GAHp= z4D+!VUON}V-s4^sv&SEqlb@I<_vHk;O%1YuFk}ItiQBiClRgXRS{8Vr{pE((e( zyPt+}OB}Zp5)KcnJl&O}I%(awc?zd82cbtOwkIDa&BIh;-7XSd!?u(89 diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz deleted file mode 100644 index fc8eee072dee3c8906d245c49ab5803c79ab5f3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 439 zcmV;o0Z9HIiwFqA^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*c5iHTZDn6?b1rZI%~8v0!!QuM?^lFe>_B2HDSoKe^pZn+XrL#9aTL{Y zl3K!&^Pu$KyHe6ZODLuEP=n>&+12dqSO}$0WhZOEL#Wo+t`}BypkoMyXxf$RA}ftG z(E$^6FwwITTivPS3GOfgO+b|8vTt^_Y0DDSawCNWP2t{Z1`m1);Yug42+B$bX-p|p z-`W6l>IxYctn8~@FAZY3!#FnU%C0ddC}XDyff|DvKc1FQ1C-GZaifdm2~>9k~&K^s%eplo@?2!GqQ$mUNsgBl{qN%?O*zt zl+5zH+}+z|(b=|Z7YFxH9oogV${*{d`tzCGxW7mZBu~@3eYxq%U7C{W?hl)Hq-Nx{ zt2z0t7G!o`OR_pkvplzLo95Mi*PW4C;Rl+u?vtl%v$w5#m*6|&Hov=Bx<{b+4B%eO z*6w@lmUCR+Or{_4_qN)VkG8=-FDJNOTr4h{s_HHd+Y+BYP0w-n`t0MU_1QT>GBVrL zz)9h-3m}Cj3c@i3>2Fh{@YKL@D?A}ckkQ-px@;d2!XN~rLkI>Af-&6B_z{AM2*FT+ zTYGr-_6Wk12hk&t1VId*;PeQ>A%bv*GNyU9*`%q%;M~6zugY_6pUT|+nspB+g|05w zqpxyxwOamOHr+nkAiH+F0jQA)1vR%|)Lbyj=f>*yb9tW_rZdZ_F^i{%`*3x*xXqig z?#gO+y7_BhP7tf|FT32`{PglX6Q9i~m#8IILoK;>TJj*AIch0r)KWNA@3OY_OZXX_ z77T0G3oJxDE&J2%u22SIltFEGSl#CQ1Ym$EtQreThZC`|lD@DKh_NQ@JH?uCqe*FSQW`%gO`MdbpOgmEdu=zivmVj+0Z=Tb*>vVr zI5D3N<}&rdyB;UEu`T<>Pv2jvw(}c#*fsk%x)SZ2HJ=0^o^+jps(fz@43yk z_LP|N!*0PS&^gdW)f9`Ww$3TD{PFT%rwky3>+EP41z;lqh`=(o5s!4tFSk$Z6`H<{U~G2a-424?LGO2PGCXjOH*OqY%Ae92M=(}%ZI&f zp7C~Peg5U3k)|tGUwJqAVe-DIwv(&nO?sVm+0W(1P7V*Yu@lVRq!y{9GzRuYz;2BJ?SUaU}^~Ng`B| z=qpK_D#>|Q>{evxtjhzL5s>pS{O2g-0v#*>IR}eC&SPR@N%}is$a!#{KvY7K|zh3z@zFUgseku10oPaAMe>w`uSbWVF=6qq^7xwN8 j`|yP&*mlO!f8YnpoF6Rz8$bBP4}7CHc;MH!djkLf%~Q^B diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz deleted file mode 100644 index 26de5bdaccd098826162bbe5fdb86449041b5636..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1504 zcmV<61t0n!iwFqC^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUu0!$WprgFJm1(wMu)OqHSOlE zZ0k+7X4yemR;w$!nY6ZPo5=&6)DO+%wk~hhoBHq1*(v>(tsyJt^UJ$x*;cFhJgYDN zvSpjCF*|G5Jo|GkvV*I&%+B}cMOoUWnV0q5s@>1l%H7aeLwD|r<(+NlnsL{18vNmO zMyJ5sIRITaxS-z)Ivl#=o6+8*`+HljsvEm;|Gpi$_C2g^0^Y(dxy$QGU`2x1D-zfENePYsCM!V?1H7`>aHuZneZT|4rSI~Zi! zFbD*L=$=8|!JvpR=u|k_*rK(BfXXB20fKP|xf{+|hrl5saCAD(%VN2l&k2Kbe^u<% z=fk^cuZ?0TrB;B?3d5!2!__t)u89v1FV8zZf<-<8JfDSatJdCnO2W@xaJs?Vsc@)5 zX73-T$Hy8t{4$p2H!~J2SL5U3U&R=Zp_!gckMm>sg`QAZ(KO9vJX{uAgoGm`!rLPu znFvW57DSP_QiXpAt*ly zB{~EpBZ5*iul1d8Anh->;yltvzqEEs)NMrt#Kb zprdIp(lk6uY($jU$ZZ6p9Dnb`2e-XbgbM7l57hlWVc>kDI z&5ax8J1rk{TJ8!v4+LUi151?+%=OxteV~>OFu;P9v7whSZ)PmG8B2D?dOu?(E+w%1 z8*6!AmG+OKz3!Ltff{U#Kp9Ur4_h;qHfd>d1e9EhICaXet*JMQ;JToP#h`sL=ngFvgYJt# z_r+k?YqhBf#bAcTV0bZEW zsdp$B}VHqDNb4=J~X?SfqTr@FB^J!Sf*+`@divzyQE?IE5}Y<<4&ozup$ zY)3zhK5pvU(aG#|J}uhfw`yre57%~MM{fB>KaaZI)Bn8V@~_x?bJ*{k9{tzOP)QN$ zRt)P___`ILZbhnF(bp}dYFcrMRc}YJNoCqbpd8kc^tB{IEy+|%vacnn(mvf$lsW*J zA&_%9RADhxbU9SX8oP diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz deleted file mode 100644 index 5ec5429411f55ab401b3535361276da36d7a593a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472 zcmV;}0Vn<+iwFqC^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUu0!$Wprg`0sZ)jM-9tN>9&pii^kJHHuoJi(Qmuz^W2P(^ zAAEL)iM{jLKdW!tWbYr~0wZt?bla}yVH<|AZNaXujSk>A{0>gQA15K*xB^y5+i7jQ zZ?&Drkbo;`qXLgRx7~I&9&0t#6drb6xWb$vjjdx0dJKB}L|DcVmkBz{B=ix872x}L zot1ds+z&{a5UN*lbrr)-aNzVbaj3?OkwV}XM?}-bnIktd~!s=;}fk5 ztQ^H8SrD=!ZajzcoI&TkUw5xqa)vB9r}kXzS#o(`$w`uHJB*0LcYD>hI7WgjS4Ew( za%q?JFiwFqC^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUu0!$Wprgu9kpRg&XnMgRMFDN(A_WotLIhQU}LJiPbZd+te=73FhM*)4HPRvhZ4I%Z8# zk&=={mgR?gTSbknn>sqVi{eyA`yzWRtKyGma^rrH5=fRLcgK9!n+ zZBugcYbnU$zLaErmZVu`>pIDb`DamzWbuV(WP_;+6%@<&_Y&&wIE7Z=e*RTRy|X`kcu$N4$Fy*c~vadUQ#kc=#L zC2+EJ*jpf5A1DYHDM)`>OtwBWaItNDK%g*Yw_&(zu1QP** zAp^Je^!7~$!eS4iCLkI?4DR5x1K|)rI71qfEZyyr#9?sm?}``cxwcPvW`9YWhk>E1 z%gyAIudmjt-}0(CraO$Tp1uIoNKGMLS}^faFw2+5s&`9yuMJbF<EXUTx;?ng zs=RFS;xL^2B`^cTI{(wI4mUr3x}S-^ttpqtC6C8ka^<+>EpevfQqaJqaID^?b?ukC zbhJ}2>|0N+5Mih6ce-<0=7stP=Klu)pCu?XCMe7}K}lVh61=`x7pCMPOeuV`Y;BV_ zcJKQ|`UaP=dqDA0A*$39RO3)%FT5B!)R+a-n7hr_c4r%lh_P39jLp56FFXlD;PX#Y zh<(4uirfa$U!*@q5yV~uDu_V!B2X^XR)K0FVud1BK1UTqta=eE9m=N6cPg8v7^a4C zm>RoF`$%-?F5P#Rj(yp7_TWpVeT}pxD@xLyvN0YO%=m(tP%zUM%e;()_k1)l=W91e zvS#+f>|IstXIHD6sjYR-`KnS5%X8)g9kYp-1^yn5W3}L zGLC`cJO=IuGVm~wf%hXBoK=U?InP>wE8Vso%7E@AyGLpYtUa)wh#nfP4zg`yIc;O<+gP@3Ec-T=LmRtfM{PS=qQ3yp KP&%@i3IG7dNB(#K diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz deleted file mode 100644 index 3c5813515bdf20fde809d40b20e5c0679ed5859e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 439 zcmV;o0Z9HIiwFqD^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUuAA{b#i52Wq5FJa&%vBb1rZI%~8v0!!QuM?^lFe>_B2HDSoKe^pZn+XrL#9aTL{Y zl3K!&^Pu$KyHe6ZODLuEP=n>&+12dqSO}$0WhZOEL#Wo+t`}BypkoMyXxf$RA}ftG z(E$^6FwwITTivPS3GOfgO+b|8vTt^_Y0DDSawCNWP2t{Z1`m1);Yug42+B$bX-p|p z-`W6l>IxYctn8~@FAZY3!#FnU%C0ddC}XDyff|DvKc1FQ1C-GZaifdm2~>9k~&K^s%eplo@?2!GvgYb{ zS9RGIvx{ykvsYV{9bRwqY<{pPtID701y!8K<{&GauXOrm%`dl}g`o`_(>+=a+PflhhyQb+*?$0>V;TQX2k9x3EJTahgp8hC6=1_Xu>yAgZNzbXf zt1I_w*}WSWdinfv^jFVc&d+|UcinBdB6RI|00^5K0mZQcTO2EN^4L24_Bg*b7Io>Q zuy%I$?mA2zCT^=;z3u8|GtB%oVTKU%`cHSZIsfVL`=~y-r!prlWwFnt)SgQjh_gMH zN<=P|XZ5OVTfSVCdv7Wv-7>jK#W(Zxrk^J;uk>e_{|^NGZGp>~;aAPCkj@3&vcijz!V6M(!3r;;!i%Kv zBIhJIrOak+7dktWLRh7QmRZ>jbkl_s>X)WvC*b83qvdH@p62E0xICSfr&UO(K7{7w z>5&99NkE73Q357Oz(CwcgHLWG#lI-mZrH{8{bq&(6jvs=!Zt@FNFRyWW8_5K=3 z=#AP(Z*q^`1kgI7HwnFcTELd5vrL_h)Y(LxRdL-m|Gw+CEEGF3K}#lR*#tpE7X*=P z(EC8P42lKeg&5QdVniPZ;txdsx=w-25Qs|6i|gy;%0Lyz$MPj-KNgTB0LV~}qA36* zR{%)101$m)%EYE5V1AFL!QVUw{yMHsV8Z;PTmYmU1>`LSjC%^0HWjGWJkrCXR2!=U zkcq)QL?Q+UVtff&hB60oNL3~9LUonWUAU8gBE7v(HCs6c9Dc=3*Armlw zp6 zGlSI`OxpBC;xpPbe1bKBcazSr=FuV6Btne+&V<-tvvzE=mTlGsls4I{9cqoMElbZKF1X?kT}V{dM5Wn*+{Z*E_2b1rZI%~8v0!!QuM?^lFe>_B2HDSoKe^pZn+ zXrL#9aTL{Yl3K!&^Pu$KyHe6ZODLuEP=n>&+12dqSO}$0WhZOEL#Wo+t`}BypkoMy zXxf$RA}ftG(E$^6FwwITTivPS3GOfgO+b|8vTt^_Y0DDSawCNWP2t{Z1`m1);Yug4 z2+B$bX-p|p-`W6l>IxYctn8~@FAZY3!#FnU%C0ddC}XDyff|DvKc1FQ1C-GZaifdm2~>9k~&K^s%eplo@?2!GbZKF1X?kT}V{dM5Wn*+{Z*E_AZD}rW0Nq&MZ`(Eye%D`N}!F98f!R$VQ&{?i?VOpY?o&TWm#{RRXgjeuJ2}7?n86c%{EPWzH6I5ud`$KSGE&bIiJ71 zsMmeHozJu8?H^UyXFJGF`W0=SXYT)*yF8)mkCVNR^n256>+`CmKc7wL`t<4SY1=gY z)2mHQpFizAp{LLGKYlvfe?lf9J6P`oW-DiVC9)MeDx~vNC|<3|R_vN^zOC3HVaTIb z^P|J#s(;@s$&4j4kl!=|!kGb}cK`=7AV)JmC~T`M_d57nngZK9;HaXPd!PFYh8MCo z7sA{vgo2D93=1KS3!!v&cNYXQa!go!c_Gxa5Sr{{(RJP1;lgnr*4;Th!7gi^J-& zE~}S|{(WS|i)UxazxwpW>Cx-D?JpK<@~%rC5V=(*7sa#^wwOw&aB3_4ZmO2Xf?iaZ zTRXdazw}G{g}bt?cYWP#LE0q)I$!7b$YrV4Mmbv*KgegOHe0N_@D1(Ux>$ghd~n#r$6^6Nl; zEtxFqYRg>FjFB#~BasoE=krz7*L}6|cQwC4`JK~8X1GZhZiwNA8E!^~o4|0RxHueA z^dN3O`Z zOiFUDs3zxw?>aF&G8f#kfI5UCJe6!G$Eo1q`S|T%TTI?QyJDuk=R1269PSSI93XQ zp;QPAwL;)nEcO`Om>CQ*YtR`3;jSqvXuJb9Rcqc`>GxKKy_IoqNr672M$Es&5Thc8 z*8?gtqT)npjKnF^LnPV$=Ol58NN_kgycvZ;?p~z#QjJkKVHl%unlO^YDZ@w-mEu}3 zu7$_72)Gsz*Mh3gt3~UI=+SQ{Q=$@>(H6@>;NsU@2;;eo3>x9**#C8R6_)di0~>Rf{ci$BSOdWpw*ZAC!u`` z>okQmr?B=ZY(ff~n8GHeu!$*b(iApKRx`XF$Z8^44W%%}&K;`HUMD0+2ySNy8kgR! z>%sZ9Z-kw&ymo)j98hjYtoteGro4sgt=zHfj`dF1;Es*%ko4ftD5srr&aHCpd*wVd z%X#dUUHu>MC!fAe!vVSW?wZtHOYZu41e~Z0?mAr=-KCMjHyhxDg}aSAYYqs-rUnB# zm@?5+s5t=nw~8FNxBw)@1ps-bk=~uLxB!IW0uYJ|KqxMdjx4}43;3Z0!qftBYyqBI z4y$$5SJa$=A70=w(+l|V1=9J2FDu_?L8>FbIs#rtAm|809RV4N0Lbs$BY+>BAf26n zhbQpU6NK>z;`{`p7y~z5Fb{B3(HsoQ87EccNVxZ@s1?s+%j`-Rdl>_1d-b`Lesd zo3)nV!Bi2E6%oB6Vo*ekiio6$ooaySf`kE%Ck-d)~U!kMa{~Gi>kfmL*U{5 zjdQ!bQ`c#g{p5$qySCX(UK}0I4;TI7mwH`IuHIK|H6cPyewqxYq5ts-Dlf73Kbrgz6gI-2*(XYihLjeK^p-}YMH7@3oxtBC Q-|jN|8%XL+ffpJ80D7U+Jpcdz diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz deleted file mode 100644 index 64fdc6bef4f16c901c05ca5186677a35d3bb2bc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 439 zcmV;o0Z9HIiwFqE^vF;G|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUvgz_Z+2y0Wq5FJa&%vBb1rZI%~8v0!!QuM?^lFe>_B2HDSoKe^pZn+XrL#9aTL{Y zl3K!&^Pu$KyHe6ZODLuEP=n>&+12dqSO}$0WhZOEL#Wo+t`}BypkoMyXxf$RA}ftG z(E$^6FwwITTivPS3GOfgO+b|8vTt^_Y0DDSawCNWP2t{Z1`m1);Yug42+B$bX-p|p z-`W6l>IxYctn8~@FAZY3!#FnU%C0ddC}XDyff|DvKc1FQ1C-GZaifdm2~>9k~&K^s%eplo@?2!Gdm#=%{te1?d;y)H23Xn-BdT*UGv97cJBYnwvbhe#no-S>gvs6ku_Jp zyQ<5!m|b*Rk-gf=?C^T4viZTHtSZ;Gi>kTZbO+hCpf7aR`fu*a)vas&XNEqr{^2+0 zXZ{v)x(Dzd9A5h0OMf|{>$A!91N~h$oBGD>=-=lPx}KcOPIgVxo!qZ$y8k#mqNgtp zK7719I3kmn9j>+@vZc4Zglx% z#PC9Kk(^RxGq($!oncV`fJeP-2ej$J_4G^AvJh}|#V9&W(P@rO$LMs5PRmeFy$Q|H z=@A1oF+hjsBLhrgfPt7tgHPs>>|c~?HzcusznNhU`7z|PX1AO*Tjyo7tZttF>+~8y z-W$2^y;0tK6P(u3dy~AkPxIFjbe5sB5jvZovogkQ)%T6tGEeMC11)KwWetQpiXh}k z1-%Sp%RpGjJr4s}As@j9IpGI+|GG|w%wUK*&5P^nB+5Vy$J_E9XWtf(A^?ccj-n<2 zBvAlJssIpWVamY98en*jra|321pYeiO<=-gWEViJc+JZ`Q3trG;qSV)Tqk=bH<3}f1I;jYgmY4YcB(L-FBro=l zbL(?{6+A~3{UDVlsbUzVyx1?p00m>k2bO#Ynh#0zVNiY0NxML+Z`6E2vrK{3V|NX^ z8lME{~TJ0 QW9`-KFR{KanhOyC0K1;wHvj+t diff --git a/cinder/tests/windows/windowsutils.py b/cinder/tests/windows/windowsutils.py deleted file mode 100644 index 4a35a5b4e..000000000 --- a/cinder/tests/windows/windowsutils.py +++ /dev/null @@ -1,145 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Pedro Navarro Perez -# -# 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. - -""" -Windows storage classes to be used in testing. -""" - -import os - -from oslo.config import cfg - -# Check needed for unit testing on Unix -if os.name == 'nt': - import wmi - - -CONF = cfg.CONF - - -class WindowsUtils(object): - def __init__(self): - self.__conn_cimv2 = None - self.__conn_wmi = None - - @property - def _conn_cimv2(self): - if self.__conn_cimv2 is None: - self.__conn_cimv2 = wmi.WMI(moniker='//./root/cimv2') - return self.__conn_cimv2 - - @property - def _conn_wmi(self): - if self.__conn_wmi is None: - self.__conn_wmi = wmi.WMI(moniker='//./root/wmi') - return self.__conn_wmi - - def find_vhd_by_name(self, name): - '''Finds a volume by its name.''' - - wt_disks = self._conn_wmi.WT_Disk(Description=name) - return wt_disks - - def volume_exists(self, name): - '''Checks if a volume exists.''' - - wt_disks = self.find_vhd_by_name(name) - if len(wt_disks) > 0: - return True - return False - - def snapshot_exists(self, name): - '''Checks if a snapshot exists.''' - - wt_snapshots = self.find_snapshot_by_name(name) - if len(wt_snapshots) > 0: - return True - return False - - def find_snapshot_by_name(self, name): - '''Finds a snapshot by its name.''' - - wt_snapshots = self._conn_wmi.WT_Snapshot(Description=name) - return wt_snapshots - - def delete_volume(self, name): - '''Deletes a volume.''' - - wt_disk = self._conn_wmi.WT_Disk(Description=name)[0] - wt_disk.Delete_() - vhdfiles = self._conn_cimv2.query( - "Select * from CIM_DataFile where Name = '" + - self._get_vhd_path(name) + "'") - if len(vhdfiles) > 0: - vhdfiles[0].Delete() - - def _get_vhd_path(self, volume_name): - '''Gets the path disk of the volume.''' - - base_vhd_folder = CONF.windows_iscsi_lun_path - return os.path.join(base_vhd_folder, volume_name + ".vhd") - - def delete_snapshot(self, name): - '''Deletes a snapshot.''' - - wt_snapshot = self._conn_wmi.WT_Snapshot(Description=name)[0] - wt_snapshot.Delete_() - vhdfile = self._conn_cimv2.query( - "Select * from CIM_DataFile where Name = '" + - self._get_vhd_path(name) + "'")[0] - vhdfile.Delete() - - def find_initiator_ids(self, target_name, initiator_name): - '''Finds a initiator id by its name.''' - wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=target_name, - Method=4, - Value=initiator_name) - return wt_idmethod - - def initiator_id_exists(self, target_name, initiator_name): - '''Checks if a initiatorId exists.''' - - wt_idmethod = self.find_initiator_ids(target_name, initiator_name) - if len(wt_idmethod) > 0: - return True - return False - - def find_exports(self, target_name): - '''Finds a export id by its name.''' - - wt_host = self._conn_wmi.WT_Host(HostName=target_name) - return wt_host - - def export_exists(self, target_name): - '''Checks if a export exists.''' - - wt_host = self.find_exports(target_name) - if len(wt_host) > 0: - return True - return False - - def delete_initiator_id(self, target_name, initiator_name): - '''Deletes a initiatorId.''' - - wt_init_id = self.find_initiator_ids(target_name, initiator_name)[0] - wt_init_id.Delete_() - - def delete_export(self, target_name): - '''Deletes an export.''' - - wt_host = self.find_exports(target_name)[0] - wt_host.RemoveAllWTDisks() - wt_host.Delete_() diff --git a/cinder/volume/drivers/windows.py b/cinder/volume/drivers/windows.py deleted file mode 100644 index 87672bb50..000000000 --- a/cinder/volume/drivers/windows.py +++ /dev/null @@ -1,245 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Pedro Navarro Perez -# 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. -""" -Volume driver for Windows Server 2012 - -This driver requires ISCSI target role installed - -""" - - -import os - -from oslo.config import cfg - -from cinder import exception -from cinder.openstack.common import log as logging -from cinder.volume import driver - -# Check needed for unit testing on Unix -if os.name == 'nt': - import wmi - - -LOG = logging.getLogger(__name__) - -windows_opts = [ - cfg.StrOpt('windows_iscsi_lun_path', - default='C:\iSCSIVirtualDisks', - help='Path to store VHD backed volumes'), -] - -CONF = cfg.CONF -CONF.register_opts(windows_opts) - - -class WindowsDriver(driver.ISCSIDriver): - """Executes volume driver commands on Windows Storage server.""" - - def __init__(self, *args, **kwargs): - super(WindowsDriver, self).__init__(*args, **kwargs) - - def do_setup(self, context): - """Setup the Windows Volume driver. - - Called one time by the manager after the driver is loaded. - Validate the flags we care about - """ - #Set the flags - self._conn_wmi = wmi.WMI(moniker='//./root/wmi') - self._conn_cimv2 = wmi.WMI(moniker='//./root/cimv2') - - def check_for_setup_error(self): - """Check that the driver is working and can communicate. - """ - #Invoking the portal an checking that is listening - wt_portal = self._conn_wmi.WT_Portal()[0] - listen = wt_portal.Listen - if not listen: - raise exception.VolumeBackendAPIException() - - def initialize_connection(self, volume, connector): - """Driver entry point to attach a volume to an instance. - """ - initiator_name = connector['initiator'] - target_name = volume['provider_location'] - - cl = self._conn_wmi.__getattr__("WT_IDMethod") - wt_idmethod = cl.new() - wt_idmethod.HostName = target_name - wt_idmethod.Method = 4 - wt_idmethod.Value = initiator_name - wt_idmethod.put() - #Getting the portal and port information - wt_portal = self._conn_wmi.WT_Portal()[0] - (address, port) = (wt_portal.Address, wt_portal.Port) - #Getting the host information - hosts = self._conn_wmi.WT_Host(Hostname=target_name) - host = hosts[0] - - properties = {} - properties['target_discovered'] = False - properties['target_portal'] = '%s:%s' % (address, port) - properties['target_iqn'] = host.TargetIQN - properties['target_lun'] = 0 - properties['volume_id'] = volume['id'] - - auth = volume['provider_auth'] - if auth: - (auth_method, auth_username, auth_secret) = auth.split() - - properties['auth_method'] = auth_method - properties['auth_username'] = auth_username - properties['auth_password'] = auth_secret - - return { - 'driver_volume_type': 'iscsi', - 'data': properties, - } - - def terminate_connection(self, volume, connector, **kwargs): - """Driver entry point to unattach a volume from an instance. - - Unmask the LUN on the storage system so the given intiator can no - longer access it. - """ - initiator_name = connector['initiator'] - provider_location = volume['provider_location'] - #DesAssigning target to initiators - wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=provider_location, - Method=4, - Value=initiator_name)[0] - wt_idmethod.Delete_() - - def create_volume(self, volume): - """Driver entry point for creating a new volume.""" - vhd_path = self._get_vhd_path(volume) - vol_name = volume['name'] - #The WMI procedure returns a Generic failure - cl = self._conn_wmi.__getattr__("WT_Disk") - cl.NewWTDisk(DevicePath=vhd_path, - Description=vol_name, - SizeInMB=volume['size'] * 1024) - - def _get_vhd_path(self, volume): - base_vhd_folder = CONF.windows_iscsi_lun_path - if not os.path.exists(base_vhd_folder): - LOG.debug(_('Creating folder %s '), base_vhd_folder) - os.makedirs(base_vhd_folder) - return os.path.join(base_vhd_folder, str(volume['name']) + ".vhd") - - def delete_volume(self, volume): - """Driver entry point for destroying existing volumes.""" - vol_name = volume['name'] - wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0] - wt_disk.Delete_() - vhdfiles = self._conn_cimv2.query( - "Select * from CIM_DataFile where Name = '" + - self._get_vhd_path(volume) + "'") - if len(vhdfiles) > 0: - vhdfiles[0].Delete() - - def create_snapshot(self, snapshot): - """Driver entry point for creating a snapshot. - """ - #Getting WT_Snapshot class - vol_name = snapshot['volume_name'] - snapshot_name = snapshot['name'] - - wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0] - #API Calls gets Generic Failure - cl = self._conn_wmi.__getattr__("WT_Snapshot") - disk_id = wt_disk.WTD - out = cl.Create(WTD=disk_id) - #Setting description since it used as a KEY - wt_snapshot_created = self._conn_wmi.WT_Snapshot(Id=out[0])[0] - wt_snapshot_created.Description = snapshot_name - wt_snapshot_created.put() - - def create_volume_from_snapshot(self, volume, snapshot): - """Driver entry point for exporting snapshots as volumes.""" - snapshot_name = snapshot['name'] - wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0] - disk_id = wt_snapshot.Export()[0] - wt_disk = self._conn_wmi.WT_Disk(WTD=disk_id)[0] - wt_disk.Description = volume['name'] - wt_disk.put() - - def delete_snapshot(self, snapshot): - """Driver entry point for deleting a snapshot.""" - snapshot_name = snapshot['name'] - wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0] - wt_snapshot.Delete_() - - def _do_export(self, _ctx, volume, ensure=False): - """Do all steps to get disk exported as LUN 0 at separate target. - - :param volume: reference of volume to be exported - :param ensure: if True, ignore errors caused by already existing - resources - :return: iscsiadm-formatted provider location string - """ - target_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) - #ISCSI target creation - try: - cl = self._conn_wmi.__getattr__("WT_Host") - cl.NewHost(HostName=target_name) - except Exception as exc: - excep_info = exc.com_error.excepinfo[2] - if not ensure or excep_info.find(u'The file exists') == -1: - raise - else: - LOG.info(_('Ignored target creation error "%s"' - ' while ensuring export'), exc) - #Get the disk to add - vol_name = volume['name'] - q = self._conn_wmi.WT_Disk(Description=vol_name) - if not len(q): - LOG.debug(_('Disk not found: %s'), vol_name) - return None - wt_disk = q[0] - wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0] - wt_host.AddWTDisk(wt_disk.WTD) - - return target_name - - def ensure_export(self, context, volume): - """Driver entry point to get the export info for an existing volume.""" - self._do_export(context, volume, ensure=True) - - def create_export(self, context, volume): - """Driver entry point to get the export info for a new volume.""" - loc = self._do_export(context, volume, ensure=False) - return {'provider_location': loc} - - def remove_export(self, context, volume): - """Driver exntry point to remove an export for a volume. - """ - target_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name']) - - #Get ISCSI target - wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0] - wt_host.RemoveAllWTDisks() - wt_host.Delete_() - - def copy_image_to_volume(self, context, volume, image_service, image_id): - """Fetch the image from image_service and write it to the volume.""" - raise NotImplementedError() - - def copy_volume_to_image(self, context, volume, image_service, image_meta): - """Copy the volume to the specified image.""" - raise NotImplementedError() diff --git a/cinder/volume/drivers/windows/__init__.py b/cinder/volume/drivers/windows/__init__.py new file mode 100644 index 000000000..2b0d839bd --- /dev/null +++ b/cinder/volume/drivers/windows/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2013 OpenStack LLC +# +# 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. diff --git a/cinder/volume/drivers/windows/windows.py b/cinder/volume/drivers/windows/windows.py new file mode 100644 index 000000000..24cf40177 --- /dev/null +++ b/cinder/volume/drivers/windows/windows.py @@ -0,0 +1,227 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Pedro Navarro Perez +# 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. +""" +Volume driver for Windows Server 2012 + +This driver requires ISCSI target role installed + +""" + +import os + +from oslo.config import cfg + +from cinder.image import image_utils +from cinder.openstack.common import log as logging +from cinder.volume import driver +from cinder.volume.drivers.windows import windows_utils + +LOG = logging.getLogger(__name__) + +windows_opts = [ + cfg.StrOpt('windows_iscsi_lun_path', + default='C:\iSCSIVirtualDisks', + help='Path to store VHD backed volumes'), +] + +CONF = cfg.CONF +CONF.register_opts(windows_opts) + + +class WindowsDriver(driver.ISCSIDriver): + """Executes volume driver commands on Windows Storage server.""" + + VERSION = '1.0.0' + + def __init__(self, *args, **kwargs): + super(WindowsDriver, self).__init__(*args, **kwargs) + self.configuration = kwargs.get('configuration', None) + if self.configuration: + self.configuration.append_config_values(windows_opts) + + def do_setup(self, context): + """Setup the Windows Volume driver. + + Called one time by the manager after the driver is loaded. + Validate the flags we care about + """ + self.utils = windows_utils.WindowsUtils() + + def check_for_setup_error(self): + """Check that the driver is working and can communicate.""" + self.utils.check_for_setup_error() + + def initialize_connection(self, volume, connector): + """Driver entry point to attach a volume to an instance.""" + initiator_name = connector['initiator'] + target_name = volume['provider_location'] + + self.utils.associate_initiator_with_iscsi_target(target_name, + initiator_name) + + properties = self.utils.get_host_information(volume, target_name) + + return { + 'driver_volume_type': 'iscsi', + 'data': properties, + } + + def terminate_connection(self, volume, connector, **kwargs): + """Driver entry point to unattach a volume from an instance. + + Unmask the LUN on the storage system so the given initiator can no + longer access it. + """ + initiator_name = connector['initiator'] + target_name = volume['provider_location'] + self.utils.delete_iscsi_target(initiator_name, target_name) + + def create_volume(self, volume): + """Driver entry point for creating a new volume.""" + vhd_path = self.local_path(volume) + vol_name = volume['name'] + vol_size = volume['size'] + + self.utils.create_volume(vhd_path, vol_name, vol_size) + + def local_path(self, volume): + base_vhd_folder = self.configuration.windows_iscsi_lun_path + if not os.path.exists(base_vhd_folder): + LOG.debug(_('Creating folder %s '), base_vhd_folder) + os.makedirs(base_vhd_folder) + return os.path.join(base_vhd_folder, str(volume['name']) + ".vhd") + + def delete_volume(self, volume): + """Driver entry point for destroying existing volumes.""" + vol_name = volume['name'] + vhd_path = self.local_path(volume) + + self.utils.delete_volume(vol_name, vhd_path) + + def create_snapshot(self, snapshot): + """Driver entry point for creating a snapshot.""" + # Getting WT_Snapshot class + vol_name = snapshot['volume_name'] + snapshot_name = snapshot['name'] + + self.utils.create_snapshot(vol_name, snapshot_name) + + def create_volume_from_snapshot(self, volume, snapshot): + """Driver entry point for exporting snapshots as volumes.""" + snapshot_name = snapshot['name'] + vol_name = volume['name'] + self.utils.create_volume_from_snapshot(vol_name, snapshot_name) + + def delete_snapshot(self, snapshot): + """Driver entry point for deleting a snapshot.""" + snapshot_name = snapshot['name'] + self.utils.delete_snapshot(snapshot_name) + + def _do_export(self, _ctx, volume, ensure=False): + """Do all steps to get disk exported as LUN 0 at separate target. + + :param volume: reference of volume to be exported + :param ensure: if True, ignore errors caused by already existing + resources + :return: iscsiadm-formatted provider location string + """ + target_name = "%s%s" % (self.configuration.iscsi_target_prefix, + volume['name']) + self.utils.create_iscsi_target(target_name, ensure) + + # Get the disk to add + vol_name = volume['name'] + self.utils.add_disk_to_target(vol_name, target_name) + + return target_name + + def ensure_export(self, context, volume): + """Driver entry point to get the export info for an existing volume.""" + self._do_export(context, volume, ensure=True) + + def create_export(self, context, volume): + """Driver entry point to get the export info for a new volume.""" + loc = self._do_export(context, volume, ensure=False) + return {'provider_location': loc} + + def remove_export(self, context, volume): + """Driver entry point to remove an export for a volume. + """ + target_name = "%s%s" % (self.configuration.iscsi_target_prefix, + volume['name']) + + self.utils.remove_iscsi_target(target_name) + + def copy_image_to_volume(self, context, volume, image_service, image_id): + """Fetch the image from image_service and write it to the volume.""" + # Convert to VHD and file back to VHD + image_utils.fetch_to_vhd(context, image_service, image_id, + self.local_path(volume)) + + def copy_volume_to_image(self, context, volume, image_service, image_meta): + """Copy the volume to the specified image.""" + + # Copy the volume to the image conversion dir + temp_vhd_path = os.path.join(self.configuration.image_conversion_dir, + str(image_meta['id']) + ".vhd") + self.utils.copy_vhd_disk(self.local_path(volume), temp_vhd_path) + image_utils.upload_volume(context, image_service, image_meta, + temp_vhd_path, 'vpc') + + def create_cloned_volume(self, volume, src_vref): + """Creates a clone of the specified volume.""" + # Create a new volume + # Copy VHD file of the volume to clone to the created volume + self.create_volume(volume) + self.utils.copy_vhd_disk(self.local_path(src_vref), + self.local_path(volume)) + + def get_volume_stats(self, refresh=False): + """Get volume stats. + + If 'refresh' is True, run update the stats first. + """ + if refresh: + self._update_volume_stats() + + return self._stats + + def _update_volume_stats(self): + """Retrieve stats info for Windows device.""" + + LOG.debug(_("Updating volume stats")) + data = {} + backend_name = self.__class__.__name__ + if self.configuration: + backend_name = self.configuration.safe_get('volume_backend_name') + data["volume_backend_name"] = backend_name or self.__class__.__name__ + data["vendor_name"] = 'Microsoft' + data["driver_version"] = self.VERSION + data["storage_protocol"] = 'iSCSI' + data['total_capacity_gb'] = 'infinite' + data['free_capacity_gb'] = 'infinite' + data['reserved_percentage'] = 100 + data['QoS_support'] = False + self._stats = data + + def extend_volume(self, volume, new_size): + """Extend an Existing Volume.""" + old_size = volume['size'] + LOG.debug(_("Extended volume from %(old_size) to %(new_size)"), + {'old_size': old_size, 'new_size': new_size}) + additional_size = (new_size - old_size) * 1024 + self.utils.extend(volume['name'], additional_size) diff --git a/cinder/volume/drivers/windows/windows_utils.py b/cinder/volume/drivers/windows/windows_utils.py new file mode 100644 index 000000000..938ac08f2 --- /dev/null +++ b/cinder/volume/drivers/windows/windows_utils.py @@ -0,0 +1,297 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Pedro Navarro Perez +# 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. +""" +Utility class for Windows Storage Server 2012 volume related operations. +""" + +import os + +from cinder import exception +from cinder.openstack.common import log as logging + +# Check needed for unit testing on Unix +if os.name == 'nt': + import wmi + +LOG = logging.getLogger(__name__) + + +class WindowsUtils(object): + """Executes volume driver commands on Windows Storage server.""" + + def __init__(self, *args, **kwargs): + # Set the flags + self._conn_wmi = wmi.WMI(moniker='//./root/wmi') + self._conn_cimv2 = wmi.WMI(moniker='//./root/cimv2') + + def check_for_setup_error(self): + """Check that the driver is working and can communicate. + Invokes the portal and checks that is listening ISCSI traffic. + """ + try: + wt_portal = self._conn_wmi.WT_Portal()[0] + listen = wt_portal.Listen + except wmi.x_wmi as exc: + err_msg = (_('check_for_setup_error: the state of the WT Portal ' + 'could not be verified. WMI exception: %s')) + LOG.error(err_msg % exc) + raise exception.VolumeBackendAPIException(data=err_msg % exc) + + if not listen: + err_msg = (_('check_for_setup_error: there is no ISCSI traffic ' + 'listening.')) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def get_host_information(self, volume, target_name): + """Getting the portal and port information.""" + try: + wt_portal = self._conn_wmi.WT_Portal()[0] + except wmi.x_wmi as exc: + err_msg = (_('get_host_information: the state of the WT Portal ' + 'could not be verified. WMI exception: %s')) + LOG.error(err_msg % exc) + raise exception.VolumeBackendAPIException(data=err_msg % exc) + (address, port) = (wt_portal.Address, wt_portal.Port) + # Getting the host information + try: + hosts = self._conn_wmi.WT_Host(Hostname=target_name) + host = hosts[0] + except wmi.x_wmi as exc: + err_msg = (_('get_host_information: the ISCSI target information ' + 'could not be retrieved. WMI exception: %s')) + LOG.error(err_msg % exc) + raise exception.VolumeBackendAPIException(data=err_msg) + + properties = {} + properties['target_discovered'] = False + properties['target_portal'] = '%s:%s' % (address, port) + properties['target_iqn'] = host.TargetIQN + properties['target_lun'] = 0 + properties['volume_id'] = volume['id'] + + auth = volume['provider_auth'] + if auth: + (auth_method, auth_username, auth_secret) = auth.split() + + properties['auth_method'] = auth_method + properties['auth_username'] = auth_username + properties['auth_password'] = auth_secret + + def associate_initiator_with_iscsi_target(self, initiator_name, + target_name): + """Sets information used by the iSCSI target entry.""" + try: + cl = self._conn_wmi.__getattr__("WT_IDMethod") + wt_idmethod = cl.new() + wt_idmethod.HostName = target_name + # Identification method is IQN + wt_idmethod.Method = 4 + wt_idmethod.Value = initiator_name + wt_idmethod.put() + except wmi.x_wmi as exc: + err_msg = (_('associate_initiator_with_iscsi_target: an ' + 'association between initiator: %(init)s and ' + 'target name: %(target)s could not be established. ' + 'WMI exception: %(wmi_exc)s') % + {'init': initiator_name, 'target': target_name, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def delete_iscsi_target(self, initiator_name, target_name): + """Removes iSCSI targets to hosts.""" + + try: + wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=target_name, + Method=4, + Value=initiator_name)[0] + wt_idmethod.Delete_() + except wmi.x_wmi as exc: + err_msg = (_( + 'delete_iscsi_target: error when deleting the iscsi target ' + 'associated with target name: %(target)s . ' + 'WMI exception: %(wmi_exc)s') % {'target': target_name, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def create_volume(self, vhd_path, vol_name, vol_size): + """Creates a volume""" + try: + cl = self._conn_wmi.__getattr__("WT_Disk") + cl.NewWTDisk(DevicePath=vhd_path, + Description=vol_name, + SizeInMB=vol_size * 1024) + except wmi.x_wmi as exc: + err_msg = (_( + 'create_volume: error when creating the volume name: ' + '%(vol_name)s . WMI exception: ' + '%(wmi_exc)s') % {'vol_name': vol_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def delete_volume(self, vol_name, vhd_path): + """Driver entry point for destroying existing volumes.""" + try: + wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0] + wt_disk.Delete_() + vhdfiles = self._conn_cimv2.query( + "Select * from CIM_DataFile where Name = '" + + vhd_path + "'") + if len(vhdfiles) > 0: + vhdfiles[0].Delete() + except wmi.x_wmi as exc: + err_msg = (_( + 'delete_volume: error when deleting the volume name: ' + '%(vol_name)s . WMI exception: ' + '%(wmi_exc)s') % {'vol_name': vol_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def create_snapshot(self, vol_name, snapshot_name): + """Driver entry point for creating a snapshot.""" + try: + wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0] + # API Calls gets Generic Failure + cl = self._conn_wmi.__getattr__("WT_Snapshot") + disk_id = wt_disk.WTD + out = cl.Create(WTD=disk_id) + # Setting description since it used as a KEY + wt_snapshot_created = self._conn_wmi.WT_Snapshot(Id=out[0])[0] + wt_snapshot_created.Description = snapshot_name + wt_snapshot_created.put() + except wmi.x_wmi as exc: + err_msg = (_( + 'create_snapshot: error when creating the snapshot name: ' + '%(vol_name)s . WMI exception: ' + '%(wmi_exc)s') % {'vol_name': snapshot_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def create_volume_from_snapshot(self, vol_name, snap_name): + """Driver entry point for exporting snapshots as volumes.""" + try: + wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snap_name)[0] + disk_id = wt_snapshot.Export()[0] + wt_disk = self._conn_wmi.WT_Disk(WTD=disk_id)[0] + wt_disk.Description = vol_name + wt_disk.put() + except wmi.x_wmi as exc: + err_msg = (_( + 'create_volume_from_snapshot: error when creating the volume ' + 'name: %(vol_name)s from snapshot name: %(snap_name)s. ' + 'WMI exception: %(wmi_exc)s') % {'vol_name': vol_name, + 'snap_name': snap_name, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def delete_snapshot(self, snap_name): + """Driver entry point for deleting a snapshot.""" + try: + wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snap_name)[0] + wt_snapshot.Delete_() + except wmi.x_wmi as exc: + err_msg = (_( + 'delete_snapshot: error when deleting the snapshot name: ' + '%(snap_name)s . WMI exception: ' + '%(wmi_exc)s') % {'snap_name': snap_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def create_iscsi_target(self, target_name, ensure): + """Creates ISCSI target.""" + try: + cl = self._conn_wmi.__getattr__("WT_Host") + cl.NewHost(HostName=target_name) + except wmi.x_wmi as exc: + excep_info = exc.com_error.excepinfo[2] + if not ensure or excep_info.find(u'The file exists') == -1: + err_msg = (_( + 'create_iscsi_target: error when creating iscsi target: ' + '%(tar_name)s . WMI exception: ' + '%(wmi_exc)s') % {'tar_name': target_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + else: + LOG.info(_('Ignored target creation error "%s"' + ' while ensuring export'), exc) + + def remove_iscsi_target(self, target_name): + """Removes ISCSI target.""" + try: + wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0] + wt_host.RemoveAllWTDisks() + wt_host.Delete_() + except wmi.x_wmi as exc: + err_msg = (_( + 'remove_iscsi_target: error when deleting iscsi target: ' + '%(tar_name)s . WMI exception: ' + '%(wmi_exc)s') % {'tar_name': target_name, 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def add_disk_to_target(self, vol_name, target_name): + """Adds the disk to the target""" + try: + q = self._conn_wmi.WT_Disk(Description=vol_name) + wt_disk = q[0] + wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0] + wt_host.AddWTDisk(wt_disk.WTD) + except wmi.x_wmi as exc: + err_msg = (_( + 'add_disk_to_target: error adding disk associated to volume : ' + '%(vol_name)s to the target name: %(tar_name)s ' + '. WMI exception: %(wmi_exc)s') % {'tar_name': target_name, + 'vol_name': vol_name, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def copy_vhd_disk(self, source_path, destination_path): + """Copy the vhd disk from source path to destination path.""" + try: + vhdfiles = self._conn_cimv2.query( + "Select * from CIM_DataFile where Name = '" + + source_path + "'") + if len(vhdfiles) > 0: + vhdfiles[0].Copy(destination_path) + except wmi.x_wmi as exc: + err_msg = (_( + 'copy_vhd_disk: error when copying disk from source path : ' + '%(src_path)s to destination path: %(dest_path)s ' + '. WMI exception: ' + '%(wmi_exc)s') % {'src_path': source_path, + 'dest_path': destination_path, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + + def extend(self, vol_name, additional_size): + """Extend an existing volume.""" + try: + q = self._conn_wmi.WT_Disk(Description=vol_name) + wt_disk = q[0] + wt_disk.Extend(additional_size) + except wmi.x_wmi as exc: + err_msg = (_( + 'extend: error when extending the volumne: %(vol_name)s ' + '.WMI exception: %(wmi_exc)s') % {'vol_name': vol_name, + 'wmi_exc': exc}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index 4dea45a4f..f2afd322d 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -102,7 +102,9 @@ MAPPING = { 'cinder.volume.storwize_svc.StorwizeSVCDriver': 'cinder.volume.drivers.storwize_svc.StorwizeSVCDriver', 'cinder.volume.windows.WindowsDriver': - 'cinder.volume.drivers.windows.WindowsDriver', + 'cinder.volume.drivers.windows.windows.WindowsDriver', + 'cinder.volume.drivers.windows.WindowsDriver': + 'cinder.volume.drivers.windows.windows.WindowsDriver', 'cinder.volume.xiv.XIVDriver': 'cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver', 'cinder.volume.drivers.xiv.XIVDriver': diff --git a/etc/cinder/cinder.conf.sample b/etc/cinder/cinder.conf.sample index bc8dc6280..693089aca 100644 --- a/etc/cinder/cinder.conf.sample +++ b/etc/cinder/cinder.conf.sample @@ -1541,7 +1541,7 @@ # -# Options defined in cinder.volume.drivers.windows +# Options defined in cinder.volume.drivers.windows.windows # # Path to store VHD backed volumes (string value) -- 2.45.2