From c52b7ef5846995facd6a54c81283ed0f35fd36f3 Mon Sep 17 00:00:00 2001 From: TommyLike Date: Wed, 27 Sep 2017 14:56:06 +0800 Subject: [PATCH] [policy in code] Add support for message, worker, cluster resources This patch adds policy in code support for message, worker and cluster resources and depends on the basic patch [1]. [1]: https://review.openstack.org/#/c/506976/ Change-Id: I04c0b79175c69d25ca6fcb50ec604123f3f09933 Partial-Implements: blueprint policy-in-code --- cinder/api/v3/clusters.py | 12 ++++--- cinder/api/v3/messages.py | 19 +++------- cinder/api/v3/workers.py | 6 ++-- cinder/policies/__init__.py | 8 ++++- cinder/policies/clusters.py | 65 +++++++++++++++++++++++++++++++++++ cinder/policies/messages.py | 61 ++++++++++++++++++++++++++++++++ cinder/policies/workers.py | 39 +++++++++++++++++++++ cinder/tests/unit/policy.json | 9 ----- etc/cinder/policy.json | 8 ----- 9 files changed, 186 insertions(+), 41 deletions(-) create mode 100644 cinder/policies/clusters.py create mode 100644 cinder/policies/messages.py create mode 100644 cinder/policies/workers.py diff --git a/cinder/api/v3/clusters.py b/cinder/api/v3/clusters.py index 53e43ac8104..9271e24a5c6 100644 --- a/cinder/api/v3/clusters.py +++ b/cinder/api/v3/clusters.py @@ -19,6 +19,7 @@ from cinder.api.v3.views import clusters as clusters_view from cinder import exception from cinder.i18n import _ from cinder import objects +from cinder.policies import clusters as policy from cinder import utils @@ -28,13 +29,12 @@ class ClusterController(wsgi.Controller): 'frozen', 'active_backend_id'} replication_fields = {'replication_status', 'frozen', 'active_backend_id'} - policy_checker = wsgi.Controller.get_policy_checker('clusters') - @wsgi.Controller.api_version(mv.CLUSTER_SUPPORT) def show(self, req, id, binary='cinder-volume'): """Return data for a given cluster name with optional binary.""" # Let the wsgi middleware convert NotAuthorized exceptions - context = self.policy_checker(req, 'get') + context = req.environ['cinder.context'] + context.authorize(policy.GET_POLICY) # Let the wsgi middleware convert NotFound exceptions cluster = objects.Cluster.get_by_id(context, None, binary=binary, name=id, services_summary=True) @@ -60,7 +60,8 @@ class ClusterController(wsgi.Controller): def _get_clusters(self, req, detail): # Let the wsgi middleware convert NotAuthorized exceptions - context = self.policy_checker(req, 'get_all') + context = req.environ['cinder.context'] + context.authorize(policy.GET_ALL_POLICY) replication_data = req.api_version_request.matches( mv.REPLICATION_CLUSTER) filters = dict(req.GET) @@ -93,7 +94,8 @@ class ClusterController(wsgi.Controller): # update endpoint API. # Let the wsgi middleware convert NotAuthorized exceptions - context = self.policy_checker(req, 'update') + context = req.environ['cinder.context'] + context.authorize(policy.UPDATE_POLICY) if id not in ('enable', 'disable'): raise exception.NotFound(message=_("Unknown action")) diff --git a/cinder/api/v3/messages.py b/cinder/api/v3/messages.py index c03e398b7f8..6d84f175f81 100644 --- a/cinder/api/v3/messages.py +++ b/cinder/api/v3/messages.py @@ -23,18 +23,7 @@ from cinder.api.v3.views import messages as messages_view from cinder.message import api as message_api from cinder.message import defined_messages from cinder.message import message_field -import cinder.policy - - -def check_policy(context, action, target_obj=None): - target = { - 'project_id': context.project_id, - 'user_id': context.user_id, - } - target.update(target_obj or {}) - - _action = 'message:%s' % action - cinder.policy.enforce(context, _action, target) +from cinder.policies import messages as policy class MessagesController(wsgi.Controller): @@ -68,7 +57,7 @@ class MessagesController(wsgi.Controller): # Not found exception will be handled at the wsgi level message = self.message_api.get(context, id) - check_policy(context, 'get', message) + context.authorize(policy.GET_POLICY) self._build_user_message(message) return self._view_builder.detail(req, message) @@ -80,7 +69,7 @@ class MessagesController(wsgi.Controller): # Not found exception will be handled at the wsgi level message = self.message_api.get(context, id) - check_policy(context, 'delete', message) + context.authorize(policy.DELETE_POLICY, target_obj=message) self.message_api.delete(context, message) return webob.Response(status_int=http_client.NO_CONTENT) @@ -90,7 +79,7 @@ class MessagesController(wsgi.Controller): """Returns a list of messages, transformed through view builder.""" context = req.environ['cinder.context'] api_version = req.api_version_request - check_policy(context, 'get_all') + context.authorize(policy.GET_ALL_POLICY) filters = None marker = None limit = None diff --git a/cinder/api/v3/workers.py b/cinder/api/v3/workers.py index fa0a8540d46..f3f5c3dfffe 100644 --- a/cinder/api/v3/workers.py +++ b/cinder/api/v3/workers.py @@ -24,6 +24,7 @@ from cinder import exception from cinder.i18n import _ from cinder import objects from cinder.objects import cleanable +from cinder.policies import workers as policy from cinder.scheduler import rpcapi as sch_rpc from cinder import utils @@ -33,8 +34,6 @@ class WorkerController(wsgi.Controller): 'is_up', 'disabled', 'resource_id', 'resource_type', 'until'} - policy_checker = wsgi.Controller.get_policy_checker('workers') - def __init__(self, *args, **kwargs): self.sch_api = sch_rpc.SchedulerAPI() @@ -104,7 +103,8 @@ class WorkerController(wsgi.Controller): def cleanup(self, req, body=None): """Do the cleanup on resources from a specific service/host/node.""" # Let the wsgi middleware convert NotAuthorized exceptions - ctxt = self.policy_checker(req, 'cleanup') + ctxt = req.environ['cinder.context'] + ctxt.authorize(policy.CLEAN_POLICY) body = body or {} params = self._prepare_params(ctxt, body, self.allowed_clean_keys) diff --git a/cinder/policies/__init__.py b/cinder/policies/__init__.py index ebb7430e334..ce99ec7a3ba 100644 --- a/cinder/policies/__init__.py +++ b/cinder/policies/__init__.py @@ -17,10 +17,16 @@ import itertools from cinder.policies import attachments from cinder.policies import base +from cinder.policies import clusters +from cinder.policies import messages +from cinder.policies import workers def list_rules(): return itertools.chain( base.list_rules(), - attachments.list_rules() + attachments.list_rules(), + messages.list_rules(), + clusters.list_rules(), + workers.list_rules() ) diff --git a/cinder/policies/clusters.py b/cinder/policies/clusters.py new file mode 100644 index 00000000000..f8913bbf4fc --- /dev/null +++ b/cinder/policies/clusters.py @@ -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 + + +GET_POLICY = 'clusters:get' +GET_ALL_POLICY = 'clusters:get_all' +UPDATE_POLICY = 'clusters:update' + + +clusters_policies = [ + policy.DocumentedRuleDefault( + name=GET_ALL_POLICY, + check_str=base.RULE_ADMIN_API, + description="""List clusters.""", + operations=[ + { + 'method': 'GET', + 'path': '/clusters' + }, + { + 'method': 'GET', + 'path': '/clusters/detail' + } + ]), + policy.DocumentedRuleDefault( + name=GET_POLICY, + check_str=base.RULE_ADMIN_API, + description="""Show cluster.""", + operations=[ + { + 'method': 'GET', + 'path': '/clusters/{cluster_id}' + } + ]), + policy.DocumentedRuleDefault( + name=UPDATE_POLICY, + check_str=base.RULE_ADMIN_API, + description="""Update cluster.""", + operations=[ + { + 'method': 'PUT', + 'path': '/clusters/{cluster_id}' + } + ]), +] + + +def list_rules(): + return clusters_policies diff --git a/cinder/policies/messages.py b/cinder/policies/messages.py new file mode 100644 index 00000000000..e9b975ca7b8 --- /dev/null +++ b/cinder/policies/messages.py @@ -0,0 +1,61 @@ +# 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 + + +DELETE_POLICY = 'message:delete' +GET_POLICY = 'message:get' +GET_ALL_POLICY = 'message:get_all' + + +messages_policies = [ + policy.DocumentedRuleDefault( + name=GET_ALL_POLICY, + check_str=base.RULE_ADMIN_OR_OWNER, + description="""List messages.""", + operations=[ + { + 'method': 'GET', + 'path': '/messages' + } + ]), + policy.DocumentedRuleDefault( + name=GET_POLICY, + check_str=base.RULE_ADMIN_OR_OWNER, + description="""Show message.""", + operations=[ + { + 'method': 'GET', + 'path': '/messages/{message_id}' + } + ]), + policy.DocumentedRuleDefault( + name=DELETE_POLICY, + check_str=base.RULE_ADMIN_OR_OWNER, + description="""Delete message.""", + operations=[ + { + 'method': 'DELETE', + 'path': '/messages/{message_id}' + } + ]), +] + + +def list_rules(): + return messages_policies diff --git a/cinder/policies/workers.py b/cinder/policies/workers.py new file mode 100644 index 00000000000..1f4e676bc29 --- /dev/null +++ b/cinder/policies/workers.py @@ -0,0 +1,39 @@ +# 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 + + +CLEAN_POLICY = 'workers:cleanup' + + +workers_policies = [ + policy.DocumentedRuleDefault( + name=CLEAN_POLICY, + check_str=base.RULE_ADMIN_API, + description="""Clean up workers.""", + operations=[ + { + 'method': 'POST', + 'path': '/workers/cleanup' + } + ]) +] + + +def list_rules(): + return workers_policies diff --git a/cinder/tests/unit/policy.json b/cinder/tests/unit/policy.json index fcb158c64ce..8645e21d961 100644 --- a/cinder/tests/unit/policy.json +++ b/cinder/tests/unit/policy.json @@ -149,13 +149,4 @@ "scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api", - "message:delete": "rule:admin_or_owner", - "message:get": "rule:admin_or_owner", - "message:get_all": "rule:admin_or_owner", - - "clusters:get": "rule:admin_api", - "clusters:get_all": "rule:admin_api", - "clusters:update": "rule:admin_api", - - "workers:cleanup": "rule:admin_api" } diff --git a/etc/cinder/policy.json b/etc/cinder/policy.json index 69cc46906b0..a6c8b0c4357 100644 --- a/etc/cinder/policy.json +++ b/etc/cinder/policy.json @@ -141,13 +141,5 @@ "group:list_replication_targets": "rule:admin_or_owner", "scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api", - "message:delete": "rule:admin_or_owner", - "message:get": "rule:admin_or_owner", - "message:get_all": "rule:admin_or_owner", - "clusters:get": "rule:admin_api", - "clusters:get_all": "rule:admin_api", - "clusters:update": "rule:admin_api", - - "workers:cleanup": "rule:admin_api" }