[policy in code] Add support for snapshot resource

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

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

Change-Id: I8e1b544f510c1a0af30a5a0b672578226c9fd315
Partial-Implements: blueprint policy-in-code
This commit is contained in:
TommyLike 2017-09-27 10:38:00 +08:00
parent bb3569a3f5
commit d5d0705343
13 changed files with 349 additions and 58 deletions

View File

@ -79,9 +79,18 @@ class AdminController(wsgi.Controller):
return update return update
def authorize(self, context, action_name): def authorize(self, context, action_name):
# e.g. "snapshot_admin_actions:reset_status" # NOTE(tommylikehu): We have two different ways to authorize during
action = '%s_admin_actions:%s' % (self.resource_name, action_name) # implementing code base policies, the if/else statement can be
extensions.extension_authorizer('volume', action)(context) # removed when all resources are upgraded.
if self.resource_name in ['snapshot']:
context.authorize(
'volume_extension:%(resource)s_admin_actions:%(action)s' %
{'resource': self.resource_name,
'action': action_name})
else:
# e.g. "snapshot_admin_actions:reset_status"
action = '%s_admin_actions:%s' % (self.resource_name, action_name)
extensions.extension_authorizer('volume', action)(context)
def _remove_worker(self, context, id): def _remove_worker(self, context, id):
# Remove the cleanup worker from the DB when we change a resource # Remove the cleanup worker from the DB when we change a resource

View File

@ -16,11 +16,7 @@
from cinder.api import extensions from cinder.api import extensions
from cinder.api.openstack import wsgi from cinder.api.openstack import wsgi
from cinder.policies import snapshots as policy
authorize = extensions.soft_extension_authorizer(
'volume',
'extended_snapshot_attributes')
class ExtendedSnapshotAttributesController(wsgi.Controller): class ExtendedSnapshotAttributesController(wsgi.Controller):
@ -33,7 +29,7 @@ class ExtendedSnapshotAttributesController(wsgi.Controller):
@wsgi.extends @wsgi.extends
def show(self, req, resp_obj, id): def show(self, req, resp_obj, id):
context = req.environ['cinder.context'] context = req.environ['cinder.context']
if authorize(context): if context.authorize(policy.EXTEND_ATTRIBUTE):
# Attach our slave template to the response object # Attach our slave template to the response object
snapshot = resp_obj.obj['snapshot'] snapshot = resp_obj.obj['snapshot']
self._extend_snapshot(req, snapshot) self._extend_snapshot(req, snapshot)
@ -41,7 +37,7 @@ class ExtendedSnapshotAttributesController(wsgi.Controller):
@wsgi.extends @wsgi.extends
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['cinder.context'] context = req.environ['cinder.context']
if authorize(context): if context.authorize(policy.EXTEND_ATTRIBUTE):
# Attach our slave template to the response object # Attach our slave template to the response object
for snapshot in list(resp_obj.obj['snapshots']): for snapshot in list(resp_obj.obj['snapshots']):
self._extend_snapshot(req, snapshot) self._extend_snapshot(req, snapshot)

View File

@ -21,15 +21,10 @@ from cinder.api.openstack import wsgi
from cinder.i18n import _ from cinder.i18n import _
from cinder import objects from cinder import objects
from cinder.objects import fields from cinder.objects import fields
from cinder.policies import snapshot_actions as policy
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def authorize(context, action_name):
action = 'snapshot_actions:%s' % action_name
extensions.extension_authorizer('snapshot', action)(context)
class SnapshotActionsController(wsgi.Controller): class SnapshotActionsController(wsgi.Controller):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SnapshotActionsController, self).__init__(*args, **kwargs) super(SnapshotActionsController, self).__init__(*args, **kwargs)
@ -45,7 +40,7 @@ class SnapshotActionsController(wsgi.Controller):
""" """
context = req.environ['cinder.context'] context = req.environ['cinder.context']
authorize(context, 'update_snapshot_status') context.authorize(policy.UPDATE_STATUS_POLICY)
LOG.debug("body: %s", body) LOG.debug("body: %s", body)
try: try:

View File

