[policy in code] Add support for qos and quota resources

This patch adds policy in code support for qos, quota,
quota class resources and depends on the group&group
snapshot patch.

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

Change-Id: Idf27d5fd09365374330ad0d4c0448f68f3cc03e8
Partial-Implements: blueprint policy-in-code
This commit is contained in:
TommyLike 2017-09-28 16:40:27 +08:00
parent d2c6dfb3d3
commit 5a099de01a
9 changed files with 253 additions and 55 deletions

View File

@ -26,6 +26,7 @@ from cinder.api.openstack import wsgi
from cinder.api.views import qos_specs as view_qos_specs
from cinder import exception
from cinder.i18n import _
from cinder.policies import qos_specs as policy
from cinder import rpc
from cinder import utils
from cinder.volume import qos_specs
@ -33,17 +34,6 @@ from cinder.volume import qos_specs
LOG = logging.getLogger(__name__)
authorize_create = extensions.extension_authorizer('volume',
'qos_specs_manage:create')
authorize_get = extensions.extension_authorizer('volume',
'qos_specs_manage:get')
authorize_get_all = extensions.extension_authorizer('volume',
'qos_specs_manage:get_all')
authorize_update = extensions.extension_authorizer('volume',
'qos_specs_manage:update')
authorize_delete = extensions.extension_authorizer('volume',
'qos_specs_manage:delete')
def _check_specs(context, specs_id):
# Not found exception will be handled at the wsgi level
@ -65,7 +55,7 @@ class QoSSpecsController(wsgi.Controller):
def index(self, req):
"""Returns the list of qos_specs."""
context = req.environ['cinder.context']
authorize_get_all(context)
context.authorize(policy.GET_ALL_POLICY)
params = req.params.copy()
@ -84,7 +74,7 @@ class QoSSpecsController(wsgi.Controller):
def create(self, req, body=None):
context = req.environ['cinder.context']
authorize_create(context)
context.authorize(policy.CREATE_POLICY)
self.assert_valid_body(body, 'qos_specs')
@ -128,7 +118,7 @@ class QoSSpecsController(wsgi.Controller):
def update(self, req, id, body=None):
context = req.environ['cinder.context']
authorize_update(context)
context.authorize(policy.UPDATE_POLICY)
self.assert_valid_body(body, 'qos_specs')
specs = body['qos_specs']
@ -158,7 +148,7 @@ class QoSSpecsController(wsgi.Controller):
def show(self, req, id):
"""Return a single qos spec item."""
context = req.environ['cinder.context']
authorize_get(context)
context.authorize(policy.GET_POLICY)
# Not found exception will be handled at the wsgi level
spec = qos_specs.get_qos_specs(context, id)
@ -168,7 +158,7 @@ class QoSSpecsController(wsgi.Controller):
def delete(self, req, id):
"""Deletes an existing qos specs."""
context = req.environ['cinder.context']
authorize_delete(context)
context.authorize(policy.DELETE_POLICY)
# Convert string to bool type in strict manner
force = utils.get_bool_param('force', req.params)
@ -204,7 +194,7 @@ class QoSSpecsController(wsgi.Controller):
def delete_keys(self, req, id, body):
"""Deletes specified keys in qos specs."""
context = req.environ['cinder.context']
authorize_delete(context)
context.authorize(policy.DELETE_POLICY)
if not (body and 'keys' in body
and isinstance(body.get('keys'), list)):
@ -232,7 +222,7 @@ class QoSSpecsController(wsgi.Controller):
def associations(self, req, id):
"""List all associations of given qos specs."""
context = req.environ['cinder.context']
authorize_get_all(context)
context.authorize(policy.GET_ALL_POLICY)
LOG.debug("Get associations for qos_spec id: %s", id)
@ -262,7 +252,7 @@ class QoSSpecsController(wsgi.Controller):
def associate(self, req, id):
"""Associate a qos specs with a volume type."""
context = req.environ['cinder.context']
authorize_update(context)
context.authorize(policy.UPDATE_POLICY)
type_id = req.params.get('vol_type_id', None)
@ -311,7 +301,7 @@ class QoSSpecsController(wsgi.Controller):
def disassociate(self, req, id):
"""Disassociate a qos specs from a volume type."""
context = req.environ['cinder.context']
authorize_update(context)
context.authorize(policy.UPDATE_POLICY)
type_id = req.params.get('vol_type_id', None)
@ -351,7 +341,7 @@ class QoSSpecsController(wsgi.Controller):
def disassociate_all(self, req, id):
"""Disassociate a qos specs from all volume types."""
context = req.environ['cinder.context']
authorize_update(context)
context.authorize(policy.UPDATE_POLICY)
LOG.debug("Disassociate qos_spec: %s from all.", id)

