]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Remove duplication of ISCSIDriver in ISERDriver
authorAnn Kamyshnikova <akamyshnikova@mirantis.com>
Fri, 6 Sep 2013 08:04:20 +0000 (12:04 +0400)
committerAnn Kamyshnikova <akamyshnikova@mirantis.com>
Tue, 5 Nov 2013 12:19:14 +0000 (16:19 +0400)
ISERDriver is almost copy of ISCSIDriver.

Change-Id: I22394c7a3b26b140b19f76e052c98d11ec59145c

cinder/brick/initiator/connector.py
cinder/tests/test_volume.py
cinder/volume/driver.py
etc/cinder/cinder.conf.sample

index 0778f946bba114e67ea5657ceceb8be2ddd1825a..8accbb1078a216bcccac286c6b4e62f24f73484d 100644 (file)
@@ -91,6 +91,13 @@ class InitiatorConnector(executor.Executor):
                                   use_multipath=use_multipath,
                                   device_scan_attempts=device_scan_attempts,
                                   *args, **kwargs)
+        elif protocol == "ISER":
+            return ISERConnector(root_helper=root_helper,
+                                 driver=driver,
+                                 execute=execute,
+                                 use_multipath=use_multipath,
+                                 device_scan_attempts=device_scan_attempts,
+                                 *args, **kwargs)
         elif protocol == "FIBRE_CHANNEL":
             return FibreChannelConnector(root_helper=root_helper,
                                          driver=driver,
@@ -501,6 +508,15 @@ class ISCSIConnector(InitiatorConnector):
         self._run_multipath('-r', check_exit_code=[0, 1, 21])
 
 
+class ISERConnector(ISCSIConnector):
+
+    def _get_device_path(self, iser_properties):
+        return ("/dev/disk/by-path/ip-%s-iser-%s-lun-%s" %
+                (iser_properties['target_portal'],
+                 iser_properties['target_iqn'],
+                 iser_properties.get('target_lun', 0)))
+
+
 class FibreChannelConnector(InitiatorConnector):
     """Connector class to attach/detach Fibre Channel volumes."""
 
index 6c6d0a7c2ccfc608054dddb813aedbbbcf6e3f89..abc749375457fd035e9c20db0b75ac5b598416b4 100644 (file)
@@ -2233,6 +2233,16 @@ class LVMVolumeDriverTestCase(DriverTestCase):
 class ISCSITestCase(DriverTestCase):
     """Test Case for ISCSIDriver"""
     driver_name = "cinder.volume.drivers.lvm.LVMISCSIDriver"
+    base_driver = driver.ISCSIDriver
+
+    def setUp(self):
+        super(ISCSITestCase, self).setUp()
+        self.configuration = mox.MockObject(conf.Configuration)
+        self.configuration.num_iscsi_scan_tries = 3
+        self.configuration.iscsi_num_targets = 100
+        self.configuration.iscsi_target_prefix = 'iqn.2010-10.org.openstack:'
+        self.configuration.iscsi_ip_address = '0.0.0.0'
+        self.configuration.iscsi_port = 3260
 
     def _attach_volume(self):
         """Attach volumes to an instance."""
@@ -2254,11 +2264,8 @@ class ISCSITestCase(DriverTestCase):
         return volume_id_list
 
     def test_do_iscsi_discovery(self):
-        configuration = mox.MockObject(conf.Configuration)
-        configuration.iscsi_ip_address = '0.0.0.0'
-        configuration.append_config_values(mox.IgnoreArg())
-
-        iscsi_driver = driver.ISCSIDriver(configuration=configuration)
+        self.configuration.append_config_values(mox.IgnoreArg())
+        iscsi_driver = self.base_driver(configuration=self.configuration)
         iscsi_driver._execute = lambda *a, **kw: \
             ("%s dummy" % CONF.iscsi_ip_address, '')
         volume = {"name": "dummy",
@@ -2270,7 +2277,7 @@ class ISCSITestCase(DriverTestCase):
                   "id": "0",
                   "provider_auth": "a b c",
                   "attached_mode": "rw"}
-        iscsi_driver = driver.ISCSIDriver()
+        iscsi_driver = self.base_driver(configuration=self.configuration)
         iscsi_driver._do_iscsi_discovery = lambda v: "0.0.0.0:0000,0 iqn:iqn 0"
         result = iscsi_driver._get_iscsi_properties(volume)
         self.assertEqual(result["target_portal"], "0.0.0.0:0000")
@@ -2304,7 +2311,7 @@ class ISCSITestCase(DriverTestCase):
         self.assertEqual(stats['free_capacity_gb'], float('0.52'))
 
     def test_validate_connector(self):
-        iscsi_driver = driver.ISCSIDriver()
+        iscsi_driver = self.base_driver(configuration=self.configuration)
         # Validate a valid connector
         connector = {'ip': '10.0.0.2',
                      'host': 'fakehost',
@@ -2320,29 +2327,16 @@ class ISCSITestCase(DriverTestCase):
 class ISERTestCase(ISCSITestCase):
     """Test Case for ISERDriver."""
     driver_name = "cinder.volume.drivers.lvm.LVMISERDriver"
+    base_driver = driver.ISERDriver
 
-    def test_do_iscsi_discovery(self):
-        configuration = mox.MockObject(conf.Configuration)
-        configuration.iser_ip_address = '0.0.0.0'
-        configuration.append_config_values(mox.IgnoreArg())
-
-        iser_driver = driver.ISERDriver(configuration=configuration)
-        iser_driver._execute = lambda *a, **kw: \
-            ("%s dummy" % CONF.iser_ip_address, '')
-        volume = {"name": "dummy",
-                  "host": "0.0.0.0"}
-        iser_driver._do_iser_discovery(volume)
-
-    def test_get_iscsi_properties(self):
-        volume = {"provider_location": '',
-                  "id": "0",
-                  "provider_auth": "a b c"}
-        iser_driver = driver.ISERDriver()
-        iser_driver._do_iser_discovery = lambda v: "0.0.0.0:0000,0 iqn:iqn 0"
-        result = iser_driver._get_iser_properties(volume)
-        self.assertEqual(result["target_portal"], "0.0.0.0:0000")
-        self.assertEqual(result["target_iqn"], "iqn:iqn")
-        self.assertEqual(result["target_lun"], 0)
+    def setUp(self):
+        super(ISERTestCase, self).setUp()
+        self.configuration = mox.MockObject(conf.Configuration)
+        self.configuration.num_iser_scan_tries = 3
+        self.configuration.iser_num_targets = 100
+        self.configuration.iser_target_prefix = 'iqn.2010-10.org.openstack:'
+        self.configuration.iser_ip_address = '0.0.0.0'
+        self.configuration.iser_port = 3260
 
 
 class FibreChannelTestCase(DriverTestCase):
index a286b4b3b7d3d38975f274729acca830a43efb1f..8b5380b1ee441aac4f39e350512344ecdd0f3567 100644 (file)
@@ -62,25 +62,6 @@ volume_opts = [
                default=3,
                help='The maximum number of times to rescan targets'
                     ' to find volume'),
-    cfg.IntOpt('num_iser_scan_tries',
-               default=3,
-               help='The maximum number of times to rescan iSER target '
-                    'to find volume'),
-    cfg.IntOpt('iser_num_targets',
-               default=100,
-               help='The maximum number of iser target ids per host'),
-    cfg.StrOpt('iser_target_prefix',
-               default='iqn.2010-10.org.iser.openstack:',
-               help='prefix for iser volumes'),
-    cfg.StrOpt('iser_ip_address',
-               default='$my_ip',
-               help='The IP address that the iSER daemon is listening on'),
-    cfg.IntOpt('iser_port',
-               default=3260,
-               help='The port that the iSER daemon is listening on'),
-    cfg.StrOpt('iser_helper',
-               default='tgtadm',
-               help='iser target user-land tool to use'),
     cfg.StrOpt('volume_backend_name',
                default=None,
                help='The backend name for a given driver implementation'),
@@ -117,9 +98,33 @@ volume_opts = [
                      'optionally, auto can be set and Cinder '
                      'will autodetect type of backing device'))]
 
