[policy in code] Add support for snapshot resource

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

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

Change-Id: I8e1b544f510c1a0af30a5a0b672578226c9fd315
Partial-Implements: blueprint policy-in-code
This commit is contained in:
TommyLike 2017-09-27 10:38:00 +08:00
parent bb3569a3f5
commit d5d0705343
13 changed files with 349 additions and 58 deletions

View File

@ -79,9 +79,18 @@ class AdminController(wsgi.Controller):
return update
def authorize(self, context, action_name):
# e.g. "snapshot_admin_actions:reset_status"
action = '%s_admin_actions:%s' % (self.resource_name, action_name)
extensions.extension_authorizer('volume', action)(context)
# NOTE(tommylikehu): 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']:
context.authorize(
'volume_extension:%(resource)s_admin_actions:%(action)s' %
{'resource': self.resource_name,
'action': action_name})
else:
# e.g. "snapshot_admin_actions:reset_status"
action = '%s_admin_actions:%s' % (self.resource_name, action_name)
extensions.extension_authorizer('volume', action)(context)
def _remove_worker(self, context, id):
# Remove the cleanup worker from the DB when we change a resource

View File

@ -16,11 +16,7 @@
from cinder.api import extensions
from cinder.api.openstack import wsgi
authorize = extensions.soft_extension_authorizer(
'volume',
'extended_snapshot_attributes')
from cinder.policies import snapshots as policy
class ExtendedSnapshotAttributesController(wsgi.Controller):
@ -33,7 +29,7 @@ class ExtendedSnapshotAttributesController(wsgi.Controller):
@wsgi.extends
def show(self, req, resp_obj, id):
context = req.environ['cinder.context']
if authorize(context):
if context.authorize(policy.EXTEND_ATTRIBUTE):
# Attach our slave template to the response object
snapshot = resp_obj.obj['snapshot']
self._extend_snapshot(req, snapshot)
@ -41,7 +37,7 @@ class ExtendedSnapshotAttributesController(wsgi.Controller):
@wsgi.extends
def detail(self, req, resp_obj):
context = req.environ['cinder.context']
if authorize(context):
if context.authorize(policy.EXTEND_ATTRIBUTE):
# Attach our slave template to the response object
for snapshot in list(resp_obj.obj['snapshots']):
self._extend_snapshot(req, snapshot)

View File

@ -21,15 +21,10 @@ from cinder.api.openstack import wsgi
from cinder.i18n import _
from cinder import objects
from cinder.objects import fields
from cinder.policies import snapshot_actions as policy
LOG = logging.getLogger(__name__)
def authorize(context, action_name):
action = 'snapshot_actions:%s' % action_name
extensions.extension_authorizer('snapshot', action)(context)
class SnapshotActionsController(wsgi.Controller):
def __init__(self, *args, **kwargs):
super(SnapshotActionsController, self).__init__(*args, **kwargs)
@ -45,7 +40,7 @@ class SnapshotActionsController(wsgi.Controller):
"""
context = req.environ['cinder.context']
authorize(context, 'update_snapshot_status')
context.authorize(policy.UPDATE_STATUS_POLICY)
LOG.debug("body: %s", body)
try:

View File

@ -22,13 +22,10 @@ from cinder.api.openstack import wsgi
from cinder.api.views import manageable_snapshots as list_manageable_view
from cinder.api.views import snapshots as snapshot_views
from cinder.i18n import _
from cinder.policies import manageable_snapshots as policy
from cinder import volume as cinder_volume
LOG = logging.getLogger(__name__)
authorize_manage = extensions.extension_authorizer('snapshot',
'snapshot_manage')
authorize_list_manageable = extensions.extension_authorizer('snapshot',
'list_manageable')
class SnapshotManageController(wsgi.Controller):
@ -86,7 +83,7 @@ class SnapshotManageController(wsgi.Controller):
"""
context = req.environ['cinder.context']
authorize_manage(context)
context.authorize(policy.MANAGE_POLICY)
if not self.is_valid_body(body, 'snapshot'):
msg = _("Missing required element snapshot in request body.")
@ -130,7 +127,7 @@ class SnapshotManageController(wsgi.Controller):
def index(self, req):
"""Returns a summary list of snapshots available to manage."""
context = req.environ['cinder.context']
authorize_list_manageable(context)
context.authorize(policy.LIST_MANAGEABLE_POLICY)
return resource_common_manage.get_manageable_resources(
req, False, self.volume_api.get_manageable_snapshots,
self._list_manageable_view)
@ -139,7 +136,7 @@ class SnapshotManageController(wsgi.Controller):
def detail(self, req):
"""Returns a detailed list of snapshots available to manage."""
context = req.environ['cinder.context']
authorize_list_manageable(context)
context.authorize(policy.LIST_MANAGEABLE_POLICY)
return resource_common_manage.get_manageable_resources(
req, True, self.volume_api.get_manageable_snapshots,
self._list_manageable_view)

View File

