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 import extensions
|
||||||
from cinder.api.openstack import wsgi
|
from cinder.api.openstack import wsgi
|
||||||
from cinder.api.views import consistencygroups as consistencygroup_views
|
from cinder.api.views import consistencygroups as consistencygroup_views
|
||||||
from cinder.consistencygroup import api as consistencygroup_api
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder import group as group_api
|
from cinder import group as group_api
|
||||||
from cinder.i18n import _
|
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
|
from cinder.volume import group_types
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -73,7 +74,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
group = self._get(context, id)
|
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)
|
self.group_api.delete(context, group, force)
|
||||||
# Not found exception will be handled at the wsgi level
|
# Not found exception will be handled at the wsgi level
|
||||||
except exception.InvalidConsistencyGroup as error:
|
except exception.InvalidConsistencyGroup as error:
|
||||||
@ -106,6 +107,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
def _get_consistencygroups(self, req, is_detail):
|
def _get_consistencygroups(self, req, is_detail):
|
||||||
"""Returns a list of consistency groups through view builder."""
|
"""Returns a list of consistency groups through view builder."""
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
context.authorize(group_policy.GET_ALL_POLICY)
|
||||||
filters = req.params.copy()
|
filters = req.params.copy()
|
||||||
|
|
||||||
# make another copy of filters, since it is being modified in
|
# 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')
|
self.assert_valid_body(body, 'consistencygroup')
|
||||||
|
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
context.authorize(group_policy.CREATE_POLICY)
|
||||||
consistencygroup = body['consistencygroup']
|
consistencygroup = body['consistencygroup']
|
||||||
self.validate_name_and_description(consistencygroup)
|
self.validate_name_and_description(consistencygroup)
|
||||||
name = consistencygroup.get('name', None)
|
name = consistencygroup.get('name', None)
|
||||||
@ -153,7 +156,6 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
{'name': name})
|
{'name': name})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
consistencygroup_api.check_policy(context, 'create')
|
|
||||||
new_consistencygroup = self.group_api.create(
|
new_consistencygroup = self.group_api.create(
|
||||||
context, name, description, group_type['id'], volume_types,
|
context, name, description, group_type['id'], volume_types,
|
||||||
availability_zone=availability_zone)
|
availability_zone=availability_zone)
|
||||||
@ -181,6 +183,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
self.assert_valid_body(body, 'consistencygroup-from-src')
|
self.assert_valid_body(body, 'consistencygroup-from-src')
|
||||||
|
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
context.authorize(group_policy.CREATE_POLICY)
|
||||||
consistencygroup = body['consistencygroup-from-src']
|
consistencygroup = body['consistencygroup-from-src']
|
||||||
self.validate_name_and_description(consistencygroup)
|
self.validate_name_and_description(consistencygroup)
|
||||||
name = consistencygroup.get('name', None)
|
name = consistencygroup.get('name', None)
|
||||||
@ -213,7 +216,6 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
self._get(context, source_cgid)
|
self._get(context, source_cgid)
|
||||||
if cgsnapshot_id:
|
if cgsnapshot_id:
|
||||||
self._get_cgsnapshot(context, cgsnapshot_id)
|
self._get_cgsnapshot(context, cgsnapshot_id)
|
||||||
consistencygroup_api.check_policy(context, 'create')
|
|
||||||
new_group = self.group_api.create_from_src(
|
new_group = self.group_api.create_from_src(
|
||||||
context, name, description, cgsnapshot_id, source_cgid)
|
context, name, description, cgsnapshot_id, source_cgid)
|
||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
@ -232,19 +234,18 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
"can not be all empty in the request body.")
|
"can not be all empty in the request body.")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
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,
|
remove_volumes,
|
||||||
allow_empty=False):
|
allow_empty=False):
|
||||||
LOG.info("Updating consistency group %(id)s with name %(name)s "
|
LOG.info("Updating consistency group %(id)s with name %(name)s "
|
||||||
"description: %(description)s add_volumes: "
|
"description: %(description)s add_volumes: "
|
||||||
"%(add_volumes)s remove_volumes: %(remove_volumes)s.",
|
"%(add_volumes)s remove_volumes: %(remove_volumes)s.",
|
||||||
{'id': id,
|
{'id': group.id,
|
||||||
'name': name,
|
'name': name,
|
||||||
'description': description,
|
'description': description,
|
||||||
'add_volumes': add_volumes,
|
'add_volumes': add_volumes,
|
||||||
'remove_volumes': remove_volumes})
|
'remove_volumes': remove_volumes})
|
||||||
|
|
||||||
group = self._get(context, id)
|
|
||||||
self.group_api.update(context, group, name, description,
|
self.group_api.update(context, group, name, description,
|
||||||
add_volumes, remove_volumes)
|
add_volumes, remove_volumes)
|
||||||
|
|
||||||
@ -273,6 +274,8 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
|
|
||||||
self.assert_valid_body(body, 'consistencygroup')
|
self.assert_valid_body(body, 'consistencygroup')
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
group = self._get(context, id)
|
||||||
|
context.authorize(group_policy.UPDATE_POLICY, target_obj=group)
|
||||||
consistencygroup = body.get('consistencygroup', None)
|
consistencygroup = body.get('consistencygroup', None)
|
||||||
self.validate_name_and_description(consistencygroup)
|
self.validate_name_and_description(consistencygroup)
|
||||||
name = consistencygroup.get('name', None)
|
name = consistencygroup.get('name', None)
|
||||||
@ -282,7 +285,7 @@ class ConsistencyGroupsController(wsgi.Controller):
|
|||||||
|
|
||||||
self._check_update_parameters(name, description, add_volumes,
|
self._check_update_parameters(name, description, add_volumes,
|
||||||
remove_volumes)
|
remove_volumes)
|
||||||
self._update(context, id, name, description, add_volumes,
|
self._update(context, group, name, description, add_volumes,
|
||||||
remove_volumes)
|
remove_volumes)
|
||||||
return webob.Response(status_int=http_client.ACCEPTED)
|
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 import microversions as mv
|
||||||
from cinder.api.openstack import wsgi
|
from cinder.api.openstack import wsgi
|
||||||
from cinder.i18n import _
|
from cinder.i18n import _
|
||||||
|
from cinder.policies import groups as group_policy
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -72,6 +73,8 @@ class ConsistencyGroupsController(cg_v2.ConsistencyGroupsController):
|
|||||||
|
|
||||||
self.assert_valid_body(body, 'consistencygroup')
|
self.assert_valid_body(body, 'consistencygroup')
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
group = self._get(context, id)
|
||||||
|
context.authorize(group_policy.UPDATE_POLICY, target_obj=group)
|
||||||
consistencygroup = body.get('consistencygroup', None)
|
consistencygroup = body.get('consistencygroup', None)
|
||||||
self.validate_name_and_description(consistencygroup)
|
self.validate_name_and_description(consistencygroup)
|
||||||
name = consistencygroup.get('name', None)
|
name = consistencygroup.get('name', None)
|
||||||
@ -83,7 +86,7 @@ class ConsistencyGroupsController(cg_v2.ConsistencyGroupsController):
|
|||||||
description,
|
description,
|
||||||
add_volumes,
|
add_volumes,
|
||||||
remove_volumes)
|
remove_volumes)
|
||||||
self._update(context, id, name, description, add_volumes,
|
self._update(context, group, name, description, add_volumes,
|
||||||
remove_volumes, allow_empty)
|
remove_volumes, allow_empty)
|
||||||
return webob.Response(status_int=http_client.ACCEPTED)
|
return webob.Response(status_int=http_client.ACCEPTED)
|
||||||
|
|
||||||
|
@ -40,25 +40,17 @@ def reset():
|
|||||||
_ENFORCER = None
|
_ENFORCER = None
|
||||||
|
|
||||||
|
|
||||||
def init(policy_file=None, rules=None, default_rule=None, use_conf=True):
|
def init(use_conf=True):
|
||||||
"""Init an Enforcer class.
|
"""Init an Enforcer class.
|
||||||
|
|
||||||
:param policy_file: Custom policy file to use, if none is specified,
|
:param use_conf: Whether to load rules from config file.
|
||||||
`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.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
global _ENFORCER
|
global _ENFORCER
|
||||||
if not _ENFORCER:
|
if not _ENFORCER:
|
||||||
_ENFORCER = policy.Enforcer(CONF,
|
_ENFORCER = policy.Enforcer(
|
||||||
policy_file=policy_file,
|
CONF,
|
||||||
rules=rules,
|
use_conf=use_conf)
|
||||||
default_rule=default_rule,
|
|
||||||
use_conf=use_conf)
|
|
||||||
register_rules(_ENFORCER)
|
register_rules(_ENFORCER)
|
||||||
_ENFORCER.load_rules()
|
_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):
|
def enforce(context, action, target):
|
||||||
"""Verifies that the action is valid on the target in this context.
|
"""Verifies that the action is valid on the target in this context.
|
||||||
|
|
||||||
:param context: cinder context
|
:param context: cinder context
|
||||||
:param action: string representing the action to be checked
|
:param action: string representing the action to be checked
|
||||||
this should be colon separated for clarity.
|
this should be colon separated for clarity.
|
||||||
i.e. ``compute:create_instance``,
|
i.e. ``compute:create_instance``,
|
||||||
``compute:attach_volume``,
|
``compute:attach_volume``,
|
||||||
``volume:attach_volume``
|
``volume:attach_volume``
|
||||||
|
|
||||||
:param object: dictionary representing the object of the action
|
:param target: dictionary representing the object of the action for object
|
||||||
for object creation this should be a dictionary representing the
|
creation this should be a dictionary representing the
|
||||||
location of the object e.g. ``{'project_id': context.project_id}``
|
location of the object e.g.
|
||||||
|
``{'project_id': context.project_id}``
|
||||||
:raises PolicyNotAuthorized: if verification fails.
|
|
||||||
|
|
||||||
|
:raises PolicyNotAuthorized: if verification fails.
|
||||||
"""
|
"""
|
||||||
init()
|
init()
|
||||||
|
|
||||||
@ -93,10 +85,10 @@ def enforce(context, action, target):
|
|||||||
def set_rules(rules, overwrite=True, use_conf=False):
|
def set_rules(rules, overwrite=True, use_conf=False):
|
||||||
"""Set rules based on the provided dict of rules.
|
"""Set rules based on the provided dict of rules.
|
||||||
|
|
||||||
:param rules: New rules to use. It should be an instance of dict.
|
:param rules: New rules to use. It should be an instance of dict.
|
||||||
:param overwrite: Whether to overwrite current rules or update them
|
:param overwrite: Whether to overwrite current rules or update them
|
||||||
with the new rules.
|
with the new rules.
|
||||||
:param use_conf: Whether to reload rules from config file.
|
:param use_conf: Whether to reload rules from config file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
init(use_conf=False)
|
init(use_conf=False)
|
||||||
@ -135,30 +127,31 @@ def get_enforcer():
|
|||||||
def authorize(context, action, target, do_raise=True, exc=None):
|
def authorize(context, action, target, do_raise=True, exc=None):
|
||||||
"""Verifies that the action is valid on the target in this context.
|
"""Verifies that the action is valid on the target in this context.
|
||||||
|
|
||||||
:param context: cinder context
|
:param context: cinder context
|
||||||
:param action: string representing the action to be checked
|
:param action: string representing the action to be checked
|
||||||
this should be colon separated for clarity.
|
this should be colon separated for clarity.
|
||||||
i.e. ``compute:create_instance``,
|
i.e. ``compute:create_instance``,
|
||||||
``compute:attach_volume``,
|
``compute:attach_volume``,
|
||||||
``volume:attach_volume``
|
``volume:attach_volume``
|
||||||
:param target: dictionary representing the object of the action
|
:param target: dictionary representing the object of the action for object
|
||||||
for object creation this should be a dictionary representing the
|
creation this should be a dictionary representing the
|
||||||
location of the object e.g. ``{'project_id': context.project_id}``
|
location of the object e.g.
|
||||||
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
``{'project_id': context.project_id}``
|
||||||
if False, returns False
|
:param do_raise: if True (the default), raises PolicyNotAuthorized;
|
||||||
:param exc: Class of the exception to raise if the check fails.
|
if False, returns False
|
||||||
Any remaining arguments passed to :meth:`authorize` (both
|
:param exc: Class of the exception to raise if the check fails.
|
||||||
positional and keyword arguments) will be passed to
|
Any remaining arguments passed to :meth:`authorize` (both
|
||||||
the exception class. If not specified,
|
positional and keyword arguments) will be passed to
|
||||||
:class:`PolicyNotAuthorized` will be used.
|
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
|
and do_raise is True. Or if 'exc' is specified it will raise an
|
||||||
exception of that type.
|
exception of that type.
|
||||||
|
|
||||||
:return: returns a non-False value (not necessarily "True") if
|
:return: returns a non-False value (not necessarily "True") if
|
||||||
authorized, and the exact value False if not authorized and
|
authorized, and the exact value False if not authorized and
|
||||||
do_raise is False.
|
do_raise is False.
|
||||||
"""
|
"""
|
||||||
init()
|
init()
|
||||||
credentials = context.to_policy_values()
|
credentials = context.to_policy_values()
|
||||||
@ -179,9 +172,7 @@ def authorize(context, action, target, do_raise=True, exc=None):
|
|||||||
|
|
||||||
|
|
||||||
def check_is_admin(context):
|
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()
|
init()
|
||||||
# the target is user-self
|
# the target is user-self
|
||||||
credentials = context.to_policy_values()
|
credentials = context.to_policy_values()
|
||||||
|
@ -28,7 +28,6 @@ import uuid
|
|||||||
import fixtures
|
import fixtures
|
||||||
import mock
|
import mock
|
||||||
from oslo_concurrency import lockutils
|
from oslo_concurrency import lockutils
|
||||||
from oslo_config import cfg
|
|
||||||
from oslo_config import fixture as config_fixture
|
from oslo_config import fixture as config_fixture
|
||||||
from oslo_log.fixture import logging_error as log_fixture
|
from oslo_log.fixture import logging_error as log_fixture
|
||||||
import oslo_messaging
|
import oslo_messaging
|
||||||
@ -39,7 +38,7 @@ from oslo_utils import timeutils
|
|||||||
import six
|
import six
|
||||||
import testtools
|
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 context
|
||||||
from cinder import coordination
|
from cinder import coordination
|
||||||
from cinder.db import migration
|
from cinder.db import migration
|
||||||
@ -54,7 +53,7 @@ from cinder.tests.unit import fake_notifier
|
|||||||
from cinder.volume import utils
|
from cinder.volume import utils
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
_DB_CACHE = None
|
_DB_CACHE = None
|
||||||
SESSION_CONFIGURED = False
|
SESSION_CONFIGURED = False
|
||||||
|
@ -61,18 +61,6 @@
|
|||||||
"backup:get_all": "",
|
"backup:get_all": "",
|
||||||
"backup:restore": "",
|
"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:delete": "",
|
||||||
"group:update": "",
|
"group:update": "",
|
||||||
"group:get": "",
|
"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.
|
@ -24,7 +24,6 @@ setup-hooks =
|
|||||||
data_files =
|
data_files =
|
||||||
etc/cinder =
|
etc/cinder =
|
||||||
etc/cinder/api-paste.ini
|
etc/cinder/api-paste.ini
|
||||||
etc/cinder/policy.json
|
|
||||||
etc/cinder/rootwrap.conf
|
etc/cinder/rootwrap.conf
|
||||||
etc/cinder/rootwrap.d = etc/cinder/rootwrap.d/*
|
etc/cinder/rootwrap.d = etc/cinder/rootwrap.d/*
|
||||||
packages =
|
packages =
|
||||||
|
Loading…
Reference in New Issue
Block a user