launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #21053
[Merge] lp:~wgrant/launchpad/config-overlay-dir into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/config-overlay-dir into lp:launchpad.
Commit message:
Support a config overlay directory.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/config-overlay-dir/+merge/307493
Support a config overlay directory.
If launchpad-lazr.conf configures launchpad.config_overlay_dir,
*-lazr.conf within that directory (relative to the config file) will be
pushed onto the top of the config stack in lexicographic order.
This is handy for non-version-controlled secrets and similar.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/config-overlay-dir into lp:launchpad.
=== modified file 'lib/lp/services/config/__init__.py'
--- lib/lp/services/config/__init__.py 2012-08-09 04:41:57 +0000
+++ lib/lp/services/config/__init__.py 2016-10-04 00:02:09 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
'''
@@ -11,6 +11,7 @@
__metaclass__ = type
+import glob
import logging
import os
import sys
@@ -213,6 +214,7 @@
config_file = os.path.join(config_dir, 'launchpad-lazr.conf')
schema = ImplicitTypeSchema(schema_file)
self._config = schema.load(config_file)
+ self._loadConfigOverlays(config_file)
try:
self._config.validate()
except ConfigErrors as error:
@@ -220,6 +222,16 @@
raise ConfigErrors(message)
self._setZConfig()
+ def _loadConfigOverlays(self, config_file):
+ """Apply config overlays from the launchpad.config_overlay_dir."""
+ rel_dir = self._config['launchpad']['config_overlay_dir']
+ dir = os.path.join(
+ os.path.dirname(os.path.abspath(config_file)), rel_dir)
+ for path in sorted(glob.glob(os.path.join(dir, '*-lazr.conf'))):
+ with open(path) as f:
+ text = f.read()
+ self._config.push(path, text)
+
@property
def zope_config_file(self):
"""Return the path to the ZConfig file for this instance."""
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2016-09-02 18:21:07 +0000
+++ lib/lp/services/config/schema-lazr.conf 2016-10-04 00:02:09 +0000
@@ -840,6 +840,12 @@
[launchpad]
+# A directory of files from which *-lazr.conf will be loaded and
+# overlayed in order on top of the main config.
+# Note that this is relative to the top-level config file, not
+# necessarily the one where the setting is actually configured!
+config_overlay_dir:
+
# The database user which will be used by this process.
# datatype: string
dbuser: launchpad_main
=== modified file 'lib/lp/services/config/tests/test_config.py'
--- lib/lp/services/config/tests/test_config.py 2013-01-07 03:47:45 +0000
+++ lib/lp/services/config/tests/test_config.py 2016-10-04 00:02:09 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
# We know we are not using root and handlers.
@@ -15,12 +15,15 @@
import os
import unittest
+from fixtures import TempDir
from lazr.config import ConfigSchema
from lazr.config.interfaces import ConfigErrors
import pkg_resources
+import testtools
import ZConfig
import lp.services.config
+from lp.services.config.fixture import ConfigUseFixture
# Configs that shouldn't be tested.
EXCLUDED_CONFIGS = ['lpnet-template']
@@ -68,7 +71,7 @@
return LAZRConfigTestCase
-class TestLaunchpadConfig(unittest.TestCase):
+class TestLaunchpadConfig(testtools.TestCase):
def test_dir(self):
# dir(config) returns methods, variables and section names.
@@ -88,6 +91,55 @@
sections = set(config._config)
self.assertEqual(sections, set(config))
+ def test_override_directory(self):
+ # The launchpad.config_overlay_dir setting can be used to load
+ # extra config files over the top. This is useful for overlaying
+ # non-version-controlled secrets.
+ config_dir = self.useFixture(TempDir(rootdir='configs')).path
+ config_name = os.path.basename(config_dir)
+ overlay_dir = self.useFixture(TempDir(rootdir='configs')).path
+ with open(os.path.join(config_dir, 'launchpad-lazr.conf'), 'w') as f:
+ f.write("""
+ [meta]
+ extends: ../testrunner/launchpad-lazr.conf
+
+ [launchpad]
+ config_overlay_dir: ../%s
+ """ % os.path.basename(overlay_dir))
+ os.symlink(
+ '../testrunner/launchpad.conf',
+ os.path.join(config_dir, 'launchpad.conf'))
+
+ config = lp.services.config.config
+
+ with ConfigUseFixture(config_name):
+ self.assertEqual('launchpad_main', config.launchpad.dbuser)
+ self.assertEqual('', config.launchpad.site_message)
+
+ with open(os.path.join(overlay_dir, '00-test-lazr.conf'), 'w') as f:
+ f.write("""
+ [launchpad]
+ dbuser: overlay-user
+ site_message: An overlay!
+ """)
+ with ConfigUseFixture(config_name):
+ self.assertEqual('overlay-user', config.launchpad.dbuser)
+ self.assertEqual('An overlay!', config.launchpad.site_message)
+
+ with open(os.path.join(overlay_dir, '01-test-lazr.conf'), 'w') as f:
+ f.write("""
+ [launchpad]
+ site_message: Another overlay!
+ """)
+ with ConfigUseFixture(config_name):
+ self.assertEqual('overlay-user', config.launchpad.dbuser)
+ self.assertEqual('Another overlay!', config.launchpad.site_message)
+
+ os.unlink(os.path.join(overlay_dir, '00-test-lazr.conf'))
+ with ConfigUseFixture(config_name):
+ self.assertEqual('launchpad_main', config.launchpad.dbuser)
+ self.assertEqual('Another overlay!', config.launchpad.site_message)
+
def test_suite():
"""Return a suite of canonical.conf and all conf files."""
Follow ups