Customize config file location when run as wsgi app.

Running keystone as a wsgi application should allow the same kind of
customization as when run from the command line. Setting sys.argv for
wsgi applications is difficult so that environment variables need to
be used for this purpose.

Closes-Bug: #1552397

Change-Id: I1cd8c7c9f8d4c748384f9b72511b677176672791
This commit is contained in:
Cristian Sava 2016-03-04 00:55:03 +00:00
parent ef07ad60b4
commit c7cb72b20e
3 changed files with 154 additions and 4 deletions

View File

@ -107,6 +107,13 @@ Keystone's primary configuration file (``etc/keystone.conf``) and the
PasteDeploy configuration file (``etc/keystone-paste.ini``) must be readable to
HTTPD in one of the default locations described in :doc:`configuration`.
Configuration file location can be customized using the ``OS_KEYSTONE_CONFIG_DIR``
environment variable: if this is set, the ``keystone.conf`` file will be searched
inside this directory. Arbitrary configuration file locations can be specified
using ``OS_KEYSTONE_CONFIG_FILES`` variable as semicolon separated entries,
representing either configuration directory based relative paths or absolute
paths.
Enable the site by creating a symlink from the file in ``sites-available`` to
``sites-enabled``, for example, on Debian/Ubuntu systems
(not required on Red Hat based systems)::

View File

@ -13,6 +13,7 @@
# under the License.
import logging
import os
from oslo_config import cfg
import oslo_i18n
@ -35,8 +36,13 @@ from keystone.version import service as keystone_service
CONF = cfg.CONF
def initialize_application(name, post_log_configured_function=lambda: None):
common.configure()
def initialize_application(name,
post_log_configured_function=lambda: None,
config_files=None):
if not config_files:
config_files = None
common.configure(config_files=config_files)
# Log the options used when starting if we're in debug mode...
if CONF.debug:
@ -58,9 +64,28 @@ def initialize_application(name, post_log_configured_function=lambda: None):
return application
def _get_config_files(env=None):
if env is None:
env = os.environ
dirname = env.get('OS_KEYSTONE_CONFIG_DIR', '').strip()
files = [s.strip() for s in
env.get('OS_KEYSTONE_CONFIG_FILES', '').split(';') if s.strip()]
if dirname:
if not files:
files = ['keystone.conf']
files = [os.path.join(dirname, fname) for fname in files]
return files
def initialize_admin_application():
return initialize_application('admin')
return initialize_application(name='admin',
config_files=_get_config_files())
def initialize_public_application():
return initialize_application('main')
return initialize_application(name='main',
config_files=_get_config_files())

View File