@ -22,13 +22,10 @@ from cinder.api.openstack import wsgi
from cinder.api.views import manageable_snapshots as list_manageable_view from cinder.api.views import manageable_snapshots as list_manageable_view
from cinder.api.views import snapshots as snapshot_views from cinder.api.views import snapshots as snapshot_views
from cinder.i18n import _ from cinder.i18n import _
from cinder.policies import manageable_snapshots as policy
from cinder import volume as cinder_volume from cinder import volume as cinder_volume
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
authorize_manage = extensions.extension_authorizer('snapshot',
'snapshot_manage')
authorize_list_manageable = extensions.extension_authorizer('snapshot',
'list_manageable')
class SnapshotManageController(wsgi.Controller): class SnapshotManageController(wsgi.Controller):
@ -86,7 +83,7 @@ class SnapshotManageController(wsgi.Controller):
""" """
context = req.environ['cinder.context'] context = req.environ['cinder.context']
authorize_manage(context) context.authorize(policy.MANAGE_POLICY)
if not self.is_valid_body(body, 'snapshot'): if not self.is_valid_body(body, 'snapshot'):
msg = _("Missing required element snapshot in request body.") msg = _("Missing required element snapshot in request body.")
@ -130,7 +127,7 @@ class SnapshotManageController(wsgi.Controller):
def index(self, req): def index(self, req):
"""Returns a summary list of snapshots available to manage.""" """Returns a summary list of snapshots available to manage."""
context = req.environ['cinder.context'] context = req.environ['cinder.context']
authorize_list_manageable(context) context.authorize(policy.LIST_MANAGEABLE_POLICY)
return resource_common_manage.get_manageable_resources( return resource_common_manage.get_manageable_resources(
req, False, self.volume_api.get_manageable_snapshots, req, False, self.volume_api.get_manageable_snapshots,
self._list_manageable_view) self._list_manageable_view)
@ -139,7 +136,7 @@ class SnapshotManageController(wsgi.Controller):
def detail(self, req): def detail(self, req):
"""Returns a detailed list of snapshots available to manage.""" """Returns a detailed list of snapshots available to manage."""
context = req.environ['cinder.context'] context = req.environ['cinder.context']
authorize_list_manageable(context) context.authorize(policy.LIST_MANAGEABLE_POLICY)
return resource_common_manage.get_manageable_resources( return resource_common_manage.get_manageable_resources(
req, True, self.volume_api.get_manageable_snapshots, req, True, self.volume_api.get_manageable_snapshots,
self._list_manageable_view) self._list_manageable_view)

View File

@ -20,10 +20,10 @@ from webob import exc
from cinder.api import extensions from cinder.api import extensions
from cinder.api.openstack import wsgi from cinder.api.openstack import wsgi
from cinder import exception from cinder import exception
from cinder.policies import manageable_snapshots as policy
from cinder import volume from cinder import volume
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('snapshot', 'snapshot_unmanage')
class SnapshotUnmanageController(wsgi.Controller): class SnapshotUnmanageController(wsgi.Controller):
@ -46,7 +46,7 @@ class SnapshotUnmanageController(wsgi.Controller):
A Not Found error is returned if the specified snapshot does not exist. A Not Found error is returned if the specified snapshot does not exist.
""" """
context = req.environ['cinder.context'] context = req.environ['cinder.context']
authorize(context) context.authorize(policy.UNMANAGE_POLICY)
LOG.info("Unmanage snapshot with id: %s", id) LOG.info("Unmanage snapshot with id: %s", id)

View File

@ -18,7 +18,11 @@ import itertools
from cinder.policies import attachments from cinder.policies import attachments
from cinder.policies import base from cinder.policies import base
from cinder.policies import clusters from cinder.policies import clusters
from cinder.policies import manageable_snapshots
from cinder.policies import messages from cinder.policies import messages
from cinder.policies import snapshot_actions
from cinder.policies import snapshot_metadata
from cinder.policies import snapshots
from cinder.policies import workers from cinder.policies import workers
@ -28,5 +32,9 @@ def list_rules():
attachments.list_rules(), attachments.list_rules(),
messages.list_rules(), messages.list_rules(),
clusters.list_rules(), clusters.list_rules(),
workers.list_rules() workers.list_rules(),
snapshot_metadata.list_rules(),
snapshots.list_rules(),
snapshot_actions.list_rules(),
manageable_snapshots.list_rules(),
) )

View File

