[policy in code] Add support for group, g-snapshot resources

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

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

Change-Id: If95a8aaa70614902a06420d1afa487827f8a3f03
Partial-Implements: blueprint policy-in-code
This commit is contained in:
TommyLike 2017-09-27 16:44:47 +08:00
parent 1462d9c2e4
commit d2c6dfb3d3
14 changed files with 447 additions and 185 deletions

View File

@ -23,7 +23,7 @@ from cinder.api.openstack import wsgi
from cinder import db
from cinder import exception
from cinder.i18n import _
from cinder import policy
from cinder.policies import group_types as policy
from cinder import rpc
from cinder import utils
from cinder.volume import group_types
@ -32,13 +32,6 @@ from cinder.volume import group_types
class GroupTypeSpecsController(wsgi.Controller):
"""The group type specs API controller for the OpenStack API."""
def _check_policy(self, context):
target = {
'project_id': context.project_id,
'user_id': context.user_id,
}
policy.enforce(context, 'group:group_types_specs', target)
def _get_group_specs(self, context, group_type_id):
group_specs = db.group_type_specs_get(context, group_type_id)
specs_dict = {}
@ -56,7 +49,7 @@ class GroupTypeSpecsController(wsgi.Controller):
def index(self, req, group_type_id):
"""Returns the list of group specs for a given group type."""
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.SPEC_POLICY)
self._check_type(context, group_type_id)
return self._get_group_specs(context, group_type_id)
@ -64,7 +57,7 @@ class GroupTypeSpecsController(wsgi.Controller):
@wsgi.response(http_client.ACCEPTED)
def create(self, req, group_type_id, body=None):
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.SPEC_POLICY)
self.assert_valid_body(body, 'group_specs')
self._check_type(context, group_type_id)
@ -84,7 +77,7 @@ class GroupTypeSpecsController(wsgi.Controller):
@wsgi.Controller.api_version(mv.GROUP_TYPE)
def update(self, req, group_type_id, id, body=None):
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.SPEC_POLICY)
if not body:
expl = _('Request body empty')
@ -113,7 +106,7 @@ class GroupTypeSpecsController(wsgi.Controller):
def show(self, req, group_type_id, id):
"""Return a single extra spec item."""
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.SPEC_POLICY)
self._check_type(context, group_type_id)
specs = self._get_group_specs(context, group_type_id)
@ -128,7 +121,7 @@ class GroupTypeSpecsController(wsgi.Controller):
def delete(self, req, group_type_id, id):
"""Deletes an existing group spec."""
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.SPEC_POLICY)
self._check_type(context, group_type_id)

View File

@ -26,7 +26,7 @@ from cinder.api.openstack import wsgi
from cinder.api.v3.views import group_types as views_types
from cinder import exception
from cinder.i18n import _
from cinder import policy
from cinder.policies import group_types as policy
from cinder import rpc
from cinder import utils
from cinder.volume import group_types
@ -37,13 +37,6 @@ class GroupTypesController(wsgi.Controller):
_view_builder_class = views_types.ViewBuilder
def _check_policy(self, context):
target = {
'project_id': context.project_id,
'user_id': context.user_id,
}
policy.enforce(context, 'group:group_types_manage', target)
@utils.if_notifications_enabled
def _notify_group_type_error(self, context, method, err,
group_type=None, id=None, name=None):
@ -61,7 +54,7 @@ class GroupTypesController(wsgi.Controller):
def create(self, req, body):
"""Creates a new group type."""
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.MANAGE_POLICY)
self.assert_valid_body(body, 'group_type')
@ -108,7 +101,7 @@ class GroupTypesController(wsgi.Controller):
def update(self, req, id, body):
# Update description for a given group type.
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.MANAGE_POLICY)
self.assert_valid_body(body, 'group_type')
@ -168,7 +161,7 @@ class GroupTypesController(wsgi.Controller):
def delete(self, req, id):
"""Deletes an existing group type."""
context = req.environ['cinder.context']
self._check_policy(context)
context.authorize(policy.MANAGE_POLICY)
try:
grp_type = group_types.get_group_type(context, id)

View File

