From 1a7c6f4a09ef9980ead0c46d080078a7bbc81d10 Mon Sep 17 00:00:00 2001 From: Pedro Navarro Perez Date: Thu, 18 Oct 2012 22:44:59 +0200 Subject: [PATCH] Adds support for Windows 2012 Storage Server blueprint windows2012driver https://blueprints.launchpad.net/cinder/+spec/windows2012driver Change-Id: I3f7efb1b976fedc4afb736b87d550a34c330c839 --- cinder/tests/test_windows.py | 217 ++++++++++++++++ cinder/tests/windows/__init__.py | 0 cinder/tests/windows/basetestcase.py | 96 +++++++ cinder/tests/windows/db_fakes.py | 42 ++++ cinder/tests/windows/mockproxy.py | 234 ++++++++++++++++++ cinder/tests/windows/stubs/README.rst | 2 + ...river.test_check_for_setup_errors_wmi.p.gz | Bin 0 -> 473 bytes ...stWindowsDriver.test_create_export_os.p.gz | Bin 0 -> 439 bytes ...tWindowsDriver.test_create_export_wmi.p.gz | Bin 0 -> 1441 bytes ...WindowsDriver.test_create_snapshot_os.p.gz | Bin 0 -> 441 bytes ...indowsDriver.test_create_snapshot_wmi.p.gz | Bin 0 -> 1479 bytes ...r.test_create_volume_from_snapshot_os.p.gz | Bin 0 -> 500 bytes ....test_create_volume_from_snapshot_wmi.p.gz | Bin 0 -> 1843 bytes ...stWindowsDriver.test_create_volume_os.p.gz | Bin 0 -> 439 bytes ...tWindowsDriver.test_create_volume_wmi.p.gz | Bin 0 -> 1057 bytes ...WindowsDriver.test_delete_snapshot_os.p.gz | Bin 0 -> 441 bytes ...indowsDriver.test_delete_snapshot_wmi.p.gz | Bin 0 -> 1502 bytes ...stWindowsDriver.test_delete_volume_os.p.gz | Bin 0 -> 472 bytes ...tWindowsDriver.test_delete_volume_wmi.p.gz | Bin 0 -> 1039 bytes ...stWindowsDriver.test_ensure_export_os.p.gz | Bin 0 -> 439 bytes ...tWindowsDriver.test_ensure_export_wmi.p.gz | Bin 0 -> 1441 bytes ...sDriver.test_initialize_connection_os.p.gz | Bin 0 -> 447 bytes ...Driver.test_initialize_connection_wmi.p.gz | Bin 0 -> 1976 bytes ...stWindowsDriver.test_remove_export_os.p.gz | Bin 0 -> 439 bytes ...tWindowsDriver.test_remove_export_wmi.p.gz | Bin 0 -> 1451 bytes cinder/tests/windows/windowsutils.py | 145 +++++++++++ cinder/volume/windows.py | 232 +++++++++++++++++ 27 files changed, 968 insertions(+) create mode 100644 cinder/tests/test_windows.py create mode 100644 cinder/tests/windows/__init__.py create mode 100644 cinder/tests/windows/basetestcase.py create mode 100644 cinder/tests/windows/db_fakes.py create mode 100644 cinder/tests/windows/mockproxy.py create mode 100644 cinder/tests/windows/stubs/README.rst create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz create mode 100644 cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz create mode 100644 cinder/tests/windows/windowsutils.py create mode 100644 cinder/volume/windows.py diff --git a/cinder/tests/test_windows.py b/cinder/tests/test_windows.py new file mode 100644 index 000000000..1b1bfcbb0 --- /dev/null +++ b/cinder/tests/test_windows.py @@ -0,0 +1,217 @@ +# 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. + +""" +Unit tests for Windows Server 2012 OpenStack Cinder volume driver +""" +import sys + +import cinder.flags +from cinder.volume import windows +from cinder.tests.windows import basetestcase +from cinder.tests.windows import db_fakes +from cinder.tests.windows import windowsutils + +FLAGS = cinder.flags.FLAGS + + +class TestWindowsDriver(basetestcase.BaseTestCase): + + def __init__(self, method): + super(TestWindowsDriver, self).__init__(method) + + def setUp(self): + super(TestWindowsDriver, self).setUp() + self.flags( + windows_iscsi_lun_path='D:\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() + + self._drv = windows.WindowsDriver() + self._drv.do_setup({}) + self._wutils = windowsutils.WindowsUtils() + + def _setup_stubs(self): + + # Modules to mock + modules_to_mock = [ + 'wmi', + 'os', + 'subprocess', + 'multiprocessing' + ] + + modules_to_test = [ + windows, + windowsutils, + sys.modules[__name__] + ] + + self._inject_mocks_in_modules(modules_to_mock, modules_to_test) + + 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" % (FLAGS.iscsi_target_prefix, + self._volume_data['name']), + self._connector_data['initiator']): + target_name = "%s%s" % (FLAGS.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" % (FLAGS.iscsi_target_prefix, + self._volume_data['name'])): + self._wutils.delete_export("%s%s" % (FLAGS.iscsi_target_prefix, + self._volume_data['name'])) + + finally: + super(TestWindowsDriver, self).tearDown() + + def test_check_for_setup_errors(self): + self._drv.check_for_setup_error() + + def test_create_volume(self): + self._create_volume() + + wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name']) + self.assertEquals(len(wt_disks), 1) + + def _create_volume(self): + self._volume_data = db_fakes.get_fake_volume_info(self._volume_id) + self._drv.create_volume(self._volume_data) + + def test_delete_volume(self): + self._create_volume() + + self._drv.delete_volume(self._volume_data) + + wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name']) + self.assertEquals(len(wt_disks), 0) + + def test_create_snapshot(self): + #Create a volume + self._create_volume() + + 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() + + snapshot_name = self._snapshot_data['name'] + wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name) + self.assertEquals(len(wt_snapshots), 1) + + 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) + + def test_create_volume_from_snapshot(self): + #Create a volume + self._create_volume() + #Create a snapshot from the previous volume + self._create_snapshot() + + self._volume_data_2 = db_fakes.get_fake_volume_info(self._volume_id_2) + + self._drv.create_volume_from_snapshot(self._volume_data_2, + self._snapshot_data) + + wt_disks = self._wutils.find_vhd_by_name(self._volume_data_2['name']) + self.assertEquals(len(wt_disks), 1) + + def test_delete_snapshot(self): + #Create a volume + self._create_volume() + #Create a snapshot from the previous volume + self._create_snapshot() + + self._drv.delete_snapshot(self._snapshot_data) + + snapshot_name = self._snapshot_data['name'] + wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name) + self.assertEquals(len(wt_snapshots), 0) + + def test_create_export(self): + #Create a volume + self._create_volume() + + retval = self._drv.create_export({}, self._volume_data) + + volume_name = self._volume_data['name'] + self.assertEquals(retval, + {'provider_location': + "%s%s" % (FLAGS.iscsi_target_prefix, volume_name)}) + + def test_initialize_connection(self): + #Create a volume + self._create_volume() + + self._drv.create_export({}, self._volume_data) + + self._connector_data = db_fakes.get_fake_connector_info(self._iqn) + + 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'] + + wt_initiator_ids = self._wutils.find_initiator_ids(target_name, + initiator_name) + self.assertEquals(len(wt_initiator_ids), 1) + + properties = init_data['data'] + self.assertNotEqual(properties['target_iqn'], None) + + def test_ensure_export(self): + #Create a volume + self._create_volume() + + self._drv.ensure_export({}, self._volume_data) + + def test_remove_export(self): + #Create a volume + self._create_volume() + + self._drv.create_export({}, self._volume_data) + + self._drv.remove_export({}, self._volume_data) diff --git a/cinder/tests/windows/__init__.py b/cinder/tests/windows/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cinder/tests/windows/basetestcase.py b/cinder/tests/windows/basetestcase.py new file mode 100644 index 000000000..24fcb91c2 --- /dev/null +++ b/cinder/tests/windows/basetestcase.py @@ -0,0 +1,96 @@ +# 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 gzip +import os +import pickle +import cinder.test + +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() + + has_errors = len([test for (test, msgs) in self._currentResult.errors + if test.id() == self.id()]) > 0 + failed = len([test for (test, msgs) in self._currentResult.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 new file mode 100644 index 000000000..938b240a8 --- /dev/null +++ b/cinder/tests/windows/db_fakes.py @@ -0,0 +1,42 @@ +# 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. + +""" +Stubouts, mocks and fixtures for windows volume test suite +""" + + +def get_fake_volume_info(name): + return { + 'name': name, + 'size': 1, + 'provider_location': 'iqn.2010-10.org.openstack:' + 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_connector_info(initiator): + return { + 'initiator': initiator, + } diff --git a/cinder/tests/windows/mockproxy.py b/cinder/tests/windows/mockproxy.py new file mode 100644 index 000000000..ff04ea709 --- /dev/null +++ b/cinder/tests/windows/mockproxy.py @@ -0,0 +1,234 @@ +# 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 + +""" +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 not name 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 new file mode 100644 index 000000000..150fd3ad1 --- /dev/null +++ b/cinder/tests/windows/stubs/README.rst @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..32a00b3d1ae8a8228e77cb4868467b90e82ff8e2 GIT binary patch literal 473 zcmV;~0Ve(*iwFp}dsk2b|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-%5*F$j literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..a511d37bf886af6fe966e84ceb6c24a47d768ae8 GIT binary patch literal 439 zcmV;o0Z9HIiwFp~dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*Wq5FJa&%vBb1rZI%~8v0!!QuM?^lFe>_B2HDSoKe=8{8uXrL#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|DvKc1FQ)7ie-%^I^cu5COTjt4Gyd3EOqk%3Qw zkz?jg8;xNe6R3C-GZaifdm2~>9k~&K^s%eplo@?2!G@{m?HS+)ew?FE(v`yX)Ft-xufZzhVbPy_l;Su&nCZ_WiPM@3zB1v6KFVDthuz~#20gh2a@UN29Z{?>;uJ_NG;5C|>= zqW>PtF$D4$0zCp3_TkOzF$hWuqOu^`2Qhv`$;Kch#2_Vl7?*XmUN4s}Mp@ER{vg}<((FRpz zOJ>aC{@qQOI!xTxU9%gSc00}dC1Iuzm(6eXYP@Se9}h%ThTk%K)4i zvE(db$sMZKRo~O)y4oAb(eswT>a zkib=^0GVzxj~*}{K8*MQlT#pHq%Ur6lJWx6Ay!sS0KT38Ab3u!D1cN_;A~>V6hMri z&I#630)+0-JZP9hz+H0(0xARmmCvtfe%esLxTAn+OTpR8V>Uc0w457&1PlgXFad)T zFy4EDl>ufN0O&;k%3!}`lmRG{4uFFpLh)Gx`Zr||g3v>*^gvP%<(OF%dzjQ7IFK5y z?Us}fcxVHh$e+O@)ykRz>I!&ZAy0h)pBe)v%n=1{{x1}q?)%)G^6#fBkeZl~j)=wu zA~_d0>5oO_3Mv*=?f^g*0Ko$wnE*^K0AvHFc5MesaLT|lNkuU~BmkzQ=X>b~9{^_r z7kdo$msNb3rz9yQ6;e_uB{ij_CPFIybp;Pp;Hk=as)(m*OgQmWPds%Vv5Mq$PVpIX zl5apT4oJ=clXZaej);iXUl|b{gvMk|GZ^1BgQ2z=OzfM%q{bP%Z;YHZGI7@A;%P`c z4T&eRD4uQ^sRQ@kF%lJ7`R7DM#zUVkh^Utbuk5D1w=dS~U?n|$6WVx|_wkGxc^1-v zlnzYkK=NmVFUbZ%HX!n2hxbtg6(Z?0Q?gQYR`RrK^nd+mRX3Y^{Ny$xQj3F_*))e$fL`%~QSuNS`qfush|{}2EGSIfrV literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..a8b094f0c24ffc41447c6f43ef434bb0f24a5077 GIT binary patch literal 441 zcmV;q0Y?5GiwFq1dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*b8ca9b7*gLUvG0RZ~)Cw%WA_g5WMeKgk0=EVk{|ssMqF_LwjhTCxdYm 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}7CHMw$0pdjkLfUIxuG literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..a862e77f848061c33598f7cd98382eb009fc4f2e GIT binary patch literal 1479 zcmV;&1vvU2iwFq1dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*b8ca9b7*gLUw3V3E^q+7SKm+DNDzMaUlH*FoSLw+zqisoP*QYx0G*Di zeL;$h*#;j;?8XL;L;c@xcGtTmZqpxkIuLSVXFdDv%s2DR6h&1(&Np_E;iah7O}n`( z+G>;4Bs(aIa(!(#lh!tEGkL(9>Y*l6%;K4XElx&-! zfMzIl?@-p6p*)(Q&I>0So3|D%Q0XnGfd%a>7`L2}&H{sIfl=qjd66%d^EujJ%s=Hj z{qy17wD%1K00BxW@m0?-;Q%qY4TvcO#KP{T1H?%L#K8kv*tTr#%46dG_?+Pn#NBdd zm5c2C6J^II)8k_ppNP}bF@J;K%v(ao>f{*s@mqN+sQ8R;$SiM~<|+BXMFff44+BiGb(!C=x=!bKRDov0~$|8AcNuw#8pppi!Zq()=wa*fC3RQdw|H8 zK0wsakoJa55Rd3BtbWN5P+!rfu9AaKV?YU*^%XM92Wc|&DlT-JKxbN|O?1Brra;gM z7zzb=rGOw6khB7Nu>e$yE-*ml&qaoPKQd~EIH~|w58)aImjyXSJ?h}19!0o}c_mod zwO0XPAvP!~GkE6AZL=sg&a4U+bTVs_S(KXS1r9Ie1s-|?{za4Ey96HE1fKc?-Zu)U zON)4PRHqqv&Z9*ruONnG5S|PokU=Ceh@K3hCxehLl%^m88N`qb!jnM;GRQ;**^>dq zE4cwB>>CV_K8s{$A!U*5vk0Xt9v$`Tg^u1uYN&+Zr4WJ^LJ~vh)euk))6r20zj1Ws z-Kc{bb#kNb-H7@akFNPk9bNl25cHrA1g$*W4q5EHz@*j-P>y1CMm>tv*$lJD_$)FZ zi%iNQ(`S)aqN!cl*7{mvd?lxZe81751VUp@ceOgdRZZ&`vaoQ_zER>BNlED4Nn|7? ziIJ2fMpD?#NVm^VEI!39S$Ons1$fW z8Hq|E5tTwuREnatU8;h&es<<6%GEvHfiuiYUkps$#1uxRer9?$G@%X-Q-@ON-%??L zPH!dMpv(p4)1BQsy4@Lshg&1T-UTwOXh*+{K5nYj=wx;_pXP0TS}yJA;l^(4$c1n8 z>!|A+|L0!QZ?X64u%`knJK2(PB77 h3qMASP&Z`k0I5tJAeGx4^LDA2`~#li@1qzI004rP$$$U= literal 0 HcmV?d00001 diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz new file mode 100644 index 0000000000000000000000000000000000000000..f8e07369169b9cee5cc1b6f3b5ccd6c6101f8388 GIT binary patch literal 500 zcmVgiwFq3dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*c5iHTZDn6(a&K*4b8ca9b7*gLUvG0RZ~)DdO;6k~5QgvbD-f4tB{qsb z^5I^~g+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&0p8B`o6lj9HuaL z+w;NSdP+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_}_X2Zu4rVR}1exY2+Q_0tq~pm3`S06Z&2C!lk2njg2Lr{T$l~i))$dhx zUAMchi+!`I{72nxyMBLD_wBygiR!qn*W0URKkJ*W?`F6DOMBbRuG{+aZr}d-wR-RW zs&-J-i^b*5deg7Bi$&F5{=2FBYKPT_en-{6cCtFY+NtXN)nZxKP1h~z_Ga6^s&+d3 zV5-jl@@2WXX*z$+hHK8>{M-Av{|X{}2k;k;FZ}-({^ND{{AF_VE&O}kZr7iiefab3 zBz(SkGkddd+y2e%^*Vh2e)Kxreevqs_lsArLrAQSH#?we5`{QUOubmYcLtBnC;A0&oUz(e{F4;hb#;>+ED zM~Z|;0^?aV{km_i8It7HOY%R6@KuJWQdPfxQ|e4PJUf|+6K$u`o}5ijP5`I+%%Xu) zeL_xu_fP0**>&Az`nX&k0FnWajBihXR0gE{ZIKj(kCHOK8aa6$ss{;E6qcssAz?~+ zd@8~+37^gQJmkob_Suc(XgG|Z(MQm{2rY*QTBQhD`*rPZcmo-}5Q_8o=$KbI0zA44 zRdcl(QGGa|w&d1?@-+<4r1CYne2q%n8vQ7@r%hMy*Smh*Zby?rq9|G!KDaJ z_~rfm&t1C@EISAh93Dn+LE0Q^n^Qvsr*j08sB+K9j^pfrD8vLrNCyaB3y72u5IG|t zR9Y(tofZqiRCCbaltJUuSL~)c-&oX6*WG89S{omB1q!dh9);InR$@#jyn-ea5cKCm zbL+)shy|=A0J@B2IM(o3+P;8!{{rR>42Vxu*_Uds3xoq5DE$L{@g(U)6hRdc1GPxqiY>VLc zK-veA@;;CyZIWq|!{eDYInpM%_xN}k;CNRFQM{$hvvXFLUVDqI#)^1U71hE`E*0Llur~n zpD3~jqrjh|1bxKTq@Xap+5a0g^r zBlM^dVQNX0=iTLr%F~=m9aE`uD)pF3o!e!M)67dOJ+k!T?E$D4&mCDW1Gs?}zS9#02Z=BrB|D)}CzA+vy*n6i7 zjLAk!E@N^drZDIXxnQe#I2YkPAC}k6n27Zs+nF~GF$FPe_p4dEYqnj#tUtf~-%~V{ zmn)_>bea!IOhjq(D)IzJVU`-Ilf0W9T4QAEXAhL>_4OBg_~b-jd{J?zL?WCjkx&s* zI#(iLMx3@P_lu_^JQa_=2p}HrFGc{nYH6Nl4%1uajXE`ah3P{EDMrUXNqYH$GG;nFOv|f}(B-EOQdi z#V{X?;hmE)95e1+k@aZUrG)t)fUu|~!ca?uCf;asX5NIWLX`O ht3$@>P`NtPSRLw4b$FvK^q{+({TGTF!x9M>005zToP+=X literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..f3f75ab7bfff404c649cbde29973e17626d41747 GIT binary patch literal 439 zcmV;o0Z9HIiwFq1dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUt@A*VRU6*c5iHTZDn6?b1rZI%~8v0!!QuM?^lFe>_B2HDSoKe=8{8uXrL#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|DvKc1FQ)7ie-%^I^cu5COTjt4Gyd3EOqk%3Qw zkz?jg8;xNe6R3C-GZaifdm2~>9k~&K^s%eplo@?2!GqQ$mUNsgBl{qN%?O)1uvqT8?r2@}cW;koC2oaA{`Kc|f?h+Fb%-*(L*@2ZB> zl+5zH+~3<~(b=|Z7f1I{9oxmO${*{d`u&;QxW7mZBu~@3L%HqBeVUT$?l+rvq-Nx{ zt2z0l7G!o`OR~O5vplzLo95MF-(8Se;Rl+u?vtl%d$6s0m*6|&How1FxksS*4B%eO zHtu`lmP=gUOs1dk_paKPkG8=-uP3-(T`jJfs_L$eyAq#2PcL!z=Hk=m&BY}`GBVrN zz)9h-3m}Cj3c@i3>2Fh{@YKL@D?A}ckkPwzS+CAF!%;M?cK3p9xZu6$B zyRzC3H-8Px0I@Fru&e#e4=>L%@wYkU61C*&TuZKX(yR2>f5`NB3 z3x>7p1r{Qnmi=jWS11E9%Amju3ZFq4GbsBEN=Ay1HOaq_wf`XAU&N6DX-aucQz}PO zYR@EzG)<(bs4ujw-TOLIfDnq26_Ar!W4RQzy7IlQtQreThZC`|lD@DKh_NQ@8^xM%vVr z7?@Ab<}&rdyB;UEu`T<>Pv4)aw(}c#*fsk%x)SZ2HJ=0^o^+jps(fz@43x( zc1TS5alc>`=p5*xYKlcwTj!Kn{&@YbQw9*ib#`z{gMUhbaQD>Qu@!PxA;yB!3(gWm68Fg$RMH*OqY%Ae92M=(}%g2Ll zp7C~Peg5THBTd(?zVdGJ-Q+`4?Iv$mH|a9#vLDN>og5!*V<(us$@i0!d;QOj=dYN) zxg4C!iRad_l01|xAD1onWy^ySyf0fml&yEKkZ|W;el8WESHZbh5&9IwxRQjgBoQh} z^pzxrN^;&6yA>Ha>+(Qm1mt`S|2Yb|KnDvz&cPy(^O)FJQhr6ROaIRgNIkwO@i&F3 bp`v|)>irX(37y;a%VqH=JrsTc&k6tl2>cki literal 0 HcmV?d00001 diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz new file mode 100644 index 0000000000000000000000000000000000000000..50522d795339377094bd297adbc667aee25032ed GIT binary patch literal 441 zcmV;q0Y?5GiwFq5dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUu0!$Wprg}is$a!#{KvY7K|zh3z@zFUgseku10oPaAMe>w`uSbWVF=6qq^7xwN8 j`|yP&*mlO!f8YnpoF6Rz8$bBP4}7CHMw$0pdjkLfV?xa~ literal 0 HcmV?d00001 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 new file mode 100644 index 0000000000000000000000000000000000000000..6013757f213890e0f0958d1d57bee14997087f69 GIT binary patch literal 1502 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 literal 0 HcmV?d00001 diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz new file mode 100644 index 0000000000000000000000000000000000000000..0bc36f2545504da5b2e625c7d88e622cc7423460 GIT binary patch literal 447 zcmV;w0YLsAiwFq7dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUukY>bZKF1X?kT}V{dM5Wn*+{Z*E_2b1rZI%~8v0!!QuM?^lFe>_B2HDSoKe=8{8u 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|DvKc1FQ)7ie-%^I^cu5COTjt4Gy zd3EOqk%3Qwkz?jg8;xNe6R3C-GZaifdm2~>9k~&K^s%eplo@?2!Go literal 0 HcmV?d00001 diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz new file mode 100644 index 0000000000000000000000000000000000000000..273068866047d89c1d5aa1f6555355b7b3ca05c6 GIT binary patch literal 1976 zcmV;p2S@lHiwFq7dsk2b|8!+@bYFLAZe(wFb1qb6b97f}Ze(wFb3}4!c4cxdbY*jN zUukY>bZKF1X?kT}V{dM5Wn*+{Z*E_AZD}rW0Nq$kZyPrdz3;COe6dqh3OW1^&_i3J zs17#LI!G@D1ZA~RwwAQY?%J*!Hc^`rvTp@y)#9lx4HOS+v!< z@Qm&+z&6>9}k}4x6cnhd^|sVh9;pn+U&U~*53A-7i)5qOYbRHw3{y0RSi{t95 zE~}Tz{#|0m@r(29r#}1sZ2r1#`^)79z3cKXaORX{Tu&?R^i)D6rmiw?r)p&#m}MoH zbF-^=tFU$0xGURw-`CA9?feuo$;4Uxdo|yke0O_2$OpNs6k@6LT`ZOHSgHV=8?e-D z#8P`y$HVo%cUEffD>Z?u<+xJCm42Uqyf%*@{|^AT7oaBc>x}#c$#01KW+cCf1Cb>6C_f@Aq$)xv1i3Mv7|SfeB^x2l+P&Xr`&_W7A;{TB5woC~uMSmMHH=%DYH;2O)0;6HcHBC-0hY%A0Uur5R1wXu^%>#TonL zf#C+H%WaiTtA4+m0po1S*{o^Tvu0m;U09YEFaGv9a>l9ZGRVp1~1iEd6|x- zmzhuVl`~7rT~LV;MSm=Dxi9x42wZ$&5I7OXb0!19D~^xC%ME#HV-zk%fjSdN%)P{{ z1A#f@Xab=L0ZoW#LPC=i=iAjPmSZ0Dh35jpNnv=97#=l-Cz0Wv^&_-G4bUDCxG66P zWYU>)0>VFYRD=$KY;p(aY(+R*8P8Uxv-P5Ln;I$mGHEANWI#nmRAfR0)o6%B+DA#U z``1Y#No2XoRF*4F9SZ3zSEJB+oMRMT4MvinBn%``Ij)LuRRLEWan%V|jkV|1vh^i& z{?jQsrK$XIFAA?QX6_uHGBqok?QC0@ZPPVx`xm}JoYwEv&O&wJIye1i=uCTZ05?|; zSJ#(K+b=idUZ9Z9L)8?j4xySDs!5@mR341@^B#$tkisTUVM8fwLJFIh!X~A#O(|?s z3fnw|Es@m*vf4;io5*T0g)w&Y$A;|nGBOw74-=vB>D~H1o0?QcAA4DO?GJ&?_zX+1 ze*^A8dM|ApdE$a6E_&jUC#X50C*&>@Q_m3Wgc-@HC&AbYvnZ(GOaA~pF!`DK31BL; z?ODqN%#gc-XJgj{Jhn|hmypF`Q|+jwfN+lhFDi3>3(V{~fY%BL_X>y?3rIH$z;ZvJ zz}@FU0f-iWQgX*#0J^>ecVO%Q0b&aXphp&imy&_S05&&7r!T_ki+K7XoxZ?qJFYfW zUlE)_hPTxdZbU&bz$?a`s|r2VcK9%NNsvo2xFn-XGPxuZA*KAXtpdovQMse zaO9~S1Q`l$yU@wQ1%NWqQZq+=QnOmS8g5d+&W&mb-H!y zsEeSZEe=DX)wa2+zTIp>`_<8R0$)w; zjv;qUaK}b>Y;wm&?E?E0Z^FF=Y^GgcQMjt{pyt7^0H?K@j_HxIMc4bz)@;~Sda zurR=3ae~9r2*+#Un8$*tNAg%OO}0!}W}~fmegbbs0c!EcEbYGywHUCK&k{W!oDK*T7^1Rv zPAF{Wgl1v7J+^Z~$97I&FED1c?*=HVNA6Ke5G?Dg#S+?(<-y346F6*H7|~~9D=dnwu)&fY#a7rTwgT^u4=cET%>Dpa KLu4uj8UO%s2+F_B2HDSoKe=8{8uXrL#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|DvKc1FQ)7ie-%^I^cu5COTjt4Gyd3EOqk%3Qw zkz?jg8;xNe6R3C-GZaifdm2~>9k~&K^s%eplo@?2!GTzMXwD^WJP(*1M1S-mNl!DeG<1?r+Ps z-e)_O9hPOay>|OW>zcM%-20pQzFBPQ@@BWMKYYy2{D0XFvNF%FZmV@$ZSy>d}jT_Z_bwf z7Ff6k@E;sr`rk``ISSWjv-zj+cT;bx8@CVtKA(l_$;skmU)Sx){iX`{pXW#6>C1yp zpDz!N0wiXK>mBfH<*`?gtte0sK2nghn#xub8u-{&6cCsY(d+!QYHk9A4G_r25C|Ru zF+7jFgFw+kU|`_f-M@L=fuJG~JpnNR#D+IG>p(d4ARGgYd0DL2dG0Ydr%%PB^qji8 zs&u~=?Yn`Y)906ypX%b}#qzgm-`*DM5M48U0GO4AfjV|z)v-XwkFC>hkL9(os0+uL zwTruV*Kz5%a8vH9U0c=LVdba53=kL9A8xrl`{~Q~Q9PJaE(4cbjk)C7bIBudw&PN; zo=f3by(*f9E?33qO@X0qiCiK2H)VR$uM?RU`Y)LO4+MO*L1DrMg&l8DG9RV{>M!iV zl)Mj93M!VBYpd36s9q!$xK#cN7H)Mwm1cr!J*uL{Q_!I*>`@h`RyYm)E5hqaW=oJ( zfi*^%tY`*S!-e|hm%5>br;=Bbl2@VR6_vd1OJ1jv*BJYzgU~!cXfcM+(nIL@rtTq3 zg0OwQ40|+R0sp+%xFK29`|Sc5uw!70dcRuKJLl!GC~uzs>ogh&(Hk5`Z-Po1l1U@G z=#A>5H~R59HGw)q)Y+aoo2awc@7wb4yKhUCV&!<>R{7|yrT|SJy-k|S{ElM50`srL zV)YU*5pEXP1192wJ%7N|02I3P#r1WPUSK9-P5KESG!y_t)9G6ZAoUb@pXfLRkR7RW zqIKv2qW5SXRm@Z1uTu{K>I48i4Zu(Ulu^JwrGP1?;0@->au_;o41~lAMpiJff&(kT zdAgmT`M%`=Xrm`j92I!5RN&;Pzp{E&DVf}W4U7i2%+ec{~a;^N?y+thdN#d;kpuAygQWWr464oiba zoO5Kaw;+??f>-oDQSvF#$QX^BxFJYQD|Mi~A%aSd2nrslt*`4#1&0I`!%`xF$pOr- z9|t9vDn5|pL)3goq7Q@WgHGB7ntvmc1x+#qdZJUHgHVCiF&vY^9khy!CC}GxOFj!x z=)o)f627p+F)ZmmMB#^|{4hvAn4w3F`Bp5Lm^3?WMoZ0TV>8;+jCN>7J2aymn$b?P zZz=nhvX89KzSopAD+iJ9IuIHE`$D3q?80xYt4Q>ovSgznjb^ledbld9%^f}*Cw2=> zd>YA-Fgg+@N5a985NXnxyhZ1scp$=bBEsQFgmfl)f9v)i!|GkO#z&(0h1d16o&7L- zyRSF1m&>#Kv}lW;tF@cmzjJ#x3+bEvIO~o(|ML-vmY6>~8jd;-4ha}fH8?%iAf0QF zciT^OI~;A$`&!Dl=rpM7O!RHlbtZ~wEeWb6(cz_95<@Ksn`|YJ0$zTsC zV=`oK4=Cku98QNQl==xBE=^o%GP0oxBO59j*--T(8>%$2p?9apT&=lU{0YB1c>Dno F008 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 = FLAGS.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/windows.py b/cinder/volume/windows.py new file mode 100644 index 000000000..28dbdbcdc --- /dev/null +++ b/cinder/volume/windows.py @@ -0,0 +1,232 @@ +# 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 +import sys + +from cinder import exception +from cinder import flags +from cinder.openstack.common import cfg +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("cinder.volume.windows.volume") + +FLAGS = flags.FLAGS + +windows_opts = [ + cfg.StrOpt('windows_iscsi_lun_path', + default='C:\iSCSIVirtualDisks', + help='Path to store VHD backed volumes'), +] + +FLAGS.register_opts(windows_opts) + + +class WindowsDriver(driver.ISCSIDriver): + """Executes volume driver commands on Windows Storage server.""" + + def __init__(self): + super(WindowsDriver, self).__init__() + + 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): + """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'] + #DesAssigning target to initiators + wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=volume['name'], + Method=4, + Value=initiator_name) + 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 = FLAGS.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" % (FLAGS.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'] + wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[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" % (FLAGS.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_() -- 2.45.2