Update oslo policy and its dependencies

This updates to commit 95a3b40004f88c096a9943ce41907eab0d4dae7a the
policy module and its dependencies:
- excutils
- fileutils
- policy

2b966f9 Fix deletion of cached file for policy enforcer
8202a96 Merge "Make policy debug logging less verbose"
238e601 Make policy debug logging less verbose
9c88dc3 file_open: fixed docstring to refer to open() instead of file()
6c7407b fileutils: port to Python 3
fe3389e Improve help strings
33a2cee save_and_reraise_exception: make logging respect the reraise parameter
15722f1 Adds a flag to determine whether to reload the rules in policy
dacc065 Merge "Update oslo log messages with translation domains"
5d1f15a Documenting policy.json syntax
fcf517d Update oslo log messages with translation domains
b59cfd9 Merge "Allow policy.json resource vs constant check"
e038d89 Fix policy tests for parallel testing
0da5de6 Allow policy.json resource vs constant check
e4b2334 Replaces use of urlutils with six in policy module
e71cd1a Merge "Trivial: Make vertical white space after license header consistent"
8b2b0b7 Use hacking import_exceptions for gettextutils._
6d0a6c3 Correct invalid docstrings
6fa29ae Trivial: Make vertical white space after license header consistent
0d8f18b Use urlutils functions instead of urllib/urllib2
12bcdb7 Remove vim header
9ef9fec Use six.string_type instead of basestring
4bfb7a2 Apply six for metaclass
1538c80 ConfigFileNotFoundError with proper argument
477bf7a Add utils for creating tempfile
33533b0 Keystone user can't perform revoke_token
d602070 Merge "excutils: replace unicode by six.u"
2ad95e4 parameterize fileutils removal functions
d3b6e97 excutils: replace unicode by six.u
e35e166 excutils: use six.reraise to re-raise
14ba138 Merge "Fix wrong argument in openstack common policy"
64bb5e2 Fix wrong argument in openstack common policy
b7edc99 Fix missing argument bug in oslo common policy
96d1f88 Merge "BaseException.message is deprecated since Python 2.6"
f58c936 Merge "Fix policy default_rule issue"
3626b6d Fix policy default_rule issue
df3f2ba BaseException.message is deprecated since Python 2.6
7bf8ee9 Allow use of hacking 0.6.0 and enable new checks
d74ac1d Merge "Fix missing argument bug in oslo common policy"
e4ac367 Fix missing argument bug in oslo common policy
1a2df89 Enable H302 hacking check
323e465 Add conditional exception reraise
22ec8ff Make AMQP based RPC consumer threads more robust
7119e29 Enable hacking H404 test.
4246ce0 Added common code into fileutils and strutils.
21ee25f Add common code for fileutils.
6d27681 Enable H306 hacking check.
1091b4f Reduce duplicated code related to policies
a514693 Removes len() on empty sequence evaluation
fde1e15 Convert unicode for python3 portability
e700d92 Replaces standard logging with common logging
65e3d8c update OpenStack, LLC to OpenStack Foundation
547ab34 Fix Copyright Headers - Rename LLC to Foundation
9e5912f Fix pep8 E125 errors.
6d102bc Provide i18n to those messages without _()
9a8c1d7 Move nova's util.synchronized decorator to openstack common.
f182936 Merge "Revert "Add support for finer-grained policy decisions""
76751a6 Revert "Add support for finer-grained policy decisions"
8b585cb Remove an unneeded 'global'
3fc4689 Add support for finer-grained policy decisions
21b69d8 Add a 'not' operator to the policy langage
fa7dc58 Add a new policy language
8c6e7a7 Remove deprecated policy engine APIs

Change-Id: Iddca4243d312c9cd768588753af49dde068d5e4b
Co-Authored-By: Jordan Pittier <jordan.pittier@cloudwatt.com>
This commit is contained in:
Julien Danjou 2014-03-05 17:24:54 +01:00
parent e5e61bf7ce
commit e8002b1cac
14 changed files with 1067 additions and 722 deletions

View File