+# for backward compatibility
+iser_opts = [
+    cfg.IntOpt('num_iser_scan_tries',
+               default=3,
+               help='The maximum number of times to rescan iSER target'
+                    'to find volume'),
+    cfg.IntOpt('iser_num_targets',
+               default=100,
+               help='The maximum number of iser target ids per host'),
+    cfg.StrOpt('iser_target_prefix',
+               default='iqn.2010-10.org.iser.openstack:',
+               help='prefix for iser volumes'),
+    cfg.StrOpt('iser_ip_address',
+               default='$my_ip',
+               help='The IP address that the iSER daemon is listening on'),
+    cfg.IntOpt('iser_port',
+               default=3260,
+               help='The port that the iSER daemon is listening on'),
+    cfg.StrOpt('iser_helper',
+               default='tgtadm',
+               help='iser target user-land tool to use'),
+]
+
 
 CONF = cfg.CONF
 CONF.register_opts(volume_opts)
+CONF.register_opts(iser_opts)
 
 
 class VolumeDriver(object):
@@ -750,91 +755,18 @@ class ISERDriver(ISCSIDriver):
       '<auth method> <auth username> <auth password>'.
       `CHAP` is the only auth_method in use at the moment.
     """
-
     def __init__(self, *args, **kwargs):
         super(ISERDriver, self).__init__(*args, **kwargs)
-
-    def _do_iser_discovery(self, volume):
-        LOG.warn(_("ISER provider_location not stored, using discovery"))
-
-        volume_name = volume['name']
-
-        (out, _err) = self._execute('iscsiadm', '-m', 'discovery',
-                                    '-t', 'sendtargets', '-p', volume['host'],
-                                    run_as_root=True)
-        for target in out.splitlines():
-            if (self.configuration.iser_ip_address in target
-                    and volume_name in target):
-                return target
-        return None
-
-    def _get_iser_properties(self, volume):
-        """Gets iser configuration
-
-        We ideally get saved information in the volume entity, but fall back
-        to discovery if need be. Discovery may be completely removed in future
-        The properties are:
-
-        :target_discovered:    boolean indicating whether discovery was used
-
-        :target_iqn:    the IQN of the iSER target
-
-        :target_portal:    the portal of the iSER target
-
-        :target_lun:    the lun of the iSER target
-
-        :volume_id:    the id of the volume (currently used by xen)
-
-        :auth_method:, :auth_username:, :auth_password:
-
-            the authentication details. Right now, either auth_method is not
-            present meaning no authentication, or auth_method == `CHAP`
-            meaning use CHAP with the specified credentials.
-        """
-
-        properties = {}
-
-        location = volume['provider_location']
-
-        if location:
-            # provider_location is the same format as iSER discovery output
-            properties['target_discovered'] = False
-        else:
-            location = self._do_iser_discovery(volume)
-
-            if not location:
-                msg = (_("Could not find iSER export for volume %s") %
-                        (volume['name']))
-                raise exception.InvalidVolume(reason=msg)
-
-            LOG.debug(_("ISER Discovery: Found %s") % (location))
-            properties['target_discovered'] = True
-
-        results = location.split(" ")
-        properties['target_portal'] = results[0].split(",")[0]
-        properties['target_iqn'] = results[1]
-        try:
-            properties['target_lun'] = int(results[2])
-        except (IndexError, ValueError):
-            if (self.configuration.volume_driver in
-                    ['cinder.volume.drivers.lvm.LVMISERDriver',
-                     'cinder.volume.drivers.lvm.ThinLVMVolumeDriver'] and
-                    self.configuration.iser_helper == 'tgtadm'):
-                properties['target_lun'] = 1
-            else:
-                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 properties
+        # for backward compatibility
+        self.configuration.num_iscsi_scan_tries = \
+            self.configuration.num_iser_scan_tries
+        self.configuration.iscsi_num_targets = \
+            self.configuration.iser_num_targets
+        self.configuration.iscsi_target_prefix = \
+            self.configuration.iser_target_prefix
+        self.configuration.iscsi_ip_address = \
+            self.configuration.iser_ip_address
+        self.configuration.iser_port = self.configuration.iser_port
 
     def initialize_connection(self, volume, connector):
         """Initializes the connection and returns connection info.
