Add cg policies and clean up old policy handling
This completes the "policy-in-code" work for Cinder by removing the old policy.json handling. It also adds new in-code checks to the legacy consistency group code for completeness. Change-Id: I810b6cb6bba2d95cc5bb477d6e2968ac1734c96b Depends-on: I364e401227fe43e2bacf8a799e10286ee445f835 Implements: bp policy-in-code
This commit is contained in:
parent
af06ceb2c5
commit
9fe72de4b6
@ -25,10 +25,11 @@ from cinder.api import common
|
||||
from cinder.api import extensions
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder.api.views import consistencygroups as consistencygroup_views
|
||||
from cinder.consistencygroup import api as consistencygroup_api
|
||||
from cinder import exception
|
||||
from cinder import group as group_api
|
||||
from cinder.i18n import _
|
||||
from cinder.policies import group_actions as gp_action_policy
|
||||
from cinder.policies import groups as group_policy
|
||||
from cinder.volume import group_types
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -73,7 +74,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
|
||||
try:
|
||||
group = self._get(context, id)
|
||||
consistencygroup_api.check_policy(context, 'delete')
|
||||
context.authorize(gp_action_policy.DELETE_POLICY, target_obj=group)
|
||||
self.group_api.delete(context, group, force)
|
||||
# Not found exception will be handled at the wsgi level
|
||||
except exception.InvalidConsistencyGroup as error:
|
||||
@ -106,6 +107,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
def _get_consistencygroups(self, req, is_detail):
|
||||
"""Returns a list of consistency groups through view builder."""
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(group_policy.GET_ALL_POLICY)
|
||||
filters = req.params.copy()
|
||||
|
||||
# make another copy of filters, since it is being modified in
|
||||
@ -131,6 +133,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
self.assert_valid_body(body, 'consistencygroup')
|
||||
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(group_policy.CREATE_POLICY)
|
||||
consistencygroup = body['consistencygroup']
|
||||
self.validate_name_and_description(consistencygroup)
|
||||
name = consistencygroup.get('name', None)
|
||||
@ -153,7 +156,6 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
{'name': name})
|
||||
|
||||
try:
|
||||
consistencygroup_api.check_policy(context, 'create')
|
||||
new_consistencygroup = self.group_api.create(
|
||||
context, name, description, group_type['id'], volume_types,
|
||||
availability_zone=availability_zone)
|
||||
@ -181,6 +183,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
self.assert_valid_body(body, 'consistencygroup-from-src')
|
||||
|
||||
context = req.environ['cinder.context']
|
||||
context.authorize(group_policy.CREATE_POLICY)
|
||||
consistencygroup = body['consistencygroup-from-src']
|
||||
self.validate_name_and_description(consistencygroup)
|
||||
name = consistencygroup.get('name', None)
|
||||
@ -213,7 +216,6 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
self._get(context, source_cgid)
|
||||
if cgsnapshot_id:
|
||||
self._get_cgsnapshot(context, cgsnapshot_id)
|
||||
consistencygroup_api.check_policy(context, 'create')
|
||||
new_group = self.group_api.create_from_src(
|
||||
context, name, description, cgsnapshot_id, source_cgid)
|
||||
except exception.NotFound:
|
||||
@ -232,19 +234,18 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
"can not be all empty in the request body.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def _update(self, context, id, name, description, add_volumes,
|
||||
def _update(self, context, group, name, description, add_volumes,
|
||||
remove_volumes,
|
||||
allow_empty=False):
|
||||
LOG.info("Updating consistency group %(id)s with name %(name)s "
|
||||
"description: %(description)s add_volumes: "
|
||||
"%(add_volumes)s remove_volumes: %(remove_volumes)s.",
|
||||
{'id': id,
|
||||
{'id': group.id,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'add_volumes': add_volumes,
|
||||
'remove_volumes': remove_volumes})
|
||||
|
||||
group = self._get(context, id)
|
||||
self.group_api.update(context, group, name, description,
|
||||
add_volumes, remove_volumes)
|
||||
|
||||
@ -273,6 +274,8 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
|
||||
self.assert_valid_body(body, 'consistencygroup')
|
||||
context = req.environ['cinder.context']
|
||||
group = self._get(context, id)
|
||||
context.authorize(group_policy.UPDATE_POLICY, target_obj=group)
|
||||
consistencygroup = body.get('consistencygroup', None)
|
||||
self.validate_name_and_description(consistencygroup)
|
||||
name = consistencygroup.get('name', None)
|
||||
@ -282,7 +285,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
||||
|
||||
self._check_update_parameters(name, description, add_volumes,
|
||||
remove_volumes)
|
||||
self._update(context, id, name, description, add_volumes,
|
||||
self._update(context, group, name, description, add_volumes,
|
||||
remove_volumes)
|
||||
return webob.Response(status_int=http_client.ACCEPTED)
|
||||
|
||||
|
@ -22,6 +22,7 @@ from cinder.api.contrib import consistencygroups as cg_v2
|
||||
from cinder.api import microversions as mv
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder.i18n import _
|
||||
from cinder.policies import groups as group_policy
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -72,6 +73,8 @@ class ConsistencyGroupsController(cg_v2.ConsistencyGroupsController):
|
||||
|
||||
self.assert_valid_body(body, 'consistencygroup')
|
||||
context = req.environ['cinder.context']
|
||||
group = self._get(context, id)
|
||||
context.authorize(group_policy.UPDATE_POLICY, target_obj=group)
|
||||
consistencygroup = body.get('consistencygroup', None)
|
||||
self.validate_name_and_description(consistencygroup)
|
||||
name = consistencygroup.get('name', None)
|
||||
@ -83,7 +86,7 @@ class ConsistencyGroupsController(cg_v2.ConsistencyGroupsController):
|
||||
description,
|
||||
add_volumes,
|
||||
remove_volumes)
|
||||
self._update(context, id, name, description, add_volumes,
|
||||
self._update(context, group, name, description, add_volumes,
|
||||
remove_volumes, allow_empty)
|
||||
return webob.Response(status_int=http_client.ACCEPTED)
|
||||
|
||||
|
@ -40,25 +40,17 @@ def reset():
|
||||
_ENFORCER = None
|
||||
|
||||
|
||||
def init(policy_file=None, rules=None, default_rule=None, use_conf=True):
|
||||
def init(use_conf=True):
|
||||
"""Init an Enforcer class.
|
||||
|
||||
:param policy_file: Custom policy file to use, if none is specified,
|
||||
`CONF.policy_file` will be used.
|
||||
:param rules: Default dictionary / Rules to use. It will be
|
||||
considered just in the first instantiation.
|
||||
:param default_rule: Default rule to use, CONF.default_rule will
|
||||
be used if none is specified.
|
||||
:param use_conf: Whether to load rules from config file.
|
||||
:param use_conf: Whether to load rules from config file.
|
||||
"""
|
||||
|
||||
global _ENFORCER
|
||||
if not _ENFORCER:
|
||||
_ENFORCER = policy.Enforcer(CONF,
|
||||
policy_file=policy_file,
|
||||
rules=rules,
|
||||
default_rule=default_rule,
|
||||
use_conf=use_conf)
|
||||
_ENFORCER = policy.Enforcer(
|
||||
CONF,
|
||||
use_conf=use_conf)
|
||||
register_rules(_ENFORCER)
|
||||
_ENFORCER.load_rules()
|
||||
|
||||
@ -66,19 +58,19 @@ def init(policy_file=None, rules=None, default_rule=None, use_conf=True):
|
||||
def enforce(context, action, target):
|
||||
"""Verifies that the action is valid on the target in this context.
|
||||
|
||||
:param context: cinder context
|
||||
:param action: string representing the action to be checked
|
||||
this should be colon separated for clarity.
|
||||
i.e. ``compute:create_instance``,
|
||||
``compute:attach_volume``,
|
||||
``volume:attach_volume``
|
||||
:param context: cinder context
|
||||
:param action: string representing the action to be checked
|
||||
this should be colon separated for clarity.
|
||||
i.e. ``compute:create_instance``,
|
||||
``compute:attach_volume``,
|
||||
``volume:attach_volume``
|
||||
|
||||
:param object: dictionary representing the object of the action
|
||||
for object creation this should be a dictionary representing the
|
||||
location of the object e.g. ``{'project_id': context.project_id}``
|
||||
|
||||
:raises PolicyNotAuthorized: if verification fails.
|
||||
:param target: dictionary representing the object of the action for object
|
||||
creation this should be a dictionary representing the
|
||||
location of the object e.g.
|
||||
``{'project_id': context.project_id}``
|
||||
|
||||
:raises PolicyNotAuthorized: if verification fails.
|
||||
"""
|
||||
init()
|
||||
|
||||
@ -93,10 +85,10 @@ def enforce(context, action, target):
|
||||
def set_rules(rules, overwrite=True, use_conf=False):
|
||||
"""Set rules based on the provided dict of rules.
|
||||
|
||||
:param rules: New rules to use. It should be an instance of dict.
|
||||
:param overwrite: Whether to overwrite current rules or update them
|
||||
with the new rules.
|
||||
:param use_conf: Whether to reload rules from config file.
|
||||
:param rules: New rules to use. It should be an instance of dict.
|
||||
:param overwrite: Whether to overwrite current rules or update them
|
||||
with the new rules.
|
||||
:param use_conf: Whether to reload rules from config file.
|
||||
"""
|
||||
|
||||
init(use_conf=False)
|
||||
@ -135,30 +127,31 @@ def get_enforcer():
|
||||
def authorize(context, action, target, do_raise=True, exc=None):
|
||||
"""Verifies that the action is valid on the target in this context.
|
||||
|
||||
:param context: cinder context
|
||||
:param action: string representing the action to be checked
|
||||
this should be colon separated for clarity.
|
||||
i.e. ``compute:create_instance``,
|
||||
``compute:attach_volume``,
|
||||
``volume:attach_volume``
|
||||
:param target: dictionary representing the object of the action
|
||||
for object creation this should be a dictionary representing the
|
||||
location of the object e.g. ``{'project_id': context.project_id}``
|
||||
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
||||
if False, returns False
|
||||
:param exc: Class of the exception to raise if the check fails.
|
||||
Any remaining arguments passed to :meth:`authorize` (both
|
||||
positional and keyword arguments) will be passed to
|
||||
the exception class. If not specified,
|
||||
:class:`PolicyNotAuthorized` will be used.
|
||||
:param context: cinder context
|
||||
:param action: string representing the action to be checked
|
||||
this should be colon separated for clarity.
|
||||
i.e. ``compute:create_instance``,
|
||||
``compute:attach_volume``,
|
||||
``volume:attach_volume``
|
||||
:param target: dictionary representing the object of the action for object
|
||||
creation this should be a dictionary representing the
|
||||
location of the object e.g.
|
||||
``{'project_id': context.project_id}``
|
||||
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
||||
if False, returns False
|
||||
:param exc: Class of the exception to raise if the check fails.
|
||||
Any remaining arguments passed to :meth:`authorize` (both
|
||||
positional and keyword arguments) will be passed to
|
||||
the exception class. If not specified,
|
||||
:class:`PolicyNotAuthorized` will be used.
|
||||
|
||||
:raises cinder.exception.PolicyNotAuthorized: if verification fails
|
||||
:raises cinder.exception.PolicyNotAuthorized: if verification fails
|
||||
and do_raise is True. Or if 'exc' is specified it will raise an
|
||||
exception of that type.
|
||||
|
||||
:return: returns a non-False value (not necessarily "True") if
|
||||
authorized, and the exact value False if not authorized and
|
||||
do_raise is False.
|
||||
:return: returns a non-False value (not necessarily "True") if
|
||||
authorized, and the exact value False if not authorized and
|
||||
do_raise is False.
|
||||
"""
|
||||
init()
|
||||
credentials = context.to_policy_values()
|
||||
@ -179,9 +172,7 @@ def authorize(context, action, target, do_raise=True, exc=None):
|
||||
|
||||
|
||||
def check_is_admin(context):
|
||||
"""Whether or not user is admin according to policy setting.
|
||||
|
||||
"""
|
||||
"""Whether or not user is admin according to policy setting."""
|
||||
init()
|
||||
# the target is user-self
|
||||
credentials = context.to_policy_values()
|
||||
|
@ -28,7 +28,6 @@ import uuid
|
||||
import fixtures
|
||||
import mock
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as config_fixture
|
||||
from oslo_log.fixture import logging_error as log_fixture
|
||||
import oslo_messaging
|
||||
@ -39,7 +38,7 @@ from oslo_utils import timeutils
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from cinder.common import config # noqa Need to register global_opts
|
||||
from cinder.common import config
|
||||
from cinder import context
|
||||
from cinder import coordination
|
||||
from cinder.db import migration
|
||||
@ -54,7 +53,7 @@ from cinder.tests.unit import fake_notifier
|
||||
from cinder.volume import utils
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF = config.CONF
|
||||
|
||||
_DB_CACHE = None
|
||||
SESSION_CONFIGURED = False
|
||||
|
@ -61,18 +61,6 @@
|
||||
"backup:get_all": "",
|
||||
"backup:restore": "",
|
||||
|
||||
"consistencygroup:create" : "",
|
||||
"consistencygroup:delete": "",
|
||||
"consistencygroup:update": "",
|
||||
"consistencygroup:get": "",
|
||||
"consistencygroup:get_all": "",
|
||||
|
||||
"consistencygroup:create_cgsnapshot" : "",
|
||||
"consistencygroup:delete_cgsnapshot": "",
|
||||
"consistencygroup:get_cgsnapshot": "",
|
||||
"consistencygroup:get_all_cgsnapshots": "",
|
||||
|
||||
|
||||
"group:delete": "",
|
||||
"group:update": "",
|
||||
"group:get": "",
|
||||
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
|
||||
"consistencygroup:create" : "group:nobody",
|
||||
"consistencygroup:delete": "group:nobody",
|
||||
"consistencygroup:update": "group:nobody",
|
||||
"consistencygroup:get": "group:nobody",
|
||||
"consistencygroup:get_all": "group:nobody",
|
||||
|
||||
"consistencygroup:create_cgsnapshot" : "group:nobody",
|
||||
"consistencygroup:delete_cgsnapshot": "group:nobody",
|
||||
"consistencygroup:get_cgsnapshot": "group:nobody",
|
||||
"consistencygroup:get_all_cgsnapshots": "group:nobody"
|
||||
|
||||
}
|
11
releasenotes/notes/policy-in-code-226f71562ab28195.yaml
Normal file
11
releasenotes/notes/policy-in-code-226f71562ab28195.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Cinder now support policy in code, which means if users don't need to
|
||||
modify any of the default policy rules, they do not need a policy file.
|
||||
Users can modify/generate a `policy.yaml` file which will override specific
|
||||
policy rules from their defaults.
|
||||
other:
|
||||
- |
|
||||
Default `policy.json` file is now removed as Cinder now uses default
|
||||
policies. A policy file is only needed if overriding one of the defaults.
|
Loading…
Reference in New Issue
Block a user