@ -20,10 +20,10 @@ from webob import exc
from cinder.api import extensions
from cinder.api.openstack import wsgi
from cinder import exception
from cinder.policies import manageable_snapshots as policy
from cinder import volume
LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('snapshot', 'snapshot_unmanage')
class SnapshotUnmanageController(wsgi.Controller):
@ -46,7 +46,7 @@ class SnapshotUnmanageController(wsgi.Controller):
A Not Found error is returned if the specified snapshot does not exist.
"""
context = req.environ['cinder.context']
authorize(context)
context.authorize(policy.UNMANAGE_POLICY)
LOG.info("Unmanage snapshot with id: %s", id)

View File

@ -18,7 +18,11 @@ import itertools
from cinder.policies import attachments
from cinder.policies import base
from cinder.policies import clusters
from cinder.policies import manageable_snapshots
from cinder.policies import messages
from cinder.policies import snapshot_actions
from cinder.policies import snapshot_metadata
from cinder.policies import snapshots
from cinder.policies import workers
@ -28,5 +32,9 @@ def list_rules():
attachments.list_rules(),
messages.list_rules(),
clusters.list_rules(),
workers.list_rules()
workers.list_rules(),
snapshot_metadata.list_rules(),
snapshots.list_rules(),
snapshot_actions.list_rules(),
manageable_snapshots.list_rules(),
)

View File

@ -0,0 +1,65 @@
# 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
MANAGE_POLICY = 'snapshot_extension:snapshot_manage'
UNMANAGE_POLICY = 'snapshot_extension:snapshot_unmanage'
LIST_MANAGEABLE_POLICY = 'snapshot_extension:list_manageable'
manageable_snapshots_policies = [
policy.DocumentedRuleDefault(
name=LIST_MANAGEABLE_POLICY,
check_str=base.RULE_ADMIN_API,
description=
"List (in detail) of snapshots which are available to manage.",
operations=[
{
'method': 'GET',
'path': '/manageable_snapshots'
},
{
'method': 'GET',
'path': '/manageable_snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=MANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Manage an existing snapshot.",
operations=[
{
'method': 'POST',
'path': '/manageable_snapshots'
}
]),
policy.DocumentedRuleDefault(
name=UNMANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Stop managing a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-unmanage)'
}
]),
]
def list_rules():
return manageable_snapshots_policies

View File

@ -0,0 +1,62 @@
# 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
RESET_STATUS_POLICY = 'volume_extension:snapshot_admin_actions:reset_status'
FORCE_DELETE_POLICY = 'volume_extension:snapshot_admin_actions:force_delete'
UPDATE_STATUS_POLICY = \
'snapshot_extension:snapshot_actions:update_snapshot_status'
snapshot_actions_policies = [
policy.DocumentedRuleDefault(
name=RESET_STATUS_POLICY,
check_str=base.RULE_ADMIN_API,
description="Reset status of a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-reset_status)'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_STATUS_POLICY,
check_str="",
description="Update database fields of snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action '
'(update_snapshot_status)'
}
]),
policy.DocumentedRuleDefault(
name=FORCE_DELETE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Force delete a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-force_delete)'
}
])
]
def list_rules():
return snapshot_actions_policies

View File

@ -0,0 +1,72 @@
# 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_POLICY = 'volume:get_snapshot_metadata'
DELETE_POLICY = 'volume:delete_snapshot_metadata'
UPDATE_POLICY = 'volume:update_snapshot_metadata'
snapshot_metadata_policies = [
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show snapshot's metadata or one specified metadata "
"with a given key.",
operations=[
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}/metadata'
},
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update snapshot's metadata or one specified "
"metadata with a given key.",
operations=[
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}/metadata'
},
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete snapshot's specified metadata "
"with a given key.",
operations=[
{
'method': 'DELETE',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
]
def list_rules():
return snapshot_metadata_policies

View File

@ -0,0 +1,103 @@
# 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:snapshots:%s'
GET_POLICY = 'volume:get_snapshot'
GET_ALL_POLICY = 'volume:get_all_snapshots'
CREATE_POLICY = 'volume:create_snapshot'
DELETE_POLICY = 'volume:delete_snapshot'
UPDATE_POLICY = 'volume:update_snapshot'
EXTEND_ATTRIBUTE = 'volume_extension:extended_snapshot_attributes'
snapshots_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List snapshots.",
operations=[
{
'method': 'GET',
'path': '/snapshots'
},
{
'method': 'GET',
'path': '/snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=EXTEND_ATTRIBUTE,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List snapshots with extended attributes.",
operations=[
{
'method': 'GET',
'path': '/snapshots'
},
{
'method': 'GET',
'path': '/snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Create snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show snapshot.",
operations=[
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update snapshot.",
operations=[
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete snapshot.",
operations=[
{
'method': 'DELETE',
'path': '/snapshots/{snapshot_id}'
}
]),
]
def list_rules():
return snapshots_policies

View File

@ -44,11 +44,9 @@
"volume:thaw_host": "rule:admin_api",
"volume:revert_to_snapshot": "",
"volume_extension:volume_admin_actions:reset_status": "rule:admin_api",
"volume_extension:snapshot_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:snapshot_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",
"volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
@ -91,11 +89,6 @@
"limits_extension:used_limits": "",
"snapshot_extension:snapshot_actions:update_snapshot_status": "",
"snapshot_extension:snapshot_manage": "rule:admin_api",
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
"snapshot_extension:list_manageable": "rule:admin_api",
"volume:create_transfer": "",
"volume:accept_transfer": "",
"volume:delete_transfer": "",

View File

@ -44,6 +44,8 @@ from cinder import objects
from cinder.objects import base as objects_base
from cinder.objects import fields
from cinder.policies import attachments as attachment_policy
from cinder.policies import snapshot_metadata as s_meta_policy
from cinder.policies import snapshots as snapshot_policy
import cinder.policy
from cinder import quota
from cinder import quota_utils
@ -624,7 +626,7 @@ class API(base.Base):
return volumes
def get_snapshot(self, context, snapshot_id):
check_policy(context, 'get_snapshot')
context.authorize(snapshot_policy.GET_POLICY)
snapshot = objects.Snapshot.get_by_id(context, snapshot_id)
# FIXME(jdg): The objects don't have the db name entries
@ -643,7 +645,7 @@ class API(base.Base):
def get_all_snapshots(self, context, search_opts=None, marker=None,
limit=None, sort_keys=None, sort_dirs=None,
offset=None):
check_policy(context, 'get_all_snapshots')
context.authorize(snapshot_policy.GET_ALL_POLICY)
search_opts = search_opts or {}
@ -827,7 +829,7 @@ class API(base.Base):
cgsnapshot_id,
commit_quota=True,
group_snapshot_id=None):
check_policy(context, 'create_snapshot', volume)
context.authorize(snapshot_policy.CREATE_POLICY)
if not volume.host:
msg = _("The snapshot cannot be created because volume has "
@ -1031,9 +1033,10 @@ class API(base.Base):
resource=result)
return result
@wrap_check_policy
def delete_snapshot(self, context, snapshot, force=False,
unmanage_only=False):
context.authorize(snapshot_policy.DELETE_POLICY,
target_obj=snapshot)
if not unmanage_only:
snapshot.assert_not_frozen()
@ -1061,8 +1064,9 @@ class API(base.Base):
LOG.info("Snapshot delete request issued successfully.",
resource=snapshot)
@wrap_check_policy
def update_snapshot(self, context, snapshot, fields):
context.authorize(snapshot_policy.UPDATE_POLICY,
target_obj=snapshot)
snapshot.update(fields)
snapshot.save()
@ -1153,21 +1157,22 @@ class API(base.Base):
resource=volume)
return db_meta
@wrap_check_policy
def get_snapshot_metadata(self, context, snapshot):
"""Get all metadata associated with a snapshot."""
context.authorize(s_meta_policy.GET_POLICY,
target_obj=snapshot)
LOG.info("Get snapshot metadata completed successfully.",
resource=snapshot)
return snapshot.metadata
@wrap_check_policy
def delete_snapshot_metadata(self, context, snapshot, key):
"""Delete the given metadata item from a snapshot."""
context.authorize(s_meta_policy.DELETE_POLICY,
target_obj=snapshot)
snapshot.delete_metadata_key(context, key)
LOG.info("Delete snapshot metadata completed successfully.",
resource=snapshot)
@wrap_check_policy
def update_snapshot_metadata(self, context,
snapshot, metadata,
delete=False):
@ -1177,6 +1182,8 @@ class API(base.Base):
`metadata` argument will be deleted.
"""
context.authorize(s_meta_policy.UPDATE_POLICY,
target_obj=snapshot)
if delete:
_metadata = metadata
else:

