Re-factor configuration loading, fix default topics (shall be a list),

update docs.
This commit is contained in:
Filip Valder
2017-01-31 14:00:15 +01:00
parent f7e5dd1f49
commit 89351fbc24
3 changed files with 110 additions and 40 deletions

View File

@@ -383,3 +383,31 @@ E.g. ``"scmurl": "git://pkgs.stg.fedoraproject.org/modules/testmodule.git?#020ea
The toplevel directory containing the trees for each architecture of a module.
This field is only present when a module finished building, i.e. with the
states 'done' or 'ready'.
Configuration
=============
MBS configures itself according to the environment where it runs + according to
the following rules (all of them are evaluated from top to bottom):
- DevConfiguration is the initial configuration chosen.
- If configuration file is found within its final installation location,
ProdConfiguration is assumed.
- If Flask app running within mod_wsgi is detected,
ProdConfiguration is assumed.
- If environment variables determining configuration file/section are found,
they are used for configuration. Following environment variables are
recognized:
- `MBS_CONFIG_FILE`: Overrides default configuration file location,
typically `/etc/module-build-service/config.py`.
- `MBS_CONFIG_SECTION`: Overrides configuration section.
It is possible to set these values in httpd using `SetEnv`,
anywhere in `/etc/profile.d/` etc.
- If test-runtime environment is detected,
TestConfiguration is used, otherwise...
- if `MODULE_BUILD_SERVICE_DEVELOPER_ENV` is set to some reasonable
value, DevConfiguration is forced and `config.py` is used directly from the
MBS's develop instance. For more information see `docs/CONTRIBUTING.rst`.

View File

@@ -133,9 +133,11 @@ Environment
The environment variable `MODULE_BUILD_SERVICE_DEVELOPER_ENV`, which if
set to "1", indicates to the Module Build Service that the development
configuration should be used. Docker and Vagrant are being run with this
environment variable set.
environment variable set. This overrides all configuration settings and forces
usage of DevConfiguration section in `conf/config.py` from MBS's develop
instance.
Anytime, you can do::
Prior to starting MBS, you can force development mode::
$ export MODULE_BUILD_SERVICE_DEVELOPER_ENV=1

View File

@@ -31,34 +31,77 @@ from os import sys
from module_build_service import logger
try:
conf_module = 'mbs_runtime_config'
mbs_runtime_config = imp.load_source(conf_module,
'/etc/module-build-service/config.py')
except:
conf_module = 'conf.config'
def init_config(app):
_init_app_config(app)
return Config(app)
def _init_app_config(app):
""" Configure app
""" Configure MBS and the Flask app
"""
app.config.from_envvar("MBS_SETTINGS", silent=True)
here = sys.path[0]
config_module = None
config_file = '/etc/module-build-service/config.py'
config_section = 'DevConfiguration'
# automagically detect production environment:
# - existing and readable config_file presets ProdConfiguration
try:
with open(config_file):
config_section = 'ProdConfiguration'
except:
pass
# - Flask app within mod_wsgi presets ProdConfiguration
flask_app_env = hasattr(app, 'request') and hasattr(app.request, 'environ')
if flask_app_env and any([var.startswith('mod_wsgi.')
for var in app.request.environ]):
config_section = 'ProdConfiguration'
# try getting config_file from os.environ
if 'MBS_CONFIG_FILE' in os.environ:
config_file = os.environ['MBS_CONFIG_FILE']
# try getting config_section from os.environ
if 'MBS_CONFIG_SECTION' in os.environ:
config_section = os.environ['MBS_CONFIG_SECTION']
# preferably get these values from Flask app
if flask_app_env:
# try getting config_file from Flask app
if 'MBS_CONFIG_FILE' in app.request.environ:
config_file = app.request.environ['MBS_CONFIG_FILE']
# try getting config_section from Flask app
if 'MBS_CONFIG_SECTION' in app.request.environ:
config_section = app.request.environ['MBS_CONFIG_SECTION']
# TestConfiguration shall only be used for running tests, otherwise...
if any(['nosetests' in arg or 'noserunner.py' in arg for arg in sys.argv]):
app.config.from_object('%s.TestConfiguration' % conf_module)
elif 'MODULE_BUILD_SERVICE_DEVELOPER_ENV' in os.environ and \
os.environ['MODULE_BUILD_SERVICE_DEVELOPER_ENV'].lower() in (
'1', 'on', 'true', 'y', 'yes'):
app.config.from_object('%s.DevConfiguration' % conf_module)
elif here not in ('/usr/bin', '/bin', '/usr/local/bin'):
app.config.from_object('%s.DevConfiguration' % conf_module)
else:
app.config.from_object('%s.ProdConfiguration' % conf_module)
config_section = 'TestConfiguration'
from conf import config
config_module = config
# ...MODULE_BUILD_SERVICE_DEVELOPER_ENV has always the last word
# and overrides anything previously set before!
# Again, check Flask app (preferably) or fallback to os.environ.
# In any of the following cases, use configuration directly from MBS package
# -> /conf/config.py.
elif (flask_app_env and
'MODULE_BUILD_SERVICE_DEVELOPER_ENV' in app.request.environ):
if app.request.environ['MODULE_BUILD_SERVICE_DEVELOPER_ENV'].lower() in (
'1', 'on', 'true', 'y', 'yes'):
config_section = 'DevConfiguration'
from conf import config
config_module = config
elif ('MODULE_BUILD_SERVICE_DEVELOPER_ENV' in os.environ and
os.environ['MODULE_BUILD_SERVICE_DEVELOPER_ENV'].lower() in (
'1', 'on', 'true', 'y', 'yes')):
config_section = 'DevConfiguration'
from conf import config
config_module = config
# try loading configuration from file
if not config_module:
try:
config_module = imp.load_source('mbs_runtime_config',
config_file)
except:
raise SystemError("Configuration file {} was not found."
.format(config_file))
# finally configure MBS and the Flask app
config_section_obj = getattr(config_module, config_section)
conf = Config(config_section_obj)
app.config.from_object(config_section_obj)
return conf
class Config(object):
@@ -199,7 +242,7 @@ class Config(object):
'desc': 'The messaging system to use.'},
'messaging_topic_prefix': {
'type': list,
'default': 'org.fedoraproject.prod',
'default': ['org.fedoraproject.prod'],
'desc': 'The messaging system topic prefixes which we are interested in.'},
'amq_recv_addresses': {
'type': list,
@@ -251,26 +294,23 @@ class Config(object):
'desc': 'Global network retry interval for read/write operations, in seconds.'},
}
def __init__(self, app=None):
def __init__(self, conf_section_obj):
"""
Initialize the Config object with defaults.
If Flask app is given, override/enrich the configuration defaults
with Flask config values/items.
Initialize the Config object with defaults and then override them
with runtime values.
"""
# set defaults
for name, values in self._defaults.items():
self.set_item(name, values['default'])
# we don't check whether app is Flask instance, we simply assume it
# so there's no need of import flask
if app is not None:
# override defaults
for key, value in app.config.items():
# lower keys
key = key.lower()
self.set_item(key, value)
# override defaults
for key in dir(conf_section_obj):
# skip keys starting with underscore
if key.startswith('_'):
continue
# set item (lower key)
self.set_item(key.lower(), getattr(conf_section_obj, key))
def set_item(self, key, value):
"""Set value for configuration item as self.key = value"""