@ -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
MANAGE_POLICY = 'snapshot_extension:snapshot_manage'
UNMANAGE_POLICY = 'snapshot_extension:snapshot_unmanage'
LIST_MANAGEABLE_POLICY = 'snapshot_extension:list_manageable'
manageable_snapshots_policies = [
policy.DocumentedRuleDefault(
name=LIST_MANAGEABLE_POLICY,
check_str=base.RULE_ADMIN_API,
description=
"List (in detail) of snapshots which are available to manage.",
operations=[
{
'method': 'GET',
'path': '/manageable_snapshots'
},
{
'method': 'GET',
'path': '/manageable_snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=MANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Manage an existing snapshot.",
operations=[
{
'method': 'POST',
'path': '/manageable_snapshots'
}
]),
policy.DocumentedRuleDefault(
name=UNMANAGE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Stop managing a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-unmanage)'
}
]),
]
def list_rules():
return manageable_snapshots_policies

View File

@ -0,0 +1,62 @@
# 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_POLICY = 'volume_extension:snapshot_admin_actions:reset_status'
FORCE_DELETE_POLICY = 'volume_extension:snapshot_admin_actions:force_delete'
UPDATE_STATUS_POLICY = \
'snapshot_extension:snapshot_actions:update_snapshot_status'
snapshot_actions_policies = [
policy.DocumentedRuleDefault(
name=RESET_STATUS_POLICY,
check_str=base.RULE_ADMIN_API,
description="Reset status of a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-reset_status)'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_STATUS_POLICY,
check_str="",
description="Update database fields of snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action '
'(update_snapshot_status)'
}
]),
policy.DocumentedRuleDefault(
name=FORCE_DELETE_POLICY,
check_str=base.RULE_ADMIN_API,
description="Force delete a snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots/{snapshot_id}/action (os-force_delete)'
}
])
]
def list_rules():
return snapshot_actions_policies

View File