@ -15,6 +15,7 @@
# under the License.
import gettext
import os
import uuid
import mock
@ -27,6 +28,7 @@ import webob
from keystone.common import wsgi
from keystone import exception
from keystone.server import wsgi as server_wsgi
from keystone.tests import unit
@ -309,6 +311,122 @@ class ApplicationTest(BaseWSGITest):
self.assertEqual(b"http://foo/identity", resp.body)
class WSGIAppConfigTest(unit.TestCase):
default_config_file = 'keystone.conf'
custom_config_dir = '/etc/kst/'
custom_config_files = ['kst.conf', 'kst2.conf']
def test_config_files_have_default_values_when_envars_not_set(self):
config_files = server_wsgi._get_config_files()
config_files.sort()
expected_config_files = []
self.assertListEqual(config_files, expected_config_files)
def test_config_files_have_default_values_with_empty_envars(self):
env = {'OS_KEYSTONE_CONFIG_FILES': '',
'OS_KEYSTONE_CONFIG_DIR': ''}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = []
self.assertListEqual(config_files, expected_config_files)
def test_can_use_single_config_file_under_default_config_dir(self):
cfg = self.custom_config_files[0]
env = {'OS_KEYSTONE_CONFIG_FILES': cfg}
config_files = server_wsgi._get_config_files(env)
expected_config_files = [cfg]
self.assertListEqual(config_files, expected_config_files)
def test_can_use_multiple_config_files_under_default_config_dir(self):
env = {'OS_KEYSTONE_CONFIG_FILES': ';'.join(self.custom_config_files)}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = self.custom_config_files
self.assertListEqual(config_files, expected_config_files)
config_with_empty_strings = self.custom_config_files + ['', ' ']
env = {'OS_KEYSTONE_CONFIG_FILES': ';'.join(config_with_empty_strings)}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
self.assertListEqual(config_files, expected_config_files)
def test_can_use_single_absolute_path_config_file(self):
cfg = self.custom_config_files[0]
cfgpath = os.path.join(self.custom_config_dir, cfg)
env = {'OS_KEYSTONE_CONFIG_FILES': cfgpath}
config_files = server_wsgi._get_config_files(env)
self.assertListEqual(config_files, [cfgpath])
def test_can_use_multiple_absolute_path_config_files(self):
cfgpaths = [os.path.join(self.custom_config_dir, cfg)
for cfg in self.custom_config_files]
cfgpaths.sort()
env = {'OS_KEYSTONE_CONFIG_FILES': ';'.join(cfgpaths)}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
self.assertListEqual(config_files, cfgpaths)
env = {'OS_KEYSTONE_CONFIG_FILES': ';'.join(cfgpaths + ['', ' '])}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
self.assertListEqual(config_files, cfgpaths)
def test_can_use_default_config_files_with_custom_config_dir(self):
env = {'OS_KEYSTONE_CONFIG_DIR': self.custom_config_dir}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = [os.path.join(self.custom_config_dir,
self.default_config_file)]
self.assertListEqual(config_files, expected_config_files)
def test_can_use_single_config_file_under_custom_config_dir(self):
cfg = self.custom_config_files[0]
env = {'OS_KEYSTONE_CONFIG_DIR': self.custom_config_dir,
'OS_KEYSTONE_CONFIG_FILES': cfg}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = [os.path.join(self.custom_config_dir, cfg)]
self.assertListEqual(config_files, expected_config_files)
def test_can_use_multiple_config_files_under_custom_config_dir(self):
env = {'OS_KEYSTONE_CONFIG_DIR': self.custom_config_dir,
'OS_KEYSTONE_CONFIG_FILES': ';'.join(self.custom_config_files)}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = [os.path.join(self.custom_config_dir, s)
for s in self.custom_config_files]
expected_config_files.sort()
self.assertListEqual(config_files, expected_config_files)
config_with_empty_strings = self.custom_config_files + ['', ' ']
env = {'OS_KEYSTONE_CONFIG_DIR': self.custom_config_dir,
'OS_KEYSTONE_CONFIG_FILES': ';'.join(config_with_empty_strings)}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
self.assertListEqual(config_files, expected_config_files)
def test_can_mix_relative_and_absolute_paths_config_file(self):
cfg0 = self.custom_config_files[0]
cfgpath0 = os.path.join(self.custom_config_dir,
self.custom_config_files[0])
cfgpath1 = os.path.join(self.custom_config_dir,
self.custom_config_files[1])
env = {'OS_KEYSTONE_CONFIG_DIR': self.custom_config_dir,
'OS_KEYSTONE_CONFIG_FILES': ';'.join([cfg0, cfgpath1])}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = [cfgpath0, cfgpath1]
expected_config_files.sort()
self.assertListEqual(config_files, expected_config_files)
env = {'OS_KEYSTONE_CONFIG_FILES': ';'.join([cfg0, cfgpath1])}
config_files = server_wsgi._get_config_files(env)
config_files.sort()
expected_config_files = [cfg0, cfgpath1]
expected_config_files.sort()
self.assertListEqual(config_files, expected_config_files)
class ExtensionRouterTest(BaseWSGITest):
def test_extensionrouter_local_config(self):
class FakeRouter(wsgi.ExtensionRouter):