[Pure Storage] Remove all REST version checks

Enforce a minimum FlashArray Purity version that will make all
REST version checking renudant as the enforced minimum version
supports all the features that are currently version-gated.

Remove any code that checks for different REST responses based on
REST response due to old REST code.

Enforced minimum Purity version matches the minimum supported
Purity version for FlashArray as of December 2021.

No change required to the purestorage pypi package used by this
driver.

Change-Id: I9fd03186b77ca442b62b1bfa28eed9026d91949b
This commit is contained in:
Simon Dodsley 2021-11-08 16:14:41 -05:00
parent f2620a1fe4
commit 8bb216dc16
3 changed files with 85 additions and 317 deletions

View File

@ -582,7 +582,6 @@ class PureDriverTestCase(test.TestCase):
self.async_array2.get.return_value = GET_ARRAY_SECONDARY
self.async_array2.replication_type = 'async'
self.purestorage_module = pure.purestorage
self.purestorage_module.VERSION = '1.4.0'
self.purestorage_module.PureHTTPError = FakePureStorageHTTPError
def fake_get_array(self, *args, **kwargs):
@ -627,15 +626,7 @@ class PureBaseSharedDriverTestCase(PureDriverTestCase):
self.driver._array = self.array
self.driver._replication_pod_name = 'cinder-pod'
self.driver._replication_pg_name = 'cinder-group'
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.purestorage_module.FlashArray.side_effect = None
self.async_array2._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
def new_fake_vol(self, set_provider_id=True, fake_context=None,
spec=None, type_extra_specs=None, type_qos_specs_id=None,
@ -808,10 +799,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
]
mock_target = mock.MagicMock()
mock_target.get.return_value = GET_ARRAY_PRIMARY
mock_target._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.purestorage_module.FlashArray.return_value = mock_target
self.driver.parse_replication_configs()
@ -848,10 +835,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
]
mock_target = mock.MagicMock()
mock_target.get.return_value = GET_ARRAY_PRIMARY
mock_target._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.purestorage_module.FlashArray.return_value = mock_target
self.driver.parse_replication_configs()
@ -912,15 +895,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
]
mock_sync_target = mock.MagicMock()
mock_sync_target.get.return_value = GET_ARRAY_SECONDARY
mock_sync_target._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.array.get.return_value = GET_ARRAY_PRIMARY
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.purestorage_module.FlashArray.side_effect = [self.array,
mock_sync_target]
self.driver.do_setup(None)
@ -1287,10 +1262,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
vol, vol_name = self.new_fake_vol(type_extra_specs=type_spec)
self.array.list_volume_private_connections.return_value = []
# Set the array to be in a sync-rep enabled version
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.driver.delete_volume(vol)
@ -1330,14 +1301,9 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
]
# Set the array to be in a sync-rep enabled version
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.driver.delete_volume(vol)
expected = [
mock.call._list_available_rest_versions(),
mock.call.list_volume_private_connections(vol_name, remote=True),
mock.call.disconnect_host(host_name_a, vol_name),
mock.call.list_host_connections(host_name_a, private=True),
@ -2203,14 +2169,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
self.driver.manage_existing_snapshot,
snap, snap_ref)
def test_manage_existing_snapshot_bad_api_version(self):
self.array._list_available_rest_versions.return_value = ['1.0', '1.1',
'1.2']
snap, _ = self.new_fake_snap()
self.assertRaises(pure.PureDriverException,
self.driver.manage_existing_snapshot,
snap, {'name': PURE_SNAPSHOT['name']})
def test_manage_existing_snapshot_get_size(self):
ref_name = PURE_SNAPSHOT['name']
snap_ref = {'name': ref_name}
@ -2262,14 +2220,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
self.driver.manage_existing_snapshot_get_size,
snap, {'name': 'non-existing-volume.snap1'})
def test_manage_existing_snapshot_get_size_bad_api_version(self):
snap, _ = self.new_fake_snap()
self.array._list_available_rest_versions.return_value = ['1.0', '1.1',
'1.2']
self.assertRaises(pure.PureDriverException,
self.driver.manage_existing_snapshot_get_size,
snap, {'name': PURE_SNAPSHOT['name']})
@ddt.data(
# 96 chars, will exceed allowable length
'volume-1e5177e7-95e5-4a0f-b170-e45f4b469f6a-cinder.'
@ -2312,14 +2262,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
self.array.rename_volume.assert_called_with(snap_name,
unmanaged_snap_name)
def test_unmanage_snapshot_bad_api_version(self):
snap, _ = self.new_fake_snap()
self.array._list_available_rest_versions.return_value = ['1.0', '1.1',
'1.2']
self.assertRaises(pure.PureDriverException,
self.driver.unmanage_snapshot,
snap)
def _test_get_manageable_things(self,
pure_objs=MANAGEABLE_PURE_VOLS,
expected_refs=MANAGEABLE_PURE_VOL_REFS,
@ -2922,12 +2864,11 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
self.async_array2.backend_id = secondary_device_id
self.driver._replication_target_arrays = [self.async_array2]
array2_v1_3 = mock.Mock()
array2_v1_3.backend_id = secondary_device_id
array2_v1_3.array_name = GET_ARRAY_SECONDARY['array_name']
array2_v1_3.array_id = GET_ARRAY_SECONDARY['id']
array2_v1_3.version = '1.3'
mock_get_array.return_value = array2_v1_3
array2 = mock.Mock()
array2.backend_id = secondary_device_id
array2.array_name = GET_ARRAY_SECONDARY['array_name']
array2.array_id = GET_ARRAY_SECONDARY['id']
mock_get_array.return_value = array2
target_array = self.async_array2
target_array.copy_volume = mock.Mock()
@ -2937,7 +2878,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
REPLICATED_PGSNAPS[1]
)
array2_v1_3.get_volume.return_value = REPLICATED_VOLUME_SNAPS
array2.get_volume.return_value = REPLICATED_VOLUME_SNAPS
context = mock.MagicMock()
new_active_id, volume_updates, __ = self.driver.failover_host(
@ -3070,17 +3011,16 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
REPLICATED_PGSNAPS[1]
)
array2_v1_3 = mock.Mock()
array2_v1_3.array_name = GET_ARRAY_SECONDARY['array_name']
array2_v1_3.array_id = GET_ARRAY_SECONDARY['id']
array2_v1_3.version = '1.3'
mock_get_array.return_value = array2_v1_3
array2 = mock.Mock()
array2.array_name = GET_ARRAY_SECONDARY['array_name']
array2.array_id = GET_ARRAY_SECONDARY['id']
mock_get_array.return_value = array2
array2_v1_3.get_volume.return_value = REPLICATED_VOLUME_SNAPS
array2.get_volume.return_value = REPLICATED_VOLUME_SNAPS
self.assert_error_propagates(
[mock_find_failover_target,
mock_get_array,
array2_v1_3.get_volume,
array2.get_volume,
self.async_array2.copy_volume],
self.driver.failover_host,
mock.Mock(), REPLICATED_VOLUME_OBJS, None
@ -3129,43 +3069,7 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
verify_https=True,
ssl_cert=cert_path,
user_agent=self.driver._user_agent,
)
def test_get_flasharray_with_request_kwargs_success(self):
san_ip = '1.2.3.4'
api_token = 'abcdef'
self.purestorage_module.FlashArray.return_value = mock.MagicMock()
self.purestorage_module.VERSION = "1.17.0"
self.driver._get_flasharray(san_ip,
api_token,
request_kwargs={"some": "arg"})
self.purestorage_module.FlashArray.assert_called_with(
san_ip,
api_token=api_token,
rest_version=None,
verify_https=None,
ssl_cert=None,
user_agent=self.driver._user_agent,
request_kwargs={"some": "arg"}
)
def test_get_flasharray_with_request_kwargs_version_too_old(self):
san_ip = '1.2.3.4'
api_token = 'abcdef'
self.purestorage_module.FlashArray.return_value = mock.MagicMock()
self.purestorage_module.VERSION = "1.10.0"
self.driver._get_flasharray(san_ip,
api_token,
request_kwargs={"some": "arg"})
self.purestorage_module.FlashArray.assert_called_with(
san_ip,
api_token=api_token,
rest_version=None,
verify_https=None,
ssl_cert=None,
user_agent=self.driver._user_agent
request_kwargs=None,
)
def test_get_wwn(self):
@ -3244,10 +3148,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
type_qos_specs_id=qos.id)
mock_get_volume_type.return_value = vol.volume_type
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
mock_get_qos_specs.return_value = qos
mock_get_repl_type.return_value = None
@ -3277,10 +3177,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
type_qos_specs_id=qos.id)
mock_get_volume_type.return_value = vol.volume_type
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
mock_get_qos_specs.return_value = qos
mock_get_repl_type.return_value = None
@ -3310,10 +3206,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
mock_get_volume_type.return_value = vol.volume_type
mock_get_qos_specs.return_value = qos
self.array.list_volume_private_connections.return_value = []
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
self.driver.manage_existing(vol, volume_ref)
self.array.list_volume_private_connections.assert_called_with(ref_name)
@ -3330,10 +3222,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
new_type = fake_volume.fake_volume_type_obj(mock_context)
new_type.qos_specs_id = qos.id
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
get_voltype = "cinder.objects.volume_type.VolumeType.get_by_name_or_id"
with mock.patch(get_voltype) as mock_get_vol_type:
mock_get_vol_type.return_value = new_type
@ -3357,10 +3245,6 @@ class PureBaseVolumeDriverTestCase(PureBaseSharedDriverTestCase):
vol, vol_name = self.new_fake_vol()
new_type = fake_volume.fake_volume_type_obj(mock_context)
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
get_voltype = "cinder.objects.volume_type.VolumeType.get_by_name_or_id"
with mock.patch(get_voltype) as mock_get_vol_type:
mock_get_vol_type.return_value = new_type
@ -3739,20 +3623,6 @@ class PureISCSIDriverTestCase(PureBaseSharedDriverTestCase):
self.mock_config.use_chap_auth = False
self.mock_config.safe_get.return_value = 'oracle-vm-server'
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11']
# Branch where we fail due to invalid version for setting personality
self.assertRaises(pure.PureDriverException, self.driver._connect,
self.array, vol_name, ISCSI_CONNECTOR, None, None)
self.assertFalse(self.array.create_host.called)
self.assertFalse(self.array.set_host.called)
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
# Branch where personality is set
self.driver._connect(self.array, vol_name, ISCSI_CONNECTOR,
None, None)
@ -4009,20 +3879,6 @@ class PureFCDriverTestCase(PureBaseSharedDriverTestCase):
self.driver._connect, self.array, vol_name, FC_CONNECTOR)
self.mock_config.safe_get.return_value = 'oracle-vm-server'
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11']
# Branch where we fail due to invalid version for setting personality
self.assertRaises(pure.PureDriverException, self.driver._connect,
self.array, vol_name, FC_CONNECTOR)
self.assertTrue(self.array.create_host.called)
self.assertFalse(self.array.set_host.called)
self.array._list_available_rest_versions.return_value = [
'1.0', '1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7', '1.8',
'1.9', '1.10', '1.11', '1.12', '1.13', '1.14', '1.15', '1.16',
'1.17', '1.18', '1.19']
# Branch where personality is set
self.driver._connect(self.array, vol_name, FC_CONNECTOR)

