VNX: add option vnx_async_migrate

Before this fix, customers can disable async migration only by passing
`--metadata async_migrate=False` in volumes metadata. This fix adds an
option named `vnx_async_migrate` which could help set the default value
of async migration for whole backend. If customers don't pass in the
`async_migrate` in metadata, the value of this option will be used.

Change-Id: I8e59039da78ecc9fb5415a10ff2a7c26ee689171
Closes-bug: #1796825
This commit is contained in:
Ryan Liang 2019-02-26 17:12:27 +08:00
parent 698b522a57
commit 3ecdc2bfc8
8 changed files with 66 additions and 12 deletions
cinder
tests/unit/volume/drivers/dell_emc/vnx
volume/drivers/dell_emc/vnx
doc/source/configuration/block-storage/drivers
releasenotes/notes

@ -573,6 +573,9 @@ test_calc_migrate_and_provision_image_cache:
test_calc_migrate_and_provision: test_calc_migrate_and_provision:
volume: *volume_base volume: *volume_base
test_calc_migrate_and_provision_default:
volume: *volume_base
test_get_backend_qos_specs: test_get_backend_qos_specs:
volume: volume:
_type: 'volume' _type: 'volume'

@ -205,6 +205,18 @@ class TestUtils(test_base.TestCase):
async_migrate) async_migrate)
self.assertEqual(provision.name, 'THICK') self.assertEqual(provision.name, 'THICK')
@res_mock.mock_driver_input
def test_calc_migrate_and_provision_default(self, mocked):
volume = mocked['volume']
volume.display_name = 'volume-ca86b9a0-d0d5-4267-8cd5-c62274056cc0'
async_migrate, provision = vnx_utils.calc_migrate_and_provision(
volume, default_async_migrate=False)
self.assertFalse(async_migrate)
self.assertEqual(provision.name, 'THICK')
async_migrate, provision = vnx_utils.calc_migrate_and_provision(
volume, default_async_migrate=True)
self.assertTrue(async_migrate)
@ut_utils.patch_extra_specs({}) @ut_utils.patch_extra_specs({})
@res_mock.mock_driver_input @res_mock.mock_driver_input
def test_get_backend_qos_specs(self, cinder_input): def test_get_backend_qos_specs(self, cinder_input):