@ -14,6 +14,7 @@
# under the License.
from cinder.api import common
from cinder.policies import group_types as policy
class ViewBuilder(common.ViewBuilder):
@ -25,9 +26,7 @@ class ViewBuilder(common.ViewBuilder):
name=group_type.get('name'),
description=group_type.get('description'),
is_public=group_type.get('is_public'))
if common.validate_policy(
context,
'group:access_group_types_specs'):
if context.authorize(policy.SHOW_ACCESS_POLICY, fatal=False):
trimmed['group_specs'] = group_type.get('group_specs')
return trimmed if brief else dict(group_type=trimmed)

View File

@ -18,8 +18,6 @@ Handles all requests relating to groups.
"""
import functools
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
@ -31,9 +29,11 @@ from cinder.db import base
from cinder import exception
from cinder.i18n import _
from cinder import objects
from cinder.objects import base as objects_base
from cinder.objects import fields as c_fields
import cinder.policy
from cinder.policies import group_actions as gp_action_policy
from cinder.policies import group_snapshot_actions as gsnap_action_policy
from cinder.policies import group_snapshots as gsnap_policy
from cinder.policies import groups as group_policy
from cinder import quota
from cinder import quota_utils
from cinder.scheduler import rpcapi as scheduler_rpcapi
@ -57,37 +57,6 @@ VALID_ADD_VOL_TO_GROUP_STATUS = (
'in-use')
def wrap_check_policy(func):
"""Check policy corresponding to the wrapped methods prior to execution.
This decorator requires the first 3 args of the wrapped function
to be (self, context, group)
"""
@functools.wraps(func)
def wrapped(self, context, target_obj, *args, **kwargs):
check_policy(context, func.__name__, target_obj)
return func(self, context, target_obj, *args, **kwargs)
return wrapped
def check_policy(context, action, target_obj=None):
target = {
'project_id': context.project_id,
'user_id': context.user_id,
}
if isinstance(target_obj, objects_base.CinderObject):
# Turn object into dict so target.update can work
target.update(
target_obj.obj_to_primitive()['versioned_object.data'] or {})
else:
target.update(target_obj or {})
_action = 'group:%s' % action
cinder.policy.enforce(context, _action, target)
class API(base.Base):
"""API for interacting with the volume manager for groups."""
@ -130,7 +99,7 @@ class API(base.Base):
def create(self, context, name, description, group_type,
volume_types, availability_zone=None):
check_policy(context, 'create')
context.authorize(group_policy.CREATE_POLICY)
req_volume_types = []
# NOTE: Admin context is required to get extra_specs of volume_types.
@ -196,7 +165,7 @@ class API(base.Base):
def create_from_src(self, context, name, description=None,
group_snapshot_id=None, source_group_id=None):
check_policy(context, 'create')
context.authorize(group_policy.CREATE_POLICY)
# Populate group_type_id and volume_type_ids
group_type_id = None
@ -514,9 +483,8 @@ class API(base.Base):
finally:
LOG.error("Failed to update quota for group %s.", group.id)
@wrap_check_policy
def delete(self, context, group, delete_volumes=False):
context.authorize(gp_action_policy.DELETE_POLICY, target_obj=group)
if not group.host:
self.update_quota(context, group, -1, group.project_id)
@ -602,10 +570,10 @@ class API(base.Base):
self.volume_rpcapi.delete_group(context, group)
@wrap_check_policy
def update(self, context, group, name, description,
add_volumes, remove_volumes):
"""Update group."""
context.authorize(group_policy.UPDATE_POLICY, target_obj=group)
# Validate name.
if name == group.name:
name = None
@ -806,12 +774,12 @@ class API(base.Base):
def get(self, context, group_id):
group = objects.Group.get_by_id(context, group_id)
check_policy(context, 'get', group)
context.authorize(group_policy.GET_POLICY, target_obj=group)
return group
def get_all(self, context, filters=None, marker=None, limit=None,
offset=None, sort_keys=None, sort_dirs=None):
check_policy(context, 'get_all')
context.authorize(group_policy.GET_ALL_POLICY)
if filters is None:
filters = {}
@ -830,10 +798,9 @@ class API(base.Base):
sort_dirs=sort_dirs)
return groups
@wrap_check_policy
def reset_status(self, context, group, status):
"""Reset status of generic group"""
context.authorize(gp_action_policy.RESET_STATUS, target_obj=group)
if status not in c_fields.GroupStatus.ALL:
msg = _("Group status: %(status)s is invalid, valid status "
"are: %(valid)s.") % {'status': status,
@ -844,8 +811,8 @@ class API(base.Base):
group.update(field)
group.save()
@wrap_check_policy
def create_group_snapshot(self, context, group, name, description):
context.authorize(gsnap_policy.CREATE_POLICY, target_obj=group)
group.assert_not_frozen()
options = {'group_id': group.id,
'user_id': context.user_id,
@ -884,7 +851,7 @@ class API(base.Base):
return group_snapshot
def delete_group_snapshot(self, context, group_snapshot, force=False):
check_policy(context, 'delete_group_snapshot')
context.authorize(gsnap_policy.DELETE_POLICY)
group_snapshot.assert_not_frozen()
values = {'status': 'deleting'}
expected = {'status': ('available', 'error')}
@ -911,12 +878,12 @@ class API(base.Base):
group_snapshot)
def update_group_snapshot(self, context, group_snapshot, fields):
check_policy(context, 'update_group_snapshot')
context.authorize(gsnap_policy.UPDATE_POLICY)
group_snapshot.update(fields)
group_snapshot.save()
def get_group_snapshot(self, context, group_snapshot_id):
check_policy(context, 'get_group_snapshot')
context.authorize(gsnap_policy.GET_POLICY)
group_snapshots = objects.GroupSnapshot.get_by_id(context,
group_snapshot_id)
return group_snapshots
@ -924,7 +891,7 @@ class API(base.Base):
def get_all_group_snapshots(self, context, filters=None, marker=None,
limit=None, offset=None, sort_keys=None,
sort_dirs=None):
check_policy(context, 'get_all_group_snapshots')
context.authorize(gsnap_policy.GET_ALL_POLICY)
filters = filters or {}
if context.is_admin and 'all_tenants' in filters:
@ -943,7 +910,7 @@ class API(base.Base):
def reset_group_snapshot_status(self, context, gsnapshot, status):
"""Reset status of group snapshot"""
check_policy(context, 'reset_group_snapshot_status')
context.authorize(gsnap_action_policy.RESET_STATUS)
if status not in c_fields.GroupSnapshotStatus.ALL:
msg = _("Group snapshot status: %(status)s is invalid, "
"valid statuses are: "
@ -969,8 +936,8 @@ class API(base.Base):
raise exception.InvalidVolumeType(reason=msg)
# Replication group API (Tiramisu)
@wrap_check_policy
def enable_replication(self, context, group):
context.authorize(gp_action_policy.ENABLE_REP, target_obj=group)
self._check_type(group)
valid_status = [c_fields.GroupStatus.AVAILABLE]
@ -1030,8 +997,8 @@ class API(base.Base):
self.volume_rpcapi.enable_replication(context, group)
@wrap_check_policy
def disable_replication(self, context, group):
context.authorize(gp_action_policy.DISABLE_REP, target_obj=group)
self._check_type(group)
valid_status = [c_fields.GroupStatus.AVAILABLE,
@ -1080,10 +1047,10 @@ class API(base.Base):
self.volume_rpcapi.disable_replication(context, group)
@wrap_check_policy
def failover_replication(self, context, group,
allow_attached_volume=False,
secondary_backend_id=None):
context.authorize(gp_action_policy.FAILOVER_REP, target_obj=group)
self._check_type(group)
valid_status = [c_fields.GroupStatus.AVAILABLE]
@ -1148,8 +1115,8 @@ class API(base.Base):
allow_attached_volume,
secondary_backend_id)
@wrap_check_policy
def list_replication_targets(self, context, group):
context.authorize(gp_action_policy.LIST_REP, target_obj=group)
self._check_type(group)
return self.volume_rpcapi.list_replication_targets(context, group)

View File

@ -20,6 +20,11 @@ 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 group_actions
from cinder.policies import group_snapshot_actions
from cinder.policies import group_snapshots
from cinder.policies import group_types
from cinder.policies import groups
from cinder.policies import manageable_snapshots
from cinder.policies import messages
from cinder.policies import snapshot_actions
@ -41,4 +46,9 @@ def list_rules():
manageable_snapshots.list_rules(),
backups.list_rules(),
backup_actions.list_rules(),
groups.list_rules(),
group_types.list_rules(),
group_snapshots.list_rules(),
group_snapshot_actions.list_rules(),
group_actions.list_rules(),
)

View File

@ -0,0 +1,93 @@
# 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 = 'group:reset_status'
ENABLE_REP = 'group:enable_replication'
DISABLE_REP = 'group:disable_replication'
FAILOVER_REP = 'group:failover_replication'
LIST_REP = 'group:list_replication_targets'
DELETE_POLICY = 'group:delete'
group_actions_policies = [
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete group.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (delete)'
}
]),
policy.DocumentedRuleDefault(
name=RESET_STATUS,
check_str=base.RULE_ADMIN_API,
description="Reset status of group.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (reset_status)'
}
]),
policy.DocumentedRuleDefault(
name=ENABLE_REP,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Enable replication.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (enable_replication)'
}
]),
policy.DocumentedRuleDefault(
name=DISABLE_REP,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Disable replication.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (disable_replication)'
}
]),
policy.DocumentedRuleDefault(
name=FAILOVER_REP,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Fail over replication.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (failover_replication)'
}
]),
policy.DocumentedRuleDefault(
name=LIST_REP,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List failover replication.",
operations=[
{
'method': 'POST',
'path': '/groups/{group_id}/action (list_replication_targets)'
}
]),
]
def list_rules():
return group_actions_policies

View File

@ -0,0 +1,40 @@
# 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 = 'group:reset_group_snapshot_status'
group_snapshot_actions_policies = [
policy.DocumentedRuleDefault(
name=RESET_STATUS,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Reset status of group snapshot.",
operations=[
{
'method': 'POST',
'path':
'/group_snapshots/{g_snapshot_id}/action (reset_status)'
}
]),
]
def list_rules():
return group_snapshot_actions_policies

View File

@ -0,0 +1,87 @@
# 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
CREATE_POLICY = 'group:create_group_snapshot'
DELETE_POLICY = 'group:delete_group_snapshot'
UPDATE_POLICY = 'group:update_group_snapshot'
GET_POLICY = 'group:get_group_snapshot'
GET_ALL_POLICY = 'group:get_all_group_snapshots'
group_snapshots_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List group snapshots.",
operations=[
{
'method': 'GET',
'path': '/group_snapshots'
},
{
'method': 'GET',
'path': '/group_snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str="",
description="Create group snapshot.",
operations=[
{
'method': 'POST',
'path': '/group_snapshots'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show group snapshot.",
operations=[
{
'method': 'GET',
'path': '/group_snapshots/{group_snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete group snapshot.",
operations=[
{
'method': 'DELETE',
'path': '/group_snapshots/{group_snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update group snapshot.",
operations=[
{
'method': 'PUT',
'path': '/group_snapshots/{group_snapshot_id}'
}
]),
]
def list_rules():
return group_snapshots_policies

View File

@ -0,0 +1,86 @@
# 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 = 'group:group_types_manage'
SHOW_ACCESS_POLICY = 'group:access_group_types_specs'
SPEC_POLICY = 'group:group_types_specs'
group_types_policies = [
policy.DocumentedRuleDefault(
name=MANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Create, update or delete a group type.",
operations=[
{
'method': 'POST',
'path': '/group_types/'
},
{
'method': 'PUT',
'path': '/group_types/{group_type_id}'
},
{
'method': 'DELETE',
'path': '/group_types/{group_type_id}'
}
]),
policy.DocumentedRuleDefault(
name=SHOW_ACCESS_POLICY,
check_str=base.RULE_ADMIN_API,
description="Show group type with type specs attributes.",
operations=[
{
'method': 'GET',
'path': '/group_types/{group_type_id}'
}
]),
policy.DocumentedRuleDefault(
name=SPEC_POLICY,
check_str=base.RULE_ADMIN_API,
description="Create, show, update and delete group type spec.",
operations=[
{
'method': 'GET',
'path': '/group_types/{group_type_id}/group_specs/{g_spec_id}'
},
{
'method': 'GET',
'path': '/group_types/{group_type_id}/group_specs'
},
{
'method': 'POST',
'path': '/group_types/{group_type_id}/group_specs'
},
{
'method': 'PUT',
'path': '/group_types/{group_type_id}/group_specs/{g_spec_id}'
},
{
'method': 'DELETE',
'path': '/group_types/{group_type_id}/group_specs/{g_spec_id}'
}
]),
]
def list_rules():
return group_types_policies

75
cinder/policies/groups.py Normal file
View File

@ -0,0 +1,75 @@
# 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
CREATE_POLICY = 'group:create'
UPDATE_POLICY = 'group:update'
GET_POLICY = 'group:get'
GET_ALL_POLICY = 'group:get_all'
groups_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List groups.",
operations=[
{
'method': 'GET',
'path': '/groups'
},
{
'method': 'GET',
'path': '/groups/detail'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str="",
description="Create group.",
operations=[
{
'method': 'POST',
'path': '/groups'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show group.",
operations=[
{
'method': 'GET',
'path': '/groups/{group_id}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update group.",
operations=[
{
'method': 'PUT',
'path': '/groups/{group_id}'
}
]),
]
def list_rules():
return groups_policies

View File

@ -22,7 +22,6 @@ from oslo_utils import timeutils
import six
import webob
import cinder.api.common as common
from cinder.api import microversions as mv
from cinder.api.v3 import group_specs as v3_group_specs
from cinder.api.v3 import group_types as v3_group_types
@ -462,8 +461,8 @@ class GroupTypesApiTest(test.TestCase):
self.assertDictEqual(expected_group_type, output['group_type'])
def __test_view_builder_show_qos_specs_id_policy(self):
with mock.patch.object(common,
'validate_policy',
with mock.patch.object(context.RequestContext,
'authorize',
side_effect=[False, True]):
view_builder = views_types.ViewBuilder()
now = timeutils.utcnow().isoformat()
@ -492,8 +491,8 @@ class GroupTypesApiTest(test.TestCase):
self.assertDictEqual(expected_group_type, output['group_type'])
def test_view_builder_show_group_specs_policy(self):
with mock.patch.object(common,
'validate_policy',
with mock.patch.object(context.RequestContext,
'authorize',
side_effect=[True, False]):
view_builder = views_types.ViewBuilder()
now = timeutils.utcnow().isoformat()
@ -524,9 +523,9 @@ class GroupTypesApiTest(test.TestCase):
self.assertDictEqual(expected_group_type, output['group_type'])
def test_view_builder_show_pass_all_policy(self):
with mock.patch.object(common,
'validate_policy',
side_effect=[True, True]):
with mock.patch.object(context.RequestContext,
'authorize',
side_effect=[True, False]):
view_builder = views_types.ViewBuilder()
now = timeutils.utcnow().isoformat()
raw_group_type = dict(
@ -625,16 +624,3 @@ class GroupTypesApiTest(test.TestCase):
)
self.assertDictEqual(expected_group_type,
output['group_types'][i])
def test_check_policy(self):
self.controller._check_policy(self.ctxt)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller._check_policy,
self.user_ctxt)
self.specs_controller._check_policy(self.ctxt)
self.assertRaises(exception.PolicyNotAuthorized,
self.specs_controller._check_policy,
self.user_ctxt)

View File

@ -49,19 +49,16 @@ class GroupAPITestCase(test.TestCase):
fake.USER_ID, fake.PROJECT_ID, auth_token=True)
@mock.patch('cinder.objects.Group.get_by_id')
@mock.patch('cinder.group.api.check_policy')
def test_get(self, mock_policy, mock_group_get):
fake_group = 'fake_group'
def test_get(self, mock_group_get):
fake_group = {'name': 'fake_group'}
mock_group_get.return_value = fake_group
grp = self.group_api.get(self.ctxt, fake.GROUP_ID)
self.assertEqual(fake_group, grp)
mock_policy.assert_called_once_with(self.ctxt, 'get', mock.ANY)
@ddt.data(True, False)
@mock.patch('cinder.objects.GroupList.get_all')
@mock.patch('cinder.objects.GroupList.get_all_by_project')
@mock.patch('cinder.group.api.check_policy')
def test_get_all(self, is_admin, mock_policy, mock_get_all_by_project,
def test_get_all(self, is_admin, mock_get_all_by_project,
mock_get_all):
self.group_api.LOG = mock.Mock()
fake_groups = ['fake_group1', 'fake_group2']
@ -73,11 +70,9 @@ class GroupAPITestCase(test.TestCase):
grps = self.group_api.get_all(self.ctxt,
filters={'all_tenants': True})
self.assertEqual(fake_groups, grps)
mock_policy.assert_called_once_with(self.ctxt, 'get_all')
else:
grps = self.group_api.get_all(self.user_ctxt)
self.assertEqual(fake_groups_by_project, grps)
mock_policy.assert_called_once_with(self.user_ctxt, 'get_all')
@mock.patch('cinder.volume.rpcapi.VolumeAPI.delete_group')
@mock.patch('cinder.db.volume_get_all_by_generic_group')
@ -87,8 +82,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.db.group_type_get')
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
@mock.patch('cinder.group.api.check_policy')
def test_create_delete(self, mock_policy, mock_volume_types_get,
def test_create_delete(self, mock_volume_types_get,
mock_group_type_get, mock_group,
mock_update_quota, mock_cast_create_group,
mock_volumes_update, mock_volume_get_all,
@ -108,7 +102,6 @@ class GroupAPITestCase(test.TestCase):
fake.GROUP_TYPE_ID,
[fake.VOLUME_TYPE_ID],
availability_zone='nova')
mock_policy.assert_called_with(self.ctxt, 'create')
self.assertEqual(grp.obj_to_primitive(), ret_group.obj_to_primitive())
ret_group.host = "test_host@fakedrv#fakepool"
@ -119,15 +112,13 @@ class GroupAPITestCase(test.TestCase):
mock_volume_get_all.assert_called_once_with(mock.ANY, ret_group.id)
mock_volumes_update.assert_called_once_with(self.ctxt, [])
mock_rpc_delete_group.assert_called_once_with(self.ctxt, ret_group)
mock_policy.assert_called_with(self.ctxt, 'delete', mock.ANY)
@mock.patch('cinder.group.api.API._cast_create_group')
@mock.patch('cinder.group.api.API.update_quota')
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.db.group_type_get_by_name')
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
@mock.patch('cinder.group.api.check_policy')
def test_create_with_group_name(self, mock_policy, mock_volume_types_get,
def test_create_with_group_name(self, mock_volume_types_get,
mock_group_type_get, mock_group,
mock_update_quota, mock_cast_create_group):
mock_volume_types_get.return_value = [{'id': fake.VOLUME_TYPE_ID}]
@ -149,14 +140,12 @@ class GroupAPITestCase(test.TestCase):
mock_group_type_get.assert_called_once_with(self.ctxt,
"fake-grouptype-name")
mock_policy.assert_called_with(self.ctxt, 'create')
@mock.patch('cinder.group.api.API._cast_create_group')
@mock.patch('cinder.group.api.API.update_quota')
@mock.patch('cinder.db.group_type_get_by_name')
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
@mock.patch('cinder.group.api.check_policy')
def test_create_with_multi_types(self, mock_policy, mock_volume_types_get,
def test_create_with_multi_types(self, mock_volume_types_get,
mock_group_type_get,
mock_update_quota,
mock_cast_create_group):
@ -180,12 +169,10 @@ class GroupAPITestCase(test.TestCase):
"fake-grouptype-name")
mock_volume_types_get.assert_called_once_with(mock.ANY,
volume_type_names)
mock_policy.assert_called_with(self.ctxt, 'create')
@mock.patch('oslo_utils.timeutils.utcnow')
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.group.api.check_policy')
def test_reset_status(self, mock_policy, mock_group, mock_time_util):
def test_reset_status(self, mock_group, mock_time_util):
mock_time_util.return_value = "time_now"
self.group_api.reset_status(self.ctxt, mock_group,
fields.GroupStatus.AVAILABLE)
@ -194,15 +181,12 @@ class GroupAPITestCase(test.TestCase):
'status': fields.GroupStatus.AVAILABLE}
mock_group.update.assert_called_once_with(update_field)
mock_group.save.assert_called_once_with()
mock_policy.assert_called_once_with(self.ctxt,
'reset_status', mock.ANY)
@mock.patch.object(GROUP_QUOTAS, "reserve")
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.db.group_type_get_by_name')
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
@mock.patch('cinder.group.api.check_policy')
def test_create_group_failed_update_quota(self, mock_policy,
def test_create_group_failed_update_quota(self,
mock_volume_types_get,
mock_group_type_get, mock_group,
mock_group_quota_reserve):
@ -230,7 +214,6 @@ class GroupAPITestCase(test.TestCase):
"fake-grouptype-name",
[fake.VOLUME_TYPE_ID],
availability_zone='nova')
mock_policy.assert_called_with(self.ctxt, 'create')
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.db.volume_get')
@ -254,8 +237,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.db.group_type_get')
@mock.patch('cinder.db.volume_types_get_by_name_or_id')
@mock.patch('cinder.group.api.check_policy')
def test_update(self, mock_policy, mock_volume_types_get,
def test_update(self, mock_volume_types_get,
mock_group_type_get, mock_group,
mock_update_quota, mock_cast_create_group,
mock_volume_get_all, mock_rpc_update_group):
@ -313,23 +295,19 @@ class GroupAPITestCase(test.TestCase):
mock_rpc_update_group.assert_called_once_with(self.ctxt, ret_group,
add_volumes=vol1.id,
remove_volumes=vol2.id)
mock_policy.assert_called_with(self.ctxt, 'update', mock.ANY)
@mock.patch('cinder.objects.GroupSnapshot.get_by_id')
@mock.patch('cinder.group.api.check_policy')
def test_get_group_snapshot(self, mock_policy, mock_group_snap):
def test_get_group_snapshot(self, mock_group_snap):
fake_group_snap = 'fake_group_snap'
mock_group_snap.return_value = fake_group_snap
grp_snap = self.group_api.get_group_snapshot(
self.ctxt, fake.GROUP_SNAPSHOT_ID)
self.assertEqual(fake_group_snap, grp_snap)
mock_policy.assert_called_with(self.ctxt, 'get_group_snapshot')
@ddt.data(True, False)
@mock.patch('cinder.objects.GroupSnapshotList.get_all')
@mock.patch('cinder.objects.GroupSnapshotList.get_all_by_project')
@mock.patch('cinder.group.api.check_policy')
def test_get_all_group_snapshots(self, is_admin, mock_policy,
def test_get_all_group_snapshots(self, is_admin,
mock_get_all_by_project,
mock_get_all):
fake_group_snaps = ['fake_group_snap1', 'fake_group_snap2']
@ -341,25 +319,19 @@ class GroupAPITestCase(test.TestCase):
grp_snaps = self.group_api.get_all_group_snapshots(
self.ctxt, filters={'all_tenants': True})
self.assertEqual(fake_group_snaps, grp_snaps)
mock_policy.assert_called_with(self.ctxt,
'get_all_group_snapshots')
else:
grp_snaps = self.group_api.get_all_group_snapshots(
self.user_ctxt)
self.assertEqual(fake_group_snaps_by_project, grp_snaps)
mock_policy.assert_called_with(self.user_ctxt,
'get_all_group_snapshots')
@mock.patch('cinder.objects.GroupSnapshot')
@mock.patch('cinder.group.api.check_policy')
def test_update_group_snapshot(self, mock_policy, mock_group_snap):
def test_update_group_snapshot(self, mock_group_snap):
grp_snap_update = {"name": "new_name",
"description": "This is a new description"}
self.group_api.update_group_snapshot(self.ctxt, mock_group_snap,
grp_snap_update)
mock_group_snap.update.assert_called_once_with(grp_snap_update)
mock_group_snap.save.assert_called_once_with()
mock_policy.assert_called_with(self.ctxt, 'update_group_snapshot')
@mock.patch('cinder.volume.rpcapi.VolumeAPI.delete_group_snapshot')
@mock.patch('cinder.volume.rpcapi.VolumeAPI.create_group_snapshot')
@ -367,8 +339,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('cinder.objects.Group')
@mock.patch('cinder.objects.GroupSnapshot')
@mock.patch('cinder.objects.SnapshotList.get_all_for_group_snapshot')
@mock.patch('cinder.group.api.check_policy')
def test_create_delete_group_snapshot(self, mock_policy,
def test_create_delete_group_snapshot(self,
mock_snap_get_all,
mock_group_snap, mock_group,
mock_create_in_db,
@ -399,12 +370,9 @@ class GroupAPITestCase(test.TestCase):
ret_group_snap.id)
mock_create_api.assert_called_once_with(self.ctxt, ret_group_snap)
mock_policy.assert_called_once_with(self.ctxt, 'create_group_snapshot',
mock.ANY)
ret_group_snap.assert_not_frozen = mock.Mock(return_value=True)
self.group_api.delete_group_snapshot(self.ctxt, ret_group_snap)
mock_delete_api.assert_called_once_with(mock.ANY, ret_group_snap)
mock_policy.assert_called_with(self.ctxt, 'delete_group_snapshot')
@mock.patch('cinder.objects.VolumeType.get_by_name_or_id')
@mock.patch('cinder.db.group_volume_type_mapping_create')
@ -484,8 +452,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('cinder.objects.Group.get_by_id')
@mock.patch('cinder.volume.rpcapi.VolumeAPI.create_group_from_src')
@mock.patch('cinder.objects.VolumeList.get_all_by_generic_group')
@mock.patch('cinder.group.api.check_policy')
def test_create_group_from_group(self, mock_policy, mock_volume_get_all,
def test_create_group_from_group(self, mock_volume_get_all,
mock_rpc_create_group_from_src,
mock_group_get,
mock_volume_api_create,
@ -548,8 +515,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('cinder.group.api.API.update_quota')
@mock.patch('cinder.objects.GroupSnapshot.get_by_id')
@mock.patch('cinder.objects.SnapshotList.get_all_for_group_snapshot')
@mock.patch('cinder.group.api.check_policy')
def test_create_from_src(self, mock_policy, mock_snap_get_all,
def test_create_from_src(self, mock_snap_get_all,
mock_group_snap_get, mock_update_quota,
mock_create_from_group,
mock_create_from_snap):
@ -606,8 +572,7 @@ class GroupAPITestCase(test.TestCase):
@mock.patch('oslo_utils.timeutils.utcnow')
@mock.patch('cinder.objects.GroupSnapshot')
@mock.patch('cinder.group.api.check_policy')
def test_reset_group_snapshot_status(self, mock_policy,
def test_reset_group_snapshot_status(self,
mock_group_snapshot,
mock_time_util):
mock_time_util.return_value = "time_now"
@ -618,8 +583,6 @@ class GroupAPITestCase(test.TestCase):
'status': fields.GroupSnapshotStatus.ERROR}
mock_group_snapshot.update.assert_called_once_with(update_field)
mock_group_snapshot.save.assert_called_once_with()
mock_policy.assert_called_once_with(self.ctxt,
'reset_group_snapshot_status')
def test_create_group_from_src_frozen(self):
service = utils.create_service(self.ctxt, {'frozen': True})

View File

@ -109,18 +109,12 @@
"consistencygroup:get_cgsnapshot": "",
"consistencygroup:get_all_cgsnapshots": "",
"group:group_types_manage": "rule:admin_api",
"group:group_types_specs": "rule:admin_api",
"group:access_group_types_specs": "rule:admin_api",
"group:group_type_access": "rule:admin_or_owner",
"group:create" : "",
"group:delete": "",
"group:update": "",
"group:get": "",
"group:get_all": "",
"group:create_group_snapshot": "",
"group:delete_group_snapshot": "",
"group:update_group_snapshot": "",
"group:get_group_snapshot": "",

View File

@ -89,30 +89,6 @@
"consistencygroup:get_cgsnapshot": "group:nobody",
"consistencygroup:get_all_cgsnapshots": "group:nobody",
"group:group_types_manage": "rule:admin_api",
"group:group_types_specs": "rule:admin_api",
"group:access_group_types_specs": "rule:admin_api",
"group:group_type_access": "rule:admin_or_owner",
"group:create" : "",
"group:delete": "rule:admin_or_owner",
"group:update": "rule:admin_or_owner",
"group:get": "rule:admin_or_owner",
"group:get_all": "rule:admin_or_owner",
"group:create_group_snapshot": "",
"group:delete_group_snapshot": "rule:admin_or_owner",
"group:update_group_snapshot": "rule:admin_or_owner",
"group:get_group_snapshot": "rule:admin_or_owner",
"group:get_all_group_snapshots": "rule:admin_or_owner",
"group:reset_group_snapshot_status":"rule:admin_api",
"group:reset_status":"rule:admin_api",
"group:enable_replication": "rule:admin_or_owner",
"group:disable_replication": "rule:admin_or_owner",
"group:failover_replication": "rule:admin_or_owner",
"group:list_replication_targets": "rule:admin_or_owner",
"scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api",
}