]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add ability to zfssa driver to create multiple initiator groups
authoramoturi <abhiram.moturi@oracle.com>
Wed, 8 Oct 2014 04:32:28 +0000 (00:32 -0400)
committerabhiram moturi <abhiram.moturi@oracle.com>
Tue, 2 Dec 2014 18:40:30 +0000 (13:40 -0500)
Currently the zfssa driver only support one initiator group. This
is causing broken scsi devices when detaching volumes from instances.
This fix adds support for configuring multiple initiator groups.

Closes-Bug: #1378390
DocImpact

Change-Id: Ib3262ebd40e9c2ff2f36d0a7b1b5b3506ed3acc1

cinder/tests/test_zfssa.py
cinder/volume/drivers/zfssa/zfssaiscsi.py
cinder/volume/drivers/zfssa/zfssarest.py
etc/cinder/cinder.conf.sample

index a09e00b0602f6e940f873e1bb8b5ce524d27ffa2..b02e7bda653eafa12698502cbe216d86db9e4cdc 100644 (file)
@@ -214,12 +214,17 @@ class FakeZFSSA(object):
 
         return out
 
+    def get_initiator_initiatorgroup(self, initiator):
+        ret = ['test-init-grp1']
+        return ret
+
 
 class TestZFSSAISCSIDriver(test.TestCase):
 
     test_vol = {
         'name': 'cindervol',
-        'size': 1
+        'size': 1,
+        'id': 1
     }
 
     test_snap = {
@@ -259,6 +264,9 @@ class TestZFSSAISCSIDriver(test.TestCase):
             'iqn.1-0.org.deb:01:d7, iqn.1-0.org.deb:01:d9'
         self.configuration.zfssa_initiator_user = ''
         self.configuration.zfssa_initiator_password = ''
+        self.configuration.zfssa_initiator_config = "{'test-init-grp1':[{'iqn':\
+            'iqn.1-0.org.deb:01:d7','user':'','password':''}],'test-init-grp\
+            2':[{'iqn':'iqn.1-0.org.deb:01:d9','user':'','password':''}]}"
         self.configuration.zfssa_target_group = 'test-target-grp1'
         self.configuration.zfssa_target_user = ''
         self.configuration.zfssa_target_password = ''
@@ -283,14 +291,20 @@ class TestZFSSAISCSIDriver(test.TestCase):
                                              self.test_snap)
         self.drv.delete_volume(self.test_vol)
 
-    def test_create_export(self):
+    def test_remove_export(self):
         self.drv.create_volume(self.test_vol)
-        self.drv.create_export({}, self.test_vol)
+        self.drv.terminate_connection(self.test_vol, '')
         self.drv.delete_volume(self.test_vol)
 
-    def test_remove_export(self):
+    def test_volume_attach_detach(self):
         self.drv.create_volume(self.test_vol)
-        self.drv.remove_export({}, self.test_vol)
+
+        connector = dict(initiator='iqn.1-0.org.deb:01:d7')
+        props = self.drv.initialize_connection(self.test_vol, connector)
+        self.assertEqual('iscsi', props['driver_volume_type'])
+        self.assertEqual(self.test_vol['id'], props['data']['volume_id'])
+
+        self.drv.terminate_connection(self.test_vol, '')
         self.drv.delete_volume(self.test_vol)
 
     def test_get_volume_stats(self):
index 882b28a125b83d581668593fe4e8009b3d242299..a18b8edbe13495975d29e5d8d3b976b31602abad 100644 (file)
 """
 ZFS Storage Appliance Cinder Volume Driver
 """
+import ast
 import base64
 
 from oslo.config import cfg
 from oslo.utils import units
 
 from cinder import exception
-from cinder.i18n import _, _LE
+from cinder.i18n import _, _LE, _LW
 from cinder.openstack.common import log
 from cinder.volume import driver
 from cinder.volume.drivers.san import san
@@ -50,6 +51,8 @@ ZFSSA_OPTS = [
                help='iSCSI initiator CHAP user.'),
     cfg.StrOpt('zfssa_initiator_password', default='',
                help='iSCSI initiator CHAP password.'),
+    cfg.StrOpt('zfssa_initiator_config', default='',
+               help='iSCSI initiators configuration.'),
     cfg.StrOpt('zfssa_target_group', default='tgt-grp',
                help='iSCSI target group name.'),
     cfg.StrOpt('zfssa_target_user', default='',
@@ -107,30 +110,46 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
                                   compression=lcfg.zfssa_lun_compression,
                                   logbias=lcfg.zfssa_lun_logbias)
 
