Make policy init more threadsafe

In a high concurrency environment, it is possible for the policy
enforcer to be halfway ready, leading to policies not being loaded.
See the linked story for more details on how that can happen.

This change fixes that in two (redundant) ways:

* policy is initialized in the web app at WSGI application
  creation, once, before the web service starts

* The global that contains the _ENFORCER is not changed from
  None to assigned until policy is fully loaded.

Because of the change in when init() happens, the unit
test is changed to not assert the initial state of the
enforcer.

Change-Id: Iae0c5c3ccda7587087606c97c615b9e44e3a68f0
Story: 2005168
Task: 29905
This commit is contained in:
Chris Dent 2019-03-08 16:28:18 +00:00
parent 98f722a603
commit 871b15ef93
3 changed files with 6 additions and 7 deletions

View File

@ -23,6 +23,7 @@ from placement import handler
from placement import microversion
from placement.objects import resource_class
from placement.objects import resource_provider
from placement import policy
from placement import requestlog
from placement import resource_class_cache as rc_cache
from placement import util
@ -122,5 +123,6 @@ def loadapp(config, project_name=NAME):
backwards compatibility
"""
application = deploy(config)
policy.init(config)
update_database(config)
return application

View File

@ -41,10 +41,11 @@ def init(conf):
# to read the policy file from config option [oslo_policy]/policy_file
# which is used by nova. In other words, to have separate policy files
# for placement and nova, we have to use separate policy_file options.
_ENFORCER = policy.Enforcer(
_enforcer = policy.Enforcer(
conf, policy_file=conf.placement.policy_file)
_ENFORCER.register_defaults(policies.list_rules())
_ENFORCER.load_rules()
_enforcer.register_defaults(policies.list_rules())
_enforcer.load_rules()
_ENFORCER = _enforcer
def get_enforcer():
@ -77,7 +78,6 @@ def authorize(context, action, target, do_raise=True):
:returns: non-False value (not necessarily "True") if authorized, and the
exact value False if not authorized and do_raise is False.
"""
init(context.config)
credentials = context.to_policy_values()
try:
# NOTE(mriedem): The "action" kwarg is for the PolicyNotAuthorized exc.

View File

@ -54,9 +54,6 @@ class PlacementPolicyTestCase(testtools.TestCase):
group='placement', policy_file=tmpfilename)
action = 'placement:test'
# Expect PolicyNotRegistered since defaults are not yet loaded.
self.assertRaises(oslo_policy.PolicyNotRegistered,
policy.authorize, self.ctxt, action, self.target)
# Load the default action and rule (defaults to "any").
enforcer = policy._get_enforcer(self.conf_fixture.conf)