Skip to content
This repository has been archived by the owner on Dec 7, 2022. It is now read-only.

Commit

Permalink
server.conf is lazily loaded
Browse files Browse the repository at this point in the history
pulp.server.config would load /etc/pulp/server.conf unconditionally at
import time. Converting this to lazily loading the config file allows
for the config object to be instantiated without immediately trying
to read the conf. This also allows changing the config files before
loading them, which makes pulp.server.config testable.

fixes #607
  • Loading branch information
seandst committed Dec 9, 2015
1 parent 9791986 commit 3f17525
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 24 deletions.
47 changes: 43 additions & 4 deletions devel/pulp/devel/unit/server/base.py
Expand Up @@ -49,14 +49,53 @@ def _load_test_config():

config.config.set('database', 'name', 'pulp_unittest')
config.config.set('server', 'storage_dir', '/tmp/pulp')
override_config_attrs()

start_logging()


def override_config_attrs():
# Remove server.conf from the autoloaded config files
# does not get restored by restore_config_attrs; server.conf shouldn't ever be used in testing
block_load_conf()

if not hasattr(config, '_overridden_attrs'):
# only save these once so we don't end up saving _enforce_config as the "original" values
setattr(config, '_overridden_attrs', {
'__setattr__': config.__setattr__,
'load_configuration': config.load_configuration,
'config.set': config.config.set,
})

# Prevent the tests from altering the config so that nobody accidentally makes global changes
config.config.set = _enforce_config
config.load_configuration = _enforce_config
config.__setattr__ = _enforce_config
config.config.__setattr__ = _enforce_config
config.load_configuration = _enforce_config
config.config.set = _enforce_config

start_logging()

def restore_config_attrs():
# Restore values overridden by _override_config_attrs
if not hasattr(config, '_overridden_attrs'):
return

for attr in '__setattr__', 'load_configuration':
setattr(config, attr, config._overridden_attrs[attr])
setattr(config.config, attr, config._overridden_attrs['config.set'])

del(config._overridden_attrs)


def block_load_conf():
# Remove server.conf from the list of autoloaded config files
# This is needed when testing modules that create objects using conf data found in the
# server config, such as DB connections, celery, etc. This should be used as little as
# possible and as early as possible, before config file loads happen
conf = '/etc/pulp/server.conf'
try:
config.remove_config_file(conf)
except RuntimeError:
# server.conf already removed, move along...
pass


class PulpWebservicesTests(unittest.TestCase):
Expand Down
1 change: 0 additions & 1 deletion devel/test/unit/server/test_base.py
Expand Up @@ -61,7 +61,6 @@ def test_load_test_config(self, start_logging, stop_logging, config_set):
self.assertTrue(config.config.set is base._enforce_config)
self.assertTrue(config.load_configuration is base._enforce_config)
self.assertTrue(config.__setattr__ is base._enforce_config)
self.assertTrue(config.config.__setattr__ is base._enforce_config)


class StartDatabaseConnectionTestCase(unittest.TestCase):
Expand Down
3 changes: 3 additions & 0 deletions nodes/test/nodes_tests/__init__.py
@@ -1,4 +1,7 @@
from pulp.devel.unit.server import base as devel_base
from pulp.devel.unit.server.base import block_load_conf

block_load_conf()


def setup():
Expand Down
63 changes: 45 additions & 18 deletions server/pulp/server/config.py
Expand Up @@ -3,7 +3,45 @@
from ConfigParser import SafeConfigParser


config = None # ConfigParser.SafeConfigParser instance
class LazyConfigParser(SafeConfigParser):
def __init__(self, *args, **kwargs):
self.reload()
SafeConfigParser.__init__(self, *args, **kwargs)

# The superclass _sections attr takes precedence over the property of
# the same name defined below. Deleting it exposes that property to hook
# the config loading mechanism into an attribute used by just about every
# ConfigParser method.
self._lazy_sections = self._sections
del self._sections

def reload(self):
self._loaded = False

@property
def _sections(self):
self._load_config()
return self._lazy_sections

def _load_config(self):
# calls to self.get/self.set access _sections, which triggers _load_config,
# so to avoid infinite recursion _loaded is set before calling those methods
if self._loaded:
return
self._loaded = True

# add the defaults first
self._sections.clear()
for section, settings in _default_values.items():
self.add_section(section)
for option, value in settings.items():
self.set(section, option, value)

# check and load config files
check_config_files()
self.read(_config_files)

config = LazyConfigParser()

# to guarantee that a section and/or setting exists, add a default value here
_default_values = {
Expand Down Expand Up @@ -112,16 +150,10 @@ def load_configuration():
"""
Check the configuration files and load the global 'config' object from them.
"""
global config
check_config_files()
config = SafeConfigParser()
# add the defaults first
for section, settings in _default_values.items():
config.add_section(section)
for option, value in settings.items():
config.set(section, option, value)
# read the config files
return config.read(_config_files)
# config is lazy, so this doesn't immediately trigger a load
# the actual load will occur the next time config is accessed
config.reload()
return config


def add_config_file(file_path):
Expand All @@ -132,11 +164,10 @@ def add_config_file(file_path):
@type file_path: str
@param file_path: full path to the new file to add
"""
global _config_files
if file_path in _config_files:
raise RuntimeError('File, %s, already in configuration files' % file_path)
_config_files.append(file_path)
load_configuration()
config.reload()


def remove_config_file(file_path):
Expand All @@ -147,11 +178,7 @@ def remove_config_file(file_path):
@type file_path: str
@param file_path: full path to the file to remove
"""
global _config_files
if file_path not in _config_files:
raise RuntimeError('File, %s, not in configuration files' % file_path)
_config_files.remove(file_path)
load_configuration()


load_configuration()
config.reload()
1 change: 0 additions & 1 deletion server/test/unit/plugins/util/test_publish_step.py
Expand Up @@ -23,7 +23,6 @@
from pulp.server.db import model
from pulp.server.managers import factory


factory.initialize()


Expand Down

0 comments on commit 3f17525

Please sign in to comment.