]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add support for Havana missing features in Windows driver
authorPedro Navarro Perez <pednape@gmail.com>
Mon, 26 Aug 2013 11:09:41 +0000 (13:09 +0200)
committerPedro Navarro Perez <pednape@gmail.com>
Sun, 1 Sep 2013 06:20:24 +0000 (08:20 +0200)
The following features were added:

-copy_volume_to_image (Havana)
-copy_image_to_volume (Havana)
-get_volume_stats (Havana)
-extend_volume (Icehouse)

The test mocking based on binary pickled files were replaced by mox.

Change-Id: I92c681280d6f7b85bcba7a5e3513f2bdb6c13f1d
Implements: blueprint windows-storage-driver-extended

33 files changed:
cinder/image/image_utils.py
cinder/tests/test_drivers_compatibility.py
cinder/tests/test_windows.py
cinder/tests/windows/basetestcase.py [deleted file]
cinder/tests/windows/db_fakes.py
cinder/tests/windows/mockproxy.py [deleted file]
cinder/tests/windows/stubs/README.rst [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz [deleted file]
cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz [deleted file]
cinder/tests/windows/windowsutils.py [deleted file]
cinder/volume/drivers/windows.py [deleted file]
cinder/volume/drivers/windows/__init__.py [new file with mode: 0644]
cinder/volume/drivers/windows/windows.py [new file with mode: 0644]
cinder/volume/drivers/windows/windows_utils.py [new file with mode: 0644]
cinder/volume/manager.py
etc/cinder/cinder.conf.sample

index 2f638ae64d8bff499a85285bc7d71cc066a6cf74..032919595f6ed0d6a83ddd6e79307c48f2cb024d 100644 (file)
@@ -183,9 +183,10 @@ class QemuImgInfo(object):
 
 def qemu_img_info(path):
     """Return a object containing the parsed output from qemu-img info."""
-    out, err = utils.execute('env', 'LC_ALL=C', 'LANG=C',
-                             'qemu-img', 'info', path,
-                             run_as_root=True)
+    cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path)
+    if os.name == 'nt':
+        cmd = cmd[3:]
+    out, err = utils.execute(*cmd, run_as_root=True)
     return QemuImgInfo(out)
 
 
@@ -232,9 +233,23 @@ def fetch_verify_image(context, image_service, image_id, dest,
                         {'fmt': fmt, 'backing_file': backing_file}))
 
 
+def fetch_to_vhd(context, image_service,
+                 image_id, dest,
+                 user_id=None, project_id=None):
+    fetch_to_volume_format(context, image_service, image_id, dest, 'vpc',
+                           user_id, project_id)
+
+
 def fetch_to_raw(context, image_service,
                  image_id, dest,
                  user_id=None, project_id=None):
+    fetch_to_volume_format(context, image_service, image_id, dest, 'raw',
+                           user_id, project_id)
+
+
+def fetch_to_volume_format(context, image_service,
+                           image_id, dest, volume_format,
+                           user_id=None, project_id=None):
     if (CONF.image_conversion_dir and not
             os.path.exists(CONF.image_conversion_dir)):
         os.makedirs(CONF.image_conversion_dir)
@@ -273,22 +288,29 @@ def fetch_to_raw(context, image_service,
         # check via 'qemu-img info' that what we copied was in fact a raw
         # image and not a different format with a backing file, which may be
         # malicious.
-        LOG.debug("%s was %s, converting to raw" % (image_id, fmt))
-        convert_image(tmp, dest, 'raw')
+        LOG.debug("%s was %s, converting to %s " % (image_id, fmt,
+                                                    volume_format))
+        convert_image(tmp, dest, volume_format)
 
         data = qemu_img_info(dest)
-        if data.file_format != "raw":
+        if data.file_format != volume_format:
             raise exception.ImageUnacceptable(
                 image_id=image_id,
-                reason=_("Converted to raw, but format is now %s") %
-                data.file_format)
+                reason=_("Converted to %(vol_format)s, but format is "
+                         "now %(file_format)s") % {'vol_format': volume_format,
+                                                   'file_format': data.
+                                                   file_format})
 
 
-def upload_volume(context, image_service, image_meta, volume_path):
+def upload_volume(context, image_service, image_meta, volume_path,
+                  volume_format='raw'):
     image_id = image_meta['id']
-    if (image_meta['disk_format'] == 'raw'):
-        LOG.debug("%s was raw, no need to convert to %s" %
-                  (image_id, image_meta['disk_format']))
+    if (image_meta['disk_format'] == volume_format):
+        LOG.debug("%s was %s, no need to convert to %s" %
+                  (image_id, volume_format, image_meta['disk_format']))
+        if os.name == 'nt':
+            with fileutils.file_open(volume_path) as image_file:
+                image_service.update(context, image_id, {}, image_file)
         with utils.temporary_chown(volume_path):
             with fileutils.file_open(volume_path) as image_file:
                 image_service.update(context, image_id, {}, image_file)
@@ -301,8 +323,8 @@ def upload_volume(context, image_service, image_meta, volume_path):
     fd, tmp = tempfile.mkstemp(dir=CONF.image_conversion_dir)
     os.close(fd)
     with fileutils.remove_path_on_error(tmp):
-        LOG.debug("%s was raw, converting to %s" %
-                  (image_id, image_meta['disk_format']))
+        LOG.debug("%s was %s, converting to %s" %
+                  (image_id, volume_format, image_meta['disk_format']))
         convert_image(volume_path, tmp, image_meta['disk_format'])
 
         data = qemu_img_info(tmp)
index d9c6cd9dd58ffaf2e7c25e1b8108b829d1880b23..1082fe7e0be6177a390db2a242f6075e806fa8da 100644 (file)
@@ -32,7 +32,7 @@ LEFTHAND_MODULE = "cinder.volume.drivers.san.hp_lefthand.HpSanISCSIDriver"
 NFS_MODULE = "cinder.volume.drivers.nfs.NfsDriver"
 SOLIDFIRE_MODULE = "cinder.volume.drivers.solidfire.SolidFireDriver"
 STORWIZE_SVC_MODULE = "cinder.volume.drivers.storwize_svc.StorwizeSVCDriver"
-WINDOWS_MODULE = "cinder.volume.drivers.windows.WindowsDriver"
+WINDOWS_MODULE = "cinder.volume.drivers.windows.windows.WindowsDriver"
 XIV_DS8K_MODULE = "cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver"
 ZADARA_MODULE = "cinder.volume.drivers.zadara.ZadaraVPSAISCSIDriver"
 NETAPP_MODULE = "cinder.volume.drivers.netapp.common.Deprecated"
