Merge "Dell EMC: PowerMax - Configurable SRDF snapshots"

This commit is contained in:
Zuul 2024-03-15 15:07:33 +00:00 committed by Gerrit Code Review
commit 08835cab08
7 changed files with 88 additions and 16 deletions

View File

@ -450,6 +450,7 @@ class PowerMaxData(object):
rep_extra_specs['sync_retries'] = 200 rep_extra_specs['sync_retries'] = 200
rep_extra_specs['rdf_group_label'] = rdf_group_name_1 rep_extra_specs['rdf_group_label'] = rdf_group_name_1
rep_extra_specs['rdf_group_no'] = rdf_group_no_1 rep_extra_specs['rdf_group_no'] = rdf_group_no_1
rep_extra_specs[utils.DISABLE_PROTECTED_SNAP] = False
rep_extra_specs2 = deepcopy(rep_extra_specs) rep_extra_specs2 = deepcopy(rep_extra_specs)
rep_extra_specs2[utils.PORTGROUPNAME] = port_group_name_f rep_extra_specs2[utils.PORTGROUPNAME] = port_group_name_f
rep_extra_specs3 = deepcopy(rep_extra_specs) rep_extra_specs3 = deepcopy(rep_extra_specs)

View File

@ -105,6 +105,7 @@ class PowerMaxReplicationTest(test.TestCase):
extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f extra_specs[utils.PORTGROUPNAME] = self.data.port_group_name_f
extra_specs[utils.IS_RE] = True extra_specs[utils.IS_RE] = True
extra_specs[utils.FORCE_VOL_EDIT] = True extra_specs[utils.FORCE_VOL_EDIT] = True
extra_specs[utils.DISABLE_PROTECTED_SNAP] = False
rep_config = self.data.rep_config_sync rep_config = self.data.rep_config_sync
rep_config = deepcopy(self.data.rep_config_sync) rep_config = deepcopy(self.data.rep_config_sync)
rep_config[utils.RDF_CONS_EXEMPT] = False rep_config[utils.RDF_CONS_EXEMPT] = False

View File

@ -1574,7 +1574,8 @@ class PowerMaxCommon(object):
if rep_config.get(utils.METROBIAS): if rep_config.get(utils.METROBIAS):
extra_specs[utils.METROBIAS] = ( extra_specs[utils.METROBIAS] = (
rep_config[utils.METROBIAS]) rep_config[utils.METROBIAS])
extra_specs[utils.DISABLE_PROTECTED_SNAP] =\
self.utils.is_protected_snap_disabled(extra_specs)
return extra_specs, qos_specs return extra_specs, qos_specs
def _get_replicated_volume_backend_id(self, volume): def _get_replicated_volume_backend_id(self, volume):
@ -2074,14 +2075,23 @@ class PowerMaxCommon(object):
return volume_name return volume_name
array = extra_specs[utils.ARRAY] array = extra_specs[utils.ARRAY]
if self.utils.is_replication_enabled(extra_specs): dps = self.utils.is_protected_snap_disabled(extra_specs)
self._validate_rdfg_status(array, extra_specs) # If a volume is not replicated and has the
# powermax:disable_protected_snap set to True,
# then clean up the volume without replication cleanup.
if dps and volume.replication_status is None:
self.masking.remove_and_reset_members(
array, volume, device_id, volume_name, extra_specs, False)
self._cleanup_device_retry(array, device_id, extra_specs)
else:
if self.utils.is_replication_enabled(extra_specs):
self._validate_rdfg_status(array, extra_specs)
self._cleanup_device_retry(array, device_id, extra_specs) self._cleanup_device_retry(array, device_id, extra_specs)
# Remove from any storage groups and cleanup replication # Remove from any storage groups and cleanup replication
self._remove_vol_and_cleanup_replication( self._remove_vol_and_cleanup_replication(
array, device_id, volume_name, extra_specs, volume) array, device_id, volume_name, extra_specs, volume)
self._delete_from_srp( self._delete_from_srp(
array, device_id, volume_name, extra_specs) array, device_id, volume_name, extra_specs)
return volume_name return volume_name
@ -2898,6 +2908,10 @@ class PowerMaxCommon(object):
create_snap, copy_mode, rep_extra_specs = False, False, dict() create_snap, copy_mode, rep_extra_specs = False, False, dict()
volume_dict = self.rest.get_volume(array, source_device_id) volume_dict = self.rest.get_volume(array, source_device_id)
replication_enabled = self.utils.is_replication_enabled(extra_specs) replication_enabled = self.utils.is_replication_enabled(extra_specs)
if self.utils.is_protected_snap_disabled(extra_specs):
extra_specs.pop(utils.IS_RE, None)
replication_enabled = False
if replication_enabled: if replication_enabled:
copy_mode = True copy_mode = True
__, rep_extra_specs, __, __ = ( __, rep_extra_specs, __, __ = (
@ -5778,6 +5792,9 @@ class PowerMaxCommon(object):
bias = True if rep_config.get(utils.METROBIAS) else False bias = True if rep_config.get(utils.METROBIAS) else False
rep_extra_specs[utils.METROBIAS] = bias rep_extra_specs[utils.METROBIAS] = bias
rep_extra_specs[utils.DISABLE_PROTECTED_SNAP] =\
self.utils.is_protected_snap_disabled(extra_specs)
# If disable compression is set, check if target array is all flash # If disable compression is set, check if target array is all flash
do_disable_compression = self.utils.is_compression_disabled( do_disable_compression = self.utils.is_compression_disabled(
extra_specs) extra_specs)
@ -7800,3 +7817,20 @@ class PowerMaxCommon(object):
'dev_ident': dev_id_from_identifier}) 'dev_ident': dev_id_from_identifier})
self.rest.rename_volume( self.rest.rename_volume(
array, dev_id_from_identifier, None) array, dev_id_from_identifier, None)
@staticmethod
def get_vendor_properties(self):
"""Retrieves the vendor properties for the powermax driver.
:param self: The object instance.
:return: A tuple containing the properties dictionary and the
driver name.
"""
properties = {}
self._set_property(
properties,
utils.DISABLE_PROTECTED_SNAP,
"Disable protected snap",
_("Prevent protected snap being created on SRDF device."),
"boolean")
return properties, "powermax"