@ -67,6 +67,7 @@ class CommonAdapter(replication.ReplicationAdapter):
self.destroy_empty_sg = None self.destroy_empty_sg = None
self.itor_auto_dereg = None self.itor_auto_dereg = None
self.queue_path = None self.queue_path = None
self.async_migrate = None
def _build_client_from_config(self, config, queue_path=None): def _build_client_from_config(self, config, queue_path=None):
return client.Client( return client.Client(
@ -104,6 +105,7 @@ class CommonAdapter(replication.ReplicationAdapter):
self.protocol = self.config.storage_protocol self.protocol = self.config.storage_protocol
self.destroy_empty_sg = self.config.destroy_empty_storage_group self.destroy_empty_sg = self.config.destroy_empty_storage_group
self.itor_auto_dereg = self.config.initiator_auto_deregistration self.itor_auto_dereg = self.config.initiator_auto_deregistration
self.async_migrate = self.config.vnx_async_migrate
self.set_extra_spec_defaults() self.set_extra_spec_defaults()
def _normalize_config(self): def _normalize_config(self):
@ -349,7 +351,8 @@ class CommonAdapter(replication.ReplicationAdapter):
volume_metadata['snapcopy'] = 'True' volume_metadata['snapcopy'] = 'True'
volume_metadata['async_migrate'] = 'False' volume_metadata['async_migrate'] = 'False'
else: else:
async_migrate, provision = utils.calc_migrate_and_provision(volume) async_migrate, provision = utils.calc_migrate_and_provision(
volume, default_async_migrate=self.async_migrate)
new_snap_name = ( new_snap_name = (
utils.construct_snap_name(volume) if async_migrate else None) utils.construct_snap_name(volume) if async_migrate else None)
new_lun_id = emc_taskflow.create_volume_from_snapshot( new_lun_id = emc_taskflow.create_volume_from_snapshot(
@ -404,7 +407,8 @@ class CommonAdapter(replication.ReplicationAdapter):
volume_metadata['snapcopy'] = 'True' volume_metadata['snapcopy'] = 'True'
volume_metadata['async_migrate'] = 'False' volume_metadata['async_migrate'] = 'False'
else: else:
async_migrate, provision = utils.calc_migrate_and_provision(volume) async_migrate, provision = utils.calc_migrate_and_provision(
volume, default_async_migrate=self.async_migrate)
new_lun_id = emc_taskflow.create_cloned_volume( new_lun_id = emc_taskflow.create_cloned_volume(
client=self.client, client=self.client,
snap_name=snap_name, snap_name=snap_name,
@ -779,7 +783,8 @@ class CommonAdapter(replication.ReplicationAdapter):
def delete_volume(self, volume): def delete_volume(self, volume):
"""Deletes an EMC volume.""" """Deletes an EMC volume."""
async_migrate = utils.is_async_migrate_enabled(volume) async_migrate = utils.is_async_migrate_enabled(
volume, default=self.async_migrate)
snap_copy = (utils.construct_snap_name(volume) if snap_copy = (utils.construct_snap_name(volume) if
utils.is_snapcopy_enabled(volume) else None) utils.is_snapcopy_enabled(volume) else None)
self.cleanup_lun_replication(volume) self.cleanup_lun_replication(volume)

@ -109,7 +109,17 @@ VNX_OPTS = [
default=False, default=False,
help='Force LUN creation even if ' help='Force LUN creation even if '
'the full threshold of pool is reached. ' 'the full threshold of pool is reached. '
'By default, the value is False.') 'By default, the value is False.'),
cfg.BoolOpt('vnx_async_migrate',
default=True,
help='Always use asynchronous migration during volume cloning '
'and creating from snapshot. As described in '
'configuration doc, async migration has some '
'constraints. Besides using metadata, customers could '
'use this option to disable async migration. Be aware '
'that `async_migrate` in metadata overrides this '
'option when both are set. By default, the value is True.'
)
] ]
CONF.register_opts(VNX_OPTS, group=configuration.SHARED_CONF_GROUP) CONF.register_opts(VNX_OPTS, group=configuration.SHARED_CONF_GROUP)

@ -86,9 +86,11 @@ class VNXDriver(driver.ManageableVD,
under `destroy_empty_stroage_group` setting to `True` under `destroy_empty_stroage_group` setting to `True`
14.0.0 - Fix bug 1794646: failed to delete LUNs from backend due to 14.0.0 - Fix bug 1794646: failed to delete LUNs from backend due to
the temporary snapshots on them wasn't deleted. the temporary snapshots on them wasn't deleted.
14.0.1 - Fix bug 1796825, add an option to set default value for
`async_migrate`.
""" """
VERSION = '14.00.00' VERSION = '14.00.01'
VENDOR = 'Dell EMC' VENDOR = 'Dell EMC'
# ThirdPartySystems wiki page # ThirdPartySystems wiki page
CI_WIKI_NAME = "EMC_VNX_CI" CI_WIKI_NAME = "EMC_VNX_CI"

@ -257,7 +257,7 @@ def is_snapcopy_enabled(volume):
return 'snapcopy' in meta and meta['snapcopy'].lower() == 'true' return 'snapcopy' in meta and meta['snapcopy'].lower() == 'true'
def is_async_migrate_enabled(volume): def is_async_migrate_enabled(volume, default=True):
extra_specs = common.ExtraSpecs.from_volume(volume) extra_specs = common.ExtraSpecs.from_volume(volume)
if extra_specs.is_replication_enabled: if extra_specs.is_replication_enabled:
# For replication-enabled volume, we should not use the async-cloned # For replication-enabled volume, we should not use the async-cloned
@ -266,8 +266,7 @@ def is_async_migrate_enabled(volume):
return False return False
meta = get_metadata(volume) meta = get_metadata(volume)
if 'async_migrate' not in meta: if 'async_migrate' not in meta:
# Asynchronous migration is the default behavior now return default
return True
return 'async_migrate' in meta and meta['async_migrate'].lower() == 'true' return 'async_migrate' in meta and meta['async_migrate'].lower() == 'true'
@ -441,7 +440,7 @@ def is_image_cache_volume(volume):
return False return False
def calc_migrate_and_provision(volume): def calc_migrate_and_provision(volume, default_async_migrate=True):
"""Returns a tuple of async migrate and provision type. """Returns a tuple of async migrate and provision type.
The first element is the flag whether to enable async migrate, The first element is the flag whether to enable async migrate,
@ -451,7 +450,8 @@ def calc_migrate_and_provision(volume):
return False, storops.VNXProvisionEnum.THIN return False, storops.VNXProvisionEnum.THIN
else: else:
specs = common.ExtraSpecs.from_volume(volume) specs = common.ExtraSpecs.from_volume(volume)
return is_async_migrate_enabled(volume), specs.provision return (is_async_migrate_enabled(volume, default_async_migrate),
specs.provision)
def get_backend_qos_specs(volume): def get_backend_qos_specs(volume):

@ -433,6 +433,16 @@ Ignore pool full threshold
If ``ignore_pool_full_threshold`` is set to ``True``, driver will force LUN If ``ignore_pool_full_threshold`` is set to ``True``, driver will force LUN
creation even if the full threshold of pool is reached. Default to ``False``. creation even if the full threshold of pool is reached. Default to ``False``.
Default value for async migration
---------------------------------
Option ``vnx_async_migrate`` is used to set the default value of async
migration for the backend. The default value of this option is `True` if it
isn't set in ``cinder.conf`` to preserve compatibility. If ``async_migrate`` is
not set in metadata of volume, the value of this option will be used.
Otherwise, ``async_migrate`` value in metadata will override the value of this
option. For more detail, refer to `asynchronous migration support`_.
Extra spec options Extra spec options
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
@ -791,8 +801,14 @@ as the default cloning method. The driver will return immediately after the
migration session starts on the VNX, which dramatically reduces the time before migration session starts on the VNX, which dramatically reduces the time before
a volume is available for use. a volume is available for use.
To disable this feature, user can add ``--metadata async_migrate=False`` when To disable this feature, user needs to do any one of below actions:
creating new volume from source.
- Configure ``vnx_async_migrate = False`` for the backend in ``cinder.conf``,
then restart Cinder services.
- Add ``--metadata async_migrate=False`` when creating new volume from source.
Be aware, ``async_migrate`` in metadata overrides the option
``vnx_async_migrate`` when both are set.
**Constraints** **Constraints**

@ -0,0 +1,6 @@
---
fixes:
- |
Dell EMC VNX Driver: Fix `bug 1796825
<https://bugs.launchpad.net/cinder/+bug/1796825>`__, adding an option named
`vnx_async_migrate` to accept the default setting for async migration.