diff -Nru cinder-22.1.0/AUTHORS cinder-22.1.1/AUTHORS --- cinder-22.1.0/AUTHORS 2023-05-17 11:15:59.000000000 +0000 +++ cinder-22.1.1/AUTHORS 2023-09-14 01:22:05.000000000 +0000 @@ -1242,6 +1242,7 @@ pran1990 prashkre rackerjoe +raghavendrat raghavendrat rajinir rajinir diff -Nru cinder-22.1.0/ChangeLog cinder-22.1.1/ChangeLog --- cinder-22.1.0/ChangeLog 2023-05-17 11:15:58.000000000 +0000 +++ cinder-22.1.1/ChangeLog 2023-09-14 01:22:04.000000000 +0000 @@ -1,11 +1,20 @@ CHANGES ======= +22.1.1 +------ + +* Fix a regression in restoring to sparse volumes +* Fix glance metadata properties filtering +* Make paramiko import optional +* HPE 3PAR: Few issues with new WSAPI (of 2023) + 22.1.0 ------ * Reject unsafe delete attachment calls * [Pure Storage] Add check for new error message +* RBD: Skip update\_features when features = 0 * Update url of "Unity Replication White Paper" 22.0.0 diff -Nru cinder-22.1.0/cinder/exception.py cinder-22.1.1/cinder/exception.py --- cinder-22.1.0/cinder/exception.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/exception.py 2023-09-14 01:21:33.000000000 +0000 @@ -1099,3 +1099,7 @@ "Compute API") code = 409 safe = True + + +class RequirementMissing(CinderException): + message = _('Requirement %(req)s is not installed.') diff -Nru cinder-22.1.0/cinder/image/image_utils.py cinder-22.1.1/cinder/image/image_utils.py --- cinder-22.1.0/cinder/image/image_utils.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/image/image_utils.py 2023-09-14 01:21:33.000000000 +0000 @@ -1290,6 +1290,16 @@ return self.temporary_images[user].get(image_id) +def _filter_out_metadata(metadata, filter_keys): + new_metadata = {} + for k, v in metadata.items(): + if any(k.startswith(filter_key) + for filter_key in filter_keys): + continue + new_metadata[k] = v + return new_metadata + + def filter_out_reserved_namespaces_metadata( metadata: Optional[dict[str, str]]) -> dict[str, str]: @@ -1303,12 +1313,12 @@ LOG.debug("No metadata to be filtered.") return {} - new_metadata = {} - for k, v in metadata.items(): - if any(k.startswith(reserved_name_space) - for reserved_name_space in reserved_name_spaces): - continue - new_metadata[k] = v + new_metadata = _filter_out_metadata(metadata, reserved_name_spaces) + # NOTE(ganso): handle adjustment of metadata structure performed by + # the cinder.volume.api.API._merge_volume_image_meta() method + if 'properties' in new_metadata: + new_metadata['properties'] = _filter_out_metadata( + metadata['properties'], reserved_name_spaces) LOG.debug("The metadata set [%s] was filtered using the reserved name " "spaces [%s], and the result is [%s].", metadata, diff -Nru cinder-22.1.0/cinder/ssh_utils.py cinder-22.1.1/cinder/ssh_utils.py --- cinder-22.1.0/cinder/ssh_utils.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/ssh_utils.py 2023-09-14 01:21:32.000000000 +0000 @@ -24,7 +24,11 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_utils import excutils -import paramiko + +try: + import paramiko +except ImportError: + paramiko = None from cinder import exception from cinder.i18n import _ @@ -65,6 +69,9 @@ self.hosts_key_file = None self.current_size = 0 + if paramiko is None: + raise exception.RequirementMissing(req='paramiko') + # Validate good config setting here. # Paramiko handles the case where the file is inaccessible. if not CONF.ssh_hosts_key_file: diff -Nru cinder-22.1.0/cinder/tests/unit/test_image_utils.py cinder-22.1.1/cinder/tests/unit/test_image_utils.py --- cinder-22.1.0/cinder/tests/unit/test_image_utils.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/tests/unit/test_image_utils.py 2023-09-14 01:21:33.000000000 +0000 @@ -2521,3 +2521,69 @@ "name spaces [%s], and the result is [%s].", metadata_for_test, keys_to_pop, expected_result) ]) + + @ddt.data( # remove default keys + ({"some_key": 13, "other_key": "test", + "os_glance_key": "this should be removed", + "os_glance_key2": "this should also be removed", + "properties": {"os_glance_key3": "this should be removed", + "os_glance_key4": "this should also be removed", + "another_key": "foobar"} + }, + None, + []), + # remove nothing + ({"some_key": 13, "other_key": "test", + "properties": {"another_key": "foobar"}}, + None, + []), + # custom config empty + ({"some_key": 13, "other_key": "test", + "os_glance_key": "this should be removed", + "os_glance_key2": "this should also be removed", + "properties": {"os_glance_key3": "this should be removed", + "os_glance_key4": "this should also be removed", + "another_key": "foobar"} + }, + [], + []), + # custom config + ({"some_key": 13, "other_key": "test", + "os_glance_key": "this should be removed", + "os_glance_key2": "this should also be removed", + "properties": {"os_glance_key3": "this should be removed", + "os_glance_key4": "this should also be removed", + "custom_key": "this should be removed", + "another_custom_key": "this should also be removed", + "another_key": "foobar"}, + }, + ['custom_key', 'another_custom_key'], + ['custom_key', 'another_custom_key'])) + @ddt.unpack + def test_filter_out_reserved_namespaces_metadata_properties( + self, metadata_for_test, config, keys_to_pop): + hardcoded_keys = ['os_glance', "img_signature"] + + keys_to_pop = hardcoded_keys + keys_to_pop + + if config: + self.override_config('reserved_image_namespaces', config) + + expected_result = { + "some_key": 13, + "other_key": "test", + "properties": { + "another_key": "foobar" + } + } + + method_return = image_utils.filter_out_reserved_namespaces_metadata( + metadata_for_test) + + self.assertEqual(expected_result, method_return) + + image_utils.LOG.debug.assert_has_calls([ + mock.call("The metadata set [%s] was filtered using the reserved " + "name spaces [%s], and the result is [%s].", + metadata_for_test, keys_to_pop, expected_result) + ]) diff -Nru cinder-22.1.0/cinder/tests/unit/test_ssh_utils.py cinder-22.1.1/cinder/tests/unit/test_ssh_utils.py --- cinder-22.1.0/cinder/tests/unit/test_ssh_utils.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/tests/unit/test_ssh_utils.py 2023-09-14 01:21:33.000000000 +0000 @@ -405,3 +405,11 @@ sshpool = None self.assertEqual(fake_close.mock_calls, close_expect_calls + close_expect_calls) + + @mock.patch('cinder.ssh_utils.paramiko', new=None) + def test_missing_paramiko(self): + self.assertRaises(exception.RequirementMissing, + ssh_utils.SSHPool, + '192.0.2.1', 22, 10, + 'test', + password='hello') diff -Nru cinder-22.1.0/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py cinder-22.1.1/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py --- cinder-22.1.0/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py 2023-09-14 01:21:33.000000000 +0000 @@ -675,6 +675,11 @@ '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 @@ 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 @@ 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': ' 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 @@ -4245,10 +4346,16 @@ 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", @@ -4280,15 +4387,20 @@ 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) @@ -6052,16 +6164,21 @@ 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} @@ -6092,6 +6209,10 @@ 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( @@ -6107,17 +6228,25 @@ 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 -Nru cinder-22.1.0/cinder/tests/unit/volume/drivers/test_rbd.py cinder-22.1.1/cinder/tests/unit/volume/drivers/test_rbd.py --- cinder-22.1.0/cinder/tests/unit/volume/drivers/test_rbd.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/tests/unit/volume/drivers/test_rbd.py 2023-09-14 01:21:33.000000000 +0000 @@ -3361,6 +3361,17 @@ {'provider_location': "{\"saved_features\":%s}" % image_features}, ret) + @common_mocks + def test_enable_multiattach_no_features(self): + image = self.mock_proxy.return_value.__enter__.return_value + image.features.return_value = 0 + + ret = self.driver._enable_multiattach(self.volume_a) + + image.update_features.assert_not_called() + + self.assertEqual({'provider_location': '{"saved_features":0}'}, ret) + @ddt.data(MULTIATTACH_FULL_FEATURES, MULTIATTACH_REDUCED_FEATURES) @common_mocks def test_disable_multiattach(self, features): @@ -3374,6 +3385,18 @@ self.assertEqual({'provider_location': None}, ret) + @common_mocks + def test_disable_multiattach_no_features(self): + image = self.mock_proxy.return_value.__enter__.return_value + self.volume_a.provider_location = '{"saved_features": 0}' + image.features.return_value = 0 + + ret = self.driver._disable_multiattach(self.volume_a) + + image.update_features.assert_not_called() + + self.assertEqual({'provider_location': None}, ret) + class ManagedRBDTestCase(test_driver.BaseDriverTestCase): driver_name = "cinder.volume.drivers.rbd.RBDDriver" diff -Nru cinder-22.1.0/cinder/tests/unit/volume/flows/test_create_volume_flow.py cinder-22.1.1/cinder/tests/unit/volume/flows/test_create_volume_flow.py --- cinder-22.1.0/cinder/tests/unit/volume/flows/test_create_volume_flow.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/tests/unit/volume/flows/test_create_volume_flow.py 2023-09-14 01:21:33.000000000 +0000 @@ -1254,7 +1254,7 @@ fake_driver = mock.MagicMock() fake_volume_manager = mock.MagicMock() backup_host = 'host@backend#pool' - fake_manager = create_volume_manager.CreateVolumeFromSpecTask( + test_manager = create_volume_manager.CreateVolumeFromSpecTask( fake_volume_manager, fake_db, fake_driver) volume_obj = fake_volume.fake_volume_obj(self.ctxt) @@ -1271,8 +1271,7 @@ if driver_error: fake_driver.create_volume_from_backup.side_effect = [ NotImplementedError] - fake_manager._create_from_backup(self.ctxt, volume_obj, - backup_obj.id) + test_manager._create_from_backup(self.ctxt, volume_obj, backup_obj.id) fake_driver.create_volume_from_backup.assert_called_once_with( volume_obj, backup_obj) if driver_error: @@ -1282,7 +1281,8 @@ mock_restore_backup.assert_called_once_with(self.ctxt, backup_host, backup_obj, - volume_obj['id']) + volume_obj['id'], + volume_is_new=True) else: fake_driver.create_volume_from_backup.assert_called_once_with( volume_obj, backup_obj) diff -Nru cinder-22.1.0/cinder/volume/drivers/hpe/hpe_3par_common.py cinder-22.1.1/cinder/volume/drivers/hpe/hpe_3par_common.py --- cinder-22.1.0/cinder/volume/drivers/hpe/hpe_3par_common.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/volume/drivers/hpe/hpe_3par_common.py 2023-09-14 01:21:33.000000000 +0000 @@ -81,6 +81,7 @@ COMPRESSION_API_VERSION = 30301215 SRSTATLD_API_VERSION = 30201200 REMOTE_COPY_API_VERSION = 30202290 +API_VERSION_2023 = 100000000 hpe3par_opts = [ cfg.StrOpt('hpe3par_api_url', @@ -300,11 +301,12 @@ 4.0.16 - In multi host env, fix multi-detach operation. Bug #1958122 4.0.17 - Added get_manageable_volumes and get_manageable_snapshots. Bug #1819903 + 4.0.19 - Update code to work with new WSAPI (of 2023). Bug #2015746 """ - VERSION = "4.0.17" + VERSION = "4.0.19" stats = {} @@ -704,9 +706,12 @@ 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 @@ -1004,7 +1009,7 @@ '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", @@ -2393,9 +2398,14 @@ 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 @@ -2466,7 +2476,7 @@ {'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: @@ -4358,15 +4368,17 @@ 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: @@ -4381,6 +4393,8 @@ 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: @@ -5300,7 +5314,11 @@ 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 -Nru cinder-22.1.0/cinder/volume/drivers/rbd.py cinder-22.1.1/cinder/volume/drivers/rbd.py --- cinder-22.1.0/cinder/volume/drivers/rbd.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/volume/drivers/rbd.py 2023-09-14 01:21:33.000000000 +0000 @@ -968,7 +968,8 @@ with RBDVolumeProxy(self, vol_name) as image: image_features = image.features() change_features = self.MULTIATTACH_EXCLUSIONS & image_features - image.update_features(change_features, False) + if change_features != 0: + image.update_features(change_features, False) return {'provider_location': self._dumps({'saved_features': image_features})} @@ -980,7 +981,8 @@ provider_location = json.loads(volume.provider_location) image_features = provider_location['saved_features'] change_features = self.MULTIATTACH_EXCLUSIONS & image_features - image.update_features(change_features, True) + if change_features != 0: + image.update_features(change_features, True) except IndexError: msg = "Could not find saved image features." raise RBDDriverException(reason=msg) diff -Nru cinder-22.1.0/cinder/volume/flows/manager/create_volume.py cinder-22.1.1/cinder/volume/flows/manager/create_volume.py --- cinder-22.1.0/cinder/volume/flows/manager/create_volume.py 2023-05-17 11:15:28.000000000 +0000 +++ cinder-22.1.1/cinder/volume/flows/manager/create_volume.py 2023-09-14 01:21:33.000000000 +0000 @@ -1172,7 +1172,7 @@ backuprpcapi = backup_rpcapi.BackupAPI() backuprpcapi.restore_backup(context, backup.host, backup, - volume.id) + volume.id, volume_is_new=True) need_update_volume = False LOG.info("Created volume %(volume_id)s from backup %(backup_id)s " diff -Nru cinder-22.1.0/cinder.egg-info/pbr.json cinder-22.1.1/cinder.egg-info/pbr.json --- cinder-22.1.0/cinder.egg-info/pbr.json 2023-05-17 11:15:59.000000000 +0000 +++ cinder-22.1.1/cinder.egg-info/pbr.json 2023-09-14 01:22:05.000000000 +0000 @@ -1 +1 @@ -{"git_version": "ba4e53095", "is_release": true} \ No newline at end of file +{"git_version": "bdf0a3d52", "is_release": true} \ No newline at end of file diff -Nru cinder-22.1.0/cinder.egg-info/PKG-INFO cinder-22.1.1/cinder.egg-info/PKG-INFO --- cinder-22.1.0/cinder.egg-info/PKG-INFO 2023-05-17 11:15:59.000000000 +0000 +++ cinder-22.1.1/cinder.egg-info/PKG-INFO 2023-09-14 01:22:05.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: cinder -Version: 22.1.0 +Version: 22.1.1 Summary: OpenStack Block Storage Home-page: https://docs.openstack.org/cinder/latest/ Author: OpenStack diff -Nru cinder-22.1.0/cinder.egg-info/SOURCES.txt cinder-22.1.1/cinder.egg-info/SOURCES.txt --- cinder-22.1.0/cinder.egg-info/SOURCES.txt 2023-05-17 11:16:00.000000000 +0000 +++ cinder-22.1.1/cinder.egg-info/SOURCES.txt 2023-09-14 01:22:06.000000000 +0000 @@ -2271,6 +2271,7 @@ releasenotes/notes/backup-snapshot-6e7447db930c31f6.yaml releasenotes/notes/backup-snapshots-2f547c8788bc11e1.yaml releasenotes/notes/backup-sparse-f396b35bfe17332e.yaml +releasenotes/notes/backup-sparse-f685f4321f2994f5.yaml releasenotes/notes/backup-update-d0b0db6a7b1c2a5b.yaml releasenotes/notes/backup-user-messages-5ee0c7ead3def8f9.yaml releasenotes/notes/backup-volumenotfound-set-to-error-fa47b3631093a702.yaml @@ -2476,6 +2477,7 @@ releasenotes/notes/bug-invalid-content-type-1715094-8yu8i9w425ua08f3.yaml releasenotes/notes/bug-reno-69539ecb9b0b5464.yaml releasenotes/notes/bug1929429-e749f5e5a242a599.yaml +releasenotes/notes/bug1945500-e4df056b8be2e0ef.yaml releasenotes/notes/bug_1828993-8e78d7bbee16ca08.yaml releasenotes/notes/bug_1870367-49b74d10a9bfcf07.yaml releasenotes/notes/bug_1945824-7f8f238e274ddebd.yaml @@ -2696,6 +2698,7 @@ releasenotes/notes/hnas_deprecate_xml-16840b5a8c25d15e.yaml releasenotes/notes/hpe-3par-add-alletra-9k-info-5e1d09e083d3faa9.yaml releasenotes/notes/hpe-3par-add-get-manageable-2926f21116c98599.yaml +releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml releasenotes/notes/hpe-3par-fix-multi-detach-in-multi-host-env-3f2211f29a336b6e.yaml releasenotes/notes/hpe-3par-peer-persistence.yaml-91cc84bf89dbb462.yaml releasenotes/notes/hpe-3par-pp-primera-a3442d004545b3a9.yaml @@ -3003,6 +3006,7 @@ releasenotes/notes/rbd-support-revert-to-snapshot-c9ca62c9efbabf5f.yaml releasenotes/notes/rbd-thin-provisioning-c98522d6fe7b71ff.yaml releasenotes/notes/rbd-total_capacity-60f10b45e3a8c8ea.yaml +releasenotes/notes/rbd-update-features-bugfix-df97b50864ce9712.yaml releasenotes/notes/rbd-v2.1-replication-64a9d0bec5987faf.yaml releasenotes/notes/rbd_replication_add_secret_uuid_config-c74d65e6d3d610c6.yaml releasenotes/notes/re-add-nexenta-driver-d3af97e33551a485.yaml diff -Nru cinder-22.1.0/debian/changelog cinder-22.1.1/debian/changelog --- cinder-22.1.0/debian/changelog 2023-06-30 17:33:59.000000000 +0000 +++ cinder-22.1.1/debian/changelog 2023-09-25 19:11:01.000000000 +0000 @@ -1,3 +1,10 @@ +cinder (2:22.1.1-0ubuntu1) lunar; urgency=medium + + * New stable point release for OpenStack Antelope (LP: #2037319). + * d/p/skip-mock-spec-failures.patch: Rebased. + + -- Corey Bryant Mon, 25 Sep 2023 15:11:01 -0400 + cinder (2:22.1.0-0ubuntu1) lunar; urgency=medium * New stable point release for OpenStack Antelope (LP: #2025491). diff -Nru cinder-22.1.0/debian/patches/skip-mock-spec-failures.patch cinder-22.1.1/debian/patches/skip-mock-spec-failures.patch --- cinder-22.1.0/debian/patches/skip-mock-spec-failures.patch 2023-06-30 17:33:59.000000000 +0000 +++ cinder-22.1.1/debian/patches/skip-mock-spec-failures.patch 2023-09-25 19:11:01.000000000 +0000 @@ -1835,7 +1835,7 @@ - self.driver._get_config) --- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py +++ /dev/null -@@ -1,10768 +0,0 @@ +@@ -1,10897 +0,0 @@ -# (c) Copyright 2013-2015 Hewlett Packard Enterprise Development LP -# All Rights Reserved. -# @@ -2513,6 +2513,11 @@ - '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 - @@ -2730,28 +2735,41 @@ - 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) - @@ -3093,6 +3111,89 @@ - 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': ' 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 @@ -6083,10 +6184,16 @@ - 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", @@ -6118,15 +6225,20 @@ - - 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) @@ -7890,16 +8002,21 @@ - - 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} @@ -7930,6 +8047,10 @@ - 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( @@ -7945,17 +8066,25 @@ - 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 -Nru cinder-22.1.0/PKG-INFO cinder-22.1.1/PKG-INFO --- cinder-22.1.0/PKG-INFO 2023-05-17 11:16:01.505023000 +0000 +++ cinder-22.1.1/PKG-INFO 2023-09-14 01:22:06.912987500 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: cinder -Version: 22.1.0 +Version: 22.1.1 Summary: OpenStack Block Storage Home-page: https://docs.openstack.org/cinder/latest/ Author: OpenStack diff -Nru cinder-22.1.0/releasenotes/notes/backup-sparse-f685f4321f2994f5.yaml cinder-22.1.1/releasenotes/notes/backup-sparse-f685f4321f2994f5.yaml --- cinder-22.1.0/releasenotes/notes/backup-sparse-f685f4321f2994f5.yaml 1970-01-01 00:00:00.000000000 +0000 +++ cinder-22.1.1/releasenotes/notes/backup-sparse-f685f4321f2994f5.yaml 2023-09-14 01:21:33.000000000 +0000 @@ -0,0 +1,7 @@ +--- +fixes: + - | + `Bug #2025277 `_: + Fixed a regression in the fix for Cinder backup restoring into + sparse volumes, where OpenStack's integrated CLI triggered a traceback. + The deprecated project-specific legacy CLI of Cinder continued to work. diff -Nru cinder-22.1.0/releasenotes/notes/bug1945500-e4df056b8be2e0ef.yaml cinder-22.1.1/releasenotes/notes/bug1945500-e4df056b8be2e0ef.yaml --- cinder-22.1.0/releasenotes/notes/bug1945500-e4df056b8be2e0ef.yaml 1970-01-01 00:00:00.000000000 +0000 +++ cinder-22.1.1/releasenotes/notes/bug1945500-e4df056b8be2e0ef.yaml 2023-09-14 01:21:33.000000000 +0000 @@ -0,0 +1,8 @@ +--- +fixes: + - | + `Bug #1945500 `_: The + original attempt at fixing this bug did not account for differences in + how glance and cinder store image metadata, and as a result some image + properties were not filtered out. This new improved fix addresses those + differences and makes the filtering more thorough. diff -Nru cinder-22.1.0/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml cinder-22.1.1/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml --- cinder-22.1.0/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml 1970-01-01 00:00:00.000000000 +0000 +++ cinder-22.1.1/releasenotes/notes/hpe-3par-code-changes-for-new-wsapi-25865a65a428ce46.yaml 2023-09-14 01:21:33.000000000 +0000 @@ -0,0 +1,4 @@ +fixes: + - | + HPE 3PAR driver `Bug #2015746 `_: + Fixed: minor code changes to work with new wsapi. diff -Nru cinder-22.1.0/releasenotes/notes/rbd-update-features-bugfix-df97b50864ce9712.yaml cinder-22.1.1/releasenotes/notes/rbd-update-features-bugfix-df97b50864ce9712.yaml --- cinder-22.1.0/releasenotes/notes/rbd-update-features-bugfix-df97b50864ce9712.yaml 1970-01-01 00:00:00.000000000 +0000 +++ cinder-22.1.1/releasenotes/notes/rbd-update-features-bugfix-df97b50864ce9712.yaml 2023-09-14 01:21:33.000000000 +0000 @@ -0,0 +1,6 @@ +--- +fixes: + - | + `Bug #1997980 `_: RBD: + Fixed failure to update rbd image features for multi-attach when + features = 0.