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:
parent
deb31a0c4d
commit
a357ca2755
@ -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
|
||||
|
||||
|
@ -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")))
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
`Bug #1915800 <https://bugs.launchpad.net/cinder/+bug/1915800>`_:
|
||||
Add support for ports filtering in XtremIO driver.
|
Loading…
Reference in New Issue
Block a user