@ -24,7 +24,7 @@ import traceback
import six
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common.gettextutils import _LE
class save_and_reraise_exception(object):
@ -49,9 +49,22 @@ class save_and_reraise_exception(object):
decide_if_need_reraise()
if not should_be_reraised:
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):
self.reraise = True
def __init__(self, reraise=True):
self.reraise = reraise
def __enter__(self):
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):
if exc_type is not None:
logging.error(_('Original exception being dropped: %s'),
traceback.format_exception(self.type_,
self.value,
self.tb))
if self.reraise:
logging.error(_LE('Original exception being dropped: %s'),
traceback.format_exception(self.type_,
self.value,
self.tb))
return False
if self.reraise:
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
this_exc_message != last_exc_message):
logging.exception(
_('Unexpected exception occurred %d time(s)... '
'retrying.') % exc_count)
_LE('Unexpected exception occurred %d time(s)... '
'retrying.') % exc_count)
last_log_time = cur_time
last_exc_message = this_exc_message
exc_count = 0

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack Foundation.
# All Rights Reserved.
#
@ -15,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
import errno
import os
import tempfile
from cinder.openstack.common import excutils
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@ -53,15 +50,15 @@ def read_cached_file(filename, force_reload=False):
"""
global _FILE_CACHE
if force_reload and filename in _FILE_CACHE:
del _FILE_CACHE[filename]
if force_reload:
delete_cached_file(filename)
reloaded = False
mtime = os.path.getmtime(filename)
cache_info = _FILE_CACHE.setdefault(filename, {})
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:
cache_info['data'] = fap.read()
cache_info['mtime'] = mtime
@ -69,42 +66,81 @@ def read_cached_file(filename, force_reload=False):
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.
:param path: File to delete
:param remove: Optional function to remove passed path
"""
try:
os.unlink(path)
remove(path)
except OSError as e:
if e.errno == errno.ENOENT:
return
else:
if e.errno != errno.ENOENT:
raise
@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.
Any exception will cause PATH to be removed.
:param path: File to work with
:param remove: Optional function to remove passed path
"""
try:
yield
except Exception:
with excutils.save_and_reraise_exception():
delete_if_exists(path)
remove(path)
def file_open(*args, **kwargs):
"""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
be able to provide a stub module that doesn't alter system
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

View File

