From 3f7acda20fb1e9e2623c86e560c4a5ab25b475e4 Mon Sep 17 00:00:00 2001 From: wanghao Date: Wed, 16 Dec 2015 17:26:13 +0800 Subject: [PATCH] Backup project attribute support Cinder has supported to query project id of volume and snapshot, for consistency, this will introduce backup project attribute in querying operation. APIImpact Add 'os-backup-project-attr:project_id: xxxx' in querying response. Implements: blueprint: backup-tenant-attribute-support Change-Id: I6fde17baffe88ab4d4e69dcc2fefdbcb8d7a4dc5 --- cinder/api/openstack/api_version_request.py | 3 +- .../openstack/rest_api_version_history.rst | 4 + cinder/api/v3/backups.py | 45 ++++++++ .../contrib/test_backup_project_attribute.py | 101 ++++++++++++++++++ cinder/tests/unit/policy.json | 1 + etc/cinder/policy.json | 1 + ...up-project-attribute-3f57051ef9159b08.yaml | 3 + 7 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 cinder/tests/unit/api/contrib/test_backup_project_attribute.py create mode 100644 releasenotes/notes/add-backup-project-attribute-3f57051ef9159b08.yaml diff --git a/cinder/api/openstack/api_version_request.py b/cinder/api/openstack/api_version_request.py index ae36fba8b7d..f49d13809d8 100644 --- a/cinder/api/openstack/api_version_request.py +++ b/cinder/api/openstack/api_version_request.py @@ -66,6 +66,7 @@ REST_API_VERSION_HISTORY = """ problem with volume metadata. * 3.16 - Migrate volume now supports cluster * 3.17 - Getting manageable volumes and snapshots now accepts cluster. + * 3.18 - Add backup project attribute. """ # The minimum and maximum versions of the API supported @@ -73,7 +74,7 @@ REST_API_VERSION_HISTORY = """ # minimum version of the API supported. # Explicitly using /v1 or /v2 enpoints will still work _MIN_API_VERSION = "3.0" -_MAX_API_VERSION = "3.17" +_MAX_API_VERSION = "3.18" _LEGACY_API_VERSION1 = "1.0" _LEGACY_API_VERSION2 = "2.0" diff --git a/cinder/api/openstack/rest_api_version_history.rst b/cinder/api/openstack/rest_api_version_history.rst index 33adba020a0..488d7dead60 100644 --- a/cinder/api/openstack/rest_api_version_history.rst +++ b/cinder/api/openstack/rest_api_version_history.rst @@ -206,3 +206,7 @@ user documentation. os-snapshot-manage and os-volume-manage now support ``cluster`` parameter on listings (summay and detailed). Both location parameters, ``cluster`` and ``host`` are exclusive and only one should be provided. + +3.18 +---- + Added backup project attribute. diff --git a/cinder/api/v3/backups.py b/cinder/api/v3/backups.py index 7db051217f7..56fc9f6a482 100644 --- a/cinder/api/v3/backups.py +++ b/cinder/api/v3/backups.py @@ -15,13 +15,20 @@ """The backups V3 api.""" +from oslo_log import log as logging from webob import exc from cinder.api.contrib import backups as backups_v2 from cinder.api.openstack import wsgi +from cinder.backup import api as backup_api +from cinder import exception from cinder.i18n import _ + BACKUP_UPDATE_MICRO_VERSION = '3.9' +BACKUP_TENANT_MICRO_VERSION = '3.18' + +LOG = logging.getLogger(__name__) class BackupsController(backups_v2.BackupsController): @@ -51,6 +58,44 @@ class BackupsController(backups_v2.BackupsController): return self._view_builder.summary(req, new_backup) + def _add_backup_project_attribute(self, req, backup): + db_backup = req.get_db_backup(backup['id']) + key = "os-backup-project-attr:project_id" + backup[key] = db_backup['project_id'] + + def show(self, req, id): + """Return data about the given backup.""" + LOG.debug('show called for member %s', id) + context = req.environ['cinder.context'] + req_version = req.api_version_request + + # Not found exception will be handled at the wsgi level + backup = self.backup_api.get(context, backup_id=id) + req.cache_db_backup(backup) + + resp_backup = self._view_builder.detail(req, backup) + if req_version.matches(BACKUP_TENANT_MICRO_VERSION): + try: + backup_api.check_policy(context, 'backup_project_attribute') + self._add_backup_project_attribute(req, resp_backup['backup']) + except exception.PolicyNotAuthorized: + pass + return resp_backup + + def detail(self, req): + resp_backup = super(BackupsController, self).detail(req) + context = req.environ['cinder.context'] + req_version = req.api_version_request + + if req_version.matches(BACKUP_TENANT_MICRO_VERSION): + try: + backup_api.check_policy(context, 'backup_project_attribute') + for bak in resp_backup['backups']: + self._add_backup_project_attribute(req, bak) + except exception.PolicyNotAuthorized: + pass + return resp_backup + def create_resource(): return wsgi.Resource(BackupsController()) diff --git a/cinder/tests/unit/api/contrib/test_backup_project_attribute.py b/cinder/tests/unit/api/contrib/test_backup_project_attribute.py new file mode 100644 index 00000000000..16cf791c88a --- /dev/null +++ b/cinder/tests/unit/api/contrib/test_backup_project_attribute.py @@ -0,0 +1,101 @@ +# Copyright (c) 2016 Huawei Technologies Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import ddt + +from oslo_serialization import jsonutils +import webob + +from cinder.api.openstack import api_version_request as api_version +from cinder.api.v3 import router as router_v3 +from cinder import backup +from cinder import context +from cinder import objects +from cinder import test +from cinder.tests.unit.api import fakes +from cinder.tests.unit.backup import fake_backup +from cinder.tests.unit import fake_constants as fake + + +def fake_backup_get(*args, **kwargs): + ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, False) + bak = { + 'id': fake.BACKUP_ID, + 'project_id': fake.PROJECT_ID, + } + return fake_backup.fake_backup_obj(ctx, **bak) + + +def fake_backup_get_all(*args, **kwargs): + return objects.BackupList(objects=[fake_backup_get()]) + + +def app(): + # no auth, just let environ['cinder.context'] pass through + api = router_v3.APIRouter() + mapper = fakes.urlmap.URLMap() + mapper['/v3'] = api + return mapper + + +@ddt.ddt +class BackupProjectAttributeTest(test.TestCase): + + def setUp(self): + super(BackupProjectAttributeTest, self).setUp() + self.stubs.Set(backup.API, 'get', fake_backup_get) + self.stubs.Set(backup.API, 'get_all', fake_backup_get_all) + + def _send_backup_request(self, ctx, detail=False, version='3.18'): + req = None + if detail: + req = webob.Request.blank(('/v3/%s/backups/detail' + % fake.PROJECT_ID)) + else: + req = webob.Request.blank('/v3/%s/backups/%s' % (fake.PROJECT_ID, + fake.BACKUP_ID)) + req.method = 'GET' + req.environ['cinder.context'] = ctx + req.headers['OpenStack-API-Version'] = 'volume ' + version + req.api_version_request = api_version.APIVersionRequest(version) + res = req.get_response(app()) + + if detail: + return jsonutils.loads(res.body)['backups'] + return jsonutils.loads(res.body)['backup'] + + @ddt.data(True, False) + def test_get_backup_with_project(self, is_admin): + ctx = context.RequestContext(fake.USER2_ID, fake.PROJECT_ID, is_admin) + bak = self._send_backup_request(ctx) + if is_admin: + self.assertEqual(fake.PROJECT_ID, + bak['os-backup-project-attr:project_id']) + else: + self.assertNotIn('os-backup-project-attr:project_id', bak) + + @ddt.data(True, False) + def test_list_detail_backups_with_project(self, is_admin): + ctx = context.RequestContext(fake.USER2_ID, fake.PROJECT_ID, is_admin) + baks = self._send_backup_request(ctx, detail=True) + if is_admin: + self.assertEqual(fake.PROJECT_ID, + baks[0]['os-backup-project-attr:project_id']) + else: + self.assertNotIn('os-backup-project-attr:project_id', baks[0]) + + def test_get_backup_under_allowed_api_version(self): + ctx = context.RequestContext(fake.USER2_ID, fake.PROJECT_ID, True) + bak = self._send_backup_request(ctx, version='3.17') + self.assertNotIn('os-backup-project-attr:project_id', bak) diff --git a/cinder/tests/unit/policy.json b/cinder/tests/unit/policy.json index c64778065a1..1b347a24400 100644 --- a/cinder/tests/unit/policy.json +++ b/cinder/tests/unit/policy.json @@ -99,6 +99,7 @@ "backup:backup-import": "rule:admin_api", "backup:backup-export": "rule:admin_api", "backup:update": "rule:admin_or_owner", + "backup:backup_project_attribute": "rule:admin_api", "volume_extension:replication:promote": "rule:admin_api", "volume_extension:replication:reenable": "rule:admin_api", diff --git a/etc/cinder/policy.json b/etc/cinder/policy.json index 7bb9cb164a7..139fe3c2312 100644 --- a/etc/cinder/policy.json +++ b/etc/cinder/policy.json @@ -92,6 +92,7 @@ "backup:backup-import": "rule:admin_api", "backup:backup-export": "rule:admin_api", "backup:update": "rule:admin_or_owner", + "backup:backup_project_attribute": "rule:admin_api", "snapshot_extension:snapshot_actions:update_snapshot_status": "", "snapshot_extension:snapshot_manage": "rule:admin_api", diff --git a/releasenotes/notes/add-backup-project-attribute-3f57051ef9159b08.yaml b/releasenotes/notes/add-backup-project-attribute-3f57051ef9159b08.yaml new file mode 100644 index 00000000000..6ac453bd7af --- /dev/null +++ b/releasenotes/notes/add-backup-project-attribute-3f57051ef9159b08.yaml @@ -0,0 +1,3 @@ +--- +features: + - Added ability to query backups by project ID. \ No newline at end of file