[policy in code] Add support for backup resource

This patch adds policy in code support for backup
resources and depends on the basic patch [1].

[1]: https://review.openstack.org/#/c/506976/

Change-Id: I9a79b5ececc587e80129cc980930e168e805b139
Partial-Implements: blueprint policy-in-code
This commit is contained in:
TommyLike 2017-09-25 16:15:29 +08:00
parent 274ce06f58
commit 1462d9c2e4
8 changed files with 201 additions and 41 deletions

View File

@ -79,10 +79,10 @@ class AdminController(wsgi.Controller):
return update
def authorize(self, context, action_name):
# NOTE(tommylikehu): We have two different ways to authorize during
# TODO(tommylike): We have two different ways to authorize during
# implementing code base policies, the if/else statement can be
# removed when all resources are upgraded.
if self.resource_name in ['snapshot']:
if self.resource_name in ['backup', 'snapshot']:
context.authorize(
'volume_extension:%(resource)s_admin_actions:%(action)s' %
{'resource': self.resource_name,

View File

@ -22,9 +22,9 @@ from cinder.api.contrib import backups as backups_v2
from cinder.api import microversions as mv
from cinder.api.openstack import wsgi
from cinder.api.v3.views import backups as backup_views
from cinder.backup import api as backup_api
from cinder import exception
from cinder.i18n import _
from cinder.policies import backups as policy
LOG = logging.getLogger(__name__)
@ -81,7 +81,7 @@ class BackupsController(backups_v2.BackupsController):
resp_backup = self._view_builder.detail(req, backup)
if req_version.matches(mv.BACKUP_PROJECT):
try:
backup_api.check_policy(context, 'backup_project_attribute')
context.authorize(policy.BACKUP_ATTRIBUTES_POLICY)
self._add_backup_project_attribute(req, resp_backup['backup'])
except exception.PolicyNotAuthorized:
pass
@ -94,7 +94,7 @@ class BackupsController(backups_v2.BackupsController):
if req_version.matches(mv.BACKUP_PROJECT):
try:
backup_api.check_policy(context, 'backup_project_attribute')
context.authorize(policy.BACKUP_ATTRIBUTES_POLICY)
for bak in resp_backup['backups']:
self._add_backup_project_attribute(req, bak)
except exception.PolicyNotAuthorized:

View File

@ -36,6 +36,7 @@ from cinder import exception
from cinder.i18n import _
from cinder import objects
from cinder.objects import fields
from cinder.policies import backups as policy
import cinder.policy
from cinder import quota
from cinder import quota_utils
@ -56,15 +57,6 @@ QUOTAS = quota.QUOTAS
IMPORT_VOLUME_ID = '00000000-0000-0000-0000-000000000000'
def check_policy(context, action):
target = {
'project_id': context.project_id,
'user_id': context.user_id,
}
_action = 'backup:%s' % action
cinder.policy.enforce(context, _action, target)
class API(base.Base):
"""API for interacting with the volume backup manager."""
@ -74,7 +66,7 @@ class API(base.Base):
super(API, self).__init__(db)
def get(self, context, backup_id):
check_policy(context, 'get')
context.authorize(policy.GET_POLICY)
return objects.Backup.get_by_id(context, backup_id)
def _check_support_to_force_delete(self, context, backup_host):
@ -93,7 +85,7 @@ class API(base.Base):
:raises BackupDriverException:
:raises ServiceNotFound:
"""
check_policy(context, 'delete')
context.authorize(policy.DELETE_POLICY)
if not force and backup.status not in [fields.BackupStatus.AVAILABLE,
fields.BackupStatus.ERROR]:
msg = _('Backup status must be available or error')
@ -118,7 +110,7 @@ class API(base.Base):
def get_all(self, context, search_opts=None, marker=None, limit=None,
offset=None, sort_keys=None, sort_dirs=None):
check_policy(context, 'get_all')
context.authorize(policy.GET_ALL_POLICY)
search_opts = search_opts or {}
@ -204,7 +196,7 @@ class API(base.Base):
container, incremental=False, availability_zone=None,
force=False, snapshot_id=None, metadata=None):
"""Make the RPC call to create a volume backup."""
check_policy(context, 'create')
context.authorize(policy.CREATE_POLICY)
utils.check_metadata_properties(metadata)
volume = self.volume_api.get(context, volume_id)
snapshot = None
@ -341,7 +333,7 @@ class API(base.Base):
def restore(self, context, backup_id, volume_id=None, name=None):
"""Make the RPC call to restore a volume backup."""
check_policy(context, 'restore')
context.authorize(policy.RESTORE_POLICY)
backup = self.get(context, backup_id)
if backup['status'] != fields.BackupStatus.AVAILABLE:
msg = _('Backup status must be available')
@ -444,7 +436,7 @@ class API(base.Base):
:returns: contains 'backup_url' and 'backup_service'
:raises InvalidBackup:
"""
check_policy(context, 'backup-export')
context.authorize(policy.EXPORT_POLICY)
backup = self.get(context, backup_id)
if backup['status'] != fields.BackupStatus.AVAILABLE:
msg = (_('Backup status must be available and not %s.') %
@ -537,7 +529,7 @@ class API(base.Base):
:raises ServiceNotFound:
:raises InvalidInput:
"""
check_policy(context, 'backup-import')
context.authorize(policy.IMPORT_POLICY)
# NOTE(ronenkat): since we don't have a backup-scheduler
# we need to find a host that support the backup service
@ -563,7 +555,7 @@ class API(base.Base):
return backup
def update(self, context, backup_id, fields):
check_policy(context, 'update')
context.authorize(policy.UPDATE_POLICY)
backup = self.get(context, backup_id)
backup.update(fields)
backup.save()

View File

@ -16,6 +16,8 @@
import itertools
from cinder.policies import attachments
from cinder.policies import backup_actions
from cinder.policies import backups
from cinder.policies import base
from cinder.policies import clusters
from cinder.policies import manageable_snapshots
@ -37,4 +39,6 @@ def list_rules():
snapshots.list_rules(),
snapshot_actions.list_rules(),
manageable_snapshots.list_rules(),
backups.list_rules(),
backup_actions.list_rules(),
)

View File

@ -0,0 +1,49 @@
# Copyright (c) 2017 Huawei Technologies Co., Ltd.
# All Rights Reserved.
#
# 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.
from oslo_policy import policy
from cinder.policies import base
BASE_POLICY_NAME = 'volume_extension:backup_admin_actions:%s'
backup_actions_policies = [
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'reset_status',
check_str=base.RULE_ADMIN_API,
description="Reset status of a backup.",
operations=[
{
'method': 'POST',
'path': '/backups/{backup_id}/action (os-reset_status)'
}
]),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'force_delete',
check_str=base.RULE_ADMIN_API,
description="Force delete a backup.",
operations=[
{
'method': 'POST',
'path': '/backups/{backup_id}/action (os-force_delete)'
}
]),
]
def list_rules():
return backup_actions_policies

134
cinder/policies/backups.py Normal file
View File

@ -0,0 +1,134 @@
# Copyright (c) 2017 Huawei Technologies Co., Ltd.
# All Rights Reserved.
#
# 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.
from oslo_policy import policy
from cinder.policies import base
GET_ALL_POLICY = 'backup:get_all'
GET_POLICY = 'backup:get'
CREATE_POLICY = 'backup:create'
UPDATE_POLICY = 'backup:update'
DELETE_POLICY = 'backup:delete'
RESTORE_POLICY = 'backup:restore'
IMPORT_POLICY = 'backup:backup-import'
EXPORT_POLICY = 'backup:export-import'
BACKUP_ATTRIBUTES_POLICY = 'backup:backup_project_attribute'
backups_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List backups.",
operations=[
{
'method': 'GET',
'path': '/backups'
},
{
'method': 'GET',
'path': '/backups/detail'
}
]),
policy.DocumentedRuleDefault(
name=BACKUP_ATTRIBUTES_POLICY,
check_str=base.RULE_ADMIN_API,
description="List backups or show backup with project attributes.",
operations=[
{
'method': 'GET',
'path': '/backups/{backup_id}'
},
{
'method': 'GET',
'path': '/backups/detail'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str="",
description="Create backup.",
operations=[
{
'method': 'POST',
'path': '/backups'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show backup.",
operations=[
{
'method': 'GET',
'path': '/backups/{backup_id}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update backup.",
operations=[
{
'method': 'PUT',
'path': '/backups/{backup_id}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete backup.",
operations=[
{
'method': 'DELETE',
'path': '/backups/{backup_id}'
}
]),
policy.DocumentedRuleDefault(
name=RESTORE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Restore backup.",
operations=[
{
'method': 'POST',
'path': '/backups/{backup_id}/restore'
}
]),
policy.DocumentedRuleDefault(
name=IMPORT_POLICY,
check_str=base.RULE_ADMIN_API,
description="Import backup.",
operations=[
{
'method': 'POST',
'path': '/backups/{backup_id}/import_record'
}
]),
policy.DocumentedRuleDefault(
name=EXPORT_POLICY,
check_str=base.RULE_ADMIN_API,
description="Export backup.",
operations=[
{
'method': 'POST',
'path': '/backups/{backup_id}/export_record'
}
]),
]
def list_rules():
return backups_policies

View File

@ -44,8 +44,6 @@
"volume:thaw_host": "rule:admin_api",
"volume:revert_to_snapshot": "",
"volume_extension:volume_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_detach": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api",
@ -95,16 +93,10 @@
"volume:get_transfer": "",
"volume:get_all_transfers": "",
"backup:create" : "",
"backup:delete": "",
"backup:get": "",
"backup:get_all": "",
"backup:restore": "",
"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",
"consistencygroup:create" : "",
"consistencygroup:delete": "",

View File

@ -46,7 +46,6 @@
"volume_extension:quota_classes:validate_setup_for_nested_quota_use": "rule:admin_api",
"volume_extension:volume_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:reset_status": "rule:admin_api",
"volume_extension:volume_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_detach": "rule:admin_api",
"volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
@ -79,16 +78,6 @@
"volume:freeze_host": "rule:admin_api",
"volume:thaw_host": "rule:admin_api",
"backup:create" : "",
"backup:delete": "rule:admin_or_owner",
"backup:get": "rule:admin_or_owner",
"backup:get_all": "rule:admin_or_owner",
"backup:restore": "rule:admin_or_owner",
"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",
"consistencygroup:create" : "group:nobody",
"consistencygroup:delete": "group:nobody",
"consistencygroup:update": "group:nobody",