-        if (lcfg.zfssa_initiator != '' and
-            (lcfg.zfssa_initiator_group == '' or
-             lcfg.zfssa_initiator_group == 'default')):
-            msg = (_('zfssa_initiator: %(ini)s'
-                     ' wont be used on '
-                     'zfssa_initiator_group= %(inigrp)s.')
-                   % {'ini': lcfg.zfssa_initiator,
-                      'inigrp': lcfg.zfssa_initiator_group})
-
-            LOG.warning(msg)
-        # Setup initiator and initiator group
-        if (lcfg.zfssa_initiator != '' and
-           lcfg.zfssa_initiator_group != '' and
-           lcfg.zfssa_initiator_group != 'default'):
-            for initiator in lcfg.zfssa_initiator.split(','):
-                self.zfssa.create_initiator(initiator,
-                                            lcfg.zfssa_initiator_group + '-' +
-                                            initiator,
-                                            chapuser=
-                                            lcfg.zfssa_initiator_user,
-                                            chapsecret=
-                                            lcfg.zfssa_initiator_password)
-                self.zfssa.add_to_initiatorgroup(initiator,
-                                                 lcfg.zfssa_initiator_group)
+        if (lcfg.zfssa_initiator_config != ''):
+            initiator_config = ast.literal_eval(lcfg.zfssa_initiator_config)
+            for initiator_group in initiator_config:
+                zfssa_initiator_group = initiator_group
+                for zfssa_initiator in initiator_config[zfssa_initiator_group]:
+                    self.zfssa.create_initiator(zfssa_initiator['iqn'],
+                                                zfssa_initiator_group + '-' +
+                                                zfssa_initiator['iqn'],
+                                                chapuser=
+                                                zfssa_initiator['user'],
+                                                chapsecret=
+                                                zfssa_initiator['password'])
+                    if (zfssa_initiator_group != 'default'):
+                        self.zfssa.add_to_initiatorgroup(
+                            zfssa_initiator['iqn'],
+                            zfssa_initiator_group)
+        else:
+            LOG.warning(_LW('zfssa_initiator_config not found. '
+                            'Using deprecated configuration options.'))
+            if (lcfg.zfssa_initiator != '' and
+                (lcfg.zfssa_initiator_group == '' or
+                 lcfg.zfssa_initiator_group == 'default')):
+                LOG.warning(_LW('zfssa_initiator: %(ini)s'
+                                ' wont be used on '
+                                'zfssa_initiator_group= %(inigrp)s.')
+                            % {'ini': lcfg.zfssa_initiator,
+                               'inigrp': lcfg.zfssa_initiator_group})
+
+            # Setup initiator and initiator group
+            if (lcfg.zfssa_initiator != '' and
+               lcfg.zfssa_initiator_group != '' and
+               lcfg.zfssa_initiator_group != 'default'):
+                for initiator in lcfg.zfssa_initiator.split(','):
+                    self.zfssa.create_initiator(
+                        initiator, lcfg.zfssa_initiator_group + '-' +
+                        initiator, chapuser=lcfg.zfssa_initiator_user,
+                        chapsecret=lcfg.zfssa_initiator_password)
+                    self.zfssa.add_to_initiatorgroup(
+                        initiator, lcfg.zfssa_initiator_group)
+
         # Parse interfaces
         interfaces = []
         for interface in lcfg.zfssa_target_interfaces.split(','):
@@ -158,11 +177,18 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
         self.zfssa.verify_pool(lcfg.zfssa_pool)
         self.zfssa.verify_project(lcfg.zfssa_pool, lcfg.zfssa_project)
 
-        if (lcfg.zfssa_initiator != '' and
-           lcfg.zfssa_initiator_group != '' and
-           lcfg.zfssa_initiator_group != 'default'):
-            for initiator in lcfg.zfssa_initiator.split(','):
-                self.zfssa.verify_initiator(initiator)
+        if (lcfg.zfssa_initiator_config != ''):
+            initiator_config = ast.literal_eval(lcfg.zfssa_initiator_config)
+            for initiator_group in initiator_config:
+                zfssa_initiator_group = initiator_group
+                for zfssa_initiator in initiator_config[zfssa_initiator_group]:
+                    self.zfssa.verify_initiator(zfssa_initiator['iqn'])
+        else:
+            if (lcfg.zfssa_initiator != '' and
+               lcfg.zfssa_initiator_group != '' and
+               lcfg.zfssa_initiator_group != 'default'):
+                for initiator in lcfg.zfssa_initiator.split(','):
+                    self.zfssa.verify_initiator(initiator)
 
             self.zfssa.verify_target(self._get_target_alias())
 
@@ -197,8 +223,6 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
                               compression=lcfg.zfssa_lun_compression,
                               logbias=lcfg.zfssa_lun_logbias)
 
-        return self._get_provider_info(volume)
-
     def delete_volume(self, volume):
         """Deletes a volume with the given volume['name']."""
         LOG.debug('zfssa.delete_volume: name=' + volume['name'])
@@ -308,35 +332,14 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
             self._update_volume_status()
         return self._stats
 