@ -0,0 +1,72 @@
# 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 = 'volume:get_snapshot_metadata'
DELETE_POLICY = 'volume:delete_snapshot_metadata'
UPDATE_POLICY = 'volume:update_snapshot_metadata'
snapshot_metadata_policies = [
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show snapshot's metadata or one specified metadata "
"with a given key.",
operations=[
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}/metadata'
},
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update snapshot's metadata or one specified "
"metadata with a given key.",
operations=[
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}/metadata'
},
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete snapshot's specified metadata "
"with a given key.",
operations=[
{
'method': 'DELETE',
'path': '/snapshots/{snapshot_id}/metadata/{key}'
}
]),
]
def list_rules():
return snapshot_metadata_policies

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
BASE_POLICY_NAME = 'volume:snapshots:%s'
GET_POLICY = 'volume:get_snapshot'
GET_ALL_POLICY = 'volume:get_all_snapshots'
CREATE_POLICY = 'volume:create_snapshot'
DELETE_POLICY = 'volume:delete_snapshot'
UPDATE_POLICY = 'volume:update_snapshot'
EXTEND_ATTRIBUTE = 'volume_extension:extended_snapshot_attributes'
snapshots_policies = [
policy.DocumentedRuleDefault(
name=GET_ALL_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List snapshots.",
operations=[
{
'method': 'GET',
'path': '/snapshots'
},
{
'method': 'GET',
'path': '/snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=EXTEND_ATTRIBUTE,
check_str=base.RULE_ADMIN_OR_OWNER,
description="List snapshots with extended attributes.",
operations=[
{
'method': 'GET',
'path': '/snapshots'
},
{
'method': 'GET',
'path': '/snapshots/detail'
}
]),
policy.DocumentedRuleDefault(
name=CREATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Create snapshot.",
operations=[
{
'method': 'POST',
'path': '/snapshots'
}
]),
policy.DocumentedRuleDefault(
name=GET_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Show snapshot.",
operations=[
{
'method': 'GET',
'path': '/snapshots/{snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=UPDATE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Update snapshot.",
operations=[
{
'method': 'PUT',
'path': '/snapshots/{snapshot_id}'
}
]),
policy.DocumentedRuleDefault(
name=DELETE_POLICY,
check_str=base.RULE_ADMIN_OR_OWNER,
description="Delete snapshot.",
operations=[
{
'method': 'DELETE',
'path': '/snapshots/{snapshot_id}'
}
]),
]
def list_rules():
return snapshots_policies

View File

@ -44,11 +44,9 @@
"volume:thaw_host": "rule:admin_api", "volume:thaw_host": "rule:admin_api",
"volume:revert_to_snapshot": "", "volume:revert_to_snapshot": "",
"volume_extension:volume_admin_actions:reset_status": "rule:admin_api", "volume_extension:volume_admin_actions:reset_status": "rule:admin_api",
"volume_extension:snapshot_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:reset_status": "rule:admin_api", "volume_extension:backup_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:force_delete": "rule:admin_api", "volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_delete": "rule:admin_api", "volume_extension:volume_admin_actions:force_delete": "rule:admin_api",
"volume_extension:snapshot_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_detach": "rule:admin_api", "volume_extension:volume_admin_actions:force_detach": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api", "volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api", "volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
@ -91,11 +89,6 @@
"limits_extension:used_limits": "", "limits_extension:used_limits": "",
"snapshot_extension:snapshot_actions:update_snapshot_status": "",
"snapshot_extension:snapshot_manage": "rule:admin_api",
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
"snapshot_extension:list_manageable": "rule:admin_api",
"volume:create_transfer": "", "volume:create_transfer": "",
"volume:accept_transfer": "", "volume:accept_transfer": "",
"volume:delete_transfer": "", "volume:delete_transfer": "",

View File

@ -44,6 +44,8 @@ from cinder import objects
from cinder.objects import base as objects_base from cinder.objects import base as objects_base
from cinder.objects import fields from cinder.objects import fields
from cinder.policies import attachments as attachment_policy from cinder.policies import attachments as attachment_policy
from cinder.policies import snapshot_metadata as s_meta_policy
from cinder.policies import snapshots as snapshot_policy
import cinder.policy import cinder.policy
from cinder import quota from cinder import quota
from cinder import quota_utils from cinder import quota_utils
@ -624,7 +626,7 @@ class API(base.Base):
return volumes return volumes
def get_snapshot(self, context, snapshot_id): def get_snapshot(self, context, snapshot_id):
check_policy(context, 'get_snapshot') context.authorize(snapshot_policy.GET_POLICY)
snapshot = objects.Snapshot.get_by_id(context, snapshot_id) snapshot = objects.Snapshot.get_by_id(context, snapshot_id)
# FIXME(jdg): The objects don't have the db name entries # FIXME(jdg): The objects don't have the db name entries
@ -643,7 +645,7 @@ class API(base.Base):
def get_all_snapshots(self, context, search_opts=None, marker=None, def get_all_snapshots(self, context, search_opts=None, marker=None,
limit=None, sort_keys=None, sort_dirs=None, limit=None, sort_keys=None, sort_dirs=None,
offset=None): offset=None):
check_policy(context, 'get_all_snapshots') context.authorize(snapshot_policy.GET_ALL_POLICY)
search_opts = search_opts or {} search_opts = search_opts or {}
@ -827,7 +829,7 @@ class API(base.Base):
cgsnapshot_id, cgsnapshot_id,
commit_quota=True, commit_quota=True,
group_snapshot_id=None): group_snapshot_id=None):
check_policy(context, 'create_snapshot', volume) context.authorize(snapshot_policy.CREATE_POLICY)
if not volume.host: if not volume.host:
msg = _("The snapshot cannot be created because volume has " msg = _("The snapshot cannot be created because volume has "
@ -1031,9 +1033,10 @@ class API(base.Base):
resource=result) resource=result)
return result return result
@wrap_check_policy
def delete_snapshot(self, context, snapshot, force=False, def delete_snapshot(self, context, snapshot, force=False,
unmanage_only=False): unmanage_only=False):
context.authorize(snapshot_policy.DELETE_POLICY,
target_obj=snapshot)
if not unmanage_only: if not unmanage_only:
snapshot.assert_not_frozen() snapshot.assert_not_frozen()
@ -1061,8 +1064,9 @@ class API(base.Base):
LOG.info("Snapshot delete request issued successfully.", LOG.info("Snapshot delete request issued successfully.",
resource=snapshot) resource=snapshot)
@wrap_check_policy
def update_snapshot(self, context, snapshot, fields): def update_snapshot(self, context, snapshot, fields):
context.authorize(snapshot_policy.UPDATE_POLICY,
target_obj=snapshot)
snapshot.update(fields) snapshot.update(fields)
snapshot.save() snapshot.save()
@ -1153,21 +1157,22 @@ class API(base.Base):
resource=volume) resource=volume)
return db_meta return db_meta
@wrap_check_policy
def get_snapshot_metadata(self, context, snapshot): def get_snapshot_metadata(self, context, snapshot):
"""Get all metadata associated with a snapshot.""" """Get all metadata associated with a snapshot."""
context.authorize(s_meta_policy.GET_POLICY,
target_obj=snapshot)
LOG.info("Get snapshot metadata completed successfully.", LOG.info("Get snapshot metadata completed successfully.",
resource=snapshot) resource=snapshot)
return snapshot.metadata return snapshot.metadata
@wrap_check_policy
def delete_snapshot_metadata(self, context, snapshot, key): def delete_snapshot_metadata(self, context, snapshot, key):
"""Delete the given metadata item from a snapshot.""" """Delete the given metadata item from a snapshot."""
context.authorize(s_meta_policy.DELETE_POLICY,
target_obj=snapshot)
snapshot.delete_metadata_key(context, key) snapshot.delete_metadata_key(context, key)
LOG.info("Delete snapshot metadata completed successfully.", LOG.info("Delete snapshot metadata completed successfully.",
resource=snapshot) resource=snapshot)
@wrap_check_policy
def update_snapshot_metadata(self, context, def update_snapshot_metadata(self, context,
snapshot, metadata, snapshot, metadata,
delete=False): delete=False):
@ -1177,6 +1182,8 @@ class API(base.Base):
`metadata` argument will be deleted. `metadata` argument will be deleted.
""" """
context.authorize(s_meta_policy.UPDATE_POLICY,
target_obj=snapshot)
if delete: if delete:
_metadata = metadata _metadata = metadata
else: else:

