summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oslo_policy/policy.py28
-rw-r--r--oslo_policy/tests/test_policy.py54
2 files changed, 79 insertions, 3 deletions
diff --git a/oslo_policy/policy.py b/oslo_policy/policy.py
index 6b7a8ca..943a396 100644
--- a/oslo_policy/policy.py
+++ b/oslo_policy/policy.py
@@ -331,6 +331,7 @@ class Enforcer(object):
self.use_conf = use_conf
self.overwrite = overwrite
self._loaded_files = []
+ self._policy_dir_mtimes = {}
def set_rules(self, rules, overwrite=True, use_conf=False):
"""Create a new :class:`Rules` based on the provided dict of rules.
@@ -357,6 +358,7 @@ class Enforcer(object):
self.default_rule = None
self.policy_path = None
self._loaded_files = []
+ self._policy_dir_mtimes = {}
def load_rules(self, force_reload=False):
"""Loads policy_path's rules.
@@ -380,9 +382,29 @@ class Enforcer(object):
path = self._get_policy_path(path)
except cfg.ConfigFilesNotFoundError:
continue
- self._walk_through_policy_directory(path,
- self._load_policy_file,
- force_reload, False)
+ if (force_reload or self._is_directory_updated(
+ self._policy_dir_mtimes, path)):
+ self._walk_through_policy_directory(path,
+ self._load_policy_file,
+ force_reload, False)
+
+ @staticmethod
+ def _is_directory_updated(cache, path):
+ # Get the current modified time and compare it to what is in
+ # the cache and check if the new mtime is greater than what
+ # is in the cache
+ mtime = 0
+ if os.path.exists(path):
+ # Make a list of all the files
+ files = [path] + [os.path.join(path, file) for file in
+ os.listdir(path)]
+ # Pick the newest one, let's use its time.
+ mtime = os.path.getmtime(max(files, key=os.path.getmtime))
+ cache_info = cache.setdefault(path, {})
+ if mtime > cache_info.get('mtime', 0):
+ cache_info['mtime'] = mtime
+ return True
+ return False
@staticmethod
def _walk_through_policy_directory(path, func, *args):
diff --git a/oslo_policy/tests/test_policy.py b/oslo_policy/tests/test_policy.py
index f1f7ddb..85cbfc9 100644
--- a/oslo_policy/tests/test_policy.py
+++ b/oslo_policy/tests/test_policy.py
@@ -15,10 +15,13 @@
"""Test of Policy Engine"""
+import os
+
import mock
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslotest import base as test_base
+import six
from oslo_policy import _checks
from oslo_policy import _parser
@@ -172,6 +175,56 @@ class EnforcerTest(base.PolicyBaseTestCase):
'policy.d/b.conf',
])
+ def test_load_directory_caching_with_files_updated(self):
+ self.create_config_file('policy.d/a.conf', POLICY_A_CONTENTS)
+
+ self.enforcer.load_rules(False)
+ self.assertIsNotNone(self.enforcer.rules)
+
+ old = six.next(six.itervalues(
+ self.enforcer._policy_dir_mtimes))
+ self.assertEqual(1, len(self.enforcer._policy_dir_mtimes))
+
+ # Touch the file
+ conf_path = os.path.join(self.config_dir, 'policy.d/a.conf')
+ stinfo = os.stat(conf_path)
+ os.utime(conf_path, (stinfo.st_atime + 10, stinfo.st_mtime + 10))
+
+ self.enforcer.load_rules(False)
+ self.assertEqual(1, len(self.enforcer._policy_dir_mtimes))
+ self.assertEqual(old, six.next(six.itervalues(
+ self.enforcer._policy_dir_mtimes)))
+
+ loaded_rules = jsonutils.loads(str(self.enforcer.rules))
+ self.assertEqual('is_admin:True', loaded_rules['admin'])
+ self.check_loaded_files([
+ 'policy.json',
+ 'policy.d/a.conf',
+ 'policy.d/a.conf',
+ ])
+
+ def test_load_directory_caching_with_files_same(self):
+ self.create_config_file('policy.d/a.conf', POLICY_A_CONTENTS)
+
+ self.enforcer.load_rules(False)
+ self.assertIsNotNone(self.enforcer.rules)
+
+ old = six.next(six.itervalues(
+ self.enforcer._policy_dir_mtimes))
+ self.assertEqual(1, len(self.enforcer._policy_dir_mtimes))
+
+ self.enforcer.load_rules(False)
+ self.assertEqual(1, len(self.enforcer._policy_dir_mtimes))
+ self.assertEqual(old, six.next(six.itervalues(
+ self.enforcer._policy_dir_mtimes)))
+
+ loaded_rules = jsonutils.loads(str(self.enforcer.rules))
+ self.assertEqual('is_admin:True', loaded_rules['admin'])
+ self.check_loaded_files([
+ 'policy.json',
+ 'policy.d/a.conf',
+ ])
+
def test_load_multiple_directories(self):
self.create_config_file('policy.d/a.conf', POLICY_A_CONTENTS)
self.create_config_file('policy.d/b.conf', POLICY_B_CONTENTS)
@@ -285,6 +338,7 @@ class EnforcerTest(base.PolicyBaseTestCase):
use_conf=True)
self.enforcer.overwrite = False
+ self.enforcer._is_directory_updated = lambda x, y: True
# Call enforce(), it will load rules from
# policy configuration files, to merge with