index 05b1907aea82032d2c4a55d5befa37bc01365dd3..af969739547d5bd02fefd686bf5aa89c6956b11e 100644 (file)
@@ -20,205 +20,365 @@ Unit tests for Windows Server 2012 OpenStack Cinder volume driver
 """
 
 
-import sys
+import os
 
 from oslo.config import cfg
 
-from cinder.tests.windows import basetestcase
+import mox as mox_lib
+from mox import IgnoreArg
+from mox import stubout
+
+from cinder import test
+
+from cinder.image import image_utils
+
 from cinder.tests.windows import db_fakes
-from cinder.tests.windows import windowsutils
-from cinder.volume.drivers import windows
+from cinder.volume import configuration as conf
+from cinder.volume.drivers.windows import windows
+from cinder.volume.drivers.windows import windows_utils
 
 
 CONF = cfg.CONF
 
 
-class TestWindowsDriver(basetestcase.BaseTestCase):
+class TestWindowsDriver(test.TestCase):
 
     def __init__(self, method):
         super(TestWindowsDriver, self).__init__(method)
 
     def setUp(self):
         super(TestWindowsDriver, self).setUp()
+        self._mox = mox_lib.Mox()
+        self.stubs = stubout.StubOutForTesting()
         self.flags(
             windows_iscsi_lun_path='C:\iSCSIVirtualDisks',
         )
-        self._volume_data = None
-        self._volume_data_2 = None
-        self._snapshot_data = None
-        self._connector_data = None
-        self._volume_id = '10958016-e196-42e3-9e7f-5d8927ae3099'
-        self._volume_id_2 = '20958016-e196-42e3-9e7f-5d8927ae3098'
-        self._snapshot_id = '30958016-e196-42e3-9e7f-5d8927ae3097'
-        self._iqn = "iqn.1991-05.com.microsoft:dell1160dsy"
-
         self._setup_stubs()
+        configuration = conf.Configuration(None)
+        configuration.append_config_values(windows.windows_opts)
+
+        self._driver = windows.WindowsDriver(configuration=configuration)
+        self._driver.do_setup({})
 
-        self._drv = windows.WindowsDriver()
-        self._drv.do_setup({})
-        self._wutils = windowsutils.WindowsUtils()
+    def tearDown(self):
+        self._mox.UnsetStubs()
+        self.stubs.UnsetAll()
+        super(TestWindowsDriver, self).tearDown()
 
     def _setup_stubs(self):
 
-        # Modules to mock
-        modules_to_mock = [
-            'wmi',
-            'os',
-            'subprocess',
-            'multiprocessing'
-        ]
+        def fake_wutils__init__(self):
+            pass
+        windows_utils.WindowsUtils.__init__ = fake_wutils__init__
 
-        modules_to_test = [
-            windows,
-            windowsutils,
-            sys.modules[__name__]
-        ]
+    def fake_local_path(self, volume):
+            return os.path.join(CONF.windows_iscsi_lun_path,
+                                str(volume['name']) + ".vhd")
 
-        self._inject_mocks_in_modules(modules_to_mock, modules_to_test)
+    def test_check_for_setup_errors(self):
+        mox = self._mox
+        drv = self._driver
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'check_for_setup_error')
+        windows_utils.WindowsUtils.check_for_setup_error()
 
-    def tearDown(self):
-        try:
-            if (self._volume_data_2 and
-                    self._wutils.volume_exists(self._volume_data_2['name'])):
-                self._wutils.delete_volume(self._volume_data_2['name'])
-
-            if (self._volume_data and
-                    self._wutils.volume_exists(
-                        self._volume_data['name'])):
-                self._wutils.delete_volume(self._volume_data['name'])
-            if (self._snapshot_data and
-                    self._wutils.snapshot_exists(
-                        self._snapshot_data['name'])):
-                self._wutils.delete_snapshot(self._snapshot_data['name'])
-            if (self._connector_data and
-                    self._wutils.initiator_id_exists(
-                        "%s%s" % (CONF.iscsi_target_prefix,
-                                  self._volume_data['name']),
-                        self._connector_data['initiator'])):
-                target_name = "%s%s" % (CONF.iscsi_target_prefix,
-                                        self._volume_data['name'])
-                initiator_name = self._connector_data['initiator']
-                self._wutils.delete_initiator_id(target_name, initiator_name)
-            if (self._volume_data and
-                    self._wutils.export_exists("%s%s" %
-                                               (CONF.iscsi_target_prefix,
-                                                self._volume_data['name']))):
-                self._wutils.delete_export(
-                    "%s%s" % (CONF.iscsi_target_prefix,
-                              self._volume_data['name']))
-
-        finally:
-            super(TestWindowsDriver, self).tearDown()
+        mox.ReplayAll()
 
-    def test_check_for_setup_errors(self):
-        self._drv.check_for_setup_error()
+        drv.check_for_setup_error()
+
+        mox.VerifyAll()
 
     def test_create_volume(self):
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+        vol = db_fakes.get_fake_volume_info()
+
+        self.stubs.Set(drv, 'local_path', self.fake_local_path)
 
-        wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
-        self.assertEquals(len(wt_disks), 1)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_volume')
 
-    def _create_volume(self):
-        self._volume_data = db_fakes.get_fake_volume_info(self._volume_id)
-        self._drv.create_volume(self._volume_data)
+        windows_utils.WindowsUtils.create_volume(self.fake_local_path(vol),
+                                                 vol['name'], vol['size'])
+
+        mox.ReplayAll()
+
+        drv.create_volume(vol)
+
+        mox.VerifyAll()
 
     def test_delete_volume(self):
-        self._create_volume()
+        """delete_volume simple test case."""
+        mox = self._mox
+        drv = self._driver
+
+        vol = db_fakes.get_fake_volume_info()
+
+        mox.StubOutWithMock(drv, 'local_path')
+        drv.local_path(vol).AndReturn(self.fake_local_path(vol))
 
-        self._drv.delete_volume(self._volume_data)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'delete_volume')
+        windows_utils.WindowsUtils.delete_volume(vol['name'],
+                                                 self.fake_local_path(vol))
+        mox.ReplayAll()
 
-        wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
-        self.assertEquals(len(wt_disks), 0)
+        drv.delete_volume(vol)
+
+        mox.VerifyAll()
 
     def test_create_snapshot(self):
-        #Create a volume
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_snapshot')
+        volume = db_fakes.get_fake_volume_info()
+        snapshot = db_fakes.get_fake_snapshot_info()
+
+        self.stubs.Set(drv, 'local_path', self.fake_local_path(snapshot))
+
+        windows_utils.WindowsUtils.create_snapshot(volume['name'],
+                                                   snapshot['name'])
 
-        wt_disks = self._wutils.find_vhd_by_name(self._volume_data['name'])
-        self.assertEquals(len(wt_disks), 1)
-        #Create a snapshot from the previous volume
-        self._create_snapshot()
+        mox.ReplayAll()
 
-        snapshot_name = self._snapshot_data['name']
-        wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name)
-        self.assertEquals(len(wt_snapshots), 1)
+        drv.create_snapshot(snapshot)
 
-    def _create_snapshot(self):
-        volume_name = self._volume_data['name']
-        snapshot_id = self._snapshot_id
-        self._snapshot_data = db_fakes.get_fake_snapshot_info(volume_name,
-                                                              snapshot_id)
-        self._drv.create_snapshot(self._snapshot_data)
+        mox.VerifyAll()
 
     def test_create_volume_from_snapshot(self):
-        #Create a volume
-        self._create_volume()
-        #Create a snapshot from the previous volume
-        self._create_snapshot()
+        mox = self._mox
+        drv = self._driver
+
+        snapshot = db_fakes.get_fake_snapshot_info()
+        volume = db_fakes.get_fake_volume_info()
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_volume_from_snapshot')
+        windows_utils.WindowsUtils.\
+            create_volume_from_snapshot(volume['name'], snapshot['name'])
 
-        self._volume_data_2 = db_fakes.get_fake_volume_info(self._volume_id_2)
+        mox.ReplayAll()
 
-        self._drv.create_volume_from_snapshot(self._volume_data_2,
-                                              self._snapshot_data)
+        drv.create_volume_from_snapshot(volume, snapshot)
 
-        wt_disks = self._wutils.find_vhd_by_name(self._volume_data_2['name'])
-        self.assertEquals(len(wt_disks), 1)
+        mox.VerifyAll()
 
     def test_delete_snapshot(self):
-        #Create a volume
-        self._create_volume()
-        #Create a snapshot from the previous volume
-        self._create_snapshot()
+        mox = self._mox
+        drv = self._driver
 
-        self._drv.delete_snapshot(self._snapshot_data)
+        snapshot = db_fakes.get_fake_snapshot_info()
 
-        snapshot_name = self._snapshot_data['name']
-        wt_snapshots = self._wutils.find_snapshot_by_name(snapshot_name)
-        self.assertEquals(len(wt_snapshots), 0)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'delete_snapshot')
+        windows_utils.WindowsUtils.delete_snapshot(snapshot['name'])
+
+        mox.ReplayAll()
+
+        drv.delete_snapshot(snapshot)
+
+        mox.VerifyAll()
 
     def test_create_export(self):
-        #Create a volume
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+
+        initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
 
-        retval = self._drv.create_export({}, self._volume_data)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_iscsi_target')
+        windows_utils.WindowsUtils.create_iscsi_target(initiator_name,
+                                                       IgnoreArg())
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'add_disk_to_target')
+        windows_utils.WindowsUtils.add_disk_to_target(volume['name'],
+                                                      initiator_name)
 
-        volume_name = self._volume_data['name']
-        self.assertEquals(
-            retval,
-            {'provider_location': "%s%s" % (CONF.iscsi_target_prefix,
-                                            volume_name)})
+        mox.ReplayAll()
+
+        export_info = drv.create_export(None, volume)
+
+        mox.VerifyAll()
+
+        self.assertEquals(export_info['provider_location'], initiator_name)
 
     def test_initialize_connection(self):
-        #Create a volume
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+        initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
+
+        connector = db_fakes.get_fake_connector_info()
 
-        self._drv.create_export({}, self._volume_data)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'associate_initiator_with_iscsi_target')
+        windows_utils.WindowsUtils.associate_initiator_with_iscsi_target(
+            volume['provider_location'], initiator_name, )
 
-        self._connector_data = db_fakes.get_fake_connector_info(self._iqn)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'get_host_information')
+        windows_utils.WindowsUtils.get_host_information(
+            volume, volume['provider_location'])
 
-        init_data = self._drv.initialize_connection(self._volume_data,
-                                                    self._connector_data)
-        target_name = self._volume_data['provider_location']
-        initiator_name = self._connector_data['initiator']
+        mox.ReplayAll()
 
-        wt_initiator_ids = self._wutils.find_initiator_ids(target_name,
-                                                           initiator_name)
-        self.assertEquals(len(wt_initiator_ids), 1)
+        drv.initialize_connection(volume, connector)
 
-        properties = init_data['data']
-        self.assertNotEqual(properties['target_iqn'], None)
+        mox.VerifyAll()
+
+    def test_terminate_connection(self):
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+        initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
+        connector = db_fakes.get_fake_connector_info()
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'delete_iscsi_target')
+        windows_utils.WindowsUtils.delete_iscsi_target(
+            initiator_name, volume['provider_location'])
+
+        mox.ReplayAll()
+
+        drv.terminate_connection(volume, connector)
+
+        mox.VerifyAll()
 
     def test_ensure_export(self):
-        #Create a volume
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+
+        initiator_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_iscsi_target')
+        windows_utils.WindowsUtils.create_iscsi_target(initiator_name, True)
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'add_disk_to_target')
+        windows_utils.WindowsUtils.add_disk_to_target(volume['name'],
+                                                      initiator_name)
+
+        mox.ReplayAll()
 
-        self._drv.ensure_export({}, self._volume_data)
+        drv.ensure_export(None, volume)
+
+        mox.VerifyAll()
 
     def test_remove_export(self):
-        #Create a volume
-        self._create_volume()
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+
+        target_name = volume['provider_location']
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'remove_iscsi_target')
+        windows_utils.WindowsUtils.remove_iscsi_target(target_name)
+
+        mox.ReplayAll()
+
+        drv.remove_export(None, volume)
+
+        mox.VerifyAll()
+
+    def test_copy_image_to_volume(self):
+        """resize_image common case usage."""
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+
+        self.stubs.Set(drv, 'local_path', self.fake_local_path)
+
+        mox.StubOutWithMock(image_utils, 'fetch_to_vhd')
+        image_utils.fetch_to_vhd(None, None, None,
+                                 self.fake_local_path(volume))
+
+        mox.ReplayAll()
+
+        drv.copy_image_to_volume(None, volume, None, None)
+
+        mox.VerifyAll()
+
+    def test_copy_volume_to_image(self):
+        mox = self._mox
+        drv = self._driver
+
+        vol = db_fakes.get_fake_volume_info()
+
+        image_meta = db_fakes.get_fake_image_meta()
+
+        self.stubs.Set(drv, 'local_path', self.fake_local_path)
+
+        mox.StubOutWithMock(image_utils, 'upload_volume')
+
+        temp_vhd_path = os.path.join(CONF.image_conversion_dir,
+                                     str(image_meta['id']) + ".vhd")
+
+        image_utils.upload_volume(None, None, image_meta, temp_vhd_path, 'vpc')
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'copy_vhd_disk')
+
+        windows_utils.WindowsUtils.copy_vhd_disk(self.fake_local_path(vol),
+                                                 temp_vhd_path)
+
+        mox.ReplayAll()
+
+        drv.copy_volume_to_image(None, vol, None, image_meta)
+
+        mox.VerifyAll()
+
+    def test_create_cloned_volume(self):
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+        volume_cloned = db_fakes.get_fake_volume_info_cloned()
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'create_volume')
+
+        windows_utils.WindowsUtils.create_volume(IgnoreArg(), IgnoreArg(),
+                                                 IgnoreArg())
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils,
+                                  'copy_vhd_disk')
+        windows_utils.WindowsUtils.copy_vhd_disk(self.fake_local_path(
+            volume_cloned), self.fake_local_path(volume))
+
+        mox.ReplayAll()
+
+        drv.create_cloned_volume(volume, volume_cloned)
+
+        mox.VerifyAll()
+
+    def test_extend_volume(self):
+        mox = self._mox
+        drv = self._driver
+
+        volume = db_fakes.get_fake_volume_info()
+
+        TEST_VOLUME_ADDITIONAL_SIZE_MB = 1024
+        TEST_VOLUME_ADDITIONAL_SIZE_GB = 1
+
+        self._mox.StubOutWithMock(windows_utils.WindowsUtils, 'extend')
+
+        windows_utils.WindowsUtils.extend(volume['name'],
+                                          TEST_VOLUME_ADDITIONAL_SIZE_MB)
+
+        new_size = volume['size'] + TEST_VOLUME_ADDITIONAL_SIZE_GB
+
+        mox.ReplayAll()
 
-        self._drv.create_export({}, self._volume_data)
+        drv.extend_volume(volume, new_size)
 
-        self._drv.remove_export({}, self._volume_data)
+        mox.VerifyAll()
diff --git a/cinder/tests/windows/basetestcase.py b/cinder/tests/windows/basetestcase.py
deleted file mode 100644 (file)
index ef749f6..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#  Copyright 2012 Cloudbase Solutions Srl
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""
-TestCase for MockProxy based tests and related classes.
-"""
-
-import cinder.test
-import gzip
-import os
-import pickle
-
-from cinder.tests.windows import mockproxy
-
-gen_test_mocks_key = 'CINDER_GENERATE_TEST_MOCKS'
-
-
-class BaseTestCase(cinder.test.TestCase):
-    """TestCase for MockProxy based tests."""
-
-    def run(self, result=None):
-        self._currentResult = result
-        super(BaseTestCase, self).run(result)
-
-    def setUp(self):
-        super(BaseTestCase, self).setUp()
-        self._mps = {}
-
-    def tearDown(self):
-        super(BaseTestCase, self).tearDown()
-
-        # python-subunit will wrap test results with a decorator.
-        # Need to access the decorated member of results to get the
-        # actual test result when using python-subunit.
-        if hasattr(self._currentResult, 'decorated'):
-            result = self._currentResult.decorated
-        else:
-            result = self._currentResult
-        has_errors = len([test for (test, msgs) in result.errors
-                          if test.id() == self.id()]) > 0
-        failed = len([test for (test, msgs) in result.failures
-                      if test.id() == self.id()]) > 0
-
-        if not has_errors and not failed:
-            self._save_mock_proxies()
-
-    def _save_mock(self, name, mock):
-        path = self._get_stub_file_path(self.id(), name)
-        pickle.dump(mock, gzip.open(path, 'wb'))
-
-    def _get_stub_file_path(self, test_name, mock_name):
-        # test naming differs between platforms
-        prefix = 'cinder.tests.'
-        if test_name.startswith(prefix):
-            test_name = test_name[len(prefix):]
-        file_name = '{0}_{1}.p.gz'.format(test_name, mock_name)
-        return os.path.join(os.path.dirname(mockproxy.__file__),
-                            "stubs", file_name)
-
-    def _load_mock(self, name):
-        path = self._get_stub_file_path(self.id(), name)
-        if os.path.exists(path):
-            return pickle.load(gzip.open(path, 'rb'))
-        else:
-            return None
-
-    def _load_mock_or_create_proxy(self, module_name):
-        m = None
-        if (not gen_test_mocks_key in os.environ or
-                os.environ[gen_test_mocks_key].lower()
-                not in ['true', 'yes', '1']):
-            m = self._load_mock(module_name)
-        else:
-            module = __import__(module_name)
-            m = mockproxy.MockProxy(module)
-            self._mps[module_name] = m
-        return m
-
-    def _inject_mocks_in_modules(self, objects_to_mock, modules_to_test):
-        for module_name in objects_to_mock:
-            mp = self._load_mock_or_create_proxy(module_name)
-            for mt in modules_to_test:
-                module_local_name = module_name.split('.')[-1]
-                setattr(mt, module_local_name, mp)
-
-    def _save_mock_proxies(self):
-        for name, mp in self._mps.items():
-            m = mp.get_mock()
-            if m.has_values():
-                self._save_mock(name, m)
index a93dbc6f9bb296f7412b216751ab35a9b8faee97..45d5c07c272555f3c35ec599bd29ef5ee30f081d 100644 (file)
@@ -19,18 +19,32 @@ Stubouts, mocks and fixtures for windows volume test suite
 """
 
 
-def get_fake_volume_info(name):
-    return {'name': name,
+def get_fake_volume_info():
+    return {'name': 'volume_name',
             'size': 1,
-            'provider_location': 'iqn.2010-10.org.openstack:' + name,
+            'provider_location': 'iqn.2010-10.org.openstack:' + 'volume_name',
             'id': 1,
             'provider_auth': None}
 
 
-def get_fake_snapshot_info(volume_name, snapshot_name):
-    return {'name': snapshot_name,
-            'volume_name': volume_name, }
+def get_fake_volume_info_cloned():
+    return {'name': 'volume_name_cloned',
+            'size': 1,
+            'provider_location': 'iqn.2010-10.org.openstack:' +
+                                 'volume_name_cloned',
+            'id': 1,
+            'provider_auth': None}
+
+
+def get_fake_image_meta():
+    return {'id': '10958016-e196-42e3-9e7f-5d8927ae3099'
+            }
+
+
+def get_fake_snapshot_info():
+    return {'name': 'snapshot_name',
+            'volume_name': 'volume_name', }
 
 
-def get_fake_connector_info(initiator):
-    return {'initiator': initiator, }
+def get_fake_connector_info():
+    return {'initiator': 'iqn.2010-10.org.openstack:' + 'volume_name', }
diff --git a/cinder/tests/windows/mockproxy.py b/cinder/tests/windows/mockproxy.py
deleted file mode 100644 (file)
index 4a48532..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#  Copyright 2012 Cloudbase Solutions Srl
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-#
-
-
-"""
-Classes for dynamic generation of mock objects.
-"""
-
-import inspect
-
-
-def serialize_obj(obj):
-    if isinstance(obj, float):
-        val = str(round(obj, 10))
-    elif isinstance(obj, dict):
-        d = {}
-        for k1, v1 in obj.items():
-            d[k1] = serialize_obj(v1)
-        val = str(d)
-    elif isinstance(obj, list):
-        l1 = []
-        for i1 in obj:
-            l1.append(serialize_obj(i1))
-        val = str(l1)
-    elif isinstance(obj, tuple):
-        l1 = ()
-        for i1 in obj:
-            l1 = l1 + (serialize_obj(i1),)
-        val = str(l1)
-    else:
-        val = str(obj)
-    return val
-
-
-def serialize_args(*args, **kwargs):
-    """Workaround for float string conversion issues in Python 2.6."""
-    return serialize_obj((args, kwargs))
-
-
-class Mock(object):
-    def _get_next_value(self, name):
-        c = self._access_count.get(name)
-        if c is None:
-            c = 0
-        else:
-            c = c + 1
-        self._access_count[name] = c
-        return self._values[name][c]
-
-    def _get_next_ret_value(self, name, params):
-        d = self._access_count.get(name)
-        if d is None:
-            d = {}
-            self._access_count[name] = d
-        c = d.get(params)
-        if c is None:
-            c = 0
-        else:
-            c = c + 1
-        d[params] = c
-        return self._values[name][params][c]
-
-    def __init__(self, values):
-        self._values = values
-        self._access_count = {}
-
-    def has_values(self):
-        return len(self._values) > 0
-
-    def __getattr__(self, name):
-        if name.startswith('__') and name.endswith('__'):
-            return object.__getattribute__(self, name)
-        else:
-            if isinstance(self._values[name], dict):
-                def newfunc(*args, **kwargs):
-                    params = serialize_args(args, kwargs)
-                    return self._get_next_ret_value(name, params)
-                return newfunc
-            else:
-                return self._get_next_value(name)
-
-    def __str__(self):
-        return self._get_next_value('__str__')
-
-    def __iter__(self):
-        return getattr(self._get_next_value('__iter__'), '__iter__')()
-
-    def __len__(self):
-        return self._get_next_value('__len__')
-
-    def __getitem__(self, key):
-        return self._get_next_ret_value('__getitem__', str(key))
-
-    def __call__(self, *args, **kwargs):
-        params = serialize_args(args, kwargs)
-        return self._get_next_ret_value('__call__', params)
-
-
-class MockProxy(object):
-    def __init__(self, wrapped):
-        self._wrapped = wrapped
-        self._recorded_values = {}
-
-    def _get_proxy_object(self, obj):
-        if (hasattr(obj, '__dict__') or
-                isinstance(obj, tuple) or
-                isinstance(obj, list) or
-                isinstance(obj, dict)):
-            p = MockProxy(obj)
-        else:
-            p = obj
-        return p
-
-    def __getattr__(self, name):
-        if name in ['_wrapped']:
-            return object.__getattribute__(self, name)
-        else:
-            attr = getattr(self._wrapped, name)
-            if (inspect.isfunction(attr) or
-                    inspect.ismethod(attr) or
-                    inspect.isbuiltin(attr)):
-                def newfunc(*args, **kwargs):
-                    result = attr(*args, **kwargs)
-                    p = self._get_proxy_object(result)
-                    params = serialize_args(args, kwargs)
-                    self._add_recorded_ret_value(name, params, p)
-                    return p
-                return newfunc
-            elif (hasattr(attr, '__dict__') or
-                  (hasattr(attr, '__getitem__') and not
-                  (isinstance(attr, str) or isinstance(attr, unicode)))):
-                p = MockProxy(attr)
-            else:
-                p = attr
-            self._add_recorded_value(name, p)
-            return p
-
-    def __setattr__(self, name, value):
-        if name in ['_wrapped', '_recorded_values']:
-            object.__setattr__(self, name, value)
-        else:
-            setattr(self._wrapped, name, value)
-
-    def _add_recorded_ret_value(self, name, params, val):
-        d = self._recorded_values.get(name)
-        if d is None:
-            d = {}
-            self._recorded_values[name] = d
-        l = d.get(params)
-        if l is None:
-            l = []
-            d[params] = l
-        l.append(val)
-
-    def _add_recorded_value(self, name, val):
-        if name not in self._recorded_values:
-            self._recorded_values[name] = []
-        self._recorded_values[name].append(val)
-
-    def get_mock(self):
-        values = {}
-        for k, v in self._recorded_values.items():
-            if isinstance(v, dict):
-                d = {}
-                values[k] = d
-                for k1, v1 in v.items():
-                    l = []
-                    d[k1] = l
-                    for i1 in v1:
-                        if isinstance(i1, MockProxy):
-                            l.append(i1.get_mock())
-                        else:
-                            l.append(i1)
-            else:
-                l = []
-                values[k] = l
-                for i in v:
-                    if isinstance(i, MockProxy):
-                        l.append(i.get_mock())
-                    elif isinstance(i, dict):
-                        d = {}
-                        for k1, v1 in v.items():
-                            if isinstance(v1, MockProxy):
-                                d[k1] = v1.get_mock()
-                            else:
-                                d[k1] = v1
-                        l.append(d)
-                    elif isinstance(i, list):
-                        l1 = []
-                        for i1 in i:
-                            if isinstance(i1, MockProxy):
-                                l1.append(i1.get_mock())
-                            else:
-                                l1.append(i1)
-                        l.append(l1)
-                    else:
-                        l.append(i)
-        return Mock(values)
-
-    def __str__(self):
-        s = str(self._wrapped)
-        self._add_recorded_value('__str__', s)
-        return s
-
-    def __len__(self):
-        l = len(self._wrapped)
-        self._add_recorded_value('__len__', l)
-        return l
-
-    def __iter__(self):
-        it = []
-        for i in self._wrapped:
-            it.append(self._get_proxy_object(i))
-        self._add_recorded_value('__iter__', it)
-        return iter(it)
-
-    def __getitem__(self, key):
-        p = self._get_proxy_object(self._wrapped[key])
-        self._add_recorded_ret_value('__getitem__', str(key), p)
-        return p
-
-    def __call__(self, *args, **kwargs):
-        c = self._wrapped(*args, **kwargs)
-        p = self._get_proxy_object(c)
-        params = serialize_args(args, kwargs)
-        self._add_recorded_ret_value('__call__', params, p)
-        return p
diff --git a/cinder/tests/windows/stubs/README.rst b/cinder/tests/windows/stubs/README.rst
deleted file mode 100644 (file)
index 150fd3a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Files with extension p.gz are compressed pickle files containing serialized
-mocks used during unit testing
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz
deleted file mode 100644 (file)
index dada5e6..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_check_for_setup_errors_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz
deleted file mode 100644 (file)
index c425615..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz
deleted file mode 100644 (file)
index 2f6ea72..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_export_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz
deleted file mode 100644 (file)
index 5e55a96..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz
deleted file mode 100644 (file)
index 4e5879f..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_snapshot_wmi.p.gz and /dev/null differ
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
deleted file mode 100644 (file)
index 5de824a..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz
deleted file mode 100644 (file)
index 8b9ead4..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_from_snapshot_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz
deleted file mode 100644 (file)
index fc8eee0..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz
deleted file mode 100644 (file)
index dad1f85..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_create_volume_wmi.p.gz and /dev/null differ
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
deleted file mode 100644 (file)
index 6918422..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz
deleted file mode 100644 (file)
index 26de5bd..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_snapshot_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz
deleted file mode 100644 (file)
index 5ec5429..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz
deleted file mode 100644 (file)
index 11fed29..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_delete_volume_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz
deleted file mode 100644 (file)
index 3c58135..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz
deleted file mode 100644 (file)
index a0b4f4f..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_ensure_export_wmi.p.gz and /dev/null differ
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
deleted file mode 100644 (file)
index 5373f01..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_os.p.gz and /dev/null differ
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
deleted file mode 100644 (file)
index b2af251..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_initialize_connection_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz
deleted file mode 100644 (file)
index 64fdc6b..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_os.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz b/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz
deleted file mode 100644 (file)
index 9a8fe70..0000000
Binary files a/cinder/tests/windows/stubs/test_windows.TestWindowsDriver.test_remove_export_wmi.p.gz and /dev/null differ
diff --git a/cinder/tests/windows/windowsutils.py b/cinder/tests/windows/windowsutils.py
deleted file mode 100644 (file)
index 4a35a5b..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-#  Copyright 2012 Pedro Navarro Perez
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""
-Windows storage classes to be used in testing.
-"""
-
-import os
-
-from oslo.config import cfg
-
-# Check needed for unit testing on Unix
-if os.name == 'nt':
-    import wmi
-
-
-CONF = cfg.CONF
-
-
-class WindowsUtils(object):
-    def __init__(self):
-        self.__conn_cimv2 = None
-        self.__conn_wmi = None
-
-    @property
-    def _conn_cimv2(self):
-        if self.__conn_cimv2 is None:
-            self.__conn_cimv2 = wmi.WMI(moniker='//./root/cimv2')
-        return self.__conn_cimv2
-
-    @property
-    def _conn_wmi(self):
-        if self.__conn_wmi is None:
-            self.__conn_wmi = wmi.WMI(moniker='//./root/wmi')
-        return self.__conn_wmi
-
-    def find_vhd_by_name(self, name):
-        '''Finds a volume by its name.'''
-
-        wt_disks = self._conn_wmi.WT_Disk(Description=name)
-        return wt_disks
-
-    def volume_exists(self, name):
-        '''Checks if a volume exists.'''
-
-        wt_disks = self.find_vhd_by_name(name)
-        if len(wt_disks) > 0:
-            return True
-        return False
-
-    def snapshot_exists(self, name):
-        '''Checks if a snapshot exists.'''
-
-        wt_snapshots = self.find_snapshot_by_name(name)
-        if len(wt_snapshots) > 0:
-            return True
-        return False
-
-    def find_snapshot_by_name(self, name):
-        '''Finds a snapshot by its name.'''
-
-        wt_snapshots = self._conn_wmi.WT_Snapshot(Description=name)
-        return wt_snapshots
-
-    def delete_volume(self, name):
-        '''Deletes a volume.'''
-
-        wt_disk = self._conn_wmi.WT_Disk(Description=name)[0]
-        wt_disk.Delete_()
-        vhdfiles = self._conn_cimv2.query(
-            "Select * from CIM_DataFile where Name = '" +
-            self._get_vhd_path(name) + "'")
-        if len(vhdfiles) > 0:
-            vhdfiles[0].Delete()
-
-    def _get_vhd_path(self, volume_name):
-        '''Gets the path disk of the volume.'''
-
-        base_vhd_folder = CONF.windows_iscsi_lun_path
-        return os.path.join(base_vhd_folder, volume_name + ".vhd")
-
-    def delete_snapshot(self, name):
-        '''Deletes a snapshot.'''
-
-        wt_snapshot = self._conn_wmi.WT_Snapshot(Description=name)[0]
-        wt_snapshot.Delete_()
-        vhdfile = self._conn_cimv2.query(
-            "Select * from CIM_DataFile where Name = '" +
-            self._get_vhd_path(name) + "'")[0]
-        vhdfile.Delete()
-
-    def find_initiator_ids(self, target_name, initiator_name):
-        '''Finds a initiator id by its name.'''
-        wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=target_name,
-                                                 Method=4,
-                                                 Value=initiator_name)
-        return wt_idmethod
-
-    def initiator_id_exists(self, target_name, initiator_name):
-        '''Checks if  a initiatorId exists.'''
-
-        wt_idmethod = self.find_initiator_ids(target_name, initiator_name)
-        if len(wt_idmethod) > 0:
-            return True
-        return False
-
-    def find_exports(self, target_name):
-        '''Finds a export id by its name.'''
-
-        wt_host = self._conn_wmi.WT_Host(HostName=target_name)
-        return wt_host
-
-    def export_exists(self, target_name):
-        '''Checks if  a export exists.'''
-
-        wt_host = self.find_exports(target_name)
-        if len(wt_host) > 0:
-            return True
-        return False
-
-    def delete_initiator_id(self, target_name, initiator_name):
-        '''Deletes a initiatorId.'''
-
-        wt_init_id = self.find_initiator_ids(target_name, initiator_name)[0]
-        wt_init_id.Delete_()
-
-    def delete_export(self, target_name):
-        '''Deletes an export.'''
-
-        wt_host = self.find_exports(target_name)[0]
-        wt_host.RemoveAllWTDisks()
-        wt_host.Delete_()
diff --git a/cinder/volume/drivers/windows.py b/cinder/volume/drivers/windows.py
deleted file mode 100644 (file)
index 87672bb..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 Pedro Navarro Perez
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-"""
-Volume driver for Windows Server 2012
-
-This driver requires ISCSI target role installed
-
-"""
-
-
-import os
-
-from oslo.config import cfg
-
-from cinder import exception
-from cinder.openstack.common import log as logging
-from cinder.volume import driver
-
-# Check needed for unit testing on Unix
-if os.name == 'nt':
-    import wmi
-
-
-LOG = logging.getLogger(__name__)
-
-windows_opts = [
-    cfg.StrOpt('windows_iscsi_lun_path',
-               default='C:\iSCSIVirtualDisks',
-               help='Path to store VHD backed volumes'),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(windows_opts)
-
-
-class WindowsDriver(driver.ISCSIDriver):
-    """Executes volume driver commands on Windows Storage server."""
-
-    def __init__(self, *args, **kwargs):
-        super(WindowsDriver, self).__init__(*args, **kwargs)
-
-    def do_setup(self, context):
-        """Setup the Windows Volume driver.
-
-        Called one time by the manager after the driver is loaded.
-        Validate the flags we care about
-        """
-        #Set the flags
-        self._conn_wmi = wmi.WMI(moniker='//./root/wmi')
-        self._conn_cimv2 = wmi.WMI(moniker='//./root/cimv2')
-
-    def check_for_setup_error(self):
-        """Check that the driver is working and can communicate.
-        """
-        #Invoking the portal an checking that is listening
-        wt_portal = self._conn_wmi.WT_Portal()[0]
-        listen = wt_portal.Listen
-        if not listen:
-            raise exception.VolumeBackendAPIException()
-
-    def initialize_connection(self, volume, connector):
-        """Driver entry point to attach a volume to an instance.
-        """
-        initiator_name = connector['initiator']
-        target_name = volume['provider_location']
-
-        cl = self._conn_wmi.__getattr__("WT_IDMethod")
-        wt_idmethod = cl.new()
-        wt_idmethod.HostName = target_name
-        wt_idmethod.Method = 4
-        wt_idmethod.Value = initiator_name
-        wt_idmethod.put()
-        #Getting the portal and port information
-        wt_portal = self._conn_wmi.WT_Portal()[0]
-        (address, port) = (wt_portal.Address, wt_portal.Port)
-        #Getting the host information
-        hosts = self._conn_wmi.WT_Host(Hostname=target_name)
-        host = hosts[0]
-
-        properties = {}
-        properties['target_discovered'] = False
-        properties['target_portal'] = '%s:%s' % (address, port)
-        properties['target_iqn'] = host.TargetIQN
-        properties['target_lun'] = 0
-        properties['volume_id'] = volume['id']
-
-        auth = volume['provider_auth']
-        if auth:
-            (auth_method, auth_username, auth_secret) = auth.split()
-
-            properties['auth_method'] = auth_method
-            properties['auth_username'] = auth_username
-            properties['auth_password'] = auth_secret
-
-        return {
-            'driver_volume_type': 'iscsi',
-            'data': properties,
-        }
-
-    def terminate_connection(self, volume, connector, **kwargs):
-        """Driver entry point to unattach a volume from an instance.
-
-        Unmask the LUN on the storage system so the given intiator can no
-        longer access it.
-        """
-        initiator_name = connector['initiator']
-        provider_location = volume['provider_location']
-        #DesAssigning target to initiators
-        wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=provider_location,
-                                                 Method=4,
-                                                 Value=initiator_name)[0]
-        wt_idmethod.Delete_()
-
-    def create_volume(self, volume):
-        """Driver entry point for creating a new volume."""
-        vhd_path = self._get_vhd_path(volume)
-        vol_name = volume['name']
-        #The WMI procedure returns a Generic failure
-        cl = self._conn_wmi.__getattr__("WT_Disk")
-        cl.NewWTDisk(DevicePath=vhd_path,
-                     Description=vol_name,
-                     SizeInMB=volume['size'] * 1024)
-
-    def _get_vhd_path(self, volume):
-        base_vhd_folder = CONF.windows_iscsi_lun_path
-        if not os.path.exists(base_vhd_folder):
-                LOG.debug(_('Creating folder %s '), base_vhd_folder)
-                os.makedirs(base_vhd_folder)
-        return os.path.join(base_vhd_folder, str(volume['name']) + ".vhd")
-
-    def delete_volume(self, volume):
-        """Driver entry point for destroying existing volumes."""
-        vol_name = volume['name']
-        wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
-        wt_disk.Delete_()
-        vhdfiles = self._conn_cimv2.query(
-            "Select * from CIM_DataFile where Name = '" +
-            self._get_vhd_path(volume) + "'")
-        if len(vhdfiles) > 0:
-            vhdfiles[0].Delete()
-
-    def create_snapshot(self, snapshot):
-        """Driver entry point for creating a snapshot.
-        """
-        #Getting WT_Snapshot class
-        vol_name = snapshot['volume_name']
-        snapshot_name = snapshot['name']
-
-        wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
-        #API Calls gets Generic Failure
-        cl = self._conn_wmi.__getattr__("WT_Snapshot")
-        disk_id = wt_disk.WTD
-        out = cl.Create(WTD=disk_id)
-        #Setting description since it used as a KEY
-        wt_snapshot_created = self._conn_wmi.WT_Snapshot(Id=out[0])[0]
-        wt_snapshot_created.Description = snapshot_name
-        wt_snapshot_created.put()
-
-    def create_volume_from_snapshot(self, volume, snapshot):
-        """Driver entry point for exporting snapshots as volumes."""
-        snapshot_name = snapshot['name']
-        wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0]
-        disk_id = wt_snapshot.Export()[0]
-        wt_disk = self._conn_wmi.WT_Disk(WTD=disk_id)[0]
-        wt_disk.Description = volume['name']
-        wt_disk.put()
-
-    def delete_snapshot(self, snapshot):
-        """Driver entry point for deleting a snapshot."""
-        snapshot_name = snapshot['name']
-        wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0]
-        wt_snapshot.Delete_()
-
-    def _do_export(self, _ctx, volume, ensure=False):
-        """Do all steps to get disk exported as LUN 0 at separate target.
-
-        :param volume: reference of volume to be exported
-        :param ensure: if True, ignore errors caused by already existing
-            resources
-        :return: iscsiadm-formatted provider location string
-        """
-        target_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
-        #ISCSI target creation
-        try:
-            cl = self._conn_wmi.__getattr__("WT_Host")
-            cl.NewHost(HostName=target_name)
-        except Exception as exc:
-            excep_info = exc.com_error.excepinfo[2]
-            if not ensure or excep_info.find(u'The file exists') == -1:
-                raise
-            else:
-                LOG.info(_('Ignored target creation error "%s"'
-                           ' while ensuring export'), exc)
-        #Get the disk to add
-        vol_name = volume['name']
-        q = self._conn_wmi.WT_Disk(Description=vol_name)
-        if not len(q):
-            LOG.debug(_('Disk not found: %s'), vol_name)
-            return None
-        wt_disk = q[0]
-        wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
-        wt_host.AddWTDisk(wt_disk.WTD)
-
-        return target_name
-
-    def ensure_export(self, context, volume):
-        """Driver entry point to get the export info for an existing volume."""
-        self._do_export(context, volume, ensure=True)
-
-    def create_export(self, context, volume):
-        """Driver entry point to get the export info for a new volume."""
-        loc = self._do_export(context, volume, ensure=False)
-        return {'provider_location': loc}
-
-    def remove_export(self, context, volume):
-        """Driver exntry point to remove an export for a volume.
-        """
-        target_name = "%s%s" % (CONF.iscsi_target_prefix, volume['name'])
-
-        #Get ISCSI target
-        wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
-        wt_host.RemoveAllWTDisks()
-        wt_host.Delete_()
-
-    def copy_image_to_volume(self, context, volume, image_service, image_id):
-        """Fetch the image from image_service and write it to the volume."""
-        raise NotImplementedError()
-
-    def copy_volume_to_image(self, context, volume, image_service, image_meta):
-        """Copy the volume to the specified image."""
-        raise NotImplementedError()
diff --git a/cinder/volume/drivers/windows/__init__.py b/cinder/volume/drivers/windows/__init__.py
new file mode 100644 (file)
index 0000000..2b0d839
--- /dev/null
@@ -0,0 +1,13 @@
+#    Copyright 2013 OpenStack LLC
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
diff --git a/cinder/volume/drivers/windows/windows.py b/cinder/volume/drivers/windows/windows.py
new file mode 100644 (file)
index 0000000..24cf401
--- /dev/null
@@ -0,0 +1,227 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Pedro Navarro Perez
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""
+Volume driver for Windows Server 2012
+
+This driver requires ISCSI target role installed
+
+"""
+
+import os
+
+from oslo.config import cfg
+
+from cinder.image import image_utils
+from cinder.openstack.common import log as logging
+from cinder.volume import driver
+from cinder.volume.drivers.windows import windows_utils
+
+LOG = logging.getLogger(__name__)
+
+windows_opts = [
+    cfg.StrOpt('windows_iscsi_lun_path',
+               default='C:\iSCSIVirtualDisks',
+               help='Path to store VHD backed volumes'),
+]
+
+CONF = cfg.CONF
+CONF.register_opts(windows_opts)
+
+
+class WindowsDriver(driver.ISCSIDriver):
+    """Executes volume driver commands on Windows Storage server."""
+
+    VERSION = '1.0.0'
+
+    def __init__(self, *args, **kwargs):
+        super(WindowsDriver, self).__init__(*args, **kwargs)
+        self.configuration = kwargs.get('configuration', None)
+        if self.configuration:
+            self.configuration.append_config_values(windows_opts)
+
+    def do_setup(self, context):
+        """Setup the Windows Volume driver.
+
+        Called one time by the manager after the driver is loaded.
+        Validate the flags we care about
+        """
+        self.utils = windows_utils.WindowsUtils()
+
+    def check_for_setup_error(self):
+        """Check that the driver is working and can communicate."""
+        self.utils.check_for_setup_error()
+
+    def initialize_connection(self, volume, connector):
+        """Driver entry point to attach a volume to an instance."""
+        initiator_name = connector['initiator']
+        target_name = volume['provider_location']
+
+        self.utils.associate_initiator_with_iscsi_target(target_name,
+                                                         initiator_name)
+
+        properties = self.utils.get_host_information(volume, target_name)
+
+        return {
+            'driver_volume_type': 'iscsi',
+            'data': properties,
+        }
+
+    def terminate_connection(self, volume, connector, **kwargs):
+        """Driver entry point to unattach a volume from an instance.
+
+        Unmask the LUN on the storage system so the given initiator can no
+        longer access it.
+        """
+        initiator_name = connector['initiator']
+        target_name = volume['provider_location']
+        self.utils.delete_iscsi_target(initiator_name, target_name)
+
+    def create_volume(self, volume):
+        """Driver entry point for creating a new volume."""
+        vhd_path = self.local_path(volume)
+        vol_name = volume['name']
+        vol_size = volume['size']
+
+        self.utils.create_volume(vhd_path, vol_name, vol_size)
+
+    def local_path(self, volume):
+        base_vhd_folder = self.configuration.windows_iscsi_lun_path
+        if not os.path.exists(base_vhd_folder):
+            LOG.debug(_('Creating folder %s '), base_vhd_folder)
+            os.makedirs(base_vhd_folder)
+        return os.path.join(base_vhd_folder, str(volume['name']) + ".vhd")
+
+    def delete_volume(self, volume):
+        """Driver entry point for destroying existing volumes."""
+        vol_name = volume['name']
+        vhd_path = self.local_path(volume)
+
+        self.utils.delete_volume(vol_name, vhd_path)
+
+    def create_snapshot(self, snapshot):
+        """Driver entry point for creating a snapshot."""
+        # Getting WT_Snapshot class
+        vol_name = snapshot['volume_name']
+        snapshot_name = snapshot['name']
+
+        self.utils.create_snapshot(vol_name, snapshot_name)
+
+    def create_volume_from_snapshot(self, volume, snapshot):
+        """Driver entry point for exporting snapshots as volumes."""
+        snapshot_name = snapshot['name']
+        vol_name = volume['name']
+        self.utils.create_volume_from_snapshot(vol_name, snapshot_name)
+
+    def delete_snapshot(self, snapshot):
+        """Driver entry point for deleting a snapshot."""
+        snapshot_name = snapshot['name']
+        self.utils.delete_snapshot(snapshot_name)
+
+    def _do_export(self, _ctx, volume, ensure=False):
+        """Do all steps to get disk exported as LUN 0 at separate target.
+
+        :param volume: reference of volume to be exported
+        :param ensure: if True, ignore errors caused by already existing
+            resources
+        :return: iscsiadm-formatted provider location string
+        """
+        target_name = "%s%s" % (self.configuration.iscsi_target_prefix,
+                                volume['name'])
+        self.utils.create_iscsi_target(target_name, ensure)
+
+        # Get the disk to add
+        vol_name = volume['name']
+        self.utils.add_disk_to_target(vol_name, target_name)
+
+        return target_name
+
+    def ensure_export(self, context, volume):
+        """Driver entry point to get the export info for an existing volume."""
+        self._do_export(context, volume, ensure=True)
+
+    def create_export(self, context, volume):
+        """Driver entry point to get the export info for a new volume."""
+        loc = self._do_export(context, volume, ensure=False)
+        return {'provider_location': loc}
+
+    def remove_export(self, context, volume):
+        """Driver entry point to remove an export for a volume.
+        """
+        target_name = "%s%s" % (self.configuration.iscsi_target_prefix,
+                                volume['name'])
+
+        self.utils.remove_iscsi_target(target_name)
+
+    def copy_image_to_volume(self, context, volume, image_service, image_id):
+        """Fetch the image from image_service and write it to the volume."""
+        # Convert to VHD and file back to VHD
+        image_utils.fetch_to_vhd(context, image_service, image_id,
+                                 self.local_path(volume))
+
+    def copy_volume_to_image(self, context, volume, image_service, image_meta):
+        """Copy the volume to the specified image."""
+
+        # Copy the volume to the image conversion dir
+        temp_vhd_path = os.path.join(self.configuration.image_conversion_dir,
+                                     str(image_meta['id']) + ".vhd")
+        self.utils.copy_vhd_disk(self.local_path(volume), temp_vhd_path)
+        image_utils.upload_volume(context, image_service, image_meta,
+                                  temp_vhd_path, 'vpc')
+
+    def create_cloned_volume(self, volume, src_vref):
+        """Creates a clone of the specified volume."""
+        # Create a new volume
+        # Copy VHD file of the volume to clone to the created volume
+        self.create_volume(volume)
+        self.utils.copy_vhd_disk(self.local_path(src_vref),
+                                 self.local_path(volume))
+
+    def get_volume_stats(self, refresh=False):
+        """Get volume stats.
+
+        If 'refresh' is True, run update the stats first.
+        """
+        if refresh:
+            self._update_volume_stats()
+
+        return self._stats
+
+    def _update_volume_stats(self):
+        """Retrieve stats info for Windows device."""
+
+        LOG.debug(_("Updating volume stats"))
+        data = {}
+        backend_name = self.__class__.__name__
+        if self.configuration:
+            backend_name = self.configuration.safe_get('volume_backend_name')
+        data["volume_backend_name"] = backend_name or self.__class__.__name__
+        data["vendor_name"] = 'Microsoft'
+        data["driver_version"] = self.VERSION
+        data["storage_protocol"] = 'iSCSI'
+        data['total_capacity_gb'] = 'infinite'
+        data['free_capacity_gb'] = 'infinite'
+        data['reserved_percentage'] = 100
+        data['QoS_support'] = False
+        self._stats = data
+
+    def extend_volume(self, volume, new_size):
+        """Extend an Existing Volume."""
+        old_size = volume['size']
+        LOG.debug(_("Extended volume from %(old_size) to %(new_size)"),
+                  {'old_size': old_size, 'new_size': new_size})
+        additional_size = (new_size - old_size) * 1024
+        self.utils.extend(volume['name'], additional_size)
diff --git a/cinder/volume/drivers/windows/windows_utils.py b/cinder/volume/drivers/windows/windows_utils.py
new file mode 100644 (file)
index 0000000..938ac08
--- /dev/null
@@ -0,0 +1,297 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Pedro Navarro Perez
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+"""
+Utility class for Windows Storage Server 2012 volume related operations.
+"""
+
+import os
+
+from cinder import exception
+from cinder.openstack.common import log as logging
+
+# Check needed for unit testing on Unix
+if os.name == 'nt':
+    import wmi
+
+LOG = logging.getLogger(__name__)
+
+
+class WindowsUtils(object):
+    """Executes volume driver commands on Windows Storage server."""
+
+    def __init__(self, *args, **kwargs):
+        # Set the flags
+        self._conn_wmi = wmi.WMI(moniker='//./root/wmi')
+        self._conn_cimv2 = wmi.WMI(moniker='//./root/cimv2')
+
+    def check_for_setup_error(self):
+        """Check that the driver is working and can communicate.
+        Invokes the portal and checks that is listening ISCSI traffic.
+        """
+        try:
+            wt_portal = self._conn_wmi.WT_Portal()[0]
+            listen = wt_portal.Listen
+        except wmi.x_wmi as exc:
+            err_msg = (_('check_for_setup_error: the state of the WT Portal '
+                         'could not be verified. WMI exception: %s'))
+            LOG.error(err_msg % exc)
+            raise exception.VolumeBackendAPIException(data=err_msg % exc)
+
+        if not listen:
+            err_msg = (_('check_for_setup_error: there is no ISCSI traffic '
+                         'listening.'))
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def get_host_information(self, volume, target_name):
+        """Getting the portal and port information."""
+        try:
+            wt_portal = self._conn_wmi.WT_Portal()[0]
+        except wmi.x_wmi as exc:
+            err_msg = (_('get_host_information: the state of the WT Portal '
+                         'could not be verified. WMI exception: %s'))
+            LOG.error(err_msg % exc)
+            raise exception.VolumeBackendAPIException(data=err_msg % exc)
+        (address, port) = (wt_portal.Address, wt_portal.Port)
+        # Getting the host information
+        try:
+            hosts = self._conn_wmi.WT_Host(Hostname=target_name)
+            host = hosts[0]
+        except wmi.x_wmi as exc:
+            err_msg = (_('get_host_information: the ISCSI target information '
+                         'could not be retrieved. WMI exception: %s'))
+            LOG.error(err_msg % exc)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+        properties = {}
+        properties['target_discovered'] = False
+        properties['target_portal'] = '%s:%s' % (address, port)
+        properties['target_iqn'] = host.TargetIQN
+        properties['target_lun'] = 0
+        properties['volume_id'] = volume['id']
+
+        auth = volume['provider_auth']
+        if auth:
+            (auth_method, auth_username, auth_secret) = auth.split()
+
+            properties['auth_method'] = auth_method
+            properties['auth_username'] = auth_username
+            properties['auth_password'] = auth_secret
+
+    def associate_initiator_with_iscsi_target(self, initiator_name,
+                                              target_name):
+        """Sets information used by the iSCSI target entry."""
+        try:
+            cl = self._conn_wmi.__getattr__("WT_IDMethod")
+            wt_idmethod = cl.new()
+            wt_idmethod.HostName = target_name
+            # Identification method is IQN
+            wt_idmethod.Method = 4
+            wt_idmethod.Value = initiator_name
+            wt_idmethod.put()
+        except wmi.x_wmi as exc:
+            err_msg = (_('associate_initiator_with_iscsi_target: an '
+                         'association between initiator: %(init)s and '
+                         'target name: %(target)s could not be established. '
+                         'WMI exception: %(wmi_exc)s') %
+                       {'init': initiator_name, 'target': target_name,
+                        'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def delete_iscsi_target(self, initiator_name, target_name):
+        """Removes iSCSI targets to hosts."""
+
+        try:
+            wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=target_name,
+                                                     Method=4,
+                                                     Value=initiator_name)[0]
+            wt_idmethod.Delete_()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'delete_iscsi_target: error when deleting the iscsi target '
+                'associated with target name: %(target)s . '
+                'WMI exception: %(wmi_exc)s') % {'target': target_name,
+                                                 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_volume(self, vhd_path, vol_name, vol_size):
+        """Creates a volume"""
+        try:
+            cl = self._conn_wmi.__getattr__("WT_Disk")
+            cl.NewWTDisk(DevicePath=vhd_path,
+                         Description=vol_name,
+                         SizeInMB=vol_size * 1024)
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'create_volume: error when creating the volume name: '
+                '%(vol_name)s . WMI exception: '
+                '%(wmi_exc)s') % {'vol_name': vol_name, 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def delete_volume(self, vol_name, vhd_path):
+        """Driver entry point for destroying existing volumes."""
+        try:
+            wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
+            wt_disk.Delete_()
+            vhdfiles = self._conn_cimv2.query(
+                "Select * from CIM_DataFile where Name = '" +
+                vhd_path + "'")
+            if len(vhdfiles) > 0:
+                vhdfiles[0].Delete()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'delete_volume: error when deleting the volume name: '
+                '%(vol_name)s . WMI exception: '
+                '%(wmi_exc)s') % {'vol_name': vol_name, 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_snapshot(self, vol_name, snapshot_name):
+        """Driver entry point for creating a snapshot."""
+        try:
+            wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
+            # API Calls gets Generic Failure
+            cl = self._conn_wmi.__getattr__("WT_Snapshot")
+            disk_id = wt_disk.WTD
+            out = cl.Create(WTD=disk_id)
+            # Setting description since it used as a KEY
+            wt_snapshot_created = self._conn_wmi.WT_Snapshot(Id=out[0])[0]
+            wt_snapshot_created.Description = snapshot_name
+            wt_snapshot_created.put()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'create_snapshot: error when creating the snapshot name: '
+                '%(vol_name)s . WMI exception: '
+                '%(wmi_exc)s') % {'vol_name': snapshot_name, 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_volume_from_snapshot(self, vol_name, snap_name):
+        """Driver entry point for exporting snapshots as volumes."""
+        try:
+            wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snap_name)[0]
+            disk_id = wt_snapshot.Export()[0]
+            wt_disk = self._conn_wmi.WT_Disk(WTD=disk_id)[0]
+            wt_disk.Description = vol_name
+            wt_disk.put()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'create_volume_from_snapshot: error when creating the volume '
+                'name: %(vol_name)s from snapshot name: %(snap_name)s. '
+                'WMI exception: %(wmi_exc)s') % {'vol_name': vol_name,
+                                                 'snap_name': snap_name,
+                                                 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def delete_snapshot(self, snap_name):
+        """Driver entry point for deleting a snapshot."""
+        try:
+            wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snap_name)[0]
+            wt_snapshot.Delete_()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'delete_snapshot: error when deleting the snapshot name: '
+                '%(snap_name)s . WMI exception: '
+                '%(wmi_exc)s') % {'snap_name': snap_name, 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def create_iscsi_target(self, target_name, ensure):
+        """Creates ISCSI target."""
+        try:
+            cl = self._conn_wmi.__getattr__("WT_Host")
+            cl.NewHost(HostName=target_name)
+        except wmi.x_wmi as exc:
+            excep_info = exc.com_error.excepinfo[2]
+            if not ensure or excep_info.find(u'The file exists') == -1:
+                err_msg = (_(
+                    'create_iscsi_target: error when creating iscsi target: '
+                    '%(tar_name)s . WMI exception: '
+                    '%(wmi_exc)s') % {'tar_name': target_name, 'wmi_exc': exc})
+                LOG.error(err_msg)
+                raise exception.VolumeBackendAPIException(data=err_msg)
+            else:
+                LOG.info(_('Ignored target creation error "%s"'
+                           ' while ensuring export'), exc)
+
+    def remove_iscsi_target(self, target_name):
+        """Removes ISCSI target."""
+        try:
+            wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
+            wt_host.RemoveAllWTDisks()
+            wt_host.Delete_()
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'remove_iscsi_target: error when deleting iscsi target: '
+                '%(tar_name)s . WMI exception: '
+                '%(wmi_exc)s') % {'tar_name': target_name, 'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def add_disk_to_target(self, vol_name, target_name):
+        """Adds the disk to the target"""
+        try:
+            q = self._conn_wmi.WT_Disk(Description=vol_name)
+            wt_disk = q[0]
+            wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
+            wt_host.AddWTDisk(wt_disk.WTD)
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'add_disk_to_target: error adding disk associated to volume : '
+                '%(vol_name)s to the target name: %(tar_name)s '
+                '. WMI exception: %(wmi_exc)s') % {'tar_name': target_name,
+                                                   'vol_name': vol_name,
+                                                   'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def copy_vhd_disk(self, source_path, destination_path):
+        """Copy the vhd disk from source path to destination path."""
+        try:
+            vhdfiles = self._conn_cimv2.query(
+                "Select * from CIM_DataFile where Name = '" +
+                source_path + "'")
+            if len(vhdfiles) > 0:
+                vhdfiles[0].Copy(destination_path)
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'copy_vhd_disk: error when copying disk from source path : '
+                '%(src_path)s to destination path: %(dest_path)s '
+                '. WMI exception: '
+                '%(wmi_exc)s') % {'src_path': source_path,
+                                  'dest_path': destination_path,
+                                  'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
+
+    def extend(self, vol_name, additional_size):
+        """Extend an existing volume."""
+        try:
+            q = self._conn_wmi.WT_Disk(Description=vol_name)
+            wt_disk = q[0]
+            wt_disk.Extend(additional_size)
+        except wmi.x_wmi as exc:
+            err_msg = (_(
+                'extend: error when extending the volumne: %(vol_name)s '
+                '.WMI exception: %(wmi_exc)s') % {'vol_name': vol_name,
+                                                  'wmi_exc': exc})
+            LOG.error(err_msg)
+            raise exception.VolumeBackendAPIException(data=err_msg)
index 4dea45a4f6eca4c61e90586426b0f895726b59ea..f2afd322d153abc0a89ee536fdaef445e8efc8ba 100644 (file)
@@ -102,7 +102,9 @@ MAPPING = {
     'cinder.volume.storwize_svc.StorwizeSVCDriver':
     'cinder.volume.drivers.storwize_svc.StorwizeSVCDriver',
     'cinder.volume.windows.WindowsDriver':
-    'cinder.volume.drivers.windows.WindowsDriver',
+    'cinder.volume.drivers.windows.windows.WindowsDriver',
+    'cinder.volume.drivers.windows.WindowsDriver':
+    'cinder.volume.drivers.windows.windows.WindowsDriver',
     'cinder.volume.xiv.XIVDriver':
     'cinder.volume.drivers.xiv_ds8k.XIVDS8KDriver',
     'cinder.volume.drivers.xiv.XIVDriver':
index bc8dc628063d3844438583ea046b56ed9af95196..693089aca8aa452e2967051001abce200566c79c 100644 (file)
 
 
 #
-# Options defined in cinder.volume.drivers.windows
+# Options defined in cinder.volume.drivers.windows.windows
 #
 
 # Path to store VHD backed volumes (string value)