View File

@ -11,14 +11,6 @@
"volume:update_volume_metadata": "rule:admin_or_owner",
"volume:get_volume_admin_metadata": "rule:admin_api",
"volume:update_volume_admin_metadata": "rule:admin_api",
"volume:get_snapshot": "rule:admin_or_owner",
"volume:get_all_snapshots": "rule:admin_or_owner",
"volume:create_snapshot": "rule:admin_or_owner",
"volume:delete_snapshot": "rule:admin_or_owner",
"volume:update_snapshot": "rule:admin_or_owner",
"volume:get_snapshot_metadata": "rule:admin_or_owner",
"volume:delete_snapshot_metadata": "rule:admin_or_owner",
"volume:update_snapshot_metadata": "rule:admin_or_owner",
"volume:extend": "rule:admin_or_owner",
"volume:extend_attached_volume": "rule:admin_or_owner",
"volume:update_readonly_flag": "rule:admin_or_owner",
@ -39,7 +31,6 @@
"volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api",
"volume_extension:volume_type_encryption": "rule:admin_api",
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:extended_snapshot_attributes": "rule:admin_or_owner",
"volume_extension:volume_image_metadata": "rule:admin_or_owner",
"volume_extension:qos_specs_manage:create": "rule:admin_api",
@ -55,11 +46,9 @@
"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:snapshot_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:snapshot_admin_actions:force_delete": "rule:admin_api",
"volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
@ -100,11 +89,6 @@
"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",
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
"snapshot_extension:list_manageable": "rule:admin_api",
"consistencygroup:create" : "group:nobody",
"consistencygroup:delete": "group:nobody",
"consistencygroup:update": "group:nobody",