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)
{'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)
# 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)
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)
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"
"""
-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()
+++ /dev/null
-# 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)
"""
-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', }
+++ /dev/null
-# 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
+++ /dev/null
-Files with extension p.gz are compressed pickle files containing serialized
-mocks used during unit testing
+++ /dev/null
-# 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_()
+++ /dev/null
-# 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()
--- /dev/null
+# 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.
--- /dev/null
+# 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)
--- /dev/null
+# 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)
'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':
#
-# Options defined in cinder.volume.drivers.windows
+# Options defined in cinder.volume.drivers.windows.windows
#
# Path to store VHD backed volumes (string value)