@@ -856,123 +788,12 @@ class ISERDriver(ISCSIDriver):
 
         """
 
-        iser_properties = self._get_iser_properties(volume)
+        iser_properties = self._get_iscsi_properties(volume)
         return {
             'driver_volume_type': 'iser',
             'data': iser_properties
         }
 
-    def _check_valid_device(self, path):
-        cmd = ('dd', 'if=%(path)s' % {"path": path},
-               'of=/dev/null', 'count=1')
-        out, info = None, None
-        try:
-            out, info = self._execute(*cmd, run_as_root=True)
-        except processutils.ProcessExecutionError as e:
-            LOG.error(_("Failed to access the device on the path "
-                        "%(path)s: %(error)s.") %
-                      {"path": path, "error": e.stderr})
-            return False
-        # If the info is none, the path does not exist.
-        if info is None:
-            return False
-        return True
-
-    def _attach_volume(self, context, volume, connector):
-        """Attach the volume."""
-        iser_properties = None
-        host_device = None
-        init_conn = self.initialize_connection(volume, connector)
-        iser_properties = init_conn['data']
-
-        # code "inspired by" nova/virt/libvirt/volume.py
-        try:
-            self._run_iscsiadm(iser_properties, ())
-        except processutils.ProcessExecutionError as exc:
-            # iscsiadm returns 21 for "No records found" after version 2.0-871
-            if exc.exit_code in [21, 255]:
-                self._run_iscsiadm(iser_properties, ('--op', 'new'))
-            else:
-                raise
-
-        if iser_properties.get('auth_method'):
-            self._iscsiadm_update(iser_properties,
-                                  "node.session.auth.authmethod",
-                                  iser_properties['auth_method'])
-            self._iscsiadm_update(iser_properties,
-                                  "node.session.auth.username",
-                                  iser_properties['auth_username'])
-            self._iscsiadm_update(iser_properties,
-                                  "node.session.auth.password",
-                                  iser_properties['auth_password'])
-
-        host_device = ("/dev/disk/by-path/ip-%s-iser-%s-lun-%s" %
-                       (iser_properties['target_portal'],
-                        iser_properties['target_iqn'],
-                        iser_properties.get('target_lun', 0)))
-
-        out = self._run_iscsiadm_bare(["-m", "session"],
-                                      run_as_root=True,
-                                      check_exit_code=[0, 1, 21])[0] or ""
-
-        portals = [{'portal': p.split(" ")[2], 'iqn': p.split(" ")[3]}
-                   for p in out.splitlines() if p.startswith("iser:")]
-
-        stripped_portal = iser_properties['target_portal'].split(",")[0]
-        length_iqn = [s for s in portals
-                      if stripped_portal ==
-                      s['portal'].split(",")[0] and
-                      s['iqn'] == iser_properties['target_iqn']]
-        if len(portals) == 0 or len(length_iqn) == 0:
-            try:
-                self._run_iscsiadm(iser_properties, ("--login",),
-                                   check_exit_code=[0, 255])
-            except processutils.ProcessExecutionError as err:
-                if err.exit_code in [15]:
-                    self._iscsiadm_update(iser_properties,
-                                          "node.startup",
-                                          "automatic")
-                    return iser_properties, host_device
-                else:
-                    raise
-
-            self._iscsiadm_update(iser_properties,
-                                  "node.startup", "automatic")
-
-            tries = 0
-            while not os.path.exists(host_device):
-                if tries >= self.configuration.num_iser_scan_tries:
-                    raise exception.CinderException(_("iSER device "
-                                                      "not found "
-                                                      "at %s") % (host_device))
-
-                LOG.warn(_("ISER volume not yet found at: %(host_device)s. "
-                           "Will rescan & retry.  Try number: %(tries)s.") %
-                         {'host_device': host_device, 'tries': tries})
-
-                # The rescan isn't documented as being necessary(?),
-                # but it helps
-                self._run_iscsiadm(iser_properties, ("--rescan",))
-
-                tries = tries + 1
-                if not os.path.exists(host_device):
-                    time.sleep(tries ** 2)
-
-            if tries != 0:
-                LOG.debug(_("Found iSER node %(host_device)s "
-                            "(after %(tries)s rescans).") %
-                          {'host_device': host_device,
-                           'tries': tries})
-
-        if not self._check_valid_device(host_device):
-            raise exception.DeviceUnavailable(path=host_device,
-                                              reason=(_("Unable to access "
-                                                        "the backend storage "
-                                                        "via the path "
-                                                        "%(path)s.") %
-                                                      {'path': host_device}))
-        return iser_properties, host_device
-
     def _update_volume_status(self):
         """Retrieve status info from volume group."""
 
index 8ab46e8e02104c99836f5cc47278c1f8e5fdcce4..8e3cdf4e9701edfa5e6d2fb1ac757d4d26b235fb 100644 (file)
 # Options defined in cinder.volume.driver
 #
 
+# The maximum number of times to rescan iSER targetto find
+# volume (integer value)
+#num_iser_scan_tries=3
+
+# The maximum number of iser target ids per host (integer
+# value)
+#iser_num_targets=100
+
+# prefix for iser volumes (string value)
+#iser_target_prefix=iqn.2010-10.org.iser.openstack:
+
+# The IP address that the iSER daemon is listening on (string
+# value)
+#iser_ip_address=$my_ip
+
+# The port that the iSER daemon is listening on (integer
+# value)
+#iser_port=3260
+
+# iser target user-land tool to use (string value)
+#iser_helper=tgtadm
+
 # number of times to attempt to run flakey shell commands
 # (integer value)
 #num_shell_tries=3
 # (integer value)
 #num_volume_device_scan_tries=3
 
-# The maximum number of times to rescan iSER target to find
-# volume (integer value)
-#num_iser_scan_tries=3
-
-# The maximum number of iser target ids per host (integer
-# value)
-#iser_num_targets=100
-
-# prefix for iser volumes (string value)
-#iser_target_prefix=iqn.2010-10.org.iser.openstack:
-
-# The IP address that the iSER daemon is listening on (string
-# value)
-#iser_ip_address=$my_ip
-
-# The port that the iSER daemon is listening on (integer
-# value)
-#iser_port=3260
-
-# iser target user-land tool to use (string value)
-#iser_helper=tgtadm
-
 # The backend name for a given driver implementation (string
 # value)
 #volume_backend_name=<None>