View File

@ -19,6 +19,7 @@ from cinder.api import extensions
from cinder.api.openstack import wsgi
from cinder import db
from cinder import exception
from cinder.policies import quota_class as policy
from cinder import quota
from cinder import utils
@ -27,9 +28,6 @@ QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
authorize = extensions.extension_authorizer('volume', 'quota_classes')
class QuotaClassSetsController(wsgi.Controller):
def _format_quota_set(self, quota_class, quota_set):
@ -41,7 +39,7 @@ class QuotaClassSetsController(wsgi.Controller):
def show(self, req, id):
context = req.environ['cinder.context']
authorize(context)
context.authorize(policy.MANAGE_POLICY)
try:
db.sqlalchemy.api.authorize_quota_class_context(context, id)
except exception.NotAuthorized:
@ -54,7 +52,7 @@ class QuotaClassSetsController(wsgi.Controller):
def update(self, req, id, body):
context = req.environ['cinder.context']
authorize(context)
context.authorize(policy.MANAGE_POLICY)
self.validate_string_length(id, 'quota_class_name',
min_length=1, max_length=255)

View File

@ -24,6 +24,7 @@ from cinder import db
from cinder.db.sqlalchemy import api as sqlalchemy_api
from cinder import exception
from cinder.i18n import _
from cinder.policies import quotas as policy
from cinder import quota
from cinder import quota_utils
from cinder import utils
@ -34,10 +35,6 @@ QUOTAS = quota.QUOTAS
GROUP_QUOTAS = quota.GROUP_QUOTAS
NON_QUOTA_KEYS = ['tenant_id', 'id']
authorize_update = extensions.extension_authorizer('volume', 'quotas:update')
authorize_show = extensions.extension_authorizer('volume', 'quotas:show')
authorize_delete = extensions.extension_authorizer('volume', 'quotas:delete')
class QuotaSetsController(wsgi.Controller):
@ -169,7 +166,7 @@ class QuotaSetsController(wsgi.Controller):
:param id: target project id that needs to be shown
"""
context = req.environ['cinder.context']
authorize_show(context)
context.authorize(policy.SHOW_POLICY)
params = req.params
target_project_id = id
@ -212,7 +209,7 @@ class QuotaSetsController(wsgi.Controller):
the resources if the update succeeds
"""
context = req.environ['cinder.context']
authorize_update(context)
context.authorize(policy.UPDATE_POLICY)
self.validate_string_length(id, 'quota_set_name',
min_length=1, max_length=255)
@ -354,7 +351,7 @@ class QuotaSetsController(wsgi.Controller):
def defaults(self, req, id):
context = req.environ['cinder.context']
authorize_show(context)
context.authorize(policy.SHOW_POLICY)
defaults = QUOTAS.get_defaults(context, project_id=id)
group_defaults = GROUP_QUOTAS.get_defaults(context, project_id=id)
defaults.update(group_defaults)
@ -371,7 +368,7 @@ class QuotaSetsController(wsgi.Controller):
:param id: target project id that needs to be deleted
"""
context = req.environ['cinder.context']
authorize_delete(context)
context.authorize(policy.DELETE_POLICY)
if QUOTAS.using_nested_quotas():
self._delete_nested_quota(context, id)
@ -440,6 +437,7 @@ class QuotaSetsController(wsgi.Controller):
no child quota would be larger than it's parent).
"""
ctxt = req.environ['cinder.context']
ctxt.authorize(policy.VALIDATE_NESTED_QUOTA_POLICY)
params = req.params
try:
resources = QUOTAS.resources

View File

