From: amoturi Date: Wed, 8 Oct 2014 04:32:28 +0000 (-0400) Subject: Add ability to zfssa driver to create multiple initiator groups X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=16db3ce22e1740ec195653970349e734e011b228;p=openstack-build%2Fcinder-build.git Add ability to zfssa driver to create multiple initiator groups 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 --- diff --git a/cinder/tests/test_zfssa.py b/cinder/tests/test_zfssa.py index a09e00b06..b02e7bda6 100644 --- a/cinder/tests/test_zfssa.py +++ b/cinder/tests/test_zfssa.py @@ -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): diff --git a/cinder/volume/drivers/zfssa/zfssaiscsi.py b/cinder/volume/drivers/zfssa/zfssaiscsi.py index 882b28a12..a18b8edbe 100644 --- a/cinder/volume/drivers/zfssa/zfssaiscsi.py +++ b/cinder/volume/drivers/zfssa/zfssaiscsi.py @@ -14,13 +14,14 @@ """ 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'], + '') diff --git a/cinder/volume/drivers/zfssa/zfssarest.py b/cinder/volume/drivers/zfssa/zfssarest.py index 762951374..92128189c 100644 --- a/cinder/volume/drivers/zfssa/zfssarest.py +++ b/cinder/volume/drivers/zfssa/zfssarest.py @@ -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 diff --git a/etc/cinder/cinder.conf.sample b/etc/cinder/cinder.conf.sample index 47842bfa9..1ae947d45 100644 --- a/etc/cinder/cinder.conf.sample +++ b/etc/cinder/cinder.conf.sample @@ -2278,6 +2278,9 @@ # 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