Merge "Update oslo policy and its dependencies"
This commit is contained in:
commit
6b62908dfd
@ -24,7 +24,7 @@ import traceback
|
|||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from cinder.openstack.common.gettextutils import _
|
from cinder.openstack.common.gettextutils import _LE
|
||||||
|
|
||||||
|
|
||||||
class save_and_reraise_exception(object):
|
class save_and_reraise_exception(object):
|
||||||
@ -49,9 +49,22 @@ class save_and_reraise_exception(object):
|
|||||||
decide_if_need_reraise()
|
decide_if_need_reraise()
|
||||||
if not should_be_reraised:
|
if not should_be_reraised:
|
||||||
ctxt.reraise = False
|
ctxt.reraise = False
|
||||||
|
|
||||||
|
If another exception occurs and reraise flag is False,
|
||||||
|
the saved exception will not be logged.
|
||||||
|
|
||||||
|
If the caller wants to raise new exception during exception handling
|
||||||
|
he/she sets reraise to False initially with an ability to set it back to
|
||||||
|
True if needed::
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
with save_and_reraise_exception(reraise=False) as ctxt:
|
||||||
|
[if statements to determine whether to raise a new exception]
|
||||||
|
# Not raising a new exception, so reraise
|
||||||
|
ctxt.reraise = True
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, reraise=True):
|
||||||
self.reraise = True
|
self.reraise = reraise
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.type_, self.value, self.tb, = sys.exc_info()
|
self.type_, self.value, self.tb, = sys.exc_info()
|
||||||
@ -59,10 +72,11 @@ class save_and_reraise_exception(object):
|
|||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
if exc_type is not None:
|
if exc_type is not None:
|
||||||
logging.error(_('Original exception being dropped: %s'),
|
if self.reraise:
|
||||||
traceback.format_exception(self.type_,
|
logging.error(_LE('Original exception being dropped: %s'),
|
||||||
self.value,
|
traceback.format_exception(self.type_,
|
||||||
self.tb))
|
self.value,
|
||||||
|
self.tb))
|
||||||
return False
|
return False
|
||||||
if self.reraise:
|
if self.reraise:
|
||||||
six.reraise(self.type_, self.value, self.tb)
|
six.reraise(self.type_, self.value, self.tb)
|
||||||
@ -88,8 +102,8 @@ def forever_retry_uncaught_exceptions(infunc):
|
|||||||
if (cur_time - last_log_time > 60 or
|
if (cur_time - last_log_time > 60 or
|
||||||
this_exc_message != last_exc_message):
|
this_exc_message != last_exc_message):
|
||||||
logging.exception(
|
logging.exception(
|
||||||
_('Unexpected exception occurred %d time(s)... '
|
_LE('Unexpected exception occurred %d time(s)... '
|
||||||
'retrying.') % exc_count)
|
'retrying.') % exc_count)
|
||||||
last_log_time = cur_time
|
last_log_time = cur_time
|
||||||
last_exc_message = this_exc_message
|
last_exc_message = this_exc_message
|
||||||
exc_count = 0
|
exc_count = 0
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2011 OpenStack Foundation.
|
# Copyright 2011 OpenStack Foundation.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
@ -15,13 +13,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from cinder.openstack.common import excutils
|
from cinder.openstack.common import excutils
|
||||||
from cinder.openstack.common.gettextutils import _
|
|
||||||
from cinder.openstack.common import log as logging
|
from cinder.openstack.common import log as logging
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -53,15 +50,15 @@ def read_cached_file(filename, force_reload=False):
|
|||||||
"""
|
"""
|
||||||
global _FILE_CACHE
|
global _FILE_CACHE
|
||||||
|
|
||||||
if force_reload and filename in _FILE_CACHE:
|
if force_reload:
|
||||||
del _FILE_CACHE[filename]
|
delete_cached_file(filename)
|
||||||
|
|
||||||
reloaded = False
|
reloaded = False
|
||||||
mtime = os.path.getmtime(filename)
|
mtime = os.path.getmtime(filename)
|
||||||
cache_info = _FILE_CACHE.setdefault(filename, {})
|
cache_info = _FILE_CACHE.setdefault(filename, {})
|
||||||
|
|
||||||
if not cache_info or mtime > cache_info.get('mtime', 0):
|
if not cache_info or mtime > cache_info.get('mtime', 0):
|
||||||
LOG.debug(_("Reloading cached file %s") % filename)
|
LOG.debug("Reloading cached file %s" % filename)
|
||||||
with open(filename) as fap:
|
with open(filename) as fap:
|
||||||
cache_info['data'] = fap.read()
|
cache_info['data'] = fap.read()
|
||||||
cache_info['mtime'] = mtime
|
cache_info['mtime'] = mtime
|
||||||
@ -69,42 +66,81 @@ def read_cached_file(filename, force_reload=False):
|
|||||||
return (reloaded, cache_info['data'])
|
return (reloaded, cache_info['data'])
|
||||||
|
|
||||||
|
|
||||||
def delete_if_exists(path):
|
def delete_cached_file(filename):
|
||||||
|
"""Delete cached file if present.
|
||||||
|
|
||||||
|
:param filename: filename to delete
|
||||||
|
"""
|
||||||
|
global _FILE_CACHE
|
||||||
|
|
||||||
|
if filename in _FILE_CACHE:
|
||||||
|
del _FILE_CACHE[filename]
|
||||||
|
|
||||||
|
|
||||||
|
def delete_if_exists(path, remove=os.unlink):
|
||||||
"""Delete a file, but ignore file not found error.
|
"""Delete a file, but ignore file not found error.
|
||||||
|
|
||||||
:param path: File to delete
|
:param path: File to delete
|
||||||
|
:param remove: Optional function to remove passed path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.unlink(path)
|
remove(path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno != errno.ENOENT:
|
||||||
return
|
|
||||||
else:
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def remove_path_on_error(path):
|
def remove_path_on_error(path, remove=delete_if_exists):
|
||||||
"""Protect code that wants to operate on PATH atomically.
|
"""Protect code that wants to operate on PATH atomically.
|
||||||
Any exception will cause PATH to be removed.
|
Any exception will cause PATH to be removed.
|
||||||
|
|
||||||
:param path: File to work with
|
:param path: File to work with
|
||||||
|
:param remove: Optional function to remove passed path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
delete_if_exists(path)
|
remove(path)
|
||||||
|
|
||||||
|
|
||||||
def file_open(*args, **kwargs):
|
def file_open(*args, **kwargs):
|
||||||
"""Open file
|
"""Open file
|
||||||
|
|
||||||
see built-in file() documentation for more details
|
see built-in open() documentation for more details
|
||||||
|
|
||||||
Note: The reason this is kept in a separate module is to easily
|
Note: The reason this is kept in a separate module is to easily
|
||||||
be able to provide a stub module that doesn't alter system
|
be able to provide a stub module that doesn't alter system
|
||||||
state at all (for unit tests)
|
state at all (for unit tests)
|
||||||
"""
|
"""
|
||||||
return file(*args, **kwargs)
|
return open(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def write_to_tempfile(content, path=None, suffix='', prefix='tmp'):
|
||||||
|
"""Create temporary file or use existing file.
|
||||||
|
|
||||||
|
This util is needed for creating temporary file with
|
||||||
|
specified content, suffix and prefix. If path is not None,
|
||||||
|
it will be used for writing content. If the path doesn't
|
||||||
|
exist it'll be created.
|
||||||
|
|
||||||
|
:param content: content for temporary file.
|
||||||
|
:param path: same as parameter 'dir' for mkstemp
|
||||||
|
:param suffix: same as parameter 'suffix' for mkstemp
|
||||||
|
:param prefix: same as parameter 'prefix' for mkstemp
|
||||||
|
|
||||||
|
For example: it can be used in database tests for creating
|
||||||
|
configuration files.
|
||||||
|
"""
|
||||||
|
if path:
|
||||||
|
ensure_tree(path)
|
||||||
|
|
||||||
|
(fd, path) = tempfile.mkstemp(suffix=suffix, dir=path, prefix=prefix)
|
||||||
|
try:
|
||||||
|
os.write(fd, content)
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
|
return path
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,46 +19,17 @@
|
|||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _
|
|
||||||
from cinder.openstack.common import policy
|
from cinder.openstack.common import policy
|
||||||
from cinder import utils
|
|
||||||
|
|
||||||
|
|
||||||
policy_opts = [
|
|
||||||
cfg.StrOpt('policy_file',
|
|
||||||
default='policy.json',
|
|
||||||
help=_('JSON file representing policy')),
|
|
||||||
cfg.StrOpt('policy_default_rule',
|
|
||||||
default='default',
|
|
||||||
help=_('Rule checked when requested rule is not found')), ]
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.register_opts(policy_opts)
|
|
||||||
|
|
||||||
_POLICY_PATH = None
|
_ENFORCER = None
|
||||||
_POLICY_CACHE = {}
|
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
|
||||||
global _POLICY_PATH
|
|
||||||
global _POLICY_CACHE
|
|
||||||
_POLICY_PATH = None
|
|
||||||
_POLICY_CACHE = {}
|
|
||||||
policy.reset()
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
global _POLICY_PATH
|
global _ENFORCER
|
||||||
global _POLICY_CACHE
|
if not _ENFORCER:
|
||||||
if not _POLICY_PATH:
|
_ENFORCER = policy.Enforcer()
|
||||||
_POLICY_PATH = utils.find_config(CONF.policy_file)
|
|
||||||
utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
|
|
||||||
reload_func=_set_brain)
|
|
||||||
|
|
||||||
|
|
||||||
def _set_brain(data):
|
|
||||||
default_rule = CONF.policy_default_rule
|
|
||||||
policy.set_brain(policy.Brain.load_json(data, default_rule))
|
|
||||||
|
|
||||||
|
|
||||||
def enforce_action(context, action):
|
def enforce_action(context, action):
|
||||||
@ -68,11 +39,8 @@ def enforce_action(context, action):
|
|||||||
applied to the given action using the policy enforcement api.
|
applied to the given action using the policy enforcement api.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
target = {
|
return enforce(context, action, {'project_id': context.project_id,
|
||||||
'project_id': context.project_id,
|
'user_id': context.user_id})
|
||||||
'user_id': context.user_id,
|
|
||||||
}
|
|
||||||
enforce(context, action, target)
|
|
||||||
|
|
||||||
|
|
||||||
def enforce(context, action, target):
|
def enforce(context, action, target):
|
||||||
@ -89,16 +57,15 @@ def enforce(context, action, target):
|
|||||||
for object creation this should be a dictionary representing the
|
for object 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 cinder.exception.PolicyNotAuthorized: if verification fails.
|
:raises PolicyNotAuthorized: if verification fails.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
init()
|
init()
|
||||||
|
|
||||||
match_list = ('rule:%s' % action,)
|
return _ENFORCER.enforce(action, target, context.to_dict(),
|
||||||
credentials = context.to_dict()
|
do_raise=True,
|
||||||
|
exc=exception.PolicyNotAuthorized,
|
||||||
policy.enforce(match_list, target, credentials,
|
action=action)
|
||||||
exception.PolicyNotAuthorized, action=action)
|
|
||||||
|
|
||||||
|
|
||||||
def check_is_admin(roles):
|
def check_is_admin(roles):
|
||||||
@ -107,8 +74,6 @@ def check_is_admin(roles):
|
|||||||
"""
|
"""
|
||||||
init()
|
init()
|
||||||
|
|
||||||
action = 'context_is_admin'
|
|
||||||
match_list = ('rule:%s' % action,)
|
|
||||||
# include project_id on target to avoid KeyError if context_is_admin
|
# include project_id on target to avoid KeyError if context_is_admin
|
||||||
# policy definition is missing, and default admin_or_owner rule
|
# policy definition is missing, and default admin_or_owner rule
|
||||||
# attempts to apply. Since our credentials dict does not include a
|
# attempts to apply. Since our credentials dict does not include a
|
||||||
@ -116,4 +81,4 @@ def check_is_admin(roles):
|
|||||||
target = {'project_id': ''}
|
target = {'project_id': ''}
|
||||||
credentials = {'roles': roles}
|
credentials = {'roles': roles}
|
||||||
|
|
||||||
return policy.enforce(match_list, target, credentials)
|
return _ENFORCER.enforce('context_is_admin', target, credentials)
|
||||||
|
@ -187,6 +187,15 @@ class TestCase(testtools.TestCase):
|
|||||||
CONF.set_override('fatal_exception_format_errors', True)
|
CONF.set_override('fatal_exception_format_errors', True)
|
||||||
# This will be cleaned up by the NestedTempfile fixture
|
# This will be cleaned up by the NestedTempfile fixture
|
||||||
CONF.set_override('lock_path', tempfile.mkdtemp())
|
CONF.set_override('lock_path', tempfile.mkdtemp())
|
||||||
|
CONF.set_override('policy_file',
|
||||||
|
os.path.join(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'..',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'cinder/tests/policy.json'))
|
||||||
|
|
||||||
def _common_cleanup(self):
|
def _common_cleanup(self):
|
||||||
"""Runs after each test method to tear down test environment."""
|
"""Runs after each test method to tear down test environment."""
|
||||||
|
@ -1,92 +1,92 @@
|
|||||||
{
|
{
|
||||||
"context_is_admin": [["role:admin"]],
|
"context_is_admin": "role:admin",
|
||||||
"admin_api": [["is_admin:True"]],
|
"admin_api": "is_admin:True",
|
||||||
"admin_or_owner": [["is_admin:True"], ["project_id:%(project_id)s"]],
|
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
||||||
|
|
||||||
"volume:create": [],
|
"volume:create": "",
|
||||||
"volume:get": [["rule:admin_or_owner"]],
|
"volume:get": "rule:admin_or_owner",
|
||||||
"volume:get_all": [],
|
"volume:get_all": "",
|
||||||
"volume:get_volume_metadata": [],
|
"volume:get_volume_metadata": "",
|
||||||
"volume:delete_volume_metadata": [],
|
"volume:delete_volume_metadata": "",
|
||||||
"volume:update_volume_metadata": [],
|
"volume:update_volume_metadata": "",
|
||||||
"volume:get_volume_admin_metadata": [["rule:admin_api"]],
|
"volume:get_volume_admin_metadata": "rule:admin_api",
|
||||||
"volume:delete_volume_admin_metadata": [["rule:admin_api"]],
|
"volume:delete_volume_admin_metadata": "rule:admin_api",
|
||||||
"volume:update_volume_admin_metadata": [["rule:admin_api"]],
|
"volume:update_volume_admin_metadata": "rule:admin_api",
|
||||||
"volume:delete": [],
|
"volume:delete": "",
|
||||||
"volume:update": [],
|
"volume:update": "",
|
||||||
"volume:attach": [],
|
"volume:attach": "",
|
||||||
"volume:detach": [],
|
"volume:detach": "",
|
||||||
"volume:reserve_volume": [],
|
"volume:reserve_volume": "",
|
||||||
"volume:unreserve_volume": [],
|
"volume:unreserve_volume": "",
|
||||||
"volume:begin_detaching": [],
|
"volume:begin_detaching": "",
|
||||||
"volume:roll_detaching": [],
|
"volume:roll_detaching": "",
|
||||||
"volume:initialize_connection": [],
|
"volume:initialize_connection": "",
|
||||||
"volume:terminate_connection": [],
|
"volume:terminate_connection": "",
|
||||||
"volume:create_snapshot": [],
|
"volume:create_snapshot": "",
|
||||||
"volume:delete_snapshot": [],
|
"volume:delete_snapshot": "",
|
||||||
"volume:get_snapshot": [],
|
"volume:get_snapshot": "",
|
||||||
"volume:get_all_snapshots": [],
|
"volume:get_all_snapshots": "",
|
||||||
"volume:update_snapshot": [],
|
"volume:update_snapshot": "",
|
||||||
"volume:extend": [],
|
"volume:extend": "",
|
||||||
"volume:migrate_volume": [["rule:admin_api"]],
|
"volume:migrate_volume": "rule:admin_api",
|
||||||
"volume:migrate_volume_completion": [["rule:admin_api"]],
|
"volume:migrate_volume_completion": "rule:admin_api",
|
||||||
"volume:update_readonly_flag": [],
|
"volume:update_readonly_flag": "",
|
||||||
"volume:retype": [],
|
"volume:retype": "",
|
||||||
"volume:copy_volume_to_image": [],
|
"volume:copy_volume_to_image": "",
|
||||||
|
|
||||||
"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:snapshot_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:snapshot_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",
|
||||||
"volume_extension:volume_actions:upload_image": [],
|
"volume_extension:volume_actions:upload_image": "",
|
||||||
"volume_extension:types_manage": [],
|
"volume_extension:types_manage": "",
|
||||||
"volume_extension:types_extra_specs": [],
|
"volume_extension:types_extra_specs": "",
|
||||||
"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:qos_specs_manage": [],
|
"volume_extension:qos_specs_manage": "",
|
||||||
"volume_extension:extended_snapshot_attributes": [],
|
"volume_extension:extended_snapshot_attributes": "",
|
||||||
"volume_extension:volume_image_metadata": [],
|
"volume_extension:volume_image_metadata": "",
|
||||||
"volume_extension:volume_host_attribute": [["rule:admin_api"]],
|
"volume_extension:volume_host_attribute": "rule:admin_api",
|
||||||
"volume_extension:volume_tenant_attribute": [["rule:admin_api"]],
|
"volume_extension:volume_tenant_attribute": "rule:admin_api",
|
||||||
"volume_extension:volume_mig_status_attribute": [["rule:admin_api"]],
|
"volume_extension:volume_mig_status_attribute": "rule:admin_api",
|
||||||
"volume_extension:hosts": [["rule:admin_api"]],
|
"volume_extension:hosts": "rule:admin_api",
|
||||||
"volume_extension:quotas:show": [],
|
"volume_extension:quotas:show": "",
|
||||||
"volume_extension:quotas:update": [],
|
"volume_extension:quotas:update": "",
|
||||||
"volume_extension:quotas:delete": [],
|
"volume_extension:quotas:delete": "",
|
||||||
"volume_extension:quota_classes": [],
|
"volume_extension:quota_classes": "",
|
||||||
"volume_extension:volume_manage": [["rule:admin_api"]],
|
"volume_extension:volume_manage": "rule:admin_api",
|
||||||
"volume_extension:volume_unmanage": [["rule:admin_api"]],
|
"volume_extension:volume_unmanage": "rule:admin_api",
|
||||||
|
|
||||||
"limits_extension:used_limits": [],
|
"limits_extension:used_limits": "",
|
||||||
|
|
||||||
"snapshot_extension:snapshot_actions:update_snapshot_status": [],
|
"snapshot_extension:snapshot_actions:update_snapshot_status": "",
|
||||||
|
|
||||||
"volume:create_transfer": [],
|
"volume:create_transfer": "",
|
||||||
"volume:accept_transfer": [],
|
"volume:accept_transfer": "",
|
||||||
"volume:delete_transfer": [],
|
"volume:delete_transfer": "",
|
||||||
"volume:get_all_transfers": [],
|
"volume:get_all_transfers": "",
|
||||||
|
|
||||||
"backup:create" : [],
|
"backup:create" : "",
|
||||||
"backup:delete": [],
|
"backup:delete": "",
|
||||||
"backup:get": [],
|
"backup:get": "",
|
||||||
"backup:get_all": [],
|
"backup:get_all": "",
|
||||||
"backup:restore": [],
|
"backup:restore": "",
|
||||||
"backup:backup-import": [["rule:admin_api"]],
|
"backup:backup-import": "rule:admin_api",
|
||||||
"backup:backup-export": [["rule:admin_api"]],
|
"backup:backup-export": "rule:admin_api",
|
||||||
|
|
||||||
"volume_extension:replication:promote": [["rule:admin_api"]],
|
"volume_extension:replication:promote": "rule:admin_api",
|
||||||
"volume_extension:replication:reenable": [["rule:admin_api"]],
|
"volume_extension:replication:reenable": "rule:admin_api",
|
||||||
|
|
||||||
"consistencygroup:create" : [],
|
"consistencygroup:create" : "",
|
||||||
"consistencygroup:delete": [],
|
"consistencygroup:delete": "",
|
||||||
"consistencygroup:get": [],
|
"consistencygroup:get": "",
|
||||||
"consistencygroup:get_all": [],
|
"consistencygroup:get_all": "",
|
||||||
|
|
||||||
"consistencygroup:create_cgsnapshot" : [],
|
"consistencygroup:create_cgsnapshot" : "",
|
||||||
"consistencygroup:delete_cgsnapshot": [],
|
"consistencygroup:delete_cgsnapshot": "",
|
||||||
"consistencygroup:get_cgsnapshot": [],
|
"consistencygroup:get_cgsnapshot": "",
|
||||||
"consistencygroup:get_all_cgsnapshots": []
|
"consistencygroup:get_all_cgsnapshots": ""
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ from oslo.config import cfg
|
|||||||
from cinder import context
|
from cinder import context
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.image import image_utils
|
from cinder.image import image_utils
|
||||||
|
from cinder.openstack.common import fileutils
|
||||||
from cinder.openstack.common import processutils
|
from cinder.openstack.common import processutils
|
||||||
from cinder.openstack.common import units
|
from cinder.openstack.common import units
|
||||||
from cinder import test
|
from cinder import test
|
||||||
@ -621,10 +622,10 @@ class TestTemporaryFile(test.TestCase):
|
|||||||
def test_file_unlinked(self):
|
def test_file_unlinked(self):
|
||||||
mox = self.mox
|
mox = self.mox
|
||||||
mox.StubOutWithMock(image_utils, 'create_temporary_file')
|
mox.StubOutWithMock(image_utils, 'create_temporary_file')
|
||||||
mox.StubOutWithMock(image_utils.os, 'unlink')
|
mox.StubOutWithMock(fileutils, 'delete_if_exists')
|
||||||
|
|
||||||
image_utils.create_temporary_file().AndReturn('somefile')
|
image_utils.create_temporary_file().AndReturn('somefile')
|
||||||
image_utils.os.unlink('somefile')
|
fileutils.delete_if_exists('somefile')
|
||||||
|
|
||||||
mox.ReplayAll()
|
mox.ReplayAll()
|
||||||
|
|
||||||
@ -634,10 +635,10 @@ class TestTemporaryFile(test.TestCase):
|
|||||||
def test_file_unlinked_on_error(self):
|
def test_file_unlinked_on_error(self):
|
||||||
mox = self.mox
|
mox = self.mox
|
||||||
mox.StubOutWithMock(image_utils, 'create_temporary_file')
|
mox.StubOutWithMock(image_utils, 'create_temporary_file')
|
||||||
mox.StubOutWithMock(image_utils.os, 'unlink')
|
mox.StubOutWithMock(fileutils, 'delete_if_exists')
|
||||||
|
|
||||||
image_utils.create_temporary_file().AndReturn('somefile')
|
image_utils.create_temporary_file().AndReturn('somefile')
|
||||||
image_utils.os.unlink('somefile')
|
fileutils.delete_if_exists('somefile')
|
||||||
|
|
||||||
mox.ReplayAll()
|
mox.ReplayAll()
|
||||||
|
|
||||||
@ -706,6 +707,7 @@ class TestXenServerImageToCoalescedVhd(test.TestCase):
|
|||||||
mox.StubOutWithMock(image_utils, 'fix_vhd_chain')
|
mox.StubOutWithMock(image_utils, 'fix_vhd_chain')
|
||||||
mox.StubOutWithMock(image_utils, 'coalesce_chain')
|
mox.StubOutWithMock(image_utils, 'coalesce_chain')
|
||||||
mox.StubOutWithMock(image_utils.os, 'unlink')
|
mox.StubOutWithMock(image_utils.os, 'unlink')
|
||||||
|
mox.StubOutWithMock(fileutils, 'delete_if_exists')
|
||||||
mox.StubOutWithMock(image_utils, 'rename_file')
|
mox.StubOutWithMock(image_utils, 'rename_file')
|
||||||
|
|
||||||
image_utils.temporary_dir().AndReturn(fake_context('somedir'))
|
image_utils.temporary_dir().AndReturn(fake_context('somedir'))
|
||||||
@ -715,7 +717,7 @@ class TestXenServerImageToCoalescedVhd(test.TestCase):
|
|||||||
image_utils.fix_vhd_chain(['somedir/0.vhd', 'somedir/1.vhd'])
|
image_utils.fix_vhd_chain(['somedir/0.vhd', 'somedir/1.vhd'])
|
||||||
image_utils.coalesce_chain(
|
image_utils.coalesce_chain(
|
||||||
['somedir/0.vhd', 'somedir/1.vhd']).AndReturn('somedir/1.vhd')
|
['somedir/0.vhd', 'somedir/1.vhd']).AndReturn('somedir/1.vhd')
|
||||||
image_utils.os.unlink('image')
|
fileutils.delete_if_exists('image')
|
||||||
image_utils.rename_file('somedir/1.vhd', 'image')
|
image_utils.rename_file('somedir/1.vhd', 'image')
|
||||||
|
|
||||||
mox.ReplayAll()
|
mox.ReplayAll()
|
||||||
|
@ -1,225 +0,0 @@
|
|||||||
|
|
||||||
# Copyright 2011 Piston Cloud Computing, Inc.
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
"""Test of Policy Engine For Cinder."""
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
import urllib2
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
import six
|
|
||||||
|
|
||||||
from cinder import context
|
|
||||||
from cinder import exception
|
|
||||||
import cinder.openstack.common.policy
|
|
||||||
from cinder.openstack.common import policy as common_policy
|
|
||||||
from cinder import policy
|
|
||||||
from cinder import test
|
|
||||||
from cinder import utils
|
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyFileTestCase(test.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(PolicyFileTestCase, self).setUp()
|
|
||||||
# since is_admin is defined by policy, create context before reset
|
|
||||||
self.context = context.RequestContext('fake', 'fake')
|
|
||||||
policy.reset()
|
|
||||||
self.target = {}
|
|
||||||
self.addCleanup(policy.reset)
|
|
||||||
|
|
||||||
def test_modified_policy_reloads(self):
|
|
||||||
with utils.tempdir() as tmpdir:
|
|
||||||
tmpfilename = os.path.join(tmpdir, 'policy')
|
|
||||||
self.flags(policy_file=tmpfilename)
|
|
||||||
|
|
||||||
action = "example:test"
|
|
||||||
with open(tmpfilename, "w") as policyfile:
|
|
||||||
policyfile.write("""{"example:test": []}""")
|
|
||||||
policy.enforce(self.context, action, self.target)
|
|
||||||
with open(tmpfilename, "w") as policyfile:
|
|
||||||
policyfile.write("""{"example:test": ["false:false"]}""")
|
|
||||||
# NOTE(vish): reset stored policy cache so we don't have to
|
|
||||||
# sleep(1)
|
|
||||||
policy._POLICY_CACHE = {}
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, self.target)
|
|
||||||
|
|
||||||
|
|
||||||
class PolicyTestCase(test.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(PolicyTestCase, self).setUp()
|
|
||||||
policy.reset()
|
|
||||||
# NOTE(vish): preload rules to circumvent reloading from file
|
|
||||||
policy.init()
|
|
||||||
rules = {
|
|
||||||
"true": [],
|
|
||||||
"example:allowed": [],
|
|
||||||
"example:denied": [["false:false"]],
|
|
||||||
"example:get_http": [["http:http://www.example.com"]],
|
|
||||||
"example:my_file": [["role:compute_admin"],
|
|
||||||
["project_id:%(project_id)s"]],
|
|
||||||
"example:early_and_fail": [["false:false", "rule:true"]],
|
|
||||||
"example:early_or_success": [["rule:true"], ["false:false"]],
|
|
||||||
"example:lowercase_admin": [["role:admin"], ["role:sysadmin"]],
|
|
||||||
"example:uppercase_admin": [["role:ADMIN"], ["role:sysadmin"]],
|
|
||||||
}
|
|
||||||
# NOTE(vish): then overload underlying brain
|
|
||||||
common_policy.set_brain(common_policy.Brain(rules))
|
|
||||||
self.context = context.RequestContext('fake', 'fake', roles=['member'])
|
|
||||||
self.target = {}
|
|
||||||
self.addCleanup(policy.reset)
|
|
||||||
|
|
||||||
def test_enforce_nonexistent_action_throws(self):
|
|
||||||
action = "example:noexist"
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, self.target)
|
|
||||||
|
|
||||||
def test_enforce_bad_action_throws(self):
|
|
||||||
action = "example:denied"
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, self.target)
|
|
||||||
|
|
||||||
def test_enforce_good_action(self):
|
|
||||||
action = "example:allowed"
|
|
||||||
policy.enforce(self.context, action, self.target)
|
|
||||||
|
|
||||||
def test_enforce_http_true(self):
|
|
||||||
|
|
||||||
def fakeurlopen(url, post_data):
|
|
||||||
return six.StringIO("True")
|
|
||||||
self.stubs.Set(urllib2, 'urlopen', fakeurlopen)
|
|
||||||
action = "example:get_http"
|
|
||||||
target = {}
|
|
||||||
result = policy.enforce(self.context, action, target)
|
|
||||||
self.assertIsNone(result)
|
|
||||||
|
|
||||||
def test_enforce_http_false(self):
|
|
||||||
|
|
||||||
def fakeurlopen(url, post_data):
|
|
||||||
return six.StringIO("False")
|
|
||||||
self.stubs.Set(urllib2, 'urlopen', fakeurlopen)
|
|
||||||
action = "example:get_http"
|
|
||||||
target = {}
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, target)
|
|
||||||
|
|
||||||
def test_templatized_enforcement(self):
|
|
||||||
target_mine = {'project_id': 'fake'}
|
|
||||||
target_not_mine = {'project_id': 'another'}
|
|
||||||
action = "example:my_file"
|
|
||||||
policy.enforce(self.context, action, target_mine)
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, target_not_mine)
|
|
||||||
|
|
||||||
def test_early_AND_enforcement(self):
|
|
||||||
action = "example:early_and_fail"
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, action, self.target)
|
|
||||||
|
|
||||||
def test_early_OR_enforcement(self):
|
|
||||||
action = "example:early_or_success"
|
|
||||||
policy.enforce(self.context, action, self.target)
|
|
||||||
|
|
||||||
def test_ignore_case_role_check(self):
|
|
||||||
lowercase_action = "example:lowercase_admin"
|
|
||||||
uppercase_action = "example:uppercase_admin"
|
|
||||||
# NOTE(dprince) we mix case in the Admin role here to ensure
|
|
||||||
# case is ignored
|
|
||||||
admin_context = context.RequestContext('admin',
|
|
||||||
'fake',
|
|
||||||
roles=['AdMiN'])
|
|
||||||
policy.enforce(admin_context, lowercase_action, self.target)
|
|
||||||
policy.enforce(admin_context, uppercase_action, self.target)
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultPolicyTestCase(test.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(DefaultPolicyTestCase, self).setUp()
|
|
||||||
policy.reset()
|
|
||||||
policy.init()
|
|
||||||
|
|
||||||
self.rules = {
|
|
||||||
"default": [],
|
|
||||||
"example:exist": [["false:false"]]
|
|
||||||
}
|
|
||||||
|
|
||||||
self._set_brain('default')
|
|
||||||
|
|
||||||
self.context = context.RequestContext('fake', 'fake')
|
|
||||||
|
|
||||||
self.addCleanup(policy.reset)
|
|
||||||
|
|
||||||
def _set_brain(self, default_rule):
|
|
||||||
brain = cinder.openstack.common.policy.Brain(self.rules,
|
|
||||||
default_rule)
|
|
||||||
cinder.openstack.common.policy.set_brain(brain)
|
|
||||||
|
|
||||||
def test_policy_called(self):
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, "example:exist", {})
|
|
||||||
|
|
||||||
def test_not_found_policy_calls_default(self):
|
|
||||||
policy.enforce(self.context, "example:noexist", {})
|
|
||||||
|
|
||||||
def test_default_not_found(self):
|
|
||||||
self._set_brain("default_noexist")
|
|
||||||
self.assertRaises(exception.PolicyNotAuthorized, policy.enforce,
|
|
||||||
self.context, "example:noexist", {})
|
|
||||||
|
|
||||||
|
|
||||||
class ContextIsAdminPolicyTestCase(test.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(ContextIsAdminPolicyTestCase, self).setUp()
|
|
||||||
policy.reset()
|
|
||||||
policy.init()
|
|
||||||
|
|
||||||
def test_default_admin_role_is_admin(self):
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['johnny-admin'])
|
|
||||||
self.assertFalse(ctx.is_admin)
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['admin'])
|
|
||||||
self.assertTrue(ctx.is_admin)
|
|
||||||
|
|
||||||
def test_custom_admin_role_is_admin(self):
|
|
||||||
# define explicit rules for context_is_admin
|
|
||||||
rules = {
|
|
||||||
'context_is_admin': [["role:administrator"], ["role:johnny-admin"]]
|
|
||||||
}
|
|
||||||
brain = common_policy.Brain(rules, CONF.policy_default_rule)
|
|
||||||
common_policy.set_brain(brain)
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['johnny-admin'])
|
|
||||||
self.assertTrue(ctx.is_admin)
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['administrator'])
|
|
||||||
self.assertTrue(ctx.is_admin)
|
|
||||||
# default rule no longer applies
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['admin'])
|
|
||||||
self.assertFalse(ctx.is_admin)
|
|
||||||
|
|
||||||
def test_context_is_admin_undefined(self):
|
|
||||||
rules = {
|
|
||||||
"admin_or_owner": [["role:admin"], ["project_id:%(project_id)s"]],
|
|
||||||
"default": [["rule:admin_or_owner"]],
|
|
||||||
}
|
|
||||||
brain = common_policy.Brain(rules, CONF.policy_default_rule)
|
|
||||||
common_policy.set_brain(brain)
|
|
||||||
ctx = context.RequestContext('fake', 'fake')
|
|
||||||
self.assertFalse(ctx.is_admin)
|
|
||||||
ctx = context.RequestContext('fake', 'fake', roles=['admin'])
|
|
||||||
self.assertTrue(ctx.is_admin)
|
|
@ -367,31 +367,6 @@ class GenericUtilsTestCase(test.TestCase):
|
|||||||
CONF.glance_port)
|
CONF.glance_port)
|
||||||
self.assertEqual(generated_url, actual_url)
|
self.assertEqual(generated_url, actual_url)
|
||||||
|
|
||||||
@mock.patch('__builtin__.open')
|
|
||||||
@mock.patch('os.path.getmtime', return_value=1)
|
|
||||||
def test_read_cached_file(self, mock_mtime, mock_open):
|
|
||||||
fake_file = "/this/is/a/fake"
|
|
||||||
cache_data = {"data": 1123, "mtime": 2}
|
|
||||||
mock_open.return_value = _get_local_mock_open()
|
|
||||||
data = utils.read_cached_file(fake_file, cache_data)
|
|
||||||
self.assertEqual(cache_data["data"], data)
|
|
||||||
mock_open.assert_called_once_with(fake_file)
|
|
||||||
|
|
||||||
@mock.patch('__builtin__.open')
|
|
||||||
@mock.patch('os.path.getmtime', return_value=1)
|
|
||||||
def test_read_modified_cached_file(self, mock_mtime, mock_open):
|
|
||||||
fake_data = 'lorem ipsum'
|
|
||||||
fake_file = "/this/is/a/fake"
|
|
||||||
mock_open.return_value = _get_local_mock_open(fake_data)
|
|
||||||
cache_data = {"data": 'original data', "mtime": 2}
|
|
||||||
mock_reload = mock.Mock()
|
|
||||||
data = utils.read_cached_file(fake_file,
|
|
||||||
cache_data,
|
|
||||||
reload_func=mock_reload)
|
|
||||||
self.assertEqual(data, fake_data)
|
|
||||||
mock_reload.assert_called_once_with(fake_data)
|
|
||||||
mock_open.assert_called_once_with(fake_file)
|
|
||||||
|
|
||||||
def test_read_file_as_root(self):
|
def test_read_file_as_root(self):
|
||||||
def fake_execute(*args, **kwargs):
|
def fake_execute(*args, **kwargs):
|
||||||
if args[1] == 'bad':
|
if args[1] == 'bad':
|
||||||
|
@ -3965,15 +3965,10 @@ class VolumePolicyTestCase(test.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(VolumePolicyTestCase, self).setUp()
|
super(VolumePolicyTestCase, self).setUp()
|
||||||
|
|
||||||
cinder.policy.reset()
|
|
||||||
cinder.policy.init()
|
cinder.policy.init()
|
||||||
|
|
||||||
self.context = context.get_admin_context()
|
self.context = context.get_admin_context()
|
||||||
self.stubs.Set(brick_lvm.LVM, '_vg_exists', lambda x: True)
|
self.stubs.Set(brick_lvm.LVM, '_vg_exists', lambda x: True)
|
||||||
self.addCleanup(cinder.policy.reset)
|
|
||||||
|
|
||||||
def _set_rules(self, rules):
|
|
||||||
cinder.common.policy.set_brain(cinder.common.policy.Brain(rules))
|
|
||||||
|
|
||||||
def test_check_policy(self):
|
def test_check_policy(self):
|
||||||
self.mox.StubOutWithMock(cinder.policy, 'enforce')
|
self.mox.StubOutWithMock(cinder.policy, 'enforce')
|
||||||
|
@ -284,7 +284,6 @@ class TestWindowsDriver(test.TestCase):
|
|||||||
mox.IgnoreArg())
|
mox.IgnoreArg())
|
||||||
windows_utils.WindowsUtils.change_disk_status(volume['name'],
|
windows_utils.WindowsUtils.change_disk_status(volume['name'],
|
||||||
mox.IsA(bool))
|
mox.IsA(bool))
|
||||||
os.unlink(mox.IsA(str))
|
|
||||||
vhdutils.VHDUtils.convert_vhd(fake_temp_path,
|
vhdutils.VHDUtils.convert_vhd(fake_temp_path,
|
||||||
fake_volume_path,
|
fake_volume_path,
|
||||||
constants.VHD_TYPE_FIXED)
|
constants.VHD_TYPE_FIXED)
|
||||||
|
@ -493,26 +493,6 @@ def sanitize_hostname(hostname):
|
|||||||
return hostname
|
return hostname
|
||||||
|
|
||||||
|
|
||||||
def read_cached_file(filename, cache_info, reload_func=None):
|
|
||||||
"""Read from a file if it has been modified.
|
|
||||||
|
|
||||||
:param cache_info: dictionary to hold opaque cache.
|
|
||||||
:param reload_func: optional function to be called with data when
|
|
||||||
file is reloaded due to a modification.
|
|
||||||
|
|
||||||
:returns: data from file
|
|
||||||
|
|
||||||
"""
|
|
||||||
mtime = os.path.getmtime(filename)
|
|
||||||
if not cache_info or mtime != cache_info.get('mtime'):
|
|
||||||
with open(filename) as fap:
|
|
||||||
cache_info['data'] = fap.read()
|
|
||||||
cache_info['mtime'] = mtime
|
|
||||||
if reload_func:
|
|
||||||
reload_func(cache_info['data'])
|
|
||||||
return cache_info['data']
|
|
||||||
|
|
||||||
|
|
||||||
def hash_file(file_like_object):
|
def hash_file(file_like_object):
|
||||||
"""Generate a hash for the contents of a file."""
|
"""Generate a hash for the contents of a file."""
|
||||||
checksum = hashlib.sha1()
|
checksum = hashlib.sha1()
|
||||||
|
@ -202,17 +202,6 @@
|
|||||||
#fatal_exception_format_errors=false
|
#fatal_exception_format_errors=false
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in cinder.policy
|
|
||||||
#
|
|
||||||
|
|
||||||
# JSON file representing policy (string value)
|
|
||||||
#policy_file=policy.json
|
|
||||||
|
|
||||||
# Rule checked when requested rule is not found (string value)
|
|
||||||
#policy_default_rule=default
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Options defined in cinder.quota
|
# Options defined in cinder.quota
|
||||||
#
|
#
|
||||||
@ -855,6 +844,18 @@
|
|||||||
#run_external_periodic_tasks=true
|
#run_external_periodic_tasks=true
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Options defined in cinder.openstack.common.policy
|
||||||
|
#
|
||||||
|
|
||||||
|
# The JSON file that defines policies. (string value)
|
||||||
|
#policy_file=policy.json
|
||||||
|
|
||||||
|
# Default rule. Enforced when a requested rule is not found.
|
||||||
|
# (string value)
|
||||||
|
#policy_default_rule=default
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Options defined in cinder.scheduler.driver
|
# Options defined in cinder.scheduler.driver
|
||||||
#
|
#
|
||||||
|
@ -1,77 +1,77 @@
|
|||||||
{
|
{
|
||||||
"context_is_admin": [["role:admin"]],
|
"context_is_admin": "role:admin",
|
||||||
"admin_or_owner": [["is_admin:True"], ["project_id:%(project_id)s"]],
|
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
|
||||||
"default": [["rule:admin_or_owner"]],
|
"default": "rule:admin_or_owner",
|
||||||
|
|
||||||
"admin_api": [["is_admin:True"]],
|
"admin_api": "is_admin:True",
|
||||||
|
|
||||||
"volume:create": [],
|
"volume:create": "",
|
||||||
"volume:get_all": [],
|
"volume:get_all": "",
|
||||||
"volume:get_volume_metadata": [],
|
"volume:get_volume_metadata": "",
|
||||||
"volume:get_volume_admin_metadata": [["rule:admin_api"]],
|
"volume:get_volume_admin_metadata": "rule:admin_api",
|
||||||
"volume:delete_volume_admin_metadata": [["rule:admin_api"]],
|
"volume:delete_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": [],
|
"volume:get_snapshot": "",
|
||||||
"volume:get_all_snapshots": [],
|
"volume:get_all_snapshots": "",
|
||||||
"volume:extend": [],
|
"volume:extend": "",
|
||||||
"volume:update_readonly_flag": [],
|
"volume:update_readonly_flag": "",
|
||||||
"volume:retype": [],
|
"volume:retype": "",
|
||||||
|
|
||||||
"volume_extension:types_manage": [["rule:admin_api"]],
|
"volume_extension:types_manage": "rule:admin_api",
|
||||||
"volume_extension:types_extra_specs": [["rule:admin_api"]],
|
"volume_extension:types_extra_specs": "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": [],
|
"volume_extension:extended_snapshot_attributes": "",
|
||||||
"volume_extension:volume_image_metadata": [],
|
"volume_extension:volume_image_metadata": "",
|
||||||
|
|
||||||
"volume_extension:quotas:show": [],
|
"volume_extension:quotas:show": "",
|
||||||
"volume_extension:quotas:update": [["rule:admin_api"]],
|
"volume_extension:quotas:update": "rule:admin_api",
|
||||||
"volume_extension:quota_classes": [],
|
"volume_extension:quota_classes": "",
|
||||||
|
|
||||||
"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:snapshot_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:snapshot_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",
|
||||||
|
|
||||||
"volume_extension:volume_host_attribute": [["rule:admin_api"]],
|
"volume_extension:volume_host_attribute": "rule:admin_api",
|
||||||
"volume_extension:volume_tenant_attribute": [["rule:admin_or_owner"]],
|
"volume_extension:volume_tenant_attribute": "rule:admin_or_owner",
|
||||||
"volume_extension:volume_mig_status_attribute": [["rule:admin_api"]],
|
"volume_extension:volume_mig_status_attribute": "rule:admin_api",
|
||||||
"volume_extension:hosts": [["rule:admin_api"]],
|
"volume_extension:hosts": "rule:admin_api",
|
||||||
"volume_extension:services": [["rule:admin_api"]],
|
"volume_extension:services": "rule:admin_api",
|
||||||
|
|
||||||
"volume_extension:volume_manage": [["rule:admin_api"]],
|
"volume_extension:volume_manage": "rule:admin_api",
|
||||||
"volume_extension:volume_unmanage": [["rule:admin_api"]],
|
"volume_extension:volume_unmanage": "rule:admin_api",
|
||||||
|
|
||||||
"volume:services": [["rule:admin_api"]],
|
"volume:services": "rule:admin_api",
|
||||||
|
|
||||||
"volume:create_transfer": [],
|
"volume:create_transfer": "",
|
||||||
"volume:accept_transfer": [],
|
"volume:accept_transfer": "",
|
||||||
"volume:delete_transfer": [],
|
"volume:delete_transfer": "",
|
||||||
"volume:get_all_transfers": [],
|
"volume:get_all_transfers": "",
|
||||||
|
|
||||||
"volume_extension:replication:promote": ["rule:admin_api"],
|
"volume_extension:replication:promote": "rule:admin_api",
|
||||||
"volume_extension:replication:reenable": ["rule:admin_api"],
|
"volume_extension:replication:reenable": "rule:admin_api",
|
||||||
|
|
||||||
"backup:create" : [],
|
"backup:create" : "",
|
||||||
"backup:delete": [],
|
"backup:delete": "",
|
||||||
"backup:get": [],
|
"backup:get": "",
|
||||||
"backup:get_all": [],
|
"backup:get_all": "",
|
||||||
"backup:restore": [],
|
"backup:restore": "",
|
||||||
"backup:backup-import": [["rule:admin_api"]],
|
"backup:backup-import": "rule:admin_api",
|
||||||
"backup:backup-export": [["rule:admin_api"]],
|
"backup:backup-export": "rule:admin_api",
|
||||||
|
|
||||||
"snapshot_extension:snapshot_actions:update_snapshot_status": [],
|
"snapshot_extension:snapshot_actions:update_snapshot_status": "",
|
||||||
|
|
||||||
"consistencygroup:create" : [["group:nobody"]],
|
"consistencygroup:create" : "group:nobody",
|
||||||
"consistencygroup:delete": [["group:nobody"]],
|
"consistencygroup:delete": "group:nobody",
|
||||||
"consistencygroup:get": [["group:nobody"]],
|
"consistencygroup:get": "group:nobody",
|
||||||
"consistencygroup:get_all": [["group:nobody"]],
|
"consistencygroup:get_all": "group:nobody",
|
||||||
|
|
||||||
"consistencygroup:create_cgsnapshot" : [],
|
"consistencygroup:create_cgsnapshot" : "",
|
||||||
"consistencygroup:delete_cgsnapshot": [],
|
"consistencygroup:delete_cgsnapshot": "",
|
||||||
"consistencygroup:get_cgsnapshot": [],
|
"consistencygroup:get_cgsnapshot": "",
|
||||||
"consistencygroup:get_all_cgsnapshots": []
|
"consistencygroup:get_all_cgsnapshots": ""
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user