@ -27,6 +27,9 @@ 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 qos_specs
from cinder.policies import quota_class
from cinder.policies import quotas
from cinder.policies import snapshot_actions
from cinder.policies import snapshot_metadata
from cinder.policies import snapshots
@ -51,4 +54,7 @@ def list_rules():
group_snapshots.list_rules(),
group_snapshot_actions.list_rules(),
group_actions.list_rules(),
qos_specs.list_rules(),
quota_class.list_rules(),
quotas.list_rules(),
)

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
CREATE_POLICY = 'volume_extension:qos_specs_manage:create'
GET_POLICY = 'volume_extension:qos_specs_manage:get'
GET_ALL_POLICY = 'volume_extension:qos_specs_manage:get_all'
UPDATE_POLICY = 'volume_extension:qos_specs_manage:update'
DELETE_POLICY = 'volume_extension:qos_specs_manage:delete'
qos_specs_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_API,
description="List qos specs or list all associations.",
operations=[
{
'method': 'GET',
'path': '/qos-specs'
},
{
'method': 'GET',
'path': '/qos-specs/{qos_id}/associations'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_API,
description="Show qos specs.",
operations=[
{
'method': 'GET',
'path': '/qos-specs/{qos_id}'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Create qos specs.",
operations=[
{
'method': 'POST',
'path': '/qos-specs'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Update qos specs (including updating association).",
operations=[
{
'method': 'PUT',
'path': '/qos-specs/{qos_id}'
},
{
'method': 'GET',
'path': '/qos-specs/{qos_id}/disassociate_all'
},
{
'method': 'GET',
'path': '/qos-specs/{qos_id}/associate'
},
{
'method': 'GET',
'path': '/qos-specs/{qos_id}/disassociate'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_API,
description="delete qos specs or unset one specified qos key.",
operations=[
{
'method': 'DELETE',
'path': '/qos-specs/{qos_id}'
},
{
'method': 'PUT',
'path': '/qos-specs/{qos_id}/delete_keys'
}
])
]
def list_rules():
return qos_specs_policies

View File

@ -0,0 +1,43 @@
# 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 = 'volume_extension:quota_classes'
quota_class_policies = [
policy.DocumentedRuleDefault(
name=MANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Show or update project quota class.",
operations=[
{
'method': 'GET',
'path': '/os-quota-class-sets/{project_id}'
},
{
'method': 'PUT',
'path': '/os-quota-class-sets/{project_id}'
}
]),
]
def list_rules():
return quota_class_policies

81
cinder/policies/quotas.py Normal file
View File

@ -0,0 +1,81 @@
# 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
SHOW_POLICY = 'volume_extension:quotas:show'
UPDATE_POLICY = 'volume_extension:quotas:update'
DELETE_POLICY = 'volume_extension:quotas:delete'
VALIDATE_NESTED_QUOTA_POLICY = \
'volume_extension:quota_classes:validate_setup_for_nested_quota_use'
quota_policies = [
policy.DocumentedRuleDefault(
name=SHOW_POLICY,
check_str="",
description="Show project quota (including usage and default).",
operations=[
{
'method': 'GET',
'path': '/os-quota-sets/{project_id}'
},
{
'method': 'GET',
'path': '/os-quota-sets/{project_id}/default'
},
{
'method': 'GET',
'path': '/os-quota-sets/{project_id}?usage=True'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Update project quota.",
operations=[
{
'method': 'PUT',
'path': '/os-quota-sets/{project_id}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Delete project quota.",
operations=[
{
'method': 'DELETE',
'path': '/os-quota-sets/{project_id}'
}
]),
policy.DocumentedRuleDefault(
name=VALIDATE_NESTED_QUOTA_POLICY,
check_str=base.RULE_ADMIN_API,
description="Validate setup for nested quota.",
operations=[
{
'method': 'GET',
'path': '/os-quota-sets/validate_setup_for_nested_quota_use'
}
]),
]
def list_rules():
return quota_policies

View File

@ -63,21 +63,12 @@
"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:qos_specs_manage:create": "rule:admin_api",
"volume_extension:qos_specs_manage:get": "rule:admin_api",
"volume_extension:qos_specs_manage:get_all": "rule:admin_api",
"volume_extension:qos_specs_manage:update": "rule:admin_api",
"volume_extension:qos_specs_manage:delete": "rule:admin_api",
"volume_extension:extended_snapshot_attributes": "",
"volume_extension:volume_image_metadata": "",
"volume_extension:volume_host_attribute": "rule:admin_api",
"volume_extension:volume_tenant_attribute": "rule:admin_api",
"volume_extension:volume_mig_status_attribute": "rule:admin_api",
"volume_extension:hosts": "rule:admin_api",
"volume_extension:quotas:show": "",
"volume_extension:quotas:update": "rule:admin_api",
"volume_extension:quotas:delete": "rule:admin_api",
"volume_extension:quota_classes": "rule:admin_api",
"volume_extension:services:index": "",
"volume_extension:services:update" : "rule:admin_api",
"volume_extension:volume_manage": "rule:admin_api",

View File

@ -33,18 +33,6 @@
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:volume_image_metadata": "rule:admin_or_owner",
"volume_extension:qos_specs_manage:create": "rule:admin_api",
"volume_extension:qos_specs_manage:get": "rule:admin_api",
"volume_extension:qos_specs_manage:get_all": "rule:admin_api",
"volume_extension:qos_specs_manage:update": "rule:admin_api",
"volume_extension:qos_specs_manage:delete": "rule:admin_api",
"volume_extension:quotas:show": "",
"volume_extension:quotas:update": "rule:admin_api",
"volume_extension:quotas:delete": "rule:admin_api",
"volume_extension:quota_classes": "rule:admin_api",
"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:volume_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_detach": "rule:admin_api",