Add ports filtering support to Dell EMC XtremIO driver

If there are some iSCSI or FC targets (ESXi for example) that
are not connected to the OpenStack host,
attach volume operation waits until timeout.
The XtremIO Cinder driver needs a new option to support ports
filtering.

Change-Id: I2a521118598de336148a56c1d5352107ece80721
Closes-Bug: #1915800
(cherry picked from commit e175d64cac)
This commit is contained in:
Ivan Pchelintsev 2021-02-16 13:29:24 +03:00 committed by Pablo Caruana
parent deb31a0c4d
commit a357ca2755
4 changed files with 119 additions and 17 deletions

View File

@ -62,6 +62,14 @@ xms_init = {'xms': {1: {'version': '4.2.0',
"name": "10.205.68.5/16",
"index": 1,
},
'10.205.68.6/16':
{"port-address":
"iqn.2008-05.com.xtremio:002e67939c34",
"ip-port": 3260,
"ip-addr": "10.205.68.6/16",
"name": "10.205.68.6/16",
"index": 1,
},
},
'targets': {'X1-SC2-target1': {'index': 1, "name": "X1-SC2-fc1",
"port-address":
@ -347,7 +355,8 @@ class BaseXtremIODriverTestCase(test.TestCase):
driver_ssl_cert_path='/test/path/root_ca.crt',
xtremio_array_busy_retry_count=5,
xtremio_array_busy_retry_interval=5,
xtremio_clean_unused_ig=False)
xtremio_clean_unused_ig=False,
xtremio_ports=[])
def safe_get(key):
return getattr(self.config, key)
@ -650,10 +659,26 @@ class XtremIODriverISCSITestCase(BaseXtremIODriverTestCase):
portals = xms_data['iscsi-portals'].copy()
xms_data['iscsi-portals'].clear()
lunmap = {'lun': 4}
self.assertRaises(exception.VolumeDriverException,
self.assertRaises(exception.VolumeBackendAPIException,
self.driver._get_iscsi_properties, lunmap)
xms_data['iscsi-portals'] = portals
def test_no_allowed_portals(self, req):
req.side_effect = xms_request
lunmap = {'lun': 4}
self.driver.allowed_ports = ['1.2.3.4']
self.assertRaises(exception.VolumeBackendAPIException,
self.driver._get_iscsi_properties, lunmap)
def test_filtered_portals(self, req):
req.side_effect = xms_request
lunmap = {'lun': 4}
self.driver.allowed_ports = ['10.205.68.6']
connection_properties = self.driver._get_iscsi_properties(lunmap)
self.assertEqual(1, len(connection_properties['target_portals']))
self.assertIn('10.205.68.6:3260',
connection_properties['target_portals'])
def test_initialize_connection(self, req):
req.side_effect = xms_request
self.driver.create_volume(self.data.test_volume)
@ -1365,6 +1390,27 @@ class XtremIODriverFCTestCase(BaseXtremIODriverTestCase):
configuration=self.config)
# ##### Connection FC#####
def test_no_targets_configured(self, req):
req.side_effect = xms_request
targets = xms_data['targets'].copy()
xms_data['targets'].clear()
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.get_targets)
xms_data['targets'] = targets
def test_no_allowed_targets(self, req):
req.side_effect = xms_request
self.driver.allowed_ports = ['58:cc:f0:98:49:22:07:02']
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.get_targets)
def test_filtered_targets(self, req):
req.side_effect = xms_request
self.driver.allowed_ports = ['21:00:00:24:ff:57:b2:36']
targets = self.driver.get_targets()
self.assertEqual(1, len(targets))
self.assertIn('21000024ff57b236', targets)
def test_initialize_connection(self, req):
req.side_effect = xms_request

View File

