From 6dd3b9c51ff698e61730aa3697bb69f0dd0011ad Mon Sep 17 00:00:00 2001 From: whoami-rajat Date: Tue, 26 Feb 2019 16:55:52 +0530 Subject: [PATCH] Add project_id in group snapshots list and show API Add ``project_id`` to response body of list group snapshots with detail and show group snapshot detail APIs. Merging the group and group snapshot response in same MV was discussed in weekly meeting[1]. [1] http://eavesdrop.openstack.org/meetings/cinder/2019/cinder.2019-02-20-16.00.log.html#l-122 Change-Id: Ided66450b5d7de32551edbce249e94f6174da2eb Implements: blueprint add-project-id-to-group-groupsnapshot-response --- api-ref/source/v3/group-snapshots.inc | 2 + api-ref/source/v3/parameters.yaml | 9 ++- ...roup-snapshots-list-detailed-response.json | 6 +- .../group-snapshots-show-response.json | 3 +- cinder/api/microversions.py | 2 +- cinder/api/openstack/api_version_request.py | 3 +- .../openstack/rest_api_version_history.rst | 5 +- cinder/api/v3/views/group_snapshots.py | 14 ++++- cinder/api/v3/views/groups.py | 2 +- cinder/policies/group_snapshots.py | 16 +++++ .../tests/unit/api/v3/test_group_snapshots.py | 60 +++++++++++++++++++ cinder/tests/unit/api/v3/test_groups.py | 24 ++++---- ...oupsnapshot-response-512013e95a80784a.yaml | 6 ++ ...id-to-group-response-512013e95a80784a.yaml | 5 -- 14 files changed, 130 insertions(+), 27 deletions(-) create mode 100644 releasenotes/notes/add-project-id-to-group-groupsnapshot-response-512013e95a80784a.yaml delete mode 100644 releasenotes/notes/add-project-id-to-group-response-512013e95a80784a.yaml diff --git a/api-ref/source/v3/group-snapshots.inc b/api-ref/source/v3/group-snapshots.inc index 47c2ad34fda..16f8cdb746c 100644 --- a/api-ref/source/v3/group-snapshots.inc +++ b/api-ref/source/v3/group-snapshots.inc @@ -80,6 +80,7 @@ Response Parameters - status: status_group_snap - description: description_group_snap_req - group_type_id: group_type_id + - project_id: project_id_group_snapshot Response Example ---------------- @@ -135,6 +136,7 @@ Response Parameters - created_at: created_at - group_id: group_id - group_type_id: group_type_id + - project_id: project_id_group_snapshot Response Example ---------------- diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml index b0959289c82..b154ee543ed 100644 --- a/api-ref/source/v3/parameters.yaml +++ b/api-ref/source/v3/parameters.yaml @@ -2216,7 +2216,14 @@ project_id_group: description: | The UUID of the volume group project. in: body - required: true + required: false + type: string + min_version: 3.58 +project_id_group_snapshot: + description: | + The UUID of the volume group snapshot project. + in: body + required: false type: string min_version: 3.58 project_id_host: diff --git a/api-ref/source/v3/samples/group-snapshots-list-detailed-response.json b/api-ref/source/v3/samples/group-snapshots-list-detailed-response.json index 7cfc7da995b..f97f5dfdebf 100644 --- a/api-ref/source/v3/samples/group-snapshots-list-detailed-response.json +++ b/api-ref/source/v3/samples/group-snapshots-list-detailed-response.json @@ -7,7 +7,8 @@ "created_at": "2015-09-16T09:28:52.000000", "name": "my_group_snapshot1", "description": "my first group snapshot", - "group_type_id": "0ef094a2-d9fd-4c79-acfd-ac60a0506b7d" + "group_type_id": "0ef094a2-d9fd-4c79-acfd-ac60a0506b7d", + "project_id": "7ccf4863071f44aeb8f141f65780c51b" }, { "id": "aed36625-a6d7-4681-ba59-c7ba3d18c148", @@ -16,7 +17,8 @@ "created_at": "2015-09-16T09:31:15.000000", "name": "my_group_snapshot2", "description": "Edited description", - "group_type_id": "7270c56e-6354-4528-8e8b-f54dee2232c8" + "group_type_id": "7270c56e-6354-4528-8e8b-f54dee2232c8", + "project_id": "7ccf4863071f44aeb8f141f65780c51b" } ] } diff --git a/api-ref/source/v3/samples/group-snapshots-show-response.json b/api-ref/source/v3/samples/group-snapshots-show-response.json index 137bfd17437..2afa30afa50 100644 --- a/api-ref/source/v3/samples/group-snapshots-show-response.json +++ b/api-ref/source/v3/samples/group-snapshots-show-response.json @@ -6,6 +6,7 @@ "created_at": "2015-09-16T09:28:52.000000", "name": "my_group_snapshot1", "description": "my first group snapshot", - "group_type_id": "7270c56e-6354-4528-8e8b-f54dee2232c8" + "group_type_id": "7270c56e-6354-4528-8e8b-f54dee2232c8", + "project_id": "7ccf4863071f44aeb8f141f65780c51b" } } diff --git a/cinder/api/microversions.py b/cinder/api/microversions.py index c9ad5dbd195..638eb27fd33 100644 --- a/cinder/api/microversions.py +++ b/cinder/api/microversions.py @@ -155,7 +155,7 @@ BACKUP_PROJECT_USER_ID = '3.56' TRANSFER_WITH_HISTORY = '3.57' -GROUP_PROJECT_ID = '3.58' +GROUP_GROUPSNAPSHOT_PROJECT_ID = '3.58' SUPPORT_TRANSFER_PAGINATION = '3.59' diff --git a/cinder/api/openstack/api_version_request.py b/cinder/api/openstack/api_version_request.py index 23597fa63a6..79bb249d523 100644 --- a/cinder/api/openstack/api_version_request.py +++ b/cinder/api/openstack/api_version_request.py @@ -132,7 +132,8 @@ REST_API_VERSION_HISTORY = """ * 3.57 - Add 'source_project_id', 'destination_project_id', 'accepted' to transfer. * 3.58 - Add ``project_id`` attribute to response body of list groups with - detail and show group detail APIs. + detail, list group snapshots with detail, show group detail and + show group snapshot detail APIs. * 3.59 - Support volume transfer pagination. """ diff --git a/cinder/api/openstack/rest_api_version_history.rst b/cinder/api/openstack/rest_api_version_history.rst index d9df4042dea..e3fea1c12d1 100644 --- a/cinder/api/openstack/rest_api_version_history.rst +++ b/cinder/api/openstack/rest_api_version_history.rst @@ -455,8 +455,9 @@ related api (create/show/list detail transfer APIs) responses. 3.58 ---- -Add ``project_id`` attribute to response body of list groups with detail and -show group detail APIs. +Add ``project_id`` attribute to response body of list groups with detail, +list group snapshots with detail, show group detail and show group snapshot +detail APIs. 3.59 ---- diff --git a/cinder/api/v3/views/group_snapshots.py b/cinder/api/v3/views/group_snapshots.py index ef7cdc45760..cf767d2b025 100644 --- a/cinder/api/v3/views/group_snapshots.py +++ b/cinder/api/v3/views/group_snapshots.py @@ -14,6 +14,8 @@ # under the License. from cinder.api import common +from cinder.api import microversions as mv +from cinder.policies import group_snapshots as policy class ViewBuilder(common.ViewBuilder): @@ -47,7 +49,7 @@ class ViewBuilder(common.ViewBuilder): def detail(self, request, group_snapshot): """Detailed view of a single group_snapshot.""" - return { + group_snapshot_ref = { 'group_snapshot': { 'id': group_snapshot.id, 'group_id': group_snapshot.group_id, @@ -58,6 +60,16 @@ class ViewBuilder(common.ViewBuilder): 'description': group_snapshot.description } } + req_version = request.api_version_request + context = request.environ['cinder.context'] + + if req_version.matches(mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, None): + if context.authorize(policy.GROUP_SNAPSHOT_ATTRIBUTES_POLICY, + fatal=False): + group_snapshot_ref['group_snapshot']['project_id'] = ( + group_snapshot.project_id) + + return group_snapshot_ref def _list_view(self, func, request, group_snapshots): """Provide a view for a list of group_snapshots.""" diff --git a/cinder/api/v3/views/groups.py b/cinder/api/v3/views/groups.py index b5fffb8df7b..5dd1a004895 100644 --- a/cinder/api/v3/views/groups.py +++ b/cinder/api/v3/views/groups.py @@ -80,7 +80,7 @@ class ViewBuilder(common.ViewBuilder): if req_version.matches(mv.GROUP_REPLICATION, None): group_ref['group']['replication_status'] = group.replication_status - if req_version.matches(mv.GROUP_PROJECT_ID, None): + if req_version.matches(mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, None): if context.authorize(policy.GROUP_ATTRIBUTES_POLICY, fatal=False): group_ref['group']['project_id'] = group.project_id diff --git a/cinder/policies/group_snapshots.py b/cinder/policies/group_snapshots.py index 8413977832f..f6299ebaa36 100644 --- a/cinder/policies/group_snapshots.py +++ b/cinder/policies/group_snapshots.py @@ -23,6 +23,7 @@ DELETE_POLICY = 'group:delete_group_snapshot' UPDATE_POLICY = 'group:update_group_snapshot' GET_POLICY = 'group:get_group_snapshot' GET_ALL_POLICY = 'group:get_all_group_snapshots' +GROUP_SNAPSHOT_ATTRIBUTES_POLICY = 'group:group_snapshot_project_attribute' group_snapshots_policies = [ @@ -80,6 +81,21 @@ group_snapshots_policies = [ 'path': '/group_snapshots/{group_snapshot_id}' } ]), + policy.DocumentedRuleDefault( + name=GROUP_SNAPSHOT_ATTRIBUTES_POLICY, + check_str=base.RULE_ADMIN_API, + description="List group snapshots or show group " + "snapshot with project attributes.", + operations=[ + { + 'method': 'GET', + 'path': '/group_snapshots/{group_snapshot_id}' + }, + { + 'method': 'GET', + 'path': '/group_snapshots/detail' + } + ]), ] diff --git a/cinder/tests/unit/api/v3/test_group_snapshots.py b/cinder/tests/unit/api/v3/test_group_snapshots.py index 7ec8f1ce310..5b5ad5665c2 100644 --- a/cinder/tests/unit/api/v3/test_group_snapshots.py +++ b/cinder/tests/unit/api/v3/test_group_snapshots.py @@ -297,6 +297,43 @@ class GroupSnapshotsAPITestCase(test.TestCase): self.controller.show, req, fake.WILL_NOT_BE_FOUND_ID) + def test_show_group_snapshot_with_project_id(self): + group_snapshot = utils.create_group_snapshot( + self.context, group_id=self.group.id) + req = fakes.HTTPRequest.blank( + '/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, + group_snapshot.id), + version=mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, + use_admin_context=True) + res_dict = self.controller.show(req, group_snapshot.id) + + self.assertEqual(1, len(res_dict)) + self.assertEqual('test_group_snapshot', + res_dict['group_snapshot']['name']) + self.assertEqual(fake.PROJECT_ID, + res_dict['group_snapshot']['project_id']) + + group_snapshot.destroy() + + def test_show_group_snapshot_without_project_id(self): + group_snapshot = utils.create_group_snapshot( + self.context, group_id=self.group.id) + # using mv.TRANSFER_WITH_HISTORY (3.57) to test the + # project_id field is not in response before mv 3.58 + req = fakes.HTTPRequest.blank( + '/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, + group_snapshot.id), + version=mv.TRANSFER_WITH_HISTORY, + use_admin_context=True) + res_dict = self.controller.show(req, group_snapshot.id) + + self.assertEqual(1, len(res_dict)) + self.assertEqual('test_group_snapshot', + res_dict['group_snapshot']['name']) + self.assertNotIn('project_id', res_dict['group_snapshot']) + + group_snapshot.destroy() + @ddt.data(True, False) def test_list_group_snapshots_json(self, is_detail): if is_detail: @@ -324,6 +361,29 @@ class GroupSnapshotsAPITestCase(test.TestCase): self.assertNotIn('description', res_dict['group_snapshots'][2 - index].keys()) + @ddt.data(True, False) + def test_list_group_snapshots_with_project_id(self, is_detail): + if is_detail: + request_url = '/v3/%s/group_snapshots/detail' + else: + request_url = '/v3/%s/group_snapshots' + req = fakes.HTTPRequest.blank( + request_url % fake.PROJECT_ID, + version=mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, + use_admin_context=True) + if is_detail: + res_dict = self.controller.detail(req) + else: + res_dict = self.controller.index(req) + + self.assertEqual(1, len(res_dict)) + self.assertEqual(3, len(res_dict['group_snapshots'])) + for group in res_dict['group_snapshots']: + if is_detail: + self.assertIsNotNone(group['project_id']) + else: + self.assertNotIn('project_id', group) + @mock.patch('cinder.db.volume_type_get') @mock.patch('cinder.quota.VolumeTypeQuotaEngine.reserve') def test_create_group_snapshot_json(self, mock_quota, mock_vol_type): diff --git a/cinder/tests/unit/api/v3/test_groups.py b/cinder/tests/unit/api/v3/test_groups.py index 6682a9a57c2..2357f32b926 100644 --- a/cinder/tests/unit/api/v3/test_groups.py +++ b/cinder/tests/unit/api/v3/test_groups.py @@ -1423,10 +1423,10 @@ class GroupsAPITestCase(test.TestCase): def test_show_group_with_project_id(self): # If the microversion >= 3.58 and "is_admin=True", "project_id" should # be contained in the response body. - req = fakes.HTTPRequest.blank('/v3/%s/groups/%s' % - (fake.PROJECT_ID, self.group1.id), - version=mv.GROUP_PROJECT_ID, - use_admin_context=True) + req = fakes.HTTPRequest.blank( + '/v3/%s/groups/%s' % (fake.PROJECT_ID, self.group1.id), + version=mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, + use_admin_context=True) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) self.assertEqual(fake.PROJECT_ID, @@ -1437,7 +1437,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank( '/v3/%s/groups/%s' % (fake.PROJECT_ID, self.group1.id), - version=mv.get_prior_version(mv.GROUP_PROJECT_ID), + version=mv.get_prior_version(mv.GROUP_GROUPSNAPSHOT_PROJECT_ID), use_admin_context=True) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) @@ -1450,10 +1450,10 @@ class GroupsAPITestCase(test.TestCase): self.group2.group_type_id = fake.GROUP_TYPE2_ID self.group2.save() - req = fakes.HTTPRequest.blank(('/v3/%s/groups/detail' - % self.ctxt.project_id), - version=mv.GROUP_PROJECT_ID, - use_admin_context=True) + req = fakes.HTTPRequest.blank( + '/v3/%s/groups/detail' % self.ctxt.project_id, + version=mv.GROUP_GROUPSNAPSHOT_PROJECT_ID, + use_admin_context=True) res_dict = self.controller.detail(req) self.assertEqual(1, len(res_dict)) @@ -1465,9 +1465,9 @@ class GroupsAPITestCase(test.TestCase): def test_show_group_without_project_id(self): # If the microversion >= 3.58 and "is_admin=False", "project_id" should # not be contained in the response body. - req = fakes.HTTPRequest.blank('/v3/%s/groups/%s' % - (fake.PROJECT_ID, self.group3.id), - version=mv.GROUP_PROJECT_ID) + req = fakes.HTTPRequest.blank( + '/v3/%s/groups/%s' % (fake.PROJECT_ID, self.group3.id), + version=mv.GROUP_GROUPSNAPSHOT_PROJECT_ID) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) self.assertNotIn('project_id', res_dict['group']) diff --git a/releasenotes/notes/add-project-id-to-group-groupsnapshot-response-512013e95a80784a.yaml b/releasenotes/notes/add-project-id-to-group-groupsnapshot-response-512013e95a80784a.yaml new file mode 100644 index 00000000000..9d84afb2b8c --- /dev/null +++ b/releasenotes/notes/add-project-id-to-group-groupsnapshot-response-512013e95a80784a.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added ``project_id`` attribute to response body of list groups with detail, + list group snapshots with detail, show group detail and show group snapshot + detail APIs since microversion "3.58". diff --git a/releasenotes/notes/add-project-id-to-group-response-512013e95a80784a.yaml b/releasenotes/notes/add-project-id-to-group-response-512013e95a80784a.yaml deleted file mode 100644 index 1ea81a4e59b..00000000000 --- a/releasenotes/notes/add-project-id-to-group-response-512013e95a80784a.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Added ``project_id`` attribute to response body of list groups with detail - and show group detail APIs since microversion "3.58".