api: Remove global conf
Change-Id: Idfb9bc3e67e963cad5277a559d8b07cd7790cdac
This commit is contained in:
parent
55916dfea7
commit
5ecb2abcdd
|
@ -15,6 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
@ -52,11 +53,14 @@ CONF.register_opts(OPTS)
|
|||
CONF.register_opts(API_OPTS, group='api')
|
||||
|
||||
|
||||
def setup_app(pecan_config=None):
|
||||
def setup_app(pecan_config=None, conf=None):
|
||||
if conf is None:
|
||||
raise RuntimeError("No configuration passed")
|
||||
|
||||
# FIXME: Replace DBHook with a hooks.TransactionHook
|
||||
app_hooks = [hooks.ConfigHook(),
|
||||
hooks.DBHook(),
|
||||
hooks.NotifierHook(),
|
||||
app_hooks = [hooks.ConfigHook(conf),
|
||||
hooks.DBHook(conf),
|
||||
hooks.NotifierHook(conf),
|
||||
hooks.TranslationHook()]
|
||||
|
||||
pecan_config = pecan_config or {
|
||||
|
@ -70,7 +74,7 @@ def setup_app(pecan_config=None):
|
|||
|
||||
app = pecan.make_app(
|
||||
pecan_config['app']['root'],
|
||||
debug=CONF.api.pecan_debug,
|
||||
debug=conf.api.pecan_debug,
|
||||
hooks=app_hooks,
|
||||
wrap_app=middleware.ParsableErrorMiddleware,
|
||||
guess_content_type_from_ext=False
|
||||
|
@ -79,25 +83,43 @@ def setup_app(pecan_config=None):
|
|||
return app
|
||||
|
||||
|
||||
def load_app():
|
||||
# NOTE(sileht): pastedeploy uses ConfigParser to handle
|
||||
# global_conf, since python 3 ConfigParser doesn't
|
||||
# allow to store object as config value, only strings are
|
||||
# permit, so to be able to pass an object created before paste load
|
||||
# the app, we store them into a global var. But the each loaded app
|
||||
# store it's configuration in unique key to be concurrency safe.
|
||||
global APPCONFIGS
|
||||
APPCONFIGS = {}
|
||||
|
||||
|
||||
def load_app(conf):
|
||||
global APPCONFIGS
|
||||
|
||||
# Build the WSGI app
|
||||
cfg_file = None
|
||||
cfg_path = cfg.CONF.api_paste_config
|
||||
cfg_path = conf.api_paste_config
|
||||
if not os.path.isabs(cfg_path):
|
||||
cfg_file = CONF.find_file(cfg_path)
|
||||
cfg_file = conf.find_file(cfg_path)
|
||||
elif os.path.exists(cfg_path):
|
||||
cfg_file = cfg_path
|
||||
|
||||
if not cfg_file:
|
||||
raise cfg.ConfigFilesNotFoundError([cfg.CONF.api_paste_config])
|
||||
raise cfg.ConfigFilesNotFoundError([conf.api_paste_config])
|
||||
|
||||
configkey = str(uuid.uuid4())
|
||||
APPCONFIGS[configkey] = conf
|
||||
|
||||
LOG.info("Full WSGI config used: %s" % cfg_file)
|
||||
return deploy.loadapp("config:" + cfg_file)
|
||||
return deploy.loadapp("config:" + cfg_file,
|
||||
global_conf={'configkey': configkey})
|
||||
|
||||
|
||||
def app_factory(global_config, **local_conf):
|
||||
return setup_app()
|
||||
global APPCONFIGS
|
||||
conf = APPCONFIGS.get(global_config.get('configkey'))
|
||||
return setup_app(conf=conf)
|
||||
|
||||
|
||||
def build_wsgi_app():
|
||||
service.prepare_service()
|
||||
return load_app()
|
||||
def build_wsgi_app(argv=None):
|
||||
return load_app(service.prepare_service(argv=argv))
|
||||
|
|
|
@ -21,5 +21,5 @@ from ceilometer import service
|
|||
from ceilometer.api import app
|
||||
|
||||
# Initialize the oslo configuration library and logging
|
||||
service.prepare_service([])
|
||||
application = app.load_app()
|
||||
conf = service.prepare_service([])
|
||||
application = app.load_app(conf)
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
import base64
|
||||
import datetime
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import timeutils
|
||||
|
@ -360,7 +359,8 @@ class MeterController(rest.RestController):
|
|||
s.message_id = published_sample.id
|
||||
|
||||
sample_dict = publisher_utils.meter_message_from_counter(
|
||||
published_sample, cfg.CONF.publisher.telemetry_secret)
|
||||
published_sample,
|
||||
pecan.request.cfg.publisher.telemetry_secret)
|
||||
if direct:
|
||||
ts = timeutils.parse_isotime(sample_dict['timestamp'])
|
||||
sample_dict['timestamp'] = timeutils.normalize_time(ts)
|
||||
|
|
|
@ -116,11 +116,12 @@ class V2Controller(object):
|
|||
@property
|
||||
def gnocchi_is_enabled(self):
|
||||
if self._gnocchi_is_enabled is None:
|
||||
if cfg.CONF.api.gnocchi_is_enabled is not None:
|
||||
self._gnocchi_is_enabled = cfg.CONF.api.gnocchi_is_enabled
|
||||
if pecan.request.cfg.api.gnocchi_is_enabled is not None:
|
||||
self._gnocchi_is_enabled = (
|
||||
pecan.request.cfg.api.gnocchi_is_enabled)
|
||||
|
||||
elif ("gnocchi" not in cfg.CONF.meter_dispatchers
|
||||
or "database" in cfg.CONF.meter_dispatchers):
|
||||
elif ("gnocchi" not in pecan.request.cfg.meter_dispatchers
|
||||
or "database" in pecan.request.cfg.meter_dispatchers):
|
||||
self._gnocchi_is_enabled = False
|
||||
else:
|
||||
try:
|
||||
|
@ -142,11 +143,11 @@ class V2Controller(object):
|
|||
@property
|
||||
def aodh_url(self):
|
||||
if self._aodh_url is None:
|
||||
if cfg.CONF.api.aodh_is_enabled is False:
|
||||
if pecan.request.cfg.api.aodh_is_enabled is False:
|
||||
self._aodh_url = ""
|
||||
elif cfg.CONF.api.aodh_url is not None:
|
||||
elif pecan.request.cfg.api.aodh_url is not None:
|
||||
self._aodh_url = self._normalize_url(
|
||||
cfg.CONF.api.aodh_url)
|
||||
pecan.request.cfg.api.aodh_url)
|
||||
else:
|
||||
try:
|
||||
catalog = keystone_client.get_service_catalog(
|
||||
|
@ -167,11 +168,11 @@ class V2Controller(object):
|
|||
@property
|
||||
def panko_url(self):
|
||||
if self._panko_url is None:
|
||||
if cfg.CONF.api.panko_is_enabled is False:
|
||||
if pecan.request.cfg.api.panko_is_enabled is False:
|
||||
self._panko_url = ""
|
||||
elif cfg.CONF.api.panko_url is not None:
|
||||
elif pecan.request.cfg.api.panko_url is not None:
|
||||
self._panko_url = self._normalize_url(
|
||||
cfg.CONF.api.panko_url)
|
||||
pecan.request.cfg.api.panko_url)
|
||||
else:
|
||||
try:
|
||||
catalog = keystone_client.get_service_catalog(
|
||||
|
|
|
@ -43,7 +43,7 @@ cfg.CONF.import_opt('default_api_return_limit', 'ceilometer.api.app',
|
|||
def enforce_limit(limit):
|
||||
"""Ensure limit is defined and is valid. if not, set a default."""
|
||||
if limit is None:
|
||||
limit = cfg.CONF.api.default_api_return_limit
|
||||
limit = pecan.request.cfg.api.default_api_return_limit
|
||||
LOG.info(_LI('No limit value provided, result set will be'
|
||||
' limited to %(limit)d.'), {'limit': limit})
|
||||
if not limit or limit <= 0:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
import oslo_messaging
|
||||
from oslo_policy import policy
|
||||
|
||||
from pecan import hooks
|
||||
|
||||
|
@ -34,17 +35,22 @@ class ConfigHook(hooks.PecanHook):
|
|||
|
||||
That allows controllers to get it.
|
||||
"""
|
||||
def __init__(self, conf):
|
||||
super(ConfigHook, self).__init__()
|
||||
self.conf = conf
|
||||
self.enforcer = policy.Enforcer(conf)
|
||||
self.enforcer.load_rules()
|
||||
|
||||
@staticmethod
|
||||
def before(state):
|
||||
state.request.cfg = cfg.CONF
|
||||
def on_route(self, state):
|
||||
state.request.cfg = self.conf
|
||||
state.request.enforcer = self.enforcer
|
||||
|
||||
|
||||
class DBHook(hooks.PecanHook):
|
||||
|
||||
def __init__(self):
|
||||
self.storage_connection = DBHook.get_connection('metering')
|
||||
self.event_storage_connection = DBHook.get_connection('event')
|
||||
def __init__(self, conf):
|
||||
self.storage_connection = self.get_connection(conf, 'metering')
|
||||
self.event_storage_connection = self.get_connection(conf, 'event')
|
||||
|
||||
if (not self.storage_connection
|
||||
and not self.event_storage_connection):
|
||||
|
@ -57,9 +63,9 @@ class DBHook(hooks.PecanHook):
|
|||
state.request.event_storage_conn = self.event_storage_connection
|
||||
|
||||
@staticmethod
|
||||
def get_connection(purpose):
|
||||
def get_connection(conf, purpose):
|
||||
try:
|
||||
return storage.get_connection_from_config(cfg.CONF, purpose)
|
||||
return storage.get_connection_from_config(conf, purpose)
|
||||
except Exception as err:
|
||||
params = {"purpose": purpose, "err": err}
|
||||
LOG.exception(_LE("Failed to connect to db, purpose %(purpose)s "
|
||||
|
@ -73,10 +79,10 @@ class NotifierHook(hooks.PecanHook):
|
|||
are posted via /v2/meters/ API.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, conf):
|
||||
transport = messaging.get_transport()
|
||||
self.notifier = oslo_messaging.Notifier(
|
||||
transport, driver=cfg.CONF.publisher_notifier.telemetry_driver,
|
||||
transport, driver=conf.publisher_notifier.telemetry_driver,
|
||||
publisher_id="ceilometer.api")
|
||||
|
||||
def before(self, state):
|
||||
|
|
|
@ -16,24 +16,11 @@
|
|||
|
||||
"""Access Control Lists (ACL's) control access the API server."""
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_policy import policy
|
||||
import pecan
|
||||
|
||||
_ENFORCER = None
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def reset():
|
||||
global _ENFORCER
|
||||
if _ENFORCER:
|
||||
_ENFORCER.clear()
|
||||
_ENFORCER = None
|
||||
|
||||
|
||||
def _has_rule(name):
|
||||
return name in _ENFORCER.rules.keys()
|
||||
return name in pecan.request.enforcer.rules.keys()
|
||||
|
||||
|
||||
def enforce(policy_name, request):
|
||||
|
@ -44,10 +31,6 @@ def enforce(policy_name, request):
|
|||
|
||||
|
||||
"""
|
||||
global _ENFORCER
|
||||
if not _ENFORCER:
|
||||
_ENFORCER = policy.Enforcer(CONF)
|
||||
_ENFORCER.load_rules()
|
||||
|
||||
rule_method = "telemetry:" + policy_name
|
||||
headers = request.headers
|
||||
|
@ -60,7 +43,7 @@ def enforce(policy_name, request):
|
|||
# maintain backward compat with Juno and previous by allowing the action if
|
||||
# there is no rule defined for it
|
||||
if ((_has_rule('default') or _has_rule(rule_method)) and
|
||||
not _ENFORCER.enforce(rule_method, {}, policy_dict)):
|
||||
not pecan.request.enforcer.enforce(rule_method, {}, policy_dict)):
|
||||
pecan.core.abort(status_code=403, detail='RBAC Authorization Failed')
|
||||
|
||||
|
||||
|
@ -75,10 +58,6 @@ def get_limited_to(headers):
|
|||
one of these.
|
||||
|
||||
"""
|
||||
global _ENFORCER
|
||||
if not _ENFORCER:
|
||||
_ENFORCER = policy.Enforcer(CONF)
|
||||
_ENFORCER.load_rules()
|
||||
|
||||
policy_dict = dict()
|
||||
policy_dict['roles'] = headers.get('X-Roles', "").split(",")
|
||||
|
@ -89,9 +68,9 @@ def get_limited_to(headers):
|
|||
# rule if the segregation rule (added in Kilo) is not defined
|
||||
rule_name = 'segregation' if _has_rule(
|
||||
'segregation') else 'context_is_admin'
|
||||
if not _ENFORCER.enforce(rule_name,
|
||||
{},
|
||||
policy_dict):
|
||||
if not pecan.request.enforcer.enforce(rule_name,
|
||||
{},
|
||||
policy_dict):
|
||||
return headers.get('X-User-Id'), headers.get('X-Project-Id')
|
||||
|
||||
return None, None
|
||||
|
|
|
@ -19,6 +19,7 @@ from keystoneauth1 import loading as ka_loading
|
|||
from oslo_config import cfg
|
||||
import oslo_i18n
|
||||
from oslo_log import log
|
||||
from oslo_policy import opts as policy_opts
|
||||
from oslo_reports import guru_meditation_report as gmr
|
||||
|
||||
from ceilometer.conf import defaults
|
||||
|
@ -62,26 +63,32 @@ keystone_client.register_keystoneauth_opts(cfg.CONF)
|
|||
|
||||
|
||||
def prepare_service(argv=None, config_files=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
|
||||
# FIXME(sileht): Use ConfigOpts() instead
|
||||
conf = cfg.CONF
|
||||
|
||||
oslo_i18n.enable_lazy()
|
||||
log.register_options(cfg.CONF)
|
||||
log_levels = (cfg.CONF.default_log_levels +
|
||||
log.register_options(conf)
|
||||
log_levels = (conf.default_log_levels +
|
||||
['futurist=INFO', 'neutronclient=INFO',
|
||||
'keystoneclient=INFO'])
|
||||
log.set_defaults(default_log_levels=log_levels)
|
||||
defaults.set_cors_middleware_defaults()
|
||||
policy_opts.set_defaults(conf)
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
cfg.CONF(argv[1:], project='ceilometer', validate_default_values=True,
|
||||
version=version.version_info.version_string(),
|
||||
default_config_files=config_files)
|
||||
conf(argv[1:], project='ceilometer', validate_default_values=True,
|
||||
version=version.version_info.version_string(),
|
||||
default_config_files=config_files)
|
||||
|
||||
ka_loading.load_auth_from_conf_options(cfg.CONF, "service_credentials")
|
||||
ka_loading.load_auth_from_conf_options(conf, "service_credentials")
|
||||
|
||||
log.setup(cfg.CONF, 'ceilometer')
|
||||
log.setup(conf, 'ceilometer')
|
||||
# NOTE(liusheng): guru cannot run with service under apache daemon, so when
|
||||
# ceilometer-api running with mod_wsgi, the argv is [], we don't start
|
||||
# guru.
|
||||
if argv:
|
||||
gmr.TextGuruMeditation.setup_autorun(version)
|
||||
messaging.setup()
|
||||
return conf
|
||||
|
|
|
@ -21,7 +21,6 @@ from oslo_policy import opts
|
|||
import pecan
|
||||
import pecan.testing
|
||||
|
||||
from ceilometer.api import rbac
|
||||
from ceilometer.tests import db as db_test_base
|
||||
|
||||
cfg.CONF.import_group('api', 'ceilometer.api.controllers.v2.root')
|
||||
|
@ -64,11 +63,10 @@ class FunctionalTest(db_test_base.TestBase):
|
|||
},
|
||||
}
|
||||
|
||||
return pecan.testing.load_test_app(self.config)
|
||||
return pecan.testing.load_test_app(self.config, conf=self.CONF)
|
||||
|
||||
def tearDown(self):
|
||||
super(FunctionalTest, self).tearDown()
|
||||
rbac.reset()
|
||||
pecan.set_config({}, overwrite=True)
|
||||
|
||||
def put_json(self, path, params, expect_errors=False, headers=None,
|
||||
|
|
|
@ -97,7 +97,7 @@ class TestAPIACL(v2.FunctionalTest):
|
|||
def _make_app(self):
|
||||
file_name = self.path_get('etc/ceilometer/api_paste.ini')
|
||||
self.CONF.set_override("api_paste_config", file_name)
|
||||
return webtest.TestApp(app.load_app())
|
||||
return webtest.TestApp(app.load_app(self.CONF))
|
||||
|
||||
def test_non_authenticated(self):
|
||||
response = self.get_json('/meters', expect_errors=True)
|
||||
|
|
|
@ -29,6 +29,7 @@ from oslo_utils import fileutils
|
|||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from ceilometer.api import app
|
||||
from ceilometer.event.storage import models
|
||||
from ceilometer.publisher import utils
|
||||
from ceilometer import sample
|
||||
|
@ -39,6 +40,17 @@ from ceilometer import storage
|
|||
# data store.
|
||||
ENGINES = ['mongodb']
|
||||
|
||||
# NOTE(chdent): Hack to restore semblance of global configuration to
|
||||
# pass to the WSGI app used per test suite. LOAD_APP_KWARGS are the olso
|
||||
# configuration, and the pecan application configuration of
|
||||
# which the critical part is a reference to the current indexer.
|
||||
LOAD_APP_KWARGS = None
|
||||
|
||||
|
||||
def setup_app():
|
||||
global LOAD_APP_KWARGS
|
||||
return app.load_app(**LOAD_APP_KWARGS)
|
||||
|
||||
|
||||
class ConfigFixture(fixture.GabbiFixture):
|
||||
"""Establish the relevant configuration for a test run."""
|
||||
|
@ -46,6 +58,8 @@ class ConfigFixture(fixture.GabbiFixture):
|
|||
def start_fixture(self):
|
||||
"""Set up config."""
|
||||
|
||||
global LOAD_APP_KWARGS
|
||||
|
||||
self.conf = None
|
||||
|
||||
# Determine the database connection.
|
||||
|
@ -94,6 +108,10 @@ class ConfigFixture(fixture.GabbiFixture):
|
|||
conf.set_override('aodh_is_enabled', False, group='api')
|
||||
conf.set_override('panko_is_enabled', False, group='api')
|
||||
|
||||
LOAD_APP_KWARGS = {
|
||||
'conf': conf,
|
||||
}
|
||||
|
||||
def stop_fixture(self):
|
||||
"""Reset the config and remove data."""
|
||||
if self.conf:
|
||||
|
|
|
@ -22,7 +22,6 @@ import os
|
|||
|
||||
from gabbi import driver
|
||||
|
||||
from ceilometer.api import app
|
||||
from ceilometer.tests.functional.gabbi import fixtures as fixture_module
|
||||
|
||||
TESTS_DIR = 'gabbits'
|
||||
|
@ -32,5 +31,5 @@ def load_tests(loader, tests, pattern):
|
|||
"""Provide a TestSuite to the discovery process."""
|
||||
test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
|
||||
return driver.build_tests(test_dir, loader, host=None,
|
||||
intercept=app.load_app,
|
||||
intercept=fixture_module.setup_app,
|
||||
fixture_module=fixture_module)
|
||||
|
|
|
@ -19,7 +19,6 @@ import os
|
|||
|
||||
from gabbi import driver
|
||||
|
||||
from ceilometer.api import app
|
||||
from ceilometer.tests.functional.gabbi import fixtures as fixture_module
|
||||
|
||||
TESTS_DIR = 'gabbits_prefix'
|
||||
|
@ -30,5 +29,5 @@ def load_tests(loader, tests, pattern):
|
|||
test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
|
||||
return driver.build_tests(test_dir, loader, host=None,
|
||||
prefix='/telemetry',
|
||||
intercept=app.setup_app,
|
||||
intercept=fixture_module.setup_app,
|
||||
fixture_module=fixture_module)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_config import fixture as fixture_config
|
||||
from oslo_log import log
|
||||
|
||||
from ceilometer.api import app
|
||||
from ceilometer.tests import base
|
||||
|
@ -27,10 +26,10 @@ class TestApp(base.BaseTestCase):
|
|||
def setUp(self):
|
||||
super(TestApp, self).setUp()
|
||||
self.CONF = self.useFixture(fixture_config.Config()).conf
|
||||
log.register_options(cfg.CONF)
|
||||
|
||||
def test_api_paste_file_not_exist(self):
|
||||
self.CONF.set_override('api_paste_config', 'non-existent-file')
|
||||
with mock.patch.object(self.CONF, 'find_file') as ff:
|
||||
ff.return_value = None
|
||||
self.assertRaises(cfg.ConfigFilesNotFoundError, app.load_app)
|
||||
self.assertRaises(cfg.ConfigFilesNotFoundError, app.load_app,
|
||||
self.CONF)
|
||||
|
|
|
@ -29,7 +29,7 @@ class TestTestNotifierHook(base.BaseTestCase):
|
|||
def test_init_notifier_with_drivers(self):
|
||||
self.CONF.set_override('telemetry_driver', 'messagingv2',
|
||||
group='publisher_notifier')
|
||||
hook = hooks.NotifierHook()
|
||||
hook = hooks.NotifierHook(self.CONF)
|
||||
notifier = hook.notifier
|
||||
self.assertIsInstance(notifier, oslo_messaging.Notifier)
|
||||
self.assertEqual(['messagingv2'], notifier._driver_names)
|
||||
|
|
Loading…
Reference in New Issue