-    def _export_volume(self, volume):
-        """Export the volume - set the initiatorgroup property."""
-        LOG.debug('_export_volume: volume name: %s' % volume['name'])
-        lcfg = self.configuration
-
-        self.zfssa.set_lun_initiatorgroup(lcfg.zfssa_pool,
-                                          lcfg.zfssa_project,
-                                          volume['name'],
-                                          lcfg.zfssa_initiator_group)
-        return self._get_provider_info(volume)
-
     def create_export(self, context, volume):
-        """Driver entry point to get the  export info for a new volume."""
-        LOG.debug('create_export: volume name: %s' % volume['name'])
-        return self._export_volume(volume)
+        pass
 
     def remove_export(self, context, volume):
-        """Driver entry point to remove an export for a volume."""
-        LOG.debug('remove_export: volume name: %s' % volume['name'])
-        lcfg = self.configuration
-        self.zfssa.set_lun_initiatorgroup(lcfg.zfssa_pool,
-                                          lcfg.zfssa_project,
-                                          volume['name'],
-                                          '')
+        pass
 
     def ensure_export(self, context, volume):
-        """Driver entry point to get the export info for an existing volume."""
-        LOG.debug('ensure_export: volume name: %s' % volume['name'])
-        return self._export_volume(volume)
+        pass
 
     def copy_image_to_volume(self, context, volume, image_service, image_id):
         self.ensure_export(context, volume)
@@ -387,3 +390,42 @@ class ZFSSAISCSIDriver(driver.ISCSIDriver):
                                  lcfg.zfssa_project,
                                  snapshot['volume_name'])
         return lun['size'] == size
+
+    def initialize_connection(self, volume, connector):
+        lcfg = self.configuration
+        init_groups = self.zfssa.get_initiator_initiatorgroup(
+            connector['initiator'])
+        for initiator_group in init_groups:
+            self.zfssa.set_lun_initiatorgroup(lcfg.zfssa_pool,
+                                              lcfg.zfssa_project,
+                                              volume['name'],
+                                              initiator_group)
+        iscsi_properties = {}
+        provider = self._get_provider_info(volume)
+        (target_portal, iqn, lun) = provider['provider_location'].split()
+        iscsi_properties['target_discovered'] = False
+        iscsi_properties['target_portal'] = target_portal
+        iscsi_properties['target_iqn'] = iqn
+        iscsi_properties['target_lun'] = lun
+        iscsi_properties['volume_id'] = volume['id']
+
+        if 'provider_auth' in provider:
+            (auth_method, auth_username, auth_password) = provider[
+                'provider_auth'].split()
+            iscsi_properties['auth_method'] = auth_method
+            iscsi_properties['auth_username'] = auth_username
+            iscsi_properties['auth_password'] = auth_password
+
+        return {
+            'driver_volume_type': 'iscsi',
+            'data': iscsi_properties
+        }
+
+    def terminate_connection(self, volume, connector, **kwargs):
+        """Driver entry point to terminate a connection for a volume."""
+        LOG.debug('terminate_connection: volume name: %s.' % volume['name'])
+        lcfg = self.configuration
+        self.zfssa.set_lun_initiatorgroup(lcfg.zfssa_pool,
+                                          lcfg.zfssa_project,
+                                          volume['name'],
+                                          '')
index 762951374aea9361a058b1bd4efe45e74bdd7536..92128189c7bbcc3f0f328bf033f14a8fe7b5d94a 100644 (file)
@@ -17,7 +17,7 @@ ZFS Storage Appliance Proxy
 import json
 
 from cinder import exception
-from cinder.i18n import _
+from cinder.i18n import _, _LE
 from cinder.openstack.common import log
 from cinder.volume.drivers.zfssa import restclient
 
@@ -628,3 +628,22 @@ class ZFSSAApi(object):
 
         val = json.loads(ret.data)
         return val['snapshot']['numclones'] != 0
+
+    def get_initiator_initiatorgroup(self, initiator):
+        """Returns the initiator group of the initiator."""
+        groups = []
+        svc = "/api/san/v1/iscsi/initiator-groups"
+        ret = self.rclient.get(svc)
+        if ret.status != restclient.Status.OK:
+            LOG.error(_LE('Error getting initiator groups.'))
+            exception_msg = (_('Error getting initiator groups.'))
+            raise exception.VolumeBackendAPIException(data=exception_msg)
+        val = json.loads(ret.data)
+        for initiator_group in val['groups']:
+            if initiator in initiator_group['initiators']:
+                groups.append(initiator_group["name"])
+        if len(groups) == 0:
+            LOG.debug("Initiator group not found. Attaching volume to "
+                      "default initiator group.")
+            groups.append('default')
+        return groups
index 47842bfa9f91913c9a2936687c1b3b317193a224..1ae947d45bc1316a23dda7ff9ad46a172538385a 100644 (file)
 # iSCSI initiator CHAP password. (string value)
 #zfssa_initiator_password=
 
+# iSCSI initiators configuration. (string value)
+#zfssa_initiator_config=
+
 # iSCSI target group name. (string value)
 #zfssa_target_group=tgt-grp