View File

@ -134,9 +134,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
4.4.1 - Report trim/discard support 4.4.1 - Report trim/discard support
4.5.0 - Add PowerMax v4 support 4.5.0 - Add PowerMax v4 support
4.5.1 - Add active/active compliance 4.5.1 - Add active/active compliance
4.5.2 - Add 'disable_protected_snap' option
""" """
VERSION = "4.5.1" VERSION = "4.5.2"
SUPPORTS_ACTIVE_ACTIVE = True SUPPORTS_ACTIVE_ACTIVE = True
# ThirdPartySystems wiki # ThirdPartySystems wiki
@ -166,6 +167,9 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
def check_for_setup_error(self): def check_for_setup_error(self):
pass pass
def _init_vendor_properties(self):
return self.common.get_vendor_properties(self)
def create_volume(self, volume): def create_volume(self, volume):
"""Creates a PowerMax/VMAX volume. """Creates a PowerMax/VMAX volume.

View File

@ -139,9 +139,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
4.4.1 - Report trim/discard support 4.4.1 - Report trim/discard support
4.5.0 - Add PowerMax v4 support 4.5.0 - Add PowerMax v4 support
4.5.1 - Add active/active compliance 4.5.1 - Add active/active compliance
4.5.2 - Add 'disable_protected_snap' option
""" """
VERSION = "4.5.1" VERSION = "4.5.2"
SUPPORTS_ACTIVE_ACTIVE = True SUPPORTS_ACTIVE_ACTIVE = True
# ThirdPartySystems wiki # ThirdPartySystems wiki
@ -171,6 +172,9 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
def check_for_setup_error(self): def check_for_setup_error(self):
pass pass
def _init_vendor_properties(self):
return self.common.get_vendor_properties(self)
def create_volume(self, volume): def create_volume(self, volume):
"""Creates a PowerMax/VMAX volume. """Creates a PowerMax/VMAX volume.
@ -255,7 +259,6 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
:param context: the context :param context: the context
:param volume_id: the volume id :param volume_id: the volume id
""" """
pass
def initialize_connection(self, volume, connector): def initialize_connection(self, volume, connector):
"""Initializes the connection and returns connection info. """Initializes the connection and returns connection info.
@ -461,15 +464,15 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
data['driver_version'] = self.VERSION data['driver_version'] = self.VERSION
self._stats = data self._stats = data
def manage_existing(self, volume, external_ref): def manage_existing(self, volume, existing_ref):
"""Manages an existing PowerMax/VMAX Volume (import to Cinder). """Manages an existing PowerMax/VMAX Volume (import to Cinder).
Renames the Volume to match the expected name for the volume. Renames the Volume to match the expected name for the volume.
Also need to consider things like QoS, Emulation, account/tenant. Also need to consider things like QoS, Emulation, account/tenant.
""" """
return self.common.manage_existing(volume, external_ref) return self.common.manage_existing(volume, existing_ref)
def manage_existing_get_size(self, volume, external_ref): def manage_existing_get_size(self, volume, existing_ref):
"""Return size of an existing PowerMax/VMAX volume to manage_existing. """Return size of an existing PowerMax/VMAX volume to manage_existing.
:param self: reference to class :param self: reference to class
@ -477,7 +480,7 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
:param external_ref: reference to the existing volume :param external_ref: reference to the existing volume
:returns: size of the volume in GB :returns: size of the volume in GB
""" """
return self.common.manage_existing_get_size(volume, external_ref) return self.common.manage_existing_get_size(volume, existing_ref)
def unmanage(self, volume): def unmanage(self, volume):
"""Export PowerMax/VMAX volume from Cinder. """Export PowerMax/VMAX volume from Cinder.
@ -550,10 +553,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
return self.common.get_manageable_snapshots(marker, limit, offset, return self.common.get_manageable_snapshots(marker, limit, offset,
sort_keys, sort_dirs) sort_keys, sort_dirs)
def retype(self, ctxt, volume, new_type, diff, host): def retype(self, context, volume, new_type, diff, host):
"""Migrate volume to another host using retype. """Migrate volume to another host using retype.
:param ctxt: context :param context: context
:param volume: the volume object including the volume_type_id :param volume: the volume object including the volume_type_id
:param new_type: the new volume type. :param new_type: the new volume type.
:param diff: difference between old and new volume types. :param diff: difference between old and new volume types.

