diff --git a/cinder/tests/unit/volume/drivers/dell_emc/test_xtremio.py b/cinder/tests/unit/volume/drivers/dell_emc/test_xtremio.py index 974e9a82f3a..4958017231b 100644 --- a/cinder/tests/unit/volume/drivers/dell_emc/test_xtremio.py +++ b/cinder/tests/unit/volume/drivers/dell_emc/test_xtremio.py @@ -329,9 +329,10 @@ class BaseXtremIODriverTestCase(test.TestCase): max_over_subscription_ratio=20.0, xtremio_volumes_per_glance_cache=100, driver_ssl_cert_verify=True, - driver_ssl_cert_path= '/test/path/root_ca.crt', + driver_ssl_cert_path='/test/path/root_ca.crt', xtremio_array_busy_retry_count=5, - xtremio_array_busy_retry_interval=5) + xtremio_array_busy_retry_interval=5, + xtremio_clean_unused_ig=False) def safe_get(key): return getattr(self.config, key) @@ -617,11 +618,27 @@ class XtremIODriverISCSITestCase(BaseXtremIODriverTestCase): def test_terminate_connection(self, req): req.side_effect = xms_request self.driver.create_volume(self.data.test_volume) - self.driver.create_volume(self.data.test_volume2) self.driver.initialize_connection(self.data.test_volume, self.data.connector) + i1 = xms_data['initiators'][1] + i1['ig-id'] = ['', i1['ig-id'], 1] self.driver.terminate_connection(self.data.test_volume, self.data.connector) + self.assertEqual(1, len(xms_data['initiator-groups'])) + + def test_terminate_connection_clean_ig(self, req): + self.driver.clean_ig = True + req.side_effect = xms_request + self.driver.create_volume(self.data.test_volume) + self.driver.initialize_connection(self.data.test_volume, + self.data.connector) + i1 = xms_data['initiators'][1] + i1['ig-id'] = ['', i1['ig-id'], 1] + xms_data['initiator-groups'][1]['num-of-vols'] = 0 + # lun mapping list is a list of triplets (IG OID, TG OID, lun number) + self.driver.terminate_connection(self.data.test_volume, + self.data.connector) + self.assertEqual(0, len(xms_data['initiator-groups'])) def test_terminate_connection_fail_on_bad_volume(self, req): req.side_effect = xms_request diff --git a/cinder/volume/drivers/dell_emc/xtremio.py b/cinder/volume/drivers/dell_emc/xtremio.py index bac055a0a1d..b3ec01dc6b9 100644 --- a/cinder/volume/drivers/dell_emc/xtremio.py +++ b/cinder/volume/drivers/dell_emc/xtremio.py @@ -28,6 +28,8 @@ supported XtremIO version 2.4 and up R/O snapshots, CHAP discovery authentication 1.0.7 - cache glance images on the array 1.0.8 - support for volume retype, CG fixes + 1.0.9 - performance improvements, support force detach, support for X2 + 1.0.10 - option to clean unused IGs """ import json @@ -71,7 +73,16 @@ XTREMIO_OPTS = [ help='Interval between retries in case array is busy'), cfg.IntOpt('xtremio_volumes_per_glance_cache', default=100, - help='Number of volumes created from each cached glance image')] + help='Number of volumes created from each cached glance image'), + cfg.BoolOpt('xtremio_clean_unused_ig', + default=False, + help='Should the driver remove initiator groups with no ' + 'volumes after the last connection was terminated. ' + 'Since the behavior till now was to leave ' + '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.')] CONF.register_opts(XTREMIO_OPTS, group=configuration.SHARED_CONF_GROUP) @@ -396,7 +407,7 @@ class XtremIOClient42(XtremIOClient4): class XtremIOVolumeDriver(san.SanDriver): """Executes commands relating to Volumes.""" - VERSION = '1.0.9' + VERSION = '1.0.10' # ThirdPartySystems wiki CI_WIKI_NAME = "EMC_XIO_CI" @@ -415,6 +426,8 @@ class XtremIOVolumeDriver(san.SanDriver): self.provisioning_factor = (self.configuration. safe_get('max_over_subscription_ratio') or DEFAULT_PROVISIONING_FACTOR) + self.clean_ig = (self.configuration.safe_get('xtremio_clean_unused_ig') + or False) self._stats = {} self.client = XtremIOClient3(self.configuration, self.cluster_id) @@ -708,6 +721,18 @@ class XtremIOVolumeDriver(san.SanDriver): except exception.NotFound: LOG.warning("terminate_connection: lun map not found") + if self.clean_ig: + for idx in ig_indexes: + try: + ig = self.client.req('initiator-groups', 'GET', + {'prop': 'num-of-vols'}, + idx=idx)['content'] + if ig['num-of-vols'] == 0: + self.client.req('initiator-groups', 'DELETE', idx=idx) + except (exception.NotFound, + exception.VolumeBackendAPIException): + LOG.warning('Failed to clean IG %d without mappings', idx) + def _get_password(self): return ''.join(RANDOM.choice (string.ascii_uppercase + string.digits) diff --git a/releasenotes/notes/xtremio-ig-cleanup-bbb4bee1f1e3611c.yaml b/releasenotes/notes/xtremio-ig-cleanup-bbb4bee1f1e3611c.yaml new file mode 100644 index 00000000000..e6f0c03e8ac --- /dev/null +++ b/releasenotes/notes/xtremio-ig-cleanup-bbb4bee1f1e3611c.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + New option to delete XtremIO initiator groups after the last volume was + detached from them, can be enabled by setting xtremio_clean_unused_ig to True