View File

@ -11,14 +11,6 @@
"volume:update_volume_metadata": "rule:admin_or_owner", "volume:update_volume_metadata": "rule:admin_or_owner",
"volume:get_volume_admin_metadata": "rule:admin_api", "volume:get_volume_admin_metadata": "rule:admin_api",
"volume:update_volume_admin_metadata": "rule:admin_api", "volume:update_volume_admin_metadata": "rule:admin_api",
"volume:get_snapshot": "rule:admin_or_owner",
"volume:get_all_snapshots": "rule:admin_or_owner",
"volume:create_snapshot": "rule:admin_or_owner",
"volume:delete_snapshot": "rule:admin_or_owner",
"volume:update_snapshot": "rule:admin_or_owner",
"volume:get_snapshot_metadata": "rule:admin_or_owner",
"volume:delete_snapshot_metadata": "rule:admin_or_owner",
"volume:update_snapshot_metadata": "rule:admin_or_owner",
"volume:extend": "rule:admin_or_owner", "volume:extend": "rule:admin_or_owner",
"volume:extend_attached_volume": "rule:admin_or_owner", "volume:extend_attached_volume": "rule:admin_or_owner",
"volume:update_readonly_flag": "rule:admin_or_owner", "volume:update_readonly_flag": "rule:admin_or_owner",
@ -39,7 +31,6 @@
"volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api", "volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api",
"volume_extension:volume_type_encryption": "rule:admin_api", "volume_extension:volume_type_encryption": "rule:admin_api",
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner", "volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:extended_snapshot_attributes": "rule:admin_or_owner",
"volume_extension:volume_image_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:create": "rule:admin_api",
@ -55,11 +46,9 @@
"volume_extension:quota_classes:validate_setup_for_nested_quota_use": "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:reset_status": "rule:admin_api",
"volume_extension:snapshot_admin_actions:reset_status": "rule:admin_api",
"volume_extension:backup_admin_actions:reset_status": "rule:admin_api", "volume_extension:backup_admin_actions:reset_status": "rule:admin_api",
"volume_extension:volume_admin_actions:force_delete": "rule:admin_api", "volume_extension:volume_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:force_detach": "rule:admin_api", "volume_extension:volume_admin_actions:force_detach": "rule:admin_api",
"volume_extension:snapshot_admin_actions:force_delete": "rule:admin_api",
"volume_extension:backup_admin_actions:force_delete": "rule:admin_api", "volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api", "volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api", "volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
@ -100,11 +89,6 @@
"backup:update": "rule:admin_or_owner", "backup:update": "rule:admin_or_owner",
"backup:backup_project_attribute": "rule:admin_api", "backup:backup_project_attribute": "rule:admin_api",
"snapshot_extension:snapshot_actions:update_snapshot_status": "",
"snapshot_extension:snapshot_manage": "rule:admin_api",
"snapshot_extension:snapshot_unmanage": "rule:admin_api",
"snapshot_extension:list_manageable": "rule:admin_api",
"consistencygroup:create" : "group:nobody", "consistencygroup:create" : "group:nobody",
"consistencygroup:delete": "group:nobody", "consistencygroup:delete": "group:nobody",
"consistencygroup:update": "group:nobody", "consistencygroup:update": "group:nobody",