@ -19,46 +19,17 @@
from oslo.config import cfg
from cinder import exception
from cinder.i18n import _
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.register_opts(policy_opts)
_POLICY_PATH = None
_POLICY_CACHE = {}
def reset():
global _POLICY_PATH
global _POLICY_CACHE
_POLICY_PATH = None
_POLICY_CACHE = {}
policy.reset()
_ENFORCER = None
def init():
global _POLICY_PATH
global _POLICY_CACHE
if not _POLICY_PATH:
_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))
global _ENFORCER
if not _ENFORCER:
_ENFORCER = policy.Enforcer()
def enforce_action(context, action):
@ -68,11 +39,8 @@ def enforce_action(context, action):
applied to the given action using the policy enforcement api.
"""
target = {
'project_id': context.project_id,
'user_id': context.user_id,
}
enforce(context, action, target)
return enforce(context, action, {'project_id': context.project_id,
'user_id': context.user_id})
def enforce(context, action, target):
@ -89,16 +57,15 @@ def enforce(context, action, target):
for object creation this should be a dictionary representing the
location of the object e.g. ``{'project_id': context.project_id}``
:raises cinder.exception.PolicyNotAuthorized: if verification fails.
:raises PolicyNotAuthorized: if verification fails.
"""
init()
match_list = ('rule:%s' % action,)
credentials = context.to_dict()
policy.enforce(match_list, target, credentials,
exception.PolicyNotAuthorized, action=action)
return _ENFORCER.enforce(action, target, context.to_dict(),
do_raise=True,
exc=exception.PolicyNotAuthorized,
action=action)
def check_is_admin(roles):
@ -107,8 +74,6 @@ def check_is_admin(roles):
"""
init()
action = 'context_is_admin'
match_list = ('rule:%s' % action,)
# include project_id on target to avoid KeyError if context_is_admin
# policy definition is missing, and default admin_or_owner rule
# attempts to apply. Since our credentials dict does not include a
@ -116,4 +81,4 @@ def check_is_admin(roles):
target = {'project_id': ''}
credentials = {'roles': roles}
return policy.enforce(match_list, target, credentials)
return _ENFORCER.enforce('context_is_admin', target, credentials)

View File

@ -187,6 +187,15 @@ class TestCase(testtools.TestCase):
CONF.set_override('fatal_exception_format_errors', True)
# This will be cleaned up by the NestedTempfile fixture
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):
"""Runs after each test method to tear down test environment."""

View File

@ -1,92 +1,92 @@
{
"context_is_admin": [["role:admin"]],
"admin_api": [["is_admin:True"]],
"admin_or_owner": [["is_admin:True"], ["project_id:%(project_id)s"]],
"context_is_admin": "role:admin",
"admin_api": "is_admin:True",
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
"volume:create": [],
"volume:get": [["rule:admin_or_owner"]],
"volume:get_all": [],
"volume:get_volume_metadata": [],
"volume:delete_volume_metadata": [],
"volume:update_volume_metadata": [],
"volume:get_volume_admin_metadata": [["rule:admin_api"]],
"volume:delete_volume_admin_metadata": [["rule:admin_api"]],
"volume:update_volume_admin_metadata": [["rule:admin_api"]],
"volume:delete": [],
"volume:update": [],
"volume:attach": [],
"volume:detach": [],
"volume:reserve_volume": [],
"volume:unreserve_volume": [],
"volume:begin_detaching": [],
"volume:roll_detaching": [],
"volume:initialize_connection": [],
"volume:terminate_connection": [],
"volume:create_snapshot": [],
"volume:delete_snapshot": [],
"volume:get_snapshot": [],
"volume:get_all_snapshots": [],
"volume:update_snapshot": [],
"volume:extend": [],
"volume:migrate_volume": [["rule:admin_api"]],
"volume:migrate_volume_completion": [["rule:admin_api"]],
"volume:update_readonly_flag": [],
"volume:retype": [],
"volume:copy_volume_to_image": [],
"volume:create": "",
"volume:get": "rule:admin_or_owner",
"volume:get_all": "",
"volume:get_volume_metadata": "",
"volume:delete_volume_metadata": "",
"volume:update_volume_metadata": "",
"volume:get_volume_admin_metadata": "rule:admin_api",
"volume:delete_volume_admin_metadata": "rule:admin_api",
"volume:update_volume_admin_metadata": "rule:admin_api",
"volume:delete": "",
"volume:update": "",
"volume:attach": "",
"volume:detach": "",
"volume:reserve_volume": "",
"volume:unreserve_volume": "",
"volume:begin_detaching": "",
"volume:roll_detaching": "",
"volume:initialize_connection": "",
"volume:terminate_connection": "",
"volume:create_snapshot": "",
"volume:delete_snapshot": "",
"volume:get_snapshot": "",
"volume:get_all_snapshots": "",
"volume:update_snapshot": "",
"volume:extend": "",
"volume:migrate_volume": "rule:admin_api",
"volume:migrate_volume_completion": "rule:admin_api",
"volume:update_readonly_flag": "",
"volume:retype": "",
"volume:copy_volume_to_image": "",
"volume_extension:volume_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:snapshot_admin_actions:force_delete": [["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_completion": [["rule:admin_api"]],
"volume_extension:volume_actions:upload_image": [],
"volume_extension:types_manage": [],
"volume_extension:types_extra_specs": [],
"volume_extension:volume_type_encryption": [["rule:admin_api"]],
"volume_extension:volume_encryption_metadata": [["rule:admin_or_owner"]],
"volume_extension:qos_specs_manage": [],
"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": [],
"volume_extension:quotas:delete": [],
"volume_extension:quota_classes": [],
"volume_extension:volume_manage": [["rule:admin_api"]],
"volume_extension:volume_unmanage": [["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: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:migrate_volume": "rule:admin_api",
"volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
"volume_extension:volume_actions:upload_image": "",
"volume_extension:types_manage": "",
"volume_extension:types_extra_specs": "",
"volume_extension:volume_type_encryption": "rule:admin_api",
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:qos_specs_manage": "",
"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": "",
"volume_extension:quotas:delete": "",
"volume_extension:quota_classes": "",
"volume_extension:volume_manage": "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:accept_transfer": [],
"volume:delete_transfer": [],
"volume:get_all_transfers": [],
"volume:create_transfer": "",
"volume:accept_transfer": "",
"volume:delete_transfer": "",
"volume:get_all_transfers": "",
"backup:create" : [],
"backup:delete": [],
"backup:get": [],
"backup:get_all": [],
"backup:restore": [],
"backup:backup-import": [["rule:admin_api"]],
"backup:backup-export": [["rule:admin_api"]],
"backup:create" : "",
"backup:delete": "",
"backup:get": "",
"backup:get_all": "",
"backup:restore": "",
"backup:backup-import": "rule:admin_api",
"backup:backup-export": "rule:admin_api",
"volume_extension:replication:promote": [["rule:admin_api"]],
"volume_extension:replication:reenable": [["rule:admin_api"]],
"volume_extension:replication:promote": "rule:admin_api",
"volume_extension:replication:reenable": "rule:admin_api",
"consistencygroup:create" : [],
"consistencygroup:delete": [],
"consistencygroup:get": [],
"consistencygroup:get_all": [],
"consistencygroup:create" : "",
"consistencygroup:delete": "",
"consistencygroup:get": "",
"consistencygroup:get_all": "",
"consistencygroup:create_cgsnapshot" : [],
"consistencygroup:delete_cgsnapshot": [],
"consistencygroup:get_cgsnapshot": [],
"consistencygroup:get_all_cgsnapshots": []
"consistencygroup:create_cgsnapshot" : "",
"consistencygroup:delete_cgsnapshot": "",
"consistencygroup:get_cgsnapshot": "",
"consistencygroup:get_all_cgsnapshots": ""
}

View File

@ -25,6 +25,7 @@ from oslo.config import cfg
from cinder import context
from cinder import exception
from cinder.image import image_utils
from cinder.openstack.common import fileutils
from cinder.openstack.common import processutils
from cinder.openstack.common import units
from cinder import test
@ -621,10 +622,10 @@ class TestTemporaryFile(test.TestCase):
def test_file_unlinked(self):
mox = self.mox
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.os.unlink('somefile')
fileutils.delete_if_exists('somefile')
mox.ReplayAll()
@ -634,10 +635,10 @@ class TestTemporaryFile(test.TestCase):
def test_file_unlinked_on_error(self):
mox = self.mox
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.os.unlink('somefile')
fileutils.delete_if_exists('somefile')
mox.ReplayAll()
@ -706,6 +707,7 @@ class TestXenServerImageToCoalescedVhd(test.TestCase):
mox.StubOutWithMock(image_utils, 'fix_vhd_chain')
mox.StubOutWithMock(image_utils, 'coalesce_chain')
mox.StubOutWithMock(image_utils.os, 'unlink')
mox.StubOutWithMock(fileutils, 'delete_if_exists')
mox.StubOutWithMock(image_utils, 'rename_file')
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.coalesce_chain(
['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')
mox.ReplayAll()

View File

@ -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)

View File

@ -367,31 +367,6 @@ class GenericUtilsTestCase(test.TestCase):
CONF.glance_port)
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 fake_execute(*args, **kwargs):
if args[1] == 'bad':

View File

@ -3920,15 +3920,10 @@ class VolumePolicyTestCase(test.TestCase):
def setUp(self):
super(VolumePolicyTestCase, self).setUp()
cinder.policy.reset()
cinder.policy.init()
self.context = context.get_admin_context()
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):
self.mox.StubOutWithMock(cinder.policy, 'enforce')

View File

@ -284,7 +284,6 @@ class TestWindowsDriver(test.TestCase):
mox.IgnoreArg())
windows_utils.WindowsUtils.change_disk_status(volume['name'],
mox.IsA(bool))
os.unlink(mox.IsA(str))
vhdutils.VHDUtils.convert_vhd(fake_temp_path,
fake_volume_path,
constants.VHD_TYPE_FIXED)

View File

@ -493,26 +493,6 @@ def sanitize_hostname(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):
"""Generate a hash for the contents of a file."""
checksum = hashlib.sha1()

View File

@ -202,17 +202,6 @@
#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
#
@ -855,6 +844,18 @@
#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
#

View File

@ -1,77 +1,77 @@
{
"context_is_admin": [["role:admin"]],
"admin_or_owner": [["is_admin:True"], ["project_id:%(project_id)s"]],
"default": [["rule:admin_or_owner"]],
"context_is_admin": "role:admin",
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
"default": "rule:admin_or_owner",
"admin_api": [["is_admin:True"]],
"admin_api": "is_admin:True",
"volume:create": [],
"volume:get_all": [],
"volume:get_volume_metadata": [],
"volume:get_volume_admin_metadata": [["rule:admin_api"]],
"volume:delete_volume_admin_metadata": [["rule:admin_api"]],
"volume:update_volume_admin_metadata": [["rule:admin_api"]],
"volume:get_snapshot": [],
"volume:get_all_snapshots": [],
"volume:extend": [],
"volume:update_readonly_flag": [],
"volume:retype": [],
"volume:create": "",
"volume:get_all": "",
"volume:get_volume_metadata": "",
"volume:get_volume_admin_metadata": "rule:admin_api",
"volume:delete_volume_admin_metadata": "rule:admin_api",
"volume:update_volume_admin_metadata": "rule:admin_api",
"volume:get_snapshot": "",
"volume:get_all_snapshots": "",
"volume:extend": "",
"volume:update_readonly_flag": "",
"volume:retype": "",
"volume_extension:types_manage": [["rule:admin_api"]],
"volume_extension:types_extra_specs": [["rule:admin_api"]],
"volume_extension:volume_type_encryption": [["rule:admin_api"]],
"volume_extension:volume_encryption_metadata": [["rule:admin_or_owner"]],
"volume_extension:extended_snapshot_attributes": [],
"volume_extension:volume_image_metadata": [],
"volume_extension:types_manage": "rule:admin_api",
"volume_extension:types_extra_specs": "rule:admin_api",
"volume_extension:volume_type_encryption": "rule:admin_api",
"volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
"volume_extension:extended_snapshot_attributes": "",
"volume_extension:volume_image_metadata": "",
"volume_extension:quotas:show": [],
"volume_extension:quotas:update": [["rule:admin_api"]],
"volume_extension:quota_classes": [],
"volume_extension:quotas:show": "",
"volume_extension:quotas:update": "rule:admin_api",
"volume_extension:quota_classes": "",
"volume_extension:volume_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_detach": [["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_completion": [["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:volume_admin_actions:force_delete": "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:volume_admin_actions:migrate_volume": "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_tenant_attribute": [["rule:admin_or_owner"]],
"volume_extension:volume_mig_status_attribute": [["rule:admin_api"]],
"volume_extension:hosts": [["rule:admin_api"]],
"volume_extension:services": [["rule:admin_api"]],
"volume_extension:volume_host_attribute": "rule:admin_api",
"volume_extension:volume_tenant_attribute": "rule:admin_or_owner",
"volume_extension:volume_mig_status_attribute": "rule:admin_api",
"volume_extension:hosts": "rule:admin_api",
"volume_extension:services": "rule:admin_api",
"volume_extension:volume_manage": [["rule:admin_api"]],
"volume_extension:volume_unmanage": [["rule:admin_api"]],
"volume_extension:volume_manage": "rule:admin_api",
"volume_extension:volume_unmanage": "rule:admin_api",
"volume:services": [["rule:admin_api"]],
"volume:services": "rule:admin_api",
"volume:create_transfer": [],
"volume:accept_transfer": [],
"volume:delete_transfer": [],
"volume:get_all_transfers": [],
"volume:create_transfer": "",
"volume:accept_transfer": "",
"volume:delete_transfer": "",
"volume:get_all_transfers": "",
"volume_extension:replication:promote": ["rule:admin_api"],
"volume_extension:replication:reenable": ["rule:admin_api"],
"volume_extension:replication:promote": "rule:admin_api",
"volume_extension:replication:reenable": "rule:admin_api",
"backup:create" : [],
"backup:delete": [],
"backup:get": [],
"backup:get_all": [],
"backup:restore": [],
"backup:backup-import": [["rule:admin_api"]],
"backup:backup-export": [["rule:admin_api"]],
"backup:create" : "",
"backup:delete": "",
"backup:get": "",
"backup:get_all": "",
"backup:restore": "",
"backup:backup-import": "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:delete": [["group:nobody"]],
"consistencygroup:get": [["group:nobody"]],
"consistencygroup:get_all": [["group:nobody"]],
"consistencygroup:create" : "group:nobody",
"consistencygroup:delete": "group:nobody",
"consistencygroup:get": "group:nobody",
"consistencygroup:get_all": "group:nobody",
"consistencygroup:create_cgsnapshot" : [],
"consistencygroup:delete_cgsnapshot": [],
"consistencygroup:get_cgsnapshot": [],
"consistencygroup:get_all_cgsnapshots": []
"consistencygroup:create_cgsnapshot" : "",
"consistencygroup:delete_cgsnapshot": "",
"consistencygroup:get_cgsnapshot": "",
"consistencygroup:get_all_cgsnapshots": ""
}