View File

@ -137,11 +137,6 @@ EXTRA_SPECS_REPL_TYPE = "replication_type"
MAX_VOL_LENGTH = 63
MAX_SNAP_LENGTH = 96
UNMANAGED_SUFFIX = '-unmanaged'
QOS_REQUIRED_API_VERSION = '1.17'
SYNC_REPLICATION_REQUIRED_API_VERSION = '1.13'
ASYNC_REPLICATION_REQUIRED_API_VERSION = '1.3'
MANAGE_SNAP_REQUIRED_API_VERSION = '1.4'
PERSONALITY_REQUIRED_API_VERSION = '1.14'
REPL_SETTINGS_PROPAGATE_RETRY_INTERVAL = 5 # 5 seconds
REPL_SETTINGS_PROPAGATE_MAX_RETRIES = 36 # 36 * 5 = 180 seconds
@ -279,24 +274,6 @@ class PureBaseVolumeDriver(san.SanDriver):
ssl_cert_path=ssl_cert_path
)
api_versions = target_array._list_available_rest_versions()
if repl_type == REPLICATION_TYPE_ASYNC:
req_api_version = ASYNC_REPLICATION_REQUIRED_API_VERSION
elif repl_type == REPLICATION_TYPE_SYNC:
req_api_version = SYNC_REPLICATION_REQUIRED_API_VERSION
else:
msg = _('Invalid replication type specified:') % repl_type
raise PureDriverException(reason=msg)
if req_api_version not in api_versions:
msg = _('Unable to do replication with Purity REST '
'API version, requires minimum of '
'%(required_version)s.') % {
'required_version': req_api_version
}
raise PureDriverException(reason=msg)
target_array_info = target_array.get()
target_array.array_name = target_array_info["array_name"]
target_array.array_id = target_array_info["id"]
@ -378,6 +355,13 @@ class PureBaseVolumeDriver(san.SanDriver):
)
array_info = self._array.get()
if version.LooseVersion(array_info["version"]) < version.LooseVersion(
'5.3.0'
):
msg = _("FlashArray Purity version less than 5.3.0 unsupported."
" Please upgrade your backend to a supported version.")
raise PureDriverException(msg)
self._array.array_name = array_info["array_name"]
self._array.array_id = array_info["id"]
self._array.replication_type = None
@ -484,11 +468,9 @@ class PureBaseVolumeDriver(san.SanDriver):
ctxt = context.get_admin_context()
type_id = volume.get('volume_type_id')
current_array = self._get_current_array()
rest_versions = current_array._list_available_rest_versions()
if type_id is not None:
volume_type = volume_types.get_volume_type(ctxt, type_id)
if QOS_REQUIRED_API_VERSION in rest_versions:
qos = self._get_qos_settings(volume_type)
qos = self._get_qos_settings(volume_type)
if qos is not None:
self.create_with_qos(current_array, vol_name, vol_size, qos)
else:
@ -509,11 +491,9 @@ class PureBaseVolumeDriver(san.SanDriver):
current_array = self._get_current_array()
ctxt = context.get_admin_context()
type_id = volume.get('volume_type_id')
rest_versions = current_array._list_available_rest_versions()
if type_id is not None:
volume_type = volume_types.get_volume_type(ctxt, type_id)
if QOS_REQUIRED_API_VERSION in rest_versions:
qos = self._get_qos_settings(volume_type)
qos = self._get_qos_settings(volume_type)
current_array.copy_volume(snap_name, vol_name)
self._extend_if_needed(current_array,
@ -606,16 +586,11 @@ class PureBaseVolumeDriver(san.SanDriver):
"""Disconnect all hosts and delete the volume"""
vol_name = self._get_vol_name(volume)
current_array = self._get_current_array()
rest_versions = current_array._list_available_rest_versions()
try:
# Do a pass over remaining connections on the current array, if
# we can try and remove any remote connections too.
if SYNC_REPLICATION_REQUIRED_API_VERSION in rest_versions:
hosts = current_array.list_volume_private_connections(
vol_name, remote=True)
else:
hosts = current_array.list_volume_private_connections(
vol_name)
hosts = current_array.list_volume_private_connections(
vol_name, remote=True)
for host_info in hosts:
host_name = host_info["host"]
self._disconnect_host(current_array, host_name, vol_name)
@ -710,18 +685,13 @@ class PureBaseVolumeDriver(san.SanDriver):
Returns True if it was the hosts last connection.
"""
vol_name = self._get_vol_name(volume)
rest_versions = array._list_available_rest_versions()
if connector is None:
# If no connector was provided it is a force-detach, remove all
# host connections for the volume
LOG.warning("Removing ALL host connections for volume %s",
vol_name)
if SYNC_REPLICATION_REQUIRED_API_VERSION in rest_versions:
# Remote connections are only allowed in newer API versions
connections = array.list_volume_private_connections(
vol_name, remote=True)
else:
connections = array.list_volume_private_connections(vol_name)
connections = array.list_volume_private_connections(
vol_name, remote=True)
for connection in connections:
self._disconnect_host(array, connection['host'], vol_name)
@ -1332,15 +1302,13 @@ class PureBaseVolumeDriver(san.SanDriver):
# Check if the volume_type has QoS settings and if so
# apply them to the newly managed volume
qos = None
rest_versions = current_array._list_available_rest_versions()
if QOS_REQUIRED_API_VERSION in rest_versions:
qos = self._get_qos_settings(volume.volume_type)
if qos is not None:
self.set_qos(current_array, new_vol_name, qos)
else:
current_array.set_volume(new_vol_name,
iops_limit='',
bandwidth_limit='')
qos = self._get_qos_settings(volume.volume_type)
if qos is not None:
self.set_qos(current_array, new_vol_name, qos)
else:
current_array.set_volume(new_vol_name,
iops_limit='',
bandwidth_limit='')
volume.provider_id = new_vol_name
async_enabled = self._enable_async_replication_if_needed(current_array,
volume)
@ -1400,24 +1368,12 @@ class PureBaseVolumeDriver(san.SanDriver):
{"ref_name": vol_name, "new_name": unmanaged_vol_name})
self._rename_volume_object(vol_name, unmanaged_vol_name)
def _verify_manage_snap_api_requirements(self):
current_array = self._get_current_array()
rest_versions = current_array._list_available_rest_versions()
if MANAGE_SNAP_REQUIRED_API_VERSION not in rest_versions:
msg = _('Unable to do manage snapshot operations with Purity REST '
'API version, requires '
'%(required_version)s.') % {
'required_version': MANAGE_SNAP_REQUIRED_API_VERSION
}
raise PureDriverException(reason=msg)
def manage_existing_snapshot(self, snapshot, existing_ref):
"""Brings an existing backend storage object under Cinder management.
We expect a snapshot name in the existing_ref that matches one in
Purity.
"""
self._verify_manage_snap_api_requirements()
self._validate_manage_existing_ref(existing_ref, is_snap=True)
ref_snap_name = existing_ref['name']
new_snap_name = self._get_snap_name(snapshot)
@ -1435,7 +1391,6 @@ class PureBaseVolumeDriver(san.SanDriver):
We expect a snapshot name in the existing_ref that matches one in
Purity.
"""
self._verify_manage_snap_api_requirements()
snap_info = self._validate_manage_existing_ref(existing_ref,
is_snap=True)
size = self._round_bytes_to_gib(snap_info['size'])
@ -1449,7 +1404,6 @@ class PureBaseVolumeDriver(san.SanDriver):
We expect a snapshot name in the existing_ref that matches one in
Purity.
"""
self._verify_manage_snap_api_requirements()
snap_name = self._get_snap_name(snapshot)
if len(snap_name + UNMANAGED_SUFFIX) > MAX_SNAP_LENGTH:
unmanaged_snap_name = snap_name[:-len(UNMANAGED_SUFFIX)] + \
@ -1573,28 +1527,13 @@ class PureBaseVolumeDriver(san.SanDriver):
verify_https=None, ssl_cert_path=None,
request_kwargs=None):
if (version.LooseVersion(purestorage.VERSION) <
version.LooseVersion('1.17.0')):
if request_kwargs is not None:
LOG.warning("Unable to specify request_kwargs='%s' on "
"purestorage.FlashArray using 'purestorage' "
"python module <1.17.0. Current version: %s",
request_kwargs,
purestorage.VERSION)
array = purestorage.FlashArray(san_ip,
api_token=api_token,
rest_version=rest_version,
verify_https=verify_https,
ssl_cert=ssl_cert_path,
user_agent=self._user_agent)
else:
array = purestorage.FlashArray(san_ip,
api_token=api_token,
rest_version=rest_version,
verify_https=verify_https,
ssl_cert=ssl_cert_path,
user_agent=self._user_agent,
request_kwargs=request_kwargs)
array = purestorage.FlashArray(san_ip,
api_token=api_token,
rest_version=rest_version,
verify_https=verify_https,
ssl_cert=ssl_cert_path,
user_agent=self._user_agent,
request_kwargs=request_kwargs)
array_info = array.get()
array.array_name = array_info["array_name"]
array.array_id = array_info["id"]
@ -1928,16 +1867,14 @@ class PureBaseVolumeDriver(san.SanDriver):
# make sure the volume gets the correct new QoS settings.
# This could mean removing existing QoS settings.
current_array = self._get_current_array()
rest_versions = current_array._list_available_rest_versions()
if QOS_REQUIRED_API_VERSION in rest_versions:
qos = self._get_qos_settings(new_type)
vol_name = self._generate_purity_vol_name(volume)
if qos is not None:
self.set_qos(current_array, vol_name, qos)
else:
current_array.set_volume(vol_name,
iops_limit='',
bandwidth_limit='')
qos = self._get_qos_settings(new_type)
vol_name = self._generate_purity_vol_name(volume)
if qos is not None:
self.set_qos(current_array, vol_name, qos)
else:
current_array.set_volume(vol_name,
iops_limit='',
bandwidth_limit='')
return True, model_update
@ -2078,23 +2015,6 @@ class PureBaseVolumeDriver(san.SanDriver):
return secondary_array.backend_id, model_updates, []
@pure_driver_debug_trace
def get_check_personality(self, array):
personality = self.configuration.safe_get('pure_host_personality')
rest_versions = array._list_available_rest_versions()
if personality:
if PERSONALITY_REQUIRED_API_VERSION not in rest_versions:
# Continuing here would mean creating a host not according
# to specificiations, possibly leading to unexpected
# behavior later on.
msg = _('Unable to set host personality with Purity REST '
'API version, requires '
'%(required_version)s.') % {
'required_version': PERSONALITY_REQUIRED_API_VERSION
}
raise PureDriverException(reason=msg)
return personality
@pure_driver_debug_trace
def set_personality(self, array, host_name, personality):
try:
@ -2446,28 +2366,12 @@ class PureBaseVolumeDriver(san.SanDriver):
return secondary_array
def _async_failover_host(self, volumes, secondary_array, pg_snap):
# NOTE(patrickeast): This currently requires a call with REST API 1.3.
# If we need to, create a temporary FlashArray for this operation.
api_version = secondary_array.get_rest_version()
LOG.debug("Current REST API for array id %(id)s is %(api_version)s",
{"id": secondary_array.array_id, "api_version": api_version})
if api_version != '1.3':
# Try to copy the flasharray as close as we can..
if hasattr(secondary_array, '_request_kwargs'):
target_array = self._get_flasharray(
secondary_array._target,
api_token=secondary_array._api_token,
rest_version='1.3',
request_kwargs=secondary_array._request_kwargs,
)
else:
target_array = self._get_flasharray(
secondary_array._target,
api_token=secondary_array._api_token,
rest_version='1.3',
)
else:
target_array = secondary_array
# Try to copy the flasharray as close as we can.
target_array = self._get_flasharray(
secondary_array._target,
api_token=secondary_array._api_token,
request_kwargs=secondary_array._request_kwargs,
)
volume_snaps = target_array.get_volume(pg_snap['name'],
snap=True,
@ -2579,11 +2483,7 @@ class PureISCSIDriver(PureBaseVolumeDriver, san.SanISCSIDriver):
def _get_host(self, array, connector, remote=False):
"""Return dict describing existing Purity host object or None."""
rest_versions = array._list_available_rest_versions()
if remote and SYNC_REPLICATION_REQUIRED_API_VERSION in rest_versions:
hosts = array.list_hosts(remote=True)
else:
hosts = array.list_hosts()
hosts = array.list_hosts(remote=remote)
matching_hosts = []
for host in hosts:
if connector["initiator"] in host["iqn"]:
@ -2746,7 +2646,7 @@ class PureISCSIDriver(PureBaseVolumeDriver, san.SanISCSIDriver):
reason=_("Unable to re-use host with unknown CHAP "
"credentials configured."))
else:
personality = self.get_check_personality(array)
personality = self.configuration.safe_get('pure_host_personality')
host_name = self._generate_purity_host_name(connector["host"])
LOG.info("Creating host object %(host_name)r with IQN:"
" %(iqn)s.", {"host_name": host_name, "iqn": iqn})
@ -2806,11 +2706,7 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
def _get_host(self, array, connector, remote=False):
"""Return dict describing existing Purity host object or None."""
rest_versions = array._list_available_rest_versions()
if remote and SYNC_REPLICATION_REQUIRED_API_VERSION in rest_versions:
hosts = array.list_hosts(remote=True)
else:
hosts = array.list_hosts()
hosts = array.list_hosts(remote=remote)
matching_hosts = []
for host in hosts:
for wwn in connector["wwpns"]:
@ -2821,18 +2717,18 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
@staticmethod
def _get_array_wwns(array):
"""Return list of wwns from the array"""
"""Return list of wwns from the array
Ensure that only true scsi FC ports are selected
and not any that are enabled for NVMe-based FC with
an associated NQN.
"""
ports = array.list_ports()
try:
valid_ports = [
port["wwn"]
for port in ports
if port["wwn"] and not port["nqn"]
]
except KeyError: # Older array code versions will not return nqn
valid_ports = [
port["wwn"] for port in ports if port["wwn"]
]
valid_ports = [
port["wwn"]
for port in ports
if port["wwn"] and not port["nqn"]
]
return valid_ports
@pure_driver_debug_trace
@ -2888,7 +2784,7 @@ class PureFCDriver(PureBaseVolumeDriver, driver.FibreChannelDriver):
LOG.info("Re-using existing purity host %(host_name)r",
{"host_name": host_name})
else:
personality = self.get_check_personality(array)
personality = self.configuration.safe_get('pure_host_personality')
host_name = self._generate_purity_host_name(connector["host"])
LOG.info("Creating host object %(host_name)r with WWN:"
" %(wwn)s.", {"host_name": host_name, "wwn": wwns})

View File

@ -0,0 +1,16 @@
---
upgrade:
- |
Pure Storage: Minimum supported FlashArray Purity//FA is changed to 5.3.0.
All FlashArray backends must be at at least this minimum version or the
driver will not initialize.
fixes:
- |
Pure Storage: Remove all API version checks in driver as the new minimum
FlashArray Purity//FA version supports all previously version-gated
features and functionality support.
other:
- |
Pure Storage: FlashArray minimum Purity//FA version is increased to 5.3.0.
All FlashArray backends must be at at least this minimum version or the
driver will not initialize.