@ -31,6 +31,7 @@ Supports XtremIO version 2.4 and up.
1.0.9 - performance improvements, support force detach, support for X2
1.0.10 - option to clean unused IGs
1.0.11 - add support for multiattach
1.0.12 - add support for ports filtering
"""
import json
@ -82,7 +83,13 @@ XTREMIO_OPTS = [
'the IG be, we default to False (not deleting IGs '
'without connected volumes); setting this parameter '
'to True will remove any IG after terminating its '
'connection to the last volume.')]
'connection to the last volume.'),
cfg.ListOpt('xtremio_ports',
default=[],
help='Allowed ports. Comma separated list of XtremIO '
'iSCSI IPs or FC WWNs (ex. 58:cc:f0:98:49:22:07:02) '
'to be used. If option is not set all ports are allowed.')
]
CONF.register_opts(XTREMIO_OPTS, group=configuration.SHARED_CONF_GROUP)
@ -420,7 +427,7 @@ class XtremIOClient42(XtremIOClient4):
class XtremIOVolumeDriver(san.SanDriver):
"""Executes commands relating to Volumes."""
VERSION = '1.0.11'
VERSION = '1.0.12'
# ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_XIO_CI"
@ -444,6 +451,10 @@ class XtremIOVolumeDriver(san.SanDriver):
self.clean_ig = (self.configuration.safe_get('xtremio_clean_unused_ig')
or False)
self._stats = {}
self.allowed_ports = [
port.strip().lower() for port in
self.configuration.safe_get('xtremio_ports')
]
self.client = XtremIOClient3(self.configuration, self.cluster_id)
@classmethod
@ -1054,6 +1065,19 @@ class XtremIOVolumeDriver(san.SanDriver):
raise (exception.VolumeBackendAPIException
(data=_("Failed to create IG, %s") % name))
def _port_is_allowed(self, port):
"""Check if port is in allowed ports list.
If allowed ports are empty then all ports are allowed.
:param port: iSCSI IP/FC WWN to check
:return: is port allowed
"""
if not self.allowed_ports:
return True
return port.lower() in self.allowed_ports
@interface.volumedriver
class XtremIOISCSIDriver(XtremIOVolumeDriver, driver.ISCSIDriver):
@ -1171,26 +1195,33 @@ class XtremIOISCSIDriver(XtremIOVolumeDriver, driver.ISCSIDriver):
multiple values. The main portal information is also returned in
:target_iqn, :target_portal, :target_lun for backward compatibility.
"""
portals = self.client.get_iscsi_portals()
if not portals:
msg = _("XtremIO not configured correctly, no iscsi portals found")
LOG.error(msg)
raise exception.VolumeDriverException(message=msg)
portal = RANDOM.choice(portals)
iscsi_portals = self.client.get_iscsi_portals()
allowed_portals = []
for iscsi_portal in iscsi_portals:
iscsi_portal['ip-addr'] = iscsi_portal['ip-addr'].split('/')[0]
if self._port_is_allowed(iscsi_portal['ip-addr']):
allowed_portals.append(iscsi_portal)
if not allowed_portals:
msg = _("There are no accessible iSCSI targets on the "
"system.")
raise exception.VolumeBackendAPIException(data=msg)
portal = RANDOM.choice(allowed_portals)
portal_addr = ('%(ip)s:%(port)d' %
{'ip': portal['ip-addr'].split('/')[0],
{'ip': portal['ip-addr'],
'port': portal['ip-port']})
tg_portals = ['%(ip)s:%(port)d' % {'ip': p['ip-addr'].split('/')[0],
tg_portals = ['%(ip)s:%(port)d' % {'ip': p['ip-addr'],
'port': p['ip-port']}
for p in portals]
for p in allowed_portals]
properties = {'target_discovered': False,
'target_iqn': portal['port-address'],
'target_lun': lunmap['lun'],
'target_portal': portal_addr,
'target_iqns': [p['port-address'] for p in portals],
'target_iqns': [
p['port-address'] for p in allowed_portals
],
'target_portals': tg_portals,
'target_luns': [lunmap['lun']] * len(portals)}
'target_luns': [lunmap['lun']] * len(allowed_portals)}
return properties
def _get_initiator_names(self, connector):
@ -1213,8 +1244,17 @@ class XtremIOFCDriver(XtremIOVolumeDriver,
if not self._targets:
try:
targets = self.client.get_fc_up_ports()
self._targets = [target['port-address'].replace(':', '')
for target in targets]
allowed_targets = []
for target in targets:
if self._port_is_allowed(target['port-address']):
allowed_targets.append(
target['port-address'].replace(':', '')
)
if not allowed_targets:
msg = _("There are no accessible Fibre Channel targets "
"on the system.")
raise exception.VolumeBackendAPIException(data=msg)
self._targets = allowed_targets
except exception.NotFound:
raise (exception.VolumeBackendAPIException
(data=_("Failed to get targets")))

View File

@ -233,6 +233,16 @@ The CHAP initiator authentication and discovery credentials (username and
password) are generated automatically by the Block Storage driver. Therefore,
there is no need to configure the initial CHAP credentials manually in XMS.
Configuring ports filtering
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The XtremIO Block Storage driver supports ports filtering to define a list
of iSCSI IP-addresses or FC WWNs which will be used to attach volumes.
If option is not set all ports are allowed.
.. code-block:: ini
xtremio_ports = iSCSI IPs or FC WWNs
.. _emc_extremio_configuration_example:
Configuration example
@ -250,6 +260,7 @@ follows:
volume_driver = cinder.volume.drivers.dell_emc.xtremio.XtremIOFibreChannelDriver
san_ip = XMS_IP
xtremio_cluster_name = Cluster01
xtremio_ports = 21:00:00:24:ff:57:b2:36,21:00:00:24:ff:57:b2:55
san_login = XMS_USER
san_password = XMS_PASSWD
volume_backend_name = XtremIOAFA

View File

@ -0,0 +1,5 @@
---
fixes:
- |
`Bug #1915800 <https://bugs.launchpad.net/cinder/+bug/1915800>`_:
Add support for ports filtering in XtremIO driver.