View File

@ -140,6 +140,7 @@ REST_API_CONNECT_TIMEOUT = 'rest_api_connect_timeout'
REST_API_READ_TIMEOUT = 'rest_api_read_timeout' REST_API_READ_TIMEOUT = 'rest_api_read_timeout'
REST_API_CONNECT_TIMEOUT_KEY = 'RestAPIConnectTimeout' REST_API_CONNECT_TIMEOUT_KEY = 'RestAPIConnectTimeout'
REST_API_READ_TIMEOUT_KEY = 'RestAPIReadTimeout' REST_API_READ_TIMEOUT_KEY = 'RestAPIReadTimeout'
DISABLE_PROTECTED_SNAP = 'powermax:disable_protected_snap'
# Array Models, Service Levels & Workloads # Array Models, Service Levels & Workloads
VMAX_HYBRID_MODELS = ['VMAX100K', 'VMAX200K', 'VMAX400K'] VMAX_HYBRID_MODELS = ['VMAX100K', 'VMAX200K', 'VMAX400K']
@ -530,6 +531,15 @@ class PowerMaxUtils(object):
host_list = host.split('+') host_list = host.split('+')
return host_list[-1] return host_list[-1]
def is_protected_snap_disabled(self, extra_specs):
"""Check is the disable_protected_snap flag set.
:param extra_specs: extra specifications :returns: boolean
"""
if extra_specs.get(DISABLE_PROTECTED_SNAP, False) in IS_TRUE:
return True
return False
def is_compression_disabled(self, extra_specs): def is_compression_disabled(self, extra_specs):
"""Check is compression is to be disabled. """Check is compression is to be disabled.

View File

@ -0,0 +1,19 @@
---
features:
- |
Dell EMC PowerMax driver: Added SRDF ``powermax:disable_protected_snap``
volume-type extra-spec property for the purpose of avoiding
overconsumption on both source and target storage arrays.
An operator may enable this functionality by creating a specific volume
type with the property::
"powermax:disable_protected_snap": "<is> True"
When disabled (which is the default and current behavior), a
replicated source volume will be protected with a snapshot of the
same volume type.
When enabled, snapshots of replicated source volumes will be treated
as regular, non-replicated devices.