summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2023-05-09 15:27:13 +0000
committerGerrit Code Review <review@openstack.org>2023-05-09 15:27:13 +0000
commitb01b451ebaeb249c3303d3ecab4a3d5705215a7a (patch)
tree43a5669396b68af5c2bdcf3ebc84e1955e8ae6b9
parent40a33360ade30abb1656aa3762051a0d96c76186 (diff)
parentb2c8bc3590eb98a4539e3a647d18092039437436 (diff)
downloadcinder-b01b451ebaeb249c3303d3ecab4a3d5705215a7a.tar.gz
Merge "HPE 3PAR: Few issues with new WSAPI (of 2023)"
-rw-r--r--cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py175
-rw-r--r--cinder/volume/drivers/hpe/hpe_3par_common.py36
-rw-r--r--releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml4
3 files changed, 183 insertions, 32 deletions
diff --git a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
index 7916792fa..018d93694 100644
--- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
+++ b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
@@ -675,6 +675,11 @@ class HPE3PARBaseDriver(test.TestCase):
'minor': 5,
'revision': 0}
+ wsapi_version_2023 = {'major': 1,
+ 'build': 100000050,
+ 'minor': 10,
+ 'revision': 0}
+
# Use this to point to latest version of wsapi
wsapi_version_latest = wsapi_version_for_compression
@@ -892,28 +897,41 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
mock_client.assert_has_calls(expected)
self.assertEqual(self.STATUS_DONE, status)
- def test_create_volume(self):
+ # (i) wsapi version is old/default
+ # (ii) wsapi version is 2023, then snapCPG isn't required
+ @ddt.data({'wsapi_version': None},
+ {'wsapi_version': HPE3PARBaseDriver.wsapi_version_2023})
+ @ddt.unpack
+ def test_create_volume(self, wsapi_version):
# setup_mock_client drive with default configuration
# and return the mock HTTP 3PAR client
- mock_client = self.setup_driver()
+ mock_client = self.setup_driver(wsapi_version=wsapi_version)
+
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
mock_create_client.return_value = mock_client
- self.driver.create_volume(self.volume)
+ if not wsapi_version:
+ # (i) old/default
+ self.driver.create_volume(self.volume)
+ else:
+ # (ii) wsapi 2023
+ common = self.driver._login()
+ common.create_volume(self.volume)
comment = Comment({
"display_name": "Foo Volume",
"type": "OpenStack",
"name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7",
"volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7"})
+ optional = {'comment': comment,
+ 'tpvv': True,
+ 'tdvv': False}
+ if not wsapi_version:
+ optional['snapCPG'] = HPE3PAR_CPG_SNAP
expected = [
mock.call.createVolume(
self.VOLUME_3PAR_NAME,
HPE3PAR_CPG,
- 2048, {
- 'comment': comment,
- 'tpvv': True,
- 'tdvv': False,
- 'snapCPG': HPE3PAR_CPG_SNAP})]
+ 2048, optional)]
mock_client.assert_has_calls(expected)
@@ -1255,6 +1273,89 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
mock_client.assert_has_calls(expected)
@mock.patch.object(volume_types, 'get_volume_type')
+ def test_create_volume_replicated_periodic_2023(self, _mock_volume_types):
+ # setup_mock_client drive with default configuration
+ # and return the mock HTTP 3PAR client
+ conf = self.setup_configuration()
+ self.replication_targets[0]['replication_mode'] = 'periodic'
+ conf.replication_device = self.replication_targets
+ mock_client = self.setup_driver(conf, None, self.wsapi_version_2023)
+ mock_client.getStorageSystemInfo.return_value = (
+ {'id': self.CLIENT_ID})
+ mock_client.getRemoteCopyGroup.side_effect = (
+ hpeexceptions.HTTPNotFound)
+ mock_client.getCPG.return_value = {'domain': None}
+ mock_replicated_client = self.setup_driver(conf, None,
+ self.wsapi_version_2023)
+ mock_replicated_client.getStorageSystemInfo.return_value = (
+ {'id': self.REPLICATION_CLIENT_ID})
+
+ _mock_volume_types.return_value = {
+ 'name': 'replicated',
+ 'extra_specs': {
+ 'replication_enabled': '<is> True',
+ 'replication:mode': 'periodic',
+ 'replication:sync_period': '900',
+ 'volume_type': self.volume_type_replicated}}
+
+ with mock.patch.object(
+ hpecommon.HPE3PARCommon,
+ '_create_client') as mock_create_client, \
+ mock.patch.object(
+ hpecommon.HPE3PARCommon,
+ '_create_replication_client') as mock_replication_client:
+ mock_create_client.return_value = mock_client
+ mock_replication_client.return_value = mock_replicated_client
+
+ common = self.driver._login()
+ return_model = common.create_volume(self.volume_replicated)
+ comment = Comment({
+ "volume_type_name": "replicated",
+ "display_name": "Foo Volume",
+ "name": "volume-d03338a9-9115-48a3-8dfc-35cdfcdc15a7",
+ "volume_type_id": "be9181f1-4040-46f2-8298-e7532f2bf9db",
+ "volume_id": "d03338a9-9115-48a3-8dfc-35cdfcdc15a7",
+ "qos": {},
+ "type": "OpenStack"})
+
+ backend_id = self.replication_targets[0]['backend_id']
+ expected = [
+ mock.call.createVolume(
+ self.VOLUME_3PAR_NAME,
+ HPE3PAR_CPG,
+ 2048, {
+ 'comment': comment,
+ 'tpvv': True,
+ 'tdvv': False}),
+ mock.call.getRemoteCopyGroup(self.RCG_3PAR_NAME),
+ mock.call.getCPG(HPE3PAR_CPG),
+ mock.call.createRemoteCopyGroup(
+ self.RCG_3PAR_NAME,
+ [{'userCPG': HPE3PAR_CPG_REMOTE,
+ 'targetName': backend_id,
+ 'mode': PERIODIC_MODE}],
+ {'localUserCPG': HPE3PAR_CPG}),
+ mock.call.addVolumeToRemoteCopyGroup(
+ self.RCG_3PAR_NAME,
+ self.VOLUME_3PAR_NAME,
+ [{'secVolumeName': self.VOLUME_3PAR_NAME,
+ 'targetName': backend_id}],
+ optional={'volumeAutoCreation': True}),
+ mock.call.modifyRemoteCopyGroup(
+ self.RCG_3PAR_NAME,
+ {'targets': [{'syncPeriod': SYNC_PERIOD,
+ 'targetName': backend_id}]}),
+ mock.call.startRemoteCopy(self.RCG_3PAR_NAME)]
+ mock_client.assert_has_calls(
+ self.get_id_login +
+ self.standard_logout +
+ self.standard_login +
+ expected)
+ self.assertEqual({'replication_status': 'enabled',
+ 'provider_location': self.CLIENT_ID},
+ return_model)
+
+ @mock.patch.object(volume_types, 'get_volume_type')
def test_create_volume_replicated_sync(self, _mock_volume_types):
# setup_mock_client drive with default configuration
# and return the mock HTTP 3PAR client
@@ -4269,10 +4370,16 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
expected_retype_specs)
self.assertEqual(expected_obj, obj)
+ # (i) wsapi version is old/default
+ # (ii) wsapi version is 2023, then snapCPG isn't required
+ @ddt.data({'wsapi_version': None},
+ {'wsapi_version': HPE3PARBaseDriver.wsapi_version_2023})
+ @ddt.unpack
@mock.patch.object(volume_types, 'get_volume_type')
- def test_manage_existing_with_no_snap_cpg(self, _mock_volume_types):
+ def test_manage_existing_with_no_snap_cpg(self, _mock_volume_types,
+ wsapi_version):
_mock_volume_types.return_value = self.volume_type
- mock_client = self.setup_driver()
+ mock_client = self.setup_driver(wsapi_version=wsapi_version)
new_comment = Comment({
"display_name": "Foo Volume",
@@ -4304,15 +4411,20 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
obj = self.driver.manage_existing(volume, existing_ref)
+ optional = {'newName': osv_matcher,
+ 'comment': new_comment}
+
+ if not wsapi_version:
+ # (i) old/default
+ # manage_existing() should be setting
+ # blank snapCPG to the userCPG
+ optional['snapCPG'] = 'testUserCpg0'
+
expected_manage = [
mock.call.getVolume(existing_ref['source-name']),
mock.call.modifyVolume(
existing_ref['source-name'],
- {'newName': osv_matcher,
- 'comment': new_comment,
- # manage_existing() should be setting
- # blank snapCPG to the userCPG
- 'snapCPG': 'testUserCpg0'})
+ optional)
]
mock_client.assert_has_calls(self.standard_login + expected_manage)
@@ -6076,16 +6188,21 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
mock_client.assert_has_calls(expected)
+ # (i) wsapi version is old/default
+ # (ii) wsapi version is 2023, then snapCPG isn't required
+ @ddt.data({'wsapi_version': None},
+ {'wsapi_version': HPE3PARBaseDriver.wsapi_version_2023})
+ @ddt.unpack
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'get_volume_settings_from_type')
@mock.patch('cinder.volume.drivers.hpe.hpe_3par_common.HPE3PARCommon.'
'is_volume_group_snap_type')
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type')
def test_create_group_from_src_group(self, cg_ss_enable, vol_ss_enable,
- typ_info):
+ typ_info, wsapi_version):
cg_ss_enable.return_value = True
vol_ss_enable.return_value = True
- mock_client = self.setup_driver()
+ mock_client = self.setup_driver(wsapi_version=wsapi_version)
task_id = 1
mock_client.copyVolume.return_value = {'taskid': task_id}
mock_client.getStorageSystemInfo.return_value = {'id': self.CLIENT_ID}
@@ -6116,6 +6233,10 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
source_grp = self.fake_group_object(
grp_id=self.SRC_CONSIS_GROUP_ID)
+ optional = {'online': True,
+ 'tpvv': mock.ANY, 'tdvv': mock.ANY}
+ if not wsapi_version:
+ optional['snapCPG'] = HPE3PAR_CPG
expected = [
mock.call.getCPG(HPE3PAR_CPG),
mock.call.createVolumeSet(
@@ -6131,17 +6252,25 @@ class TestHPE3PARDriverBase(HPE3PARBaseDriver):
mock.ANY,
self.VOLUME_NAME_3PAR,
HPE3PAR_CPG,
- {'snapCPG': HPE3PAR_CPG, 'online': True,
- 'tpvv': mock.ANY, 'tdvv': mock.ANY}),
+ optional),
mock.call.addVolumeToVolumeSet(
self.CONSIS_GROUP_NAME,
self.VOLUME_NAME_3PAR)]
# Create a consistency group from a source consistency group.
- self.driver.create_group_from_src(
- context.get_admin_context(), group,
- [volume], source_group=source_grp,
- source_vols=[source_volume])
+ if not wsapi_version:
+ # (i) old/default
+ self.driver.create_group_from_src(
+ context.get_admin_context(), group,
+ [volume], source_group=source_grp,
+ source_vols=[source_volume])
+ else:
+ # (ii) wsapi 2023
+ common = self.driver._login()
+ common.create_group_from_src(
+ context.get_admin_context(), group,
+ [volume], source_group=source_grp,
+ source_vols=[source_volume])
mock_client.assert_has_calls(expected)
diff --git a/cinder/volume/drivers/hpe/hpe_3par_common.py b/cinder/volume/drivers/hpe/hpe_3par_common.py
index 94c346b37..2d9534a16 100644
--- a/cinder/volume/drivers/hpe/hpe_3par_common.py
+++ b/cinder/volume/drivers/hpe/hpe_3par_common.py
@@ -81,6 +81,7 @@ FLASH_CACHE_API_VERSION = 30201200
COMPRESSION_API_VERSION = 30301215
SRSTATLD_API_VERSION = 30201200
REMOTE_COPY_API_VERSION = 30202290
+API_VERSION_2023 = 100000000
hpe3par_opts = [
cfg.StrOpt('hpe3par_api_url',
@@ -302,11 +303,12 @@ class HPE3PARCommon(object):
Bug #1819903
4.0.18 - During conversion of volume to base volume,
error out if it has child snapshot(s). Bug #1994521
+ 4.0.19 - Update code to work with new WSAPI (of 2023). Bug #2015746
"""
- VERSION = "4.0.18"
+ VERSION = "4.0.19"
stats = {}
@@ -706,9 +708,12 @@ class HPE3PARCommon(object):
compression = self.get_compression_policy(
type_info['hpe3par_keys'])
- optional = {'online': True, 'snapCPG': snapcpg,
+ optional = {'online': True,
'tpvv': tpvv, 'tdvv': tdvv}
+ if self.API_VERSION < API_VERSION_2023:
+ optional['snapCPG'] = snapcpg
+
if compression is not None:
optional['compression'] = compression
@@ -1006,7 +1011,7 @@ class HPE3PARCommon(object):
'comment': json.dumps(new_comment)}
# Ensure that snapCPG is set
- if 'snapCPG' not in vol:
+ if 'snapCPG' not in vol and self.API_VERSION < API_VERSION_2023:
new_vals['snapCPG'] = vol['userCPG']
LOG.info("Virtual volume %(disp)s '%(new)s' snapCPG "
"is empty so it will be set to: %(cpg)s",
@@ -2395,9 +2400,14 @@ class HPE3PARCommon(object):
comments['qos'] = qos
extras = {'comment': json.dumps(comments),
- 'snapCPG': snap_cpg,
'tpvv': tpvv}
+ LOG.debug("self.API_VERSION: %(version)s",
+ {'version': self.API_VERSION})
+
+ if self.API_VERSION < API_VERSION_2023:
+ extras['snapCPG'] = snap_cpg
+
# Only set the dedup option if the backend supports it.
if self.API_VERSION >= DEDUP_API_VERSION:
extras['tdvv'] = tdvv
@@ -2468,7 +2478,7 @@ class HPE3PARCommon(object):
{'src': src_name, 'dest': dest_name})
optional = {'tpvv': tpvv, 'online': True}
- if snap_cpg is not None:
+ if snap_cpg is not None and self.API_VERSION < API_VERSION_2023:
optional['snapCPG'] = snap_cpg
if self.API_VERSION >= DEDUP_API_VERSION:
@@ -4377,15 +4387,17 @@ class HPE3PARCommon(object):
local_cpg)
rcg_target = {'targetName': target['backend_id'],
'mode': replication_mode_num,
- 'snapCPG': cpg,
'userCPG': cpg}
+ if self.API_VERSION < API_VERSION_2023:
+ rcg_target['snapCPG'] = cpg
rcg_targets.append(rcg_target)
sync_target = {'targetName': target['backend_id'],
'syncPeriod': replication_sync_period}
sync_targets.append(sync_target)
- optional = {'localSnapCPG': vol_settings['snap_cpg'],
- 'localUserCPG': local_cpg}
+ optional = {'localUserCPG': local_cpg}
+ if self.API_VERSION < API_VERSION_2023:
+ optional['localSnapCPG'] = vol_settings['snap_cpg']
pool = volume_utils.extract_host(volume['host'], level='pool')
domain = self.get_domain(pool)
if domain:
@@ -4400,6 +4412,8 @@ class HPE3PARCommon(object):
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
+ LOG.debug("created rcg %(name)s", {'name': rcg_name})
+
# Add volume to remote copy group.
rcg_targets = []
for target in self._replication_targets:
@@ -5319,7 +5333,11 @@ class ModifyVolumeTask(flow_utils.CinderTask):
comment_dict = self._get_new_comment(
old_comment, new_vvs, new_qos, new_type_name, new_type_id)
- if new_snap_cpg != old_snap_cpg:
+ LOG.debug("API_VERSION: %(ver_1)s, API_VERSION_2023: %(ver_2)s",
+ {'ver_1': common.API_VERSION,
+ 'ver_2': API_VERSION_2023})
+ if (new_snap_cpg != old_snap_cpg and
+ common.API_VERSION < API_VERSION_2023):
# Modify the snap_cpg. This will fail with snapshots.
LOG.info("Modifying %(volume_name)s snap_cpg from "
"%(old_snap_cpg)s to %(new_snap_cpg)s.",
diff --git a/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml b/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml
new file mode 100644
index 000000000..82cbc97d9
--- /dev/null
+++ b/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml
@@ -0,0 +1,4 @@
+fixes:
+ - |
+ HPE 3PAR driver `Bug #2015746 <https://bugs.launchpad.net/cinder/+bug/2015746>`_:
+ Fixed: minor code changes to work with new wsapi.