launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #05040
[Merge] lp:~wgrant/launchpad/overridable-dbconfig into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/overridable-dbconfig into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/overridable-dbconfig/+merge/76316
Allow DatabaseConfig's settings to be overridden, so production code doesn't have to push ugly config overlay stacks and handle crufty database config sections. initZopeless will be rebuilt on top of this.
--
https://code.launchpad.net/~wgrant/launchpad/overridable-dbconfig/+merge/76316
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/overridable-dbconfig into lp:launchpad.
=== modified file 'daemons/librarian.tac'
--- daemons/librarian.tac 2011-03-11 13:37:12 +0000
+++ daemons/librarian.tac 2011-09-21 01:36:18 +0000
@@ -25,7 +25,9 @@
from lp.services.twistedsupport.loggingsupport import set_up_oops_reporting
# Connect to database
-dbconfig.setConfigSection('librarian')
+dbconfig.override(
+ dbuser=config.librarian.dbuser,
+ isolation_level=config.librarian.isolation_level)
execute_zcml_for_scripts()
if os.environ.get('LP_TEST_INSTANCE'):
=== modified file 'lib/canonical/config/__init__.py'
--- lib/canonical/config/__init__.py 2011-09-16 09:31:34 +0000
+++ lib/canonical/config/__init__.py 2011-09-21 01:36:18 +0000
@@ -402,8 +402,11 @@
raise ValueError(
"Invalid log level %s. "
"Should be DEBUG, CRITICAL, ERROR, FATAL, INFO, WARNING "
- "as per logging module." % value
- )
+ "as per logging module." % value)
+
+
+class DatabaseConfigOverrides(object):
+ pass
class DatabaseConfig:
@@ -420,6 +423,9 @@
'dbuser', 'rw_main_master', 'rw_main_slave', 'ro_main_master',
'ro_main_slave'])
+ def __init__(self):
+ self.reset()
+
@property
def main_master(self):
# Its a bit silly having ro_main_master and rw_main_master.
@@ -438,6 +444,23 @@
else:
return self.rw_main_slave
+ def override(self, **kwargs):
+ """Override one or more config attributes.
+
+ Overriding a value to None removes the override.
+ """
+ for attr, value in kwargs.iteritems():
+ assert attr in self._db_config_attrs, (
+ "%s cannot be overriden" % attr)
+ if value is None:
+ if hasattr(self.overrides, attr):
+ delattr(self.overrides, attr)
+ else:
+ setattr(self.overrides, attr, value)
+
+ def reset(self):
+ self.overrides = DatabaseConfigOverrides()
+
def setConfigSection(self, section_name):
self._config_section = section_name
@@ -456,7 +479,7 @@
overlay = config
for part in self._config_section.split('.'):
overlay = getattr(overlay, part)
- return [overlay, config.database]
+ return [self.overrides, overlay, config.database]
def __getattr__(self, name):
sections = self._getConfigSections()
=== modified file 'lib/canonical/config/tests/test_database_config.py'
--- lib/canonical/config/tests/test_database_config.py 2011-09-05 15:42:27 +0000
+++ lib/canonical/config/tests/test_database_config.py 2011-09-21 01:36:18 +0000
@@ -3,7 +3,11 @@
__metaclass__ = type
-from canonical.config import config, dbconfig
+from canonical.config import (
+ config,
+ DatabaseConfig,
+ dbconfig,
+ )
from canonical.launchpad.readonly import read_only_file_exists
from canonical.launchpad.tests.readonly import (
remove_read_only_file,
@@ -37,6 +41,39 @@
self.assertEquals(expected_db, dbconfig.rw_main_master)
self.assertEquals('launchpad_main', dbconfig.dbuser)
+ def test_override(self):
+ # dbuser and isolation_level can be overridden at runtime, without
+ # requiring a custom config overlay.
+ dbc = DatabaseConfig()
+ dbc.setConfigSection('launchpad')
+ self.assertEqual('launchpad_main', dbc.dbuser)
+ self.assertEqual('serializable', dbc.isolation_level)
+
+ # dbuser and isolation_level overrides both work.
+ dbc.override(dbuser='not_launchpad', isolation_level='autocommit')
+ self.assertEqual('not_launchpad', dbc.dbuser)
+ self.assertEqual('autocommit', dbc.isolation_level)
+
+ # Overriding dbuser again preserves the isolation_level override.
+ dbc.override(dbuser='also_not_launchpad')
+ self.assertEqual('also_not_launchpad', dbc.dbuser)
+ self.assertEqual('autocommit', dbc.isolation_level)
+
+ # Overriding with None removes the override.
+ dbc.override(dbuser=None, isolation_level=None)
+ self.assertEqual('launchpad_main', dbc.dbuser)
+ self.assertEqual('serializable', dbc.isolation_level)
+
+ def test_reset(self):
+ # reset() removes any overrides.
+ dbc = DatabaseConfig()
+ dbc.setConfigSection('launchpad')
+ self.assertEqual('launchpad_main', dbc.dbuser)
+ dbc.override(dbuser='not_launchpad')
+ self.assertEqual('not_launchpad', dbc.dbuser)
+ dbc.reset()
+ self.assertEqual('launchpad_main', dbc.dbuser)
+
def test_required_values(self):
# Some variables are required to have a value, such as dbuser. So we
# get a ValueError if they are not set.
=== modified file 'lib/canonical/launchpad/webapp/ftests/test_adapter.txt'
--- lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2011-09-19 13:25:14 +0000
+++ lib/canonical/launchpad/webapp/ftests/test_adapter.txt 2011-09-21 01:36:18 +0000
@@ -423,10 +423,8 @@
>>> print store.execute("select current_user").get_one()[0]
launchpad_main
- >>> from canonical.config import config, dbconfig
- >>> config.statistician.dbuser
- 'statistician'
- >>> dbconfig.setConfigSection('statistician')
+ >>> from canonical.config import dbconfig
+ >>> dbconfig.override(dbuser='statistician')
>>> reset_store()
>>> print store.execute("select current_user").get_one()[0]
statistician
@@ -452,9 +450,9 @@
<BLANKLINE>
>>> transaction.abort()
-So you need to explicitly set the user back:
+So you need to explicitly set the user back to the default:
- >>> dbconfig.setConfigSection('launchpad')
+ >>> dbconfig.override(dbuser=None)
>>> reset_store()
>>> print store.execute("select current_user").get_one()[0]
launchpad_main
=== modified file 'lib/canonical/testing/layers.py'
--- lib/canonical/testing/layers.py 2011-09-18 13:04:13 +0000
+++ lib/canonical/testing/layers.py 2011-09-21 01:36:18 +0000
@@ -217,7 +217,10 @@
sure the right data is available.
"""
disconnect_stores()
- dbconfig.setConfigSection(database_config_section)
+ section = getattr(config, database_config_section)
+ dbconfig.override(
+ dbuser=getattr(section, 'dbuser', None),
+ isolation_level=getattr(section, 'isolation_level', None))
main_store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
assert main_store is not None, 'Failed to reconnect'