diff --git a/placement/cmd/manage.py b/placement/cmd/manage.py index 48dc924d2..d33f3c08a 100644 --- a/placement/cmd/manage.py +++ b/placement/cmd/manage.py @@ -69,19 +69,20 @@ def setup_commands(): def main(): - CONF = conf.CONF + config = cfg.ConfigOpts() + conf.register_opts(config) command_opts = setup_commands() - CONF.register_cli_opts(command_opts) - CONF(sys.argv[1:], project='placement', - version=version_info.version_string(), - default_config_files=None) - db_api.configure(CONF) + config.register_cli_opts(command_opts) + config(sys.argv[1:], project='placement', + version=version_info.version_string(), + default_config_files=None) + db_api.configure(config) try: - func = CONF.command.func + func = config.command.func return_code = func() # If return_code ends up None we assume 0. sys.exit(return_code or 0) except cfg.NoSuchOptError: - CONF.print_help() + config.print_help() sys.exit(1) diff --git a/placement/conf/__init__.py b/placement/conf/__init__.py index a40da7fad..9bac2e802 100644 --- a/placement/conf/__init__.py +++ b/placement/conf/__init__.py @@ -14,18 +14,19 @@ # under the License. from __future__ import absolute_import -from oslo_config import cfg - from placement.conf import api from placement.conf import base from placement.conf import database from placement.conf import paths from placement.conf import placement -CONF = cfg.CONF -api.register_opts(CONF) -base.register_opts(CONF) -database.register_opts(CONF) -paths.register_opts(CONF) -placement.register_opts(CONF) +# To avoid global config, we require an existing ConfigOpts is passed +# to register_opts. Then the caller can have some assurance that the +# config they are using will maintain some independence. +def register_opts(conf): + api.register_opts(conf) + base.register_opts(conf) + database.register_opts(conf) + paths.register_opts(conf) + placement.register_opts(conf) diff --git a/placement/context.py b/placement/context.py index 49535c5af..1a8c9a19f 100644 --- a/placement/context.py +++ b/placement/context.py @@ -20,6 +20,10 @@ from placement import policy @enginefacade.transaction_context_provider class RequestContext(context.RequestContext): + def __init__(self, *args, **kwargs): + self.config = None + super(RequestContext, self).__init__(*args, **kwargs) + def can(self, action, target=None, fatal=True): """Verifies that the given action is valid on the target in this context. diff --git a/placement/db/sqlalchemy/alembic/env.py b/placement/db/sqlalchemy/alembic/env.py index 2d5353095..8602bc855 100644 --- a/placement/db/sqlalchemy/alembic/env.py +++ b/placement/db/sqlalchemy/alembic/env.py @@ -15,15 +15,14 @@ from __future__ import with_statement from logging.config import fileConfig from alembic import context +from oslo_config import cfg +from oslo_db import exception as db_exc from placement import conf from placement.db.sqlalchemy import models from placement import db_api as placement_db -CONF = conf.CONF - - # this is the Alembic Config object, which provides # access to the values within the .ini file in use. config = context.config @@ -45,26 +44,6 @@ target_metadata = models.BASE.metadata # ... etc. -def run_migrations_offline(): - """Run migrations in 'offline' mode. - - This configures the context with just a URL - and not an Engine, though an Engine is acceptable - here as well. By skipping the Engine creation - we don't even need a DBAPI to be available. - - Calls to context.execute() here emit the given string to the - script output. - - """ - url = CONF.placement_database.connection - context.configure( - url=url, target_metadata=target_metadata, literal_binds=True) - - with context.begin_transaction(): - context.run_migrations() - - def run_migrations_online(): """Run migrations in 'online' mode. @@ -72,12 +51,17 @@ def run_migrations_online(): and associate a connection with the context. """ - # If CONF and the database are not already configured, set them up. This - # can happen when using the alembic command line tool. - if not CONF.placement_database.connection: - CONF([], project="placement", default_config_files=None) - placement_db.configure(CONF) - connectable = placement_db.get_placement_engine() + try: + connectable = placement_db.get_placement_engine() + except db_exc.CantStartEngineError: + # We are being called from a context where the database hasn't been + # configured so we need to set up Config and config the database. + # This is usually the alembic command line. + config = cfg.ConfigOpts() + conf.register_opts(config) + config([], project="placement", default_config_files=None) + placement_db.configure(config) + connectable = placement_db.get_placement_engine() with connectable.connect() as connection: context.configure( @@ -87,7 +71,8 @@ def run_migrations_online(): with context.begin_transaction(): context.run_migrations() + if context.is_offline_mode(): - run_migrations_offline() + raise Exception('offline mode disabled') else: run_migrations_online() diff --git a/placement/deploy.py b/placement/deploy.py index b2ec24676..0ffb6fcdb 100644 --- a/placement/deploy.py +++ b/placement/deploy.py @@ -57,7 +57,7 @@ def deploy(conf): fault_middleware = fault_wrap.FaultWrapper request_log = requestlog.RequestLog - application = handler.PlacementHandler() + application = handler.PlacementHandler(config=conf) # configure microversion middleware in the old school way application = microversion_middleware( application, microversion.SERVICE_TYPE, microversion.VERSIONS, diff --git a/placement/handler.py b/placement/handler.py index 3b97ab0ed..da92b993f 100644 --- a/placement/handler.py +++ b/placement/handler.py @@ -192,10 +192,13 @@ class PlacementHandler(object): """ def __init__(self, **local_config): - # NOTE(cdent): Local config currently unused. self._map = make_map(ROUTE_DECLARATIONS) + self.config = local_config['config'] def __call__(self, environ, start_response): + # set a reference to the oslo.config ConfigOpts on the RequestContext + context = environ['placement.context'] + context.config = self.config # Check that an incoming request with a content-length header # that is an integer > 0 and not empty, also has a content-type # header that is not empty. If not raise a 400. diff --git a/placement/handlers/util.py b/placement/handlers/util.py index 732e92ec5..fd3eed1b3 100644 --- a/placement/handlers/util.py +++ b/placement/handlers/util.py @@ -11,7 +11,6 @@ # under the License. """DB Utility methods for placement.""" -from oslo_config import cfg from oslo_log import log as logging import webob @@ -23,7 +22,6 @@ from placement.objects import project as project_obj from placement.objects import user as user_obj -CONF = cfg.CONF LOG = logging.getLogger(__name__) @@ -54,8 +52,8 @@ def ensure_consumer(ctx, consumer_uuid, project_id, user_id, created_new_consumer = False requires_consumer_generation = want_version.matches((1, 28)) if project_id is None: - project_id = CONF.placement.incomplete_consumer_project_id - user_id = CONF.placement.incomplete_consumer_user_id + project_id = ctx.config.placement.incomplete_consumer_project_id + user_id = ctx.config.placement.incomplete_consumer_user_id try: proj = project_obj.Project.get_by_external_id(ctx, project_id) except exception.NotFound: diff --git a/placement/objects/project.py b/placement/objects/project.py index 1f3d4d6cf..147843e5b 100644 --- a/placement/objects/project.py +++ b/placement/objects/project.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg from oslo_db import exception as db_exc from oslo_versionedobjects import base from oslo_versionedobjects import fields @@ -20,7 +19,6 @@ from placement.db.sqlalchemy import models from placement import db_api from placement import exception -CONF = cfg.CONF PROJECT_TBL = models.Project.__table__ @@ -29,7 +27,7 @@ def ensure_incomplete_project(ctx): """Ensures that a project record is created for the "incomplete consumer project". Returns the internal ID of that record. """ - incomplete_id = CONF.placement.incomplete_consumer_project_id + incomplete_id = ctx.config.placement.incomplete_consumer_project_id sel = sa.select([PROJECT_TBL.c.id]).where( PROJECT_TBL.c.external_id == incomplete_id) res = ctx.session.execute(sel).fetchone() diff --git a/placement/objects/resource_provider.py b/placement/objects/resource_provider.py index 33295bdfd..3f2980f84 100644 --- a/placement/objects/resource_provider.py +++ b/placement/objects/resource_provider.py @@ -23,7 +23,6 @@ import random import os_traits from oslo_concurrency import lockutils -from oslo_config import cfg from oslo_db import api as oslo_db_api from oslo_db import exception as db_exc from oslo_log import log as logging @@ -63,7 +62,6 @@ _RC_CACHE = None _TRAIT_LOCK = 'trait_sync' _TRAITS_SYNCED = False -CONF = cfg.CONF LOG = logging.getLogger(__name__) @@ -4014,9 +4012,9 @@ class AllocationCandidates(base.VersionedObject): """Returns an AllocationCandidates object containing all resource providers matching a set of supplied resource constraints, with a set of allocation requests constructed from that list of resource - providers. If CONF.placement.randomize_allocation_candidates is True - (default is False) then the order of the allocation requests will - be randomized. + providers. If CONF.placement.randomize_allocation_candidates (on + contex.config) is True (default is False) then the order of the + allocation requests will be randomized. :param context: Nova RequestContext. :param requests: Dict, keyed by suffix, of placement.lib.RequestGroup @@ -4159,16 +4157,17 @@ class AllocationCandidates(base.VersionedObject): alloc_request_objs, summary_objs = _merge_candidates( candidates, group_policy=group_policy) - return cls._limit_results(alloc_request_objs, summary_objs, limit) + return cls._limit_results(context, alloc_request_objs, summary_objs, + limit) @staticmethod - def _limit_results(alloc_request_objs, summary_objs, limit): + def _limit_results(context, alloc_request_objs, summary_objs, limit): # Limit the number of allocation request objects. We do this after # creating all of them so that we can do a random slice without # needing to mess with the complex sql above or add additional # columns to the DB. if limit and limit < len(alloc_request_objs): - if CONF.placement.randomize_allocation_candidates: + if context.config.placement.randomize_allocation_candidates: alloc_request_objs = random.sample(alloc_request_objs, limit) else: alloc_request_objs = alloc_request_objs[:limit] @@ -4187,7 +4186,7 @@ class AllocationCandidates(base.VersionedObject): continue kept_summary_objs.append(summary) summary_objs = kept_summary_objs - elif CONF.placement.randomize_allocation_candidates: + elif context.config.placement.randomize_allocation_candidates: random.shuffle(alloc_request_objs) return alloc_request_objs, summary_objs diff --git a/placement/objects/user.py b/placement/objects/user.py index 853428e43..8d0c217a5 100644 --- a/placement/objects/user.py +++ b/placement/objects/user.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg from oslo_db import exception as db_exc from oslo_versionedobjects import base from oslo_versionedobjects import fields @@ -20,7 +19,6 @@ from placement.db.sqlalchemy import models from placement import db_api from placement import exception -CONF = cfg.CONF USER_TBL = models.User.__table__ @@ -29,7 +27,7 @@ def ensure_incomplete_user(ctx): """Ensures that a user record is created for the "incomplete consumer user". Returns the internal ID of that record. """ - incomplete_id = CONF.placement.incomplete_consumer_user_id + incomplete_id = ctx.config.placement.incomplete_consumer_user_id sel = sa.select([USER_TBL.c.id]).where( USER_TBL.c.external_id == incomplete_id) res = ctx.session.execute(sel).fetchone() diff --git a/placement/policy.py b/placement/policy.py index 1f223f78a..dbbcccb76 100644 --- a/placement/policy.py +++ b/placement/policy.py @@ -20,7 +20,6 @@ from placement import exception from placement import policies -CONF = cfg.CONF LOG = logging.getLogger(__name__) _ENFORCER_PLACEMENT = None @@ -33,7 +32,7 @@ def reset(): _ENFORCER_PLACEMENT = None -def init(): +def init(conf): """Init an Enforcer class. Sets the _ENFORCER_PLACEMENT global.""" global _ENFORCER_PLACEMENT if not _ENFORCER_PLACEMENT: @@ -43,7 +42,7 @@ def init(): # 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_PLACEMENT = policy.Enforcer( - CONF, policy_file=CONF.placement.policy_file) + conf, policy_file=conf.placement.policy_file) _ENFORCER_PLACEMENT.register_defaults(policies.list_rules()) _ENFORCER_PLACEMENT.load_rules() @@ -53,7 +52,7 @@ def get_enforcer(): # files from overrides on disk and defaults in code. We can just pass an # empty list and let oslo do the config lifting for us. cfg.CONF([], project='placement') - init() + init(cfg.CONF) return _ENFORCER_PLACEMENT @@ -74,7 +73,7 @@ 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() + init(context.config) credentials = context.to_policy_values() try: # NOTE(mriedem): The "action" kwarg is for the PolicyNotAuthorized exc. diff --git a/placement/tests/fixtures.py b/placement/tests/fixtures.py index ef649e166..9b2f29d94 100644 --- a/placement/tests/fixtures.py +++ b/placement/tests/fixtures.py @@ -14,11 +14,14 @@ # License for the specific language governing permissions and limitations # under the License. -"""Fixtures for Nova tests.""" +"""Fixtures for Placement tests.""" from __future__ import absolute_import +import tempfile import fixtures +from oslo_concurrency.fixture import lockutils as lock_fixture +from oslo_concurrency import lockutils from oslo_config import cfg from placement.db.sqlalchemy import migration @@ -27,16 +30,10 @@ from placement import deploy from placement.objects import resource_provider -CONF = cfg.CONF -session_configured = False - - def reset(): """Call this to allow the placement db fixture to be reconfigured in the same process. """ - global session_configured - session_configured = False placement_db.placement_context_manager.dispose_pool() # TODO(cdent): Future handling in sqlalchemy may allow doing this # in a less hacky way. @@ -46,26 +43,25 @@ def reset(): class Database(fixtures.Fixture): - def __init__(self, set_config=False): + def __init__(self, conf_fixture, set_config=False): """Create a database fixture.""" super(Database, self).__init__() - global session_configured - if not session_configured: - if set_config: - try: - CONF.register_opt(cfg.StrOpt('connection'), - group='placement_database') - except cfg.DuplicateOptError: - # already registered - pass - CONF.set_override('connection', 'sqlite://', - group='placement_database') - placement_db.configure(CONF) - session_configured = True + if set_config: + try: + conf_fixture.register_opt( + cfg.StrOpt('connection'), group='placement_database') + except cfg.DuplicateOptError: + # already registered + pass + conf_fixture.config(connection='sqlite://', + group='placement_database') + self.conf_fixture = conf_fixture self.get_engine = placement_db.get_placement_engine def setUp(self): super(Database, self).setUp() + reset() + placement_db.configure(self.conf_fixture.conf) migration.create_schema() resource_provider._TRAITS_SYNCED = False resource_provider._RC_CACHE = None @@ -76,3 +72,15 @@ class Database(fixtures.Fixture): reset() resource_provider._TRAITS_SYNCED = False resource_provider._RC_CACHE = None + + +class ExternalLockFixture(lock_fixture.LockFixture): + """Provide a predictable inter-process file-based lock that doesn't + require oslo.config, by setting its own lock_path. + + This is used to prevent live database test from conflicting with + one another in a concurrent enviornment. + """ + def __init__(self, name): + lock_path = tempfile.gettempdir() + self.mgr = lockutils.lock(name, external=True, lock_path=lock_path) diff --git a/placement/tests/functional/base.py b/placement/tests/functional/base.py index b28f57e63..ed674523e 100644 --- a/placement/tests/functional/base.py +++ b/placement/tests/functional/base.py @@ -16,15 +16,13 @@ from oslo_log.fixture import logging_error from oslotest import output import testtools +from placement import conf from placement import context from placement.tests import fixtures from placement.tests.functional.fixtures import capture from placement.tests.unit import policy_fixture -CONF = cfg.CONF - - class TestCase(testtools.TestCase): """A base test case for placement functional tests. @@ -36,14 +34,14 @@ class TestCase(testtools.TestCase): super(TestCase, self).setUp() # Manage required configuration - conf_fixture = self.useFixture(config_fixture.Config(CONF)) - conf_fixture.config( - group='placement_database', - connection='sqlite://', - sqlite_synchronous=False) - CONF([], default_config_files=[]) + self.conf_fixture = self.useFixture( + config_fixture.Config(cfg.ConfigOpts())) + conf.register_opts(self.conf_fixture.conf) + self.placement_db = self.useFixture(fixtures.Database( + self.conf_fixture, set_config=True)) + self.conf_fixture.conf([], default_config_files=[]) - self.useFixture(policy_fixture.PolicyFixture()) + self.useFixture(policy_fixture.PolicyFixture(self.conf_fixture)) self.useFixture(capture.Logging()) self.useFixture(output.CaptureOutput()) @@ -51,5 +49,5 @@ class TestCase(testtools.TestCase): self.useFixture(capture.WarningsFixture()) self.useFixture(logging_error.get_logging_handle_error_fixture()) - self.placement_db = self.useFixture(fixtures.Database()) self.context = context.RequestContext() + self.context.config = self.conf_fixture.conf diff --git a/placement/tests/functional/db/test_allocation_candidates.py b/placement/tests/functional/db/test_allocation_candidates.py index ad4a9c658..377d71d9c 100644 --- a/placement/tests/functional/db/test_allocation_candidates.py +++ b/placement/tests/functional/db/test_allocation_candidates.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. import os_traits -from oslo_config import cfg from oslo_utils.fixture import uuidsentinel as uuids import six import sqlalchemy as sa @@ -22,9 +21,6 @@ from placement import rc_fields as fields from placement.tests.functional.db import test_base as tb -CONF = cfg.CONF - - class ProviderDBHelperTestCase(tb.PlacementDbBaseTestCase): def test_get_provider_ids_matching(self): @@ -705,8 +701,8 @@ class AllocationCandidatesTestCase(tb.PlacementDbBaseTestCase): # Do it again, with conf set to randomize. We can't confirm the # random-ness but we can be sure the code path doesn't explode. - CONF.set_override('randomize_allocation_candidates', True, - group='placement') + self.conf_fixture.config(randomize_allocation_candidates=True, + group='placement') # Ask for two candidates. limit = 2 diff --git a/placement/tests/functional/db/test_consumer.py b/placement/tests/functional/db/test_consumer.py index 771d59bae..a2f38ac5b 100644 --- a/placement/tests/functional/db/test_consumer.py +++ b/placement/tests/functional/db/test_consumer.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg from oslo_utils.fixture import uuidsentinel as uuids import sqlalchemy as sa @@ -25,7 +24,6 @@ from placement.tests.functional import base from placement.tests.functional.db import test_base as tb -CONF = cfg.CONF CONSUMER_TBL = consumer_obj.CONSUMER_TBL PROJECT_TBL = project_obj.PROJECT_TBL USER_TBL = user_obj.USER_TBL @@ -137,7 +135,8 @@ class CreateIncompleteConsumersTestCase(base.TestCase): @db_api.placement_context_manager.reader def _check_incomplete_consumers(self, ctx): - incomplete_project_id = CONF.placement.incomplete_consumer_project_id + config = ctx.config + incomplete_project_id = config.placement.incomplete_consumer_project_id # Verify we have a record in projects for the missing sentinel sel = PROJECT_TBL.select( @@ -147,7 +146,7 @@ class CreateIncompleteConsumersTestCase(base.TestCase): incomplete_proj_id = rec['id'] # Verify we have a record in users for the missing sentinel - incomplete_user_id = CONF.placement.incomplete_consumer_user_id + incomplete_user_id = config.placement.incomplete_consumer_user_id sel = user_obj.USER_TBL.select( USER_TBL.c.external_id == incomplete_user_id) rec = ctx.session.execute(sel).first() diff --git a/placement/tests/functional/db/test_migrations.py b/placement/tests/functional/db/test_migrations.py index e538f94bd..ca9fb3fd6 100644 --- a/placement/tests/functional/db/test_migrations.py +++ b/placement/tests/functional/db/test_migrations.py @@ -25,11 +25,10 @@ the tests. import contextlib import functools -import tempfile from alembic import script import mock -from oslo_concurrency.fixture import lockutils as concurrency +from oslo_config import cfg from oslo_config import fixture as config_fixture from oslo_db import exception as db_exc from oslo_db.sqlalchemy import enginefacade @@ -46,7 +45,6 @@ from placement import db_api from placement.tests import fixtures as db_fixture -CONF = conf.CONF DB_NAME = 'openstack_citest' LOG = logging.getLogger(__name__) @@ -64,8 +62,7 @@ def configure(conf_fixture, db_url): here, not done as a base class as the mess of mixins makes that inscrutable. So instead we create a nice simple function. """ - conf_fixture.config(lock_path=tempfile.gettempdir(), - group='oslo_concurrency') + conf.register_opts(conf_fixture.conf) conf_fixture.config(group='placement_database', connection=db_url) # We need to retry at least once (and quickly) otherwise the connection # test routines in oslo_db do not run, and the exception handling for @@ -192,11 +189,11 @@ class MigrationCheckersMixin(object): def setUp(self): self.addCleanup(db_fixture.reset) db_url = generate_url(self.DRIVER) - conf_fixture = self.useFixture(config_fixture.Config(CONF)) + conf_fixture = self.useFixture(config_fixture.Config(cfg.ConfigOpts())) configure(conf_fixture, db_url) - self.useFixture(concurrency.LockFixture('test_mig')) + self.useFixture(db_fixture.ExternalLockFixture('test_mig')) db_fixture.reset() - db_api.configure(CONF) + db_api.configure(conf_fixture.conf) try: self.engine = db_api.get_placement_engine() except (db_exc.DBNonExistentDatabase, db_exc.DBConnectionError): @@ -261,11 +258,11 @@ class TestMigrationsPostgresql(MigrationCheckersMixin, class ModelsMigrationSyncMixin(object): def setUp(self): url = generate_url(self.DRIVER) - conf_fixture = self.useFixture(config_fixture.Config(CONF)) + conf_fixture = self.useFixture(config_fixture.Config(cfg.ConfigOpts())) configure(conf_fixture, url) - self.useFixture(concurrency.LockFixture('test_mig')) + self.useFixture(db_fixture.ExternalLockFixture('test_mig')) db_fixture.reset() - db_api.configure(CONF) + db_api.configure(conf_fixture.conf) super(ModelsMigrationSyncMixin, self).setUp() # This is required to prevent the global opportunistic db settings # leaking into other tests. diff --git a/placement/tests/functional/fixtures/gabbits.py b/placement/tests/functional/fixtures/gabbits.py index e364ae699..bb074b075 100644 --- a/placement/tests/functional/fixtures/gabbits.py +++ b/placement/tests/functional/fixtures/gabbits.py @@ -23,6 +23,7 @@ from oslo_utils.fixture import uuidsentinel as uuids from oslo_utils import uuidutils from oslotest import output +from placement import conf from placement import context from placement import deploy from placement.objects import project as project_obj @@ -36,10 +37,14 @@ from placement.tests.functional.fixtures import capture from placement.tests.unit import policy_fixture -CONF = cfg.CONF +# This global conf is not a global olso_config.cfg.CONF. It's a global +# used locally to work around a limitation in the way that gabbi instantiates +# the WSGI application being tested. +CONF = None def setup_app(): + global CONF return deploy.loadapp(CONF) @@ -47,6 +52,7 @@ class APIFixture(fixture.GabbiFixture): """Setup the required backend fixtures for a basic placement service.""" def start_fixture(self): + global CONF # Set up stderr and stdout captures by directly driving the # existing nova fixtures that do that. This captures the # output that happens outside individual tests (for @@ -62,31 +68,35 @@ class APIFixture(fixture.GabbiFixture): self.warnings_fixture = capture.WarningsFixture() self.warnings_fixture.setUp() - self.conf_fixture = config_fixture.Config(CONF) + # Do not use global CONF + self.conf_fixture = config_fixture.Config(cfg.ConfigOpts()) self.conf_fixture.setUp() - self.conf_fixture.config( - group="placement_database", - connection='sqlite://', - sqlite_synchronous=False) + conf.register_opts(self.conf_fixture.conf) self.conf_fixture.config(group='api', auth_strategy='noauth2') + self.placement_db_fixture = fixtures.Database( + self.conf_fixture, set_config=True) + self.placement_db_fixture.setUp() + self.context = context.RequestContext() # Register CORS opts, but do not set config. This has the # effect of exercising the "don't use cors" path in # deploy.py. Without setting some config the group will not # be present. - CONF.register_opts(cors.CORS_OPTS, 'cors') + self.conf_fixture.register_opts(cors.CORS_OPTS, 'cors') # Set default policy opts, otherwise the deploy module can # NoSuchOptError. - policy_opts.set_defaults(CONF) + policy_opts.set_defaults(self.conf_fixture.conf) # Make sure default_config_files is an empty list, not None. - # If None /etc/nova/nova.conf is read and confuses results. - CONF([], default_config_files=[]) + # If None /etc/placement/placement.conf is read and confuses results. + self.conf_fixture.conf([], default_config_files=[]) - self.placement_db_fixture = fixtures.Database() - self.placement_db_fixture.setUp() + # Turn on a policy fixture. + self.policy_fixture = policy_fixture.PolicyFixture( + self.conf_fixture) + self.policy_fixture.setUp() os.environ['RP_UUID'] = uuidutils.generate_uuid() os.environ['RP_NAME'] = uuidutils.generate_uuid() @@ -100,14 +110,18 @@ class APIFixture(fixture.GabbiFixture): os.environ['CONSUMER_UUID'] = uuidutils.generate_uuid() os.environ['PARENT_PROVIDER_UUID'] = uuidutils.generate_uuid() os.environ['ALT_PARENT_PROVIDER_UUID'] = uuidutils.generate_uuid() + CONF = self.conf_fixture.conf def stop_fixture(self): + global CONF self.placement_db_fixture.cleanUp() self.warnings_fixture.cleanUp() self.output_stream_fixture.cleanUp() self.standard_logging_fixture.cleanUp() self.logging_error_fixture.cleanUp() + self.policy_fixture.cleanUp() self.conf_fixture.cleanUp() + CONF = None class AllocationFixture(APIFixture): @@ -476,8 +490,6 @@ class OpenPolicyFixture(APIFixture): def start_fixture(self): super(OpenPolicyFixture, self).start_fixture() - self.placement_policy_fixture = policy_fixture.PolicyFixture() - self.placement_policy_fixture.setUp() # Get all of the registered rules and set them to '@' to allow any # user to have access. The nova policy "admin_or_owner" concept does # not really apply to most of placement resources since they do not @@ -489,8 +501,7 @@ class OpenPolicyFixture(APIFixture): if name in ['placement', 'admin_api']: continue rules[name] = '@' - self.placement_policy_fixture.set_rules(rules) + self.policy_fixture.set_rules(rules) def stop_fixture(self): super(OpenPolicyFixture, self).stop_fixture() - self.placement_policy_fixture.cleanUp() diff --git a/placement/tests/functional/fixtures/placement.py b/placement/tests/functional/fixtures/placement.py index 07bf9d418..6e910f9b0 100644 --- a/placement/tests/functional/fixtures/placement.py +++ b/placement/tests/functional/fixtures/placement.py @@ -14,14 +14,14 @@ from __future__ import absolute_import import fixtures from oslo_config import cfg from oslo_config import fixture as config_fixture +from oslo_policy import opts as policy_opts from oslo_utils import uuidutils from wsgi_intercept import interceptor +from placement import conf from placement import deploy from placement.tests import fixtures as db_fixture - - -CONF = cfg.CONF +from placement.tests.unit import policy_fixture class PlacementFixture(fixtures.Fixture): @@ -34,22 +34,33 @@ class PlacementFixture(fixtures.Fixture): all calls would be passing this token. This fixture takes care of starting a fixture for an in-RAM placement - database, unless the db kwargs is False. + database, unless the db kwarg is False. Used by other services, including nova, for functional tests. """ - def __init__(self, token='admin', db=True): + def __init__(self, token='admin', conf_fixture=None, db=True): self.token = token self.db = db + self.conf_fixture = conf_fixture def setUp(self): super(PlacementFixture, self).setUp() - if self.db: - self.useFixture(db_fixture.Database(set_config=True)) + if not self.conf_fixture: + config = cfg.ConfigOpts() + self.conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(self.conf_fixture.conf) - conf_fixture = config_fixture.Config(CONF) - conf_fixture.config(group='api', auth_strategy='noauth2') - loader = deploy.loadapp(CONF) + if self.db: + self.useFixture(db_fixture.Database(self.conf_fixture, + set_config=True)) + policy_opts.set_defaults(self.conf_fixture.conf) + self.conf_fixture.config(group='api', auth_strategy='noauth2') + + self.conf_fixture.conf([], default_config_files=[]) + + self.useFixture(policy_fixture.PolicyFixture(self.conf_fixture)) + + loader = deploy.loadapp(self.conf_fixture.conf) app = lambda: loader self.endpoint = 'http://%s/placement' % uuidutils.generate_uuid() intercept = interceptor.RequestsInterceptor(app, url=self.endpoint) diff --git a/placement/tests/functional/test_direct.py b/placement/tests/functional/test_direct.py index d0e79dddd..d82762cb0 100644 --- a/placement/tests/functional/test_direct.py +++ b/placement/tests/functional/test_direct.py @@ -11,26 +11,31 @@ # under the License. from oslo_config import cfg +from oslo_policy import opts as policy_opts from oslo_utils.fixture import uuidsentinel +from placement import conf from placement import direct from placement.tests.functional import base -CONF = cfg.CONF - - class TestDirect(base.TestCase): + def setUp(self): + super(TestDirect, self).setUp() + self.conf = cfg.ConfigOpts() + conf.register_opts(self.conf) + policy_opts.set_defaults(self.conf) + def test_direct_is_there(self): - with direct.PlacementDirect(CONF) as client: + with direct.PlacementDirect(self.conf) as client: resp = client.get('/') self.assertTrue(resp) data = resp.json() self.assertEqual('v1.0', data['versions'][0]['id']) def test_get_resource_providers(self): - with direct.PlacementDirect(CONF) as client: + with direct.PlacementDirect(self.conf) as client: resp = client.get('/resource_providers') self.assertTrue(resp) data = resp.json() @@ -38,7 +43,7 @@ class TestDirect(base.TestCase): def test_create_resource_provider(self): data = {'name': 'fake'} - with direct.PlacementDirect(CONF) as client: + with direct.PlacementDirect(self.conf) as client: resp = client.post('/resource_providers', json=data) self.assertTrue(resp) resp = client.get('/resource_providers') @@ -48,13 +53,13 @@ class TestDirect(base.TestCase): def test_json_validation_happens(self): data = {'name': 'fake', 'cowsay': 'moo'} - with direct.PlacementDirect(CONF) as client: + with direct.PlacementDirect(self.conf) as client: resp = client.post('/resource_providers', json=data) self.assertFalse(resp) self.assertEqual(400, resp.status_code) def test_microversion_handling(self): - with direct.PlacementDirect(CONF) as client: + with direct.PlacementDirect(self.conf) as client: # create parent parent_data = {'name': uuidsentinel.p_rp, 'uuid': uuidsentinel.p_rp} diff --git a/placement/tests/functional/test_verify_policy.py b/placement/tests/functional/test_verify_policy.py index 7b25fa04f..eced0e3e4 100644 --- a/placement/tests/functional/test_verify_policy.py +++ b/placement/tests/functional/test_verify_policy.py @@ -10,16 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_config import cfg - from placement import direct from placement import handler from placement.tests.functional import base -CONF = cfg.CONF - - class TestVerifyPolicy(base.TestCase): """Verify that all defined placement routes have a policy.""" @@ -42,7 +37,8 @@ class TestVerifyPolicy(base.TestCase): (method, route, response.status_code)) def test_verify_policy(self): - with direct.PlacementDirect(CONF, latest_microversion=True) as client: + conf = self.conf_fixture.conf + with direct.PlacementDirect(conf, latest_microversion=True) as client: for route, methods in handler.ROUTE_DECLARATIONS.items(): if route in self.EXCEPTIONS: continue diff --git a/placement/tests/unit/cmd/test_manage.py b/placement/tests/unit/cmd/test_manage.py index 5a96dad7a..ab945c904 100644 --- a/placement/tests/unit/cmd/test_manage.py +++ b/placement/tests/unit/cmd/test_manage.py @@ -19,15 +19,17 @@ import six import testtools from placement.cmd import manage +from placement import conf class TestCommandParsers(testtools.TestCase): def setUp(self): super(TestCommandParsers, self).setUp() - self.conf = cfg.CONF + self.conf = cfg.ConfigOpts() conf_fixture = config_fixture.Config(self.conf) self.useFixture(conf_fixture) + conf.register_opts(conf_fixture.conf) # Quiet output from argparse (used within oslo_config). # If you are debugging, commenting this out might be useful. self.output = self.useFixture( diff --git a/placement/tests/unit/handlers/test_util.py b/placement/tests/unit/handlers/test_util.py index d02715ba1..730381c4b 100644 --- a/placement/tests/unit/handlers/test_util.py +++ b/placement/tests/unit/handlers/test_util.py @@ -14,12 +14,14 @@ import fixtures import microversion_parse -import mock +from oslo_config import cfg +from oslo_config import fixture as config_fixture from oslo_utils.fixture import uuidsentinel import testtools import webob from placement import conf +from placement import context from placement import exception from placement.handlers import util from placement import microversion @@ -28,12 +30,12 @@ from placement.objects import project as project_obj from placement.objects import user as user_obj -CONF = conf.CONF - - class TestEnsureConsumer(testtools.TestCase): def setUp(self): super(TestEnsureConsumer, self).setUp() + self.conf = cfg.ConfigOpts() + self.useFixture(config_fixture.Config(self.conf)) + conf.register_opts(self.conf) self.mock_project_get = self.useFixture(fixtures.MockPatch( 'placement.objects.project.' 'Project.get_by_external_id')).mock @@ -52,7 +54,8 @@ class TestEnsureConsumer(testtools.TestCase): self.mock_consumer_create = self.useFixture(fixtures.MockPatch( 'placement.objects.consumer.' 'Consumer.create')).mock - self.ctx = mock.sentinel.ctx + self.ctx = context.RequestContext(user_id='fake', project_id='fake') + self.ctx.config = self.conf self.consumer_id = uuidsentinel.consumer self.project_id = uuidsentinel.project self.user_id = uuidsentinel.user @@ -144,9 +147,9 @@ class TestEnsureConsumer(testtools.TestCase): consumer_gen, self.before_version) self.mock_project_get.assert_called_once_with( - self.ctx, CONF.placement.incomplete_consumer_project_id) + self.ctx, self.conf.placement.incomplete_consumer_project_id) self.mock_user_get.assert_called_once_with( - self.ctx, CONF.placement.incomplete_consumer_user_id) + self.ctx, self.conf.placement.incomplete_consumer_user_id) self.mock_consumer_get.assert_called_once_with( self.ctx, self.consumer_id) self.mock_project_create.assert_called_once() diff --git a/placement/tests/unit/objects/test_resource_provider.py b/placement/tests/unit/objects/test_resource_provider.py index c9cb3fd25..e21fbca7f 100644 --- a/placement/tests/unit/objects/test_resource_provider.py +++ b/placement/tests/unit/objects/test_resource_provider.py @@ -11,11 +11,14 @@ # under the License. import mock +from oslo_config import cfg +from oslo_config import fixture as config_fixture from oslo_utils.fixture import uuidsentinel as uuids from oslo_utils import timeutils import six import testtools +from placement import conf from placement import context from placement import exception from placement.objects import resource_provider @@ -103,6 +106,10 @@ class _TestCase(testtools.TestCase): self.user_id = 'fake-user' self.project_id = 'fake-project' self.context = context.RequestContext(self.user_id, self.project_id) + config = cfg.ConfigOpts() + self.conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(config) + self.context.config = config class TestResourceProviderNoDB(_TestCase): @@ -356,6 +363,6 @@ class TestAllocationCandidatesNoDB(_TestCase): sum6 = mock.Mock(resource_provider=mock.Mock(uuid=6)) sum_in = [sum1, sum0, sum4, sum8, sum5, sum7, sum6] aro, sum = resource_provider.AllocationCandidates._limit_results( - aro_in, sum_in, 2) + self.context, aro_in, sum_in, 2) self.assertEqual(aro_in[:2], aro) self.assertEqual(set([sum1, sum0, sum4, sum8, sum5]), set(sum)) diff --git a/placement/tests/unit/policy_fixture.py b/placement/tests/unit/policy_fixture.py index 5e2aa9478..394365cf4 100644 --- a/placement/tests/unit/policy_fixture.py +++ b/placement/tests/unit/policy_fixture.py @@ -14,8 +14,6 @@ import fixtures -from oslo_config import cfg -from oslo_config import fixture as config_fixture from oslo_policy import policy as oslo_policy from placement.conf import paths @@ -23,15 +21,19 @@ from placement import policy as placement_policy class PolicyFixture(fixtures.Fixture): + + def __init__(self, conf_fixture): + self.conf_fixture = conf_fixture + super(PolicyFixture, self).__init__() + """Load the default placement policy for tests.""" def setUp(self): super(PolicyFixture, self).setUp() - self.conf_fixture = self.useFixture(config_fixture.Config(cfg.CONF)) policy_file = paths.state_path_def( 'etc/placement/placement-policy.yaml') self.conf_fixture.config(group='placement', policy_file=policy_file) placement_policy.reset() - placement_policy.init() + placement_policy.init(self.conf_fixture.conf) self.addCleanup(placement_policy.reset) @staticmethod diff --git a/placement/tests/unit/test_db_api.py b/placement/tests/unit/test_db_api.py index fe9bbff38..4ffd956ac 100644 --- a/placement/tests/unit/test_db_api.py +++ b/placement/tests/unit/test_db_api.py @@ -17,17 +17,17 @@ import testtools from oslo_config import cfg from oslo_config import fixture as config_fixture +from placement import conf from placement import db_api -CONF = cfg.CONF - - class DbApiTests(testtools.TestCase): def setUp(self): super(DbApiTests, self).setUp() - self.conf_fixture = self.useFixture(config_fixture.Config(CONF)) + config = cfg.ConfigOpts() + self.conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(self.conf_fixture.conf) db_api.configure.reset() @mock.patch.object(db_api.placement_context_manager, "configure") diff --git a/placement/tests/unit/test_db_conf.py b/placement/tests/unit/test_db_conf.py index 162f63dae..9484e98e3 100644 --- a/placement/tests/unit/test_db_conf.py +++ b/placement/tests/unit/test_db_conf.py @@ -16,8 +16,7 @@ import testtools from oslo_config import cfg from oslo_config import fixture as config_fixture - -CONF = cfg.CONF +from placement import conf class TestPlacementDBConf(testtools.TestCase): @@ -25,7 +24,9 @@ class TestPlacementDBConf(testtools.TestCase): def setUp(self): super(TestPlacementDBConf, self).setUp() - self.conf_fixture = self.useFixture(config_fixture.Config(CONF)) + config = cfg.ConfigOpts() + self.conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(config) def test_missing_config_raises(self): """Not setting [placement_database]/connection is an error.""" diff --git a/placement/tests/unit/test_deploy.py b/placement/tests/unit/test_deploy.py index b99b17f45..6b575b749 100644 --- a/placement/tests/unit/test_deploy.py +++ b/placement/tests/unit/test_deploy.py @@ -13,31 +13,39 @@ # under the License. """Unit tests for the deply function used to build the Placement service.""" +from keystonemiddleware import auth_token from oslo_config import cfg +from oslo_config import fixture as config_fixture from oslo_policy import opts as policy_opts import testtools import webob +from placement import conf from placement import deploy -CONF = cfg.CONF - - class DeployTest(testtools.TestCase): def test_auth_middleware_factory(self): """Make sure that configuration settings make their way to the keystone middleware correctly. """ + config = cfg.ConfigOpts() + conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(conf_fixture.conf) + # NOTE(cdent): There appears to be no simple way to get the list of + # options used by the auth_token middleware. So we pull from an + # existing data structure. + auth_token_opts = auth_token.AUTH_TOKEN_OPTS[0][1] + conf_fixture.register_opts(auth_token_opts, group='keystone_authtoken') www_authenticate_uri = 'http://example.com/identity' - CONF.set_override('www_authenticate_uri', www_authenticate_uri, + conf_fixture.config(www_authenticate_uri=www_authenticate_uri, group='keystone_authtoken') # ensure that the auth_token middleware is chosen - CONF.set_override('auth_strategy', 'keystone', group='api') + conf_fixture.config(auth_strategy='keystone', group='api') # register and default policy opts (referenced by deploy) - policy_opts.set_defaults(CONF) - app = deploy.deploy(CONF) + policy_opts.set_defaults(conf_fixture.conf) + app = deploy.deploy(conf_fixture.conf) req = webob.Request.blank('/resource_providers', method="GET") response = req.get_response(app) diff --git a/placement/tests/unit/test_handler.py b/placement/tests/unit/test_handler.py index 230b3572d..56c044a09 100644 --- a/placement/tests/unit/test_handler.py +++ b/placement/tests/unit/test_handler.py @@ -128,10 +128,11 @@ class PlacementLoggingTest(testtools.TestCase): @mock.patch("placement.handler.LOG") def test_404_no_error_log(self, mocked_log): environ = _environ(path='/hello', method='GET') + config = mock.MagicMock() context_mock = mock.Mock() context_mock.to_policy_values.return_value = {'roles': ['admin']} environ['placement.context'] = context_mock - app = handler.PlacementHandler() + app = handler.PlacementHandler(config=config) self.assertRaises(webob.exc.HTTPNotFound, app, environ, start_response) mocked_log.error.assert_not_called() @@ -160,7 +161,9 @@ class ContentHeadersTest(testtools.TestCase): def setUp(self): super(ContentHeadersTest, self).setUp() self.environ = _environ(path='/') - self.app = handler.PlacementHandler() + config = mock.MagicMock() + self.environ['placement.context'] = mock.MagicMock() + self.app = handler.PlacementHandler(config=config) def test_no_content_type(self): self.environ['CONTENT_LENGTH'] = '10' diff --git a/placement/tests/unit/test_policy.py b/placement/tests/unit/test_policy.py index b57b899f6..1b5372841 100644 --- a/placement/tests/unit/test_policy.py +++ b/placement/tests/unit/test_policy.py @@ -12,32 +12,33 @@ import os +import fixtures from oslo_config import cfg from oslo_config import fixture as config_fixture from oslo_policy import policy as oslo_policy import testtools +from placement import conf from placement import context from placement import exception from placement import policy from placement.tests.unit import policy_fixture -from placement import util - - -CONF = cfg.CONF class PlacementPolicyTestCase(testtools.TestCase): """Tests interactions with placement policy.""" def setUp(self): super(PlacementPolicyTestCase, self).setUp() - self.conf_fixture = self.useFixture(config_fixture.Config(CONF)) + config = cfg.ConfigOpts() + self.conf_fixture = self.useFixture(config_fixture.Config(config)) + conf.register_opts(config) self.ctxt = context.RequestContext(user_id='fake', project_id='fake') self.target = {'user_id': 'fake', 'project_id': 'fake'} - # A value is required in the database connection opt for CONF to + # A value is required in the database connection opt for conf to # parse. - CONF.set_default('connection', 'stub', group='placement_database') - CONF([], default_config_files=[]) + self.conf_fixture.config(connection='stub', group='placement_database') + config([], default_config_files=[]) + self.ctxt.config = config policy.reset() self.addCleanup(policy.reset) @@ -46,39 +47,40 @@ class PlacementPolicyTestCase(testtools.TestCase): authorizations against a fake rule between updates to the physical policy file. """ - with util.tempdir() as tmpdir: - tmpfilename = os.path.join(tmpdir, 'placement-policy.yaml') + tempdir = self.useFixture(fixtures.TempDir()) + tmpfilename = os.path.join(tempdir.path, 'placement-policy.yaml') - self.conf_fixture.config( - group='placement', policy_file=tmpfilename) + self.conf_fixture.config( + 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) + 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() - rule = oslo_policy.RuleDefault(action, '') - enforcer.register_default(rule) + # Load the default action and rule (defaults to "any"). + enforcer = policy.get_enforcer() + rule = oslo_policy.RuleDefault(action, '') + enforcer.register_default(rule) - # Now auth should work because the action is registered and anyone - # can perform the action. - policy.authorize(self.ctxt, action, self.target) + # Now auth should work because the action is registered and anyone + # can perform the action. + policy.authorize(self.ctxt, action, self.target) - # Now update the policy file and reload it to disable the action - # from all users. - with open(tmpfilename, "w") as policyfile: - policyfile.write('"%s": "!"' % action) - enforcer.load_rules(force_reload=True) - self.assertRaises(exception.PolicyNotAuthorized, policy.authorize, - self.ctxt, action, self.target) + # Now update the policy file and reload it to disable the action + # from all users. + with open(tmpfilename, "w") as policyfile: + policyfile.write('"%s": "!"' % action) + enforcer.load_rules(force_reload=True) + self.assertRaises(exception.PolicyNotAuthorized, policy.authorize, + self.ctxt, action, self.target) def test_authorize_do_raise_false(self): """Tests that authorize does not raise an exception when the check fails. """ - fixture = self.useFixture(policy_fixture.PolicyFixture()) + fixture = self.useFixture( + policy_fixture.PolicyFixture(self.conf_fixture)) fixture.set_rules({'placement': '!'}) self.assertFalse( policy.authorize( diff --git a/placement/tests/unit/test_util.py b/placement/tests/unit/test_util.py index 9c6618fd4..b91369930 100644 --- a/placement/tests/unit/test_util.py +++ b/placement/tests/unit/test_util.py @@ -18,7 +18,6 @@ import datetime import fixtures import microversion_parse import mock -from oslo_config import cfg from oslo_middleware import request_id from oslo_utils.fixture import uuidsentinel from oslo_utils import timeutils @@ -33,9 +32,6 @@ from placement.objects import resource_provider as rp_obj from placement import util -CONF = cfg.CONF - - class TestCheckAccept(testtools.TestCase): """Confirm behavior of util.check_accept.""" diff --git a/placement/util.py b/placement/util.py index c9b26b693..79ac0a087 100644 --- a/placement/util.py +++ b/placement/util.py @@ -11,13 +11,9 @@ # under the License. """Utility methods for placement API.""" -import contextlib import functools -import shutil -import tempfile import jsonschema -from oslo_config import cfg from oslo_log import log as logging from oslo_middleware import request_id from oslo_serialization import jsonutils @@ -31,7 +27,6 @@ from placement.i18n import _ # microversion import placement.microversion -CONF = cfg.CONF LOG = logging.getLogger(__name__) # Error code handling constants @@ -398,21 +393,6 @@ def normalize_member_of_qs_param(value): return value -@contextlib.contextmanager -def tempdir(**kwargs): - argdict = kwargs.copy() - if 'dir' not in argdict: - argdict['dir'] = CONF.tempdir - tmpdir = tempfile.mkdtemp(**argdict) - try: - yield tmpdir - finally: - try: - shutil.rmtree(tmpdir) - except OSError as e: - LOG.error('Could not remove tmpdir: %s', e) - - def run_once(message, logger, cleanup=None): """This is a utility function decorator to ensure a function is run once and only once in an interpreter instance. diff --git a/placement/wsgi.py b/placement/wsgi.py index 56afbd120..d91225939 100644 --- a/placement/wsgi.py +++ b/placement/wsgi.py @@ -18,6 +18,7 @@ import logging as py_logging import os import os.path +from oslo_config import cfg from oslo_log import log as logging from oslo_middleware import cors from oslo_policy import opts as policy_opts @@ -67,21 +68,23 @@ def _get_config_files(env=None): return None -def _parse_args(argv, default_config_files): - logging.register_options(conf.CONF) +def _parse_args(config, argv, default_config_files): + # register placement's config options + conf.register_opts(config) + logging.register_options(config) if profiler: - profiler.set_defaults(conf.CONF) + profiler.set_defaults(config) _set_middleware_defaults() # This is needed so we can check [oslo_policy]/enforce_scope in the # deploy module. - policy_opts.set_defaults(conf.CONF) + policy_opts.set_defaults(config) - conf.CONF(argv[1:], project='placement', - version=version_info.version_string(), - default_config_files=default_config_files) + config(argv[1:], project='placement', + version=version_info.version_string(), + default_config_files=default_config_files) def _set_middleware_defaults(): @@ -110,26 +113,25 @@ def init_application(): # initialize the config system conffiles = _get_config_files() - # NOTE(lyarwood): Call reset to ensure the ConfigOpts object doesn't - # already contain registered options if the app is reloaded. - conf.CONF.reset() + config = cfg.ConfigOpts() + conf.register_opts(config) # This will raise cfg.RequiredOptError when a required option is not set # (notably the database connection string). We want this to be a hard fail # that prevents the application from starting. The error will show up in # the wsgi server's logs. - _parse_args([], default_config_files=conffiles) + _parse_args(config, [], default_config_files=conffiles) # initialize the logging system - setup_logging(conf.CONF) + setup_logging(config) # configure database - db_api.configure(conf.CONF) + db_api.configure(config) # dump conf at debug if log_options - if conf.CONF.log_options: - conf.CONF.log_opt_values( + if config.log_options: + config.log_opt_values( logging.getLogger(__name__), logging.DEBUG) # build and return our WSGI app - return deploy.loadapp(conf.CONF) + return deploy.loadapp(config)