From a8de10cde0b83743e8e453c8318cd1ab15e7c419 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 30 Oct 2013 10:02:38 -0400 Subject: DB: fixed how Django settings are loaded --- src/lib/Bcfg2/Client/__init__.py | 2 +- src/lib/Bcfg2/DBSettings.py | 178 ++++++++++++++++++++ src/lib/Bcfg2/Options/Parser.py | 41 ++++- src/lib/Bcfg2/Reporting/Storage/DjangoORM.py | 16 +- .../migrations/0002_convert_perms_to_mode.py | 3 +- src/lib/Bcfg2/Server/Admin.py | 24 ++- src/lib/Bcfg2/Server/Core.py | 22 +-- src/lib/Bcfg2/Server/Reports/updatefix.py | 3 +- src/lib/Bcfg2/Server/models.py | 4 +- src/lib/Bcfg2/settings.py | 185 --------------------- 10 files changed, 242 insertions(+), 236 deletions(-) create mode 100644 src/lib/Bcfg2/DBSettings.py delete mode 100644 src/lib/Bcfg2/settings.py (limited to 'src/lib') diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py index bae81f480..2461c1316 100644 --- a/src/lib/Bcfg2/Client/__init__.py +++ b/src/lib/Bcfg2/Client/__init__.py @@ -305,7 +305,7 @@ class Client(object): socket.gaierror, socket.error): err = sys.exc_info()[1] - self.logger.error("Failed to declare version: %s" % err) + self.fatal_error("Failed to declare version: %s" % err) self.run_probes() diff --git a/src/lib/Bcfg2/DBSettings.py b/src/lib/Bcfg2/DBSettings.py new file mode 100644 index 000000000..24835a3e8 --- /dev/null +++ b/src/lib/Bcfg2/DBSettings.py @@ -0,0 +1,178 @@ +""" Django settings for the Bcfg2 server """ + +import os +import sys +import logging +import Bcfg2.Logger +import Bcfg2.Options + +try: + import django + import django.conf + HAS_DJANGO = True +except ImportError: + HAS_DJANGO = False + +# required for reporting +try: + import south # pylint: disable=W0611 + HAS_SOUTH = True +except ImportError: + HAS_SOUTH = False + +settings = dict( # pylint: disable=C0103 + TIME_ZONE=None, + TEMPLATE_DEBUG=False, + DEBUG=False, + ALLOWED_HOSTS=['*'], + MEDIA_URL='/site_media/', + MANAGERS=(('Root', 'root')), + ADMINS=(('Root', 'root')), + # Language code for this installation. All choices can be found + # here: + # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes + # http://blogs.law.harvard.edu/tech/stories/storyReader$15 + LANGUAGE_CODE='en-us', + SITE_ID=1, + INSTALLED_APPS=('django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.admin', + 'Bcfg2.Server'), + MEDIA_ROOT='', + STATIC_URL='/media/', + # TODO - make this unique + SECRET_KEY='eb5+y%oy-qx*2+62vv=gtnnxg1yig_odu0se5$h0hh#pc*lmo7', + TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader'), + MIDDLEWARE_CLASSES=( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.middleware.doc.XViewMiddleware'), + ROOT_URLCONF='Bcfg2.Reporting.urls', + AUTHENTICATION_BACKENDS=('django.contrib.auth.backends.ModelBackend'), + LOGIN_URL='/login', + SESSION_EXPIRE_AT_BROWSER_CLOSE=True, + TEMPLATE_DIRS=( + '/usr/share/python-support/python-django/django/contrib/admin/' + 'templates/'), + TEMPLATE_CONTEXT_PROCESSORS=( + 'django.contrib.auth.context_processors.auth', + 'django.core.context_processors.debug', + 'django.core.context_processors.i18n', + 'django.core.context_processors.media', + 'django.core.context_processors.request')) + +if HAS_SOUTH: + settings['INSTALLED_APPS'] += ('south', 'Bcfg2.Reporting') +if 'BCFG2_LEGACY_MODELS' in os.environ: + settings['INSTALLED_APPS'] += ('Bcfg2.Server.Reports.reports',) + +if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] < 3: + settings['CACHE_BACKEND'] = 'locmem:///' +else: + settings['CACHES'] = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + } + } + + +def finalize_django_config(opts=None, silent=False): + """ Perform final Django configuration """ + if opts is None: + opts = Bcfg2.Options.setup + settings['DATABASES'] = dict( + default=dict( + ENGINE="django.db.backends.%s" % opts.db_engine, + NAME=opts.db_name, + USER=opts.db_user, + PASSWORD=opts.db_password, + HOST=opts.db_host, + PORT=opts.db_port, + OPTIONS=opts.db_opts, + SCHEMA=opts.db_schema)) + + settings['TIME_ZONE'] = opts.timezone + + settings['TEMPLATE_DEBUG'] = settings['DEBUG'] = \ + opts.web_debug + if opts.web_debug: + print("Warning: Setting web_debug to True causes extraordinary " + "memory leaks. Only use this setting if you know what " + "you're doing.") + + if opts.web_prefix: + settings['MEDIA_URL'] = \ + opts.web_prefix.rstrip('/') + \ + settings['MEDIA_URL'] + + logger = logging.getLogger() + + logger.debug("Finalizing Django settings: %s" % settings) + try: + django.conf.settings.configure(**settings) + except RuntimeError: + if not silent: + logger.warning("Failed to finalize Django settings: %s" % + sys.exc_info()[1]) + + +class _OptionContainer(object): + """ Container for options loaded at import-time to configure + databases """ + parse_first = True + options = [ + Bcfg2.Options.Common.repository, + Bcfg2.Options.PathOption( + '-W', '--web-config', cf=('reporting', 'config'), + default="/etc/bcfg2-web.conf", + action=Bcfg2.Options.ConfigFileAction, + help='Web interface configuration file'), + Bcfg2.Options.Option( + cf=('database', 'engine'), default='sqlite3', + help='Database engine', dest='db_engine'), + Bcfg2.Options.Option( + cf=('database', 'name'), default='/etc/bcfg2.sqlite', + help="Database name", dest="db_name"), + Bcfg2.Options.Option( + cf=('database', 'user'), help='Database username', dest='db_user'), + Bcfg2.Options.Option( + cf=('database', 'password'), help='Database password', + dest='db_password'), + Bcfg2.Options.Option( + cf=('database', 'host'), help='Database host', dest='db_host'), + Bcfg2.Options.Option( + cf=('database', 'port'), help='Database port', dest='db_port'), + Bcfg2.Options.Option( + cf=('database', 'schema'), help='Database schema', + dest='db_schema'), + Bcfg2.Options.Option( + cf=('database', 'options'), help='Database options', + dest='db_opts', type=Bcfg2.Options.Types.comma_dict, + default=dict()), + Bcfg2.Options.Option( + cf=('reporting', 'timezone'), help='Django timezone'), + Bcfg2.Options.BooleanOption( + cf=('reporting', 'web_debug'), help='Django debug'), + Bcfg2.Options.Option( + cf=('reporting', 'web_prefix'), help='Web prefix')] + + @staticmethod + def component_parsed_hook(opts): + """ Finalize the Django config after this component's options + are parsed. """ + finalize_django_config(opts=opts) + + @staticmethod + def options_parsed_hook(): + """ Finalize the Django config after all options are parsed. + This is added in case the DBSettings component isn't added + early enough in option parsing to be parsed in the 'early' + phase. Chances are good that things will break if that + happens, but we do our best to be a good citizen. """ + finalize_django_config(silent=True) + +Bcfg2.Options.get_parser().add_component(_OptionContainer) diff --git a/src/lib/Bcfg2/Options/Parser.py b/src/lib/Bcfg2/Options/Parser.py index bede85a1f..9258d000b 100644 --- a/src/lib/Bcfg2/Options/Parser.py +++ b/src/lib/Bcfg2/Options/Parser.py @@ -74,6 +74,11 @@ class Parser(argparse.ArgumentParser): self.namespace = kwargs.pop('namespace', setup) add_base_options = kwargs.pop('add_base_options', True) + #: Flag to indicate that this is the pre-parsing 'early' run + #: for important options like database settings that must be + #: loaded before other components can be. + self._early = kwargs.pop('early', False) + if 'add_help' not in kwargs: kwargs['add_help'] = add_base_options argparse.ArgumentParser.__init__(self, **kwargs) @@ -185,8 +190,8 @@ class Parser(argparse.ArgumentParser): :param argv: The argument list to parse. By default, ``sys.argv[1:]`` is used. This is stored in :attr:`Bcfg2.Options.Parser.argv` for reuse by - :func:`Bcfg2.Options.Parser.reparse`. :type - argv: list + :func:`Bcfg2.Options.Parser.reparse`. + :type argv: list """ if argv is None: argv = sys.argv[1:] @@ -204,7 +209,26 @@ class Parser(argparse.ArgumentParser): self.error("Could not read %s" % bootstrap.config) self.add_config_file(self.configfile.dest, bootstrap.config) - # phase 2: re-parse command line, loading additional + # phase 2: re-parse command line for early options; currently, + # that's database options + if not self._early: + early_opts = argparse.Namespace() + early_parser = Parser(add_help=False, namespace=early_opts, + early=True) + # add the repo option so we can resolve + # macros + early_parser.add_options([repository]) + early_components = [] + for component in self.components: + if getattr(component, "parse_first", False): + early_components.append(component) + early_parser.add_component(component) + early_parser.parse(self.argv) + for component in early_components: + if hasattr(component, "component_parsed_hook"): + getattr(component, "component_parsed_hook")(early_opts) + + # phase 3: re-parse command line, loading additional # components, until all components have been loaded. On each # iteration, set defaults from config file/environment # variables @@ -216,7 +240,7 @@ class Parser(argparse.ArgumentParser): self._finalize() self._parse_config_options() - # phase 3: fix up macros + # phase 4: fix up macros repo = getattr(self.namespace, "repository", repository.default) for attr in dir(self.namespace): value = getattr(self.namespace, attr) @@ -224,10 +248,11 @@ class Parser(argparse.ArgumentParser): setattr(self.namespace, attr, value.replace("", repo, 1)) - # phase 4: call post-parsing hooks - for component in self.components: - if hasattr(component, "options_parsed_hook"): - getattr(component, "options_parsed_hook")() + # phase 5: call post-parsing hooks + if not self._early: + for component in self.components: + if hasattr(component, "options_parsed_hook"): + getattr(component, "options_parsed_hook")() return self.namespace diff --git a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py index 69da9c571..f6f46ee12 100644 --- a/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py +++ b/src/lib/Bcfg2/Reporting/Storage/DjangoORM.py @@ -2,16 +2,11 @@ The base for the original DjangoORM (DBStats) """ -import os -import traceback from lxml import etree from datetime import datetime from time import strptime - -os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings' -from Bcfg2 import settings - import Bcfg2.Options +import Bcfg2.DBSettings from Bcfg2.Compat import md5 from Bcfg2.Reporting.Storage.base import StorageBase, StorageError from Bcfg2.Server.Plugin.exceptions import PluginExecutionError @@ -377,9 +372,6 @@ class DjangoORM(StorageBase): def validate(self): """Validate backend storage. Should be called once when loaded""" - - settings.read_config() - # verify our database schema try: if Bcfg2.Options.setup.debug: @@ -392,9 +384,9 @@ class DjangoORM(StorageBase): management.call_command("migrate", verbosity=vrb, interactive=False) except: - self.logger.error("Failed to update database schema: %s" % - sys.exc_info()[1]) - raise StorageError + msg = "Failed to update database schema: %s" % sys.exc_info()[1] + self.logger.error(msg) + raise StorageError(msg) def GetExtra(self, client): """Fetch extra entries for a client""" diff --git a/src/lib/Bcfg2/Reporting/migrations/0002_convert_perms_to_mode.py b/src/lib/Bcfg2/Reporting/migrations/0002_convert_perms_to_mode.py index 668094cf5..37cdd146c 100644 --- a/src/lib/Bcfg2/Reporting/migrations/0002_convert_perms_to_mode.py +++ b/src/lib/Bcfg2/Reporting/migrations/0002_convert_perms_to_mode.py @@ -3,8 +3,7 @@ import datetime from south.db import db from south.v2 import SchemaMigration from django.db import models - -from Bcfg2 import settings +from django.conf import settings class Migration(SchemaMigration): diff --git a/src/lib/Bcfg2/Server/Admin.py b/src/lib/Bcfg2/Server/Admin.py index c82a6d7fd..6a56657cf 100644 --- a/src/lib/Bcfg2/Server/Admin.py +++ b/src/lib/Bcfg2/Server/Admin.py @@ -15,6 +15,7 @@ import argparse import lxml.etree import Bcfg2.Logger import Bcfg2.Options +import Bcfg2.DBSettings import Bcfg2.Server.Core import Bcfg2.Client.Proxy from Bcfg2.Server.Plugin import PullSource, Generator, MetadataConsistencyError @@ -22,10 +23,9 @@ from Bcfg2.Utils import hostnames2ranges, Executor, safe_input import Bcfg2.Server.Plugins.Metadata try: - import Bcfg2.settings - os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings' from django.core.exceptions import ImproperlyConfigured from django.core import management + import django.conf import Bcfg2.Server.models HAS_DJANGO = True @@ -833,12 +833,11 @@ class _ReportsCmd(AdminCmd): # pylint: disable=W0223 self.reports_classes = () def setup(self): - # this has to be imported after options are parsed, - # because Django finalizes its settings as soon as it's - # loaded, which means that if we import this before - # Bcfg2.settings has been populated, Django gets a null - # configuration, and subsequent updates to Bcfg2.settings - # won't help. + # this has to be imported after options are parsed, because + # Django finalizes its settings as soon as it's loaded, which + # means that if we import this before Bcfg2.DBSettings has + # been populated, Django gets a null configuration, and + # subsequent updates to Bcfg2.DBSettings won't help. import Bcfg2.Reporting.models # pylint: disable=W0621 self.reports_entries = (Bcfg2.Reporting.models.Group, Bcfg2.Reporting.models.Bundle, @@ -884,7 +883,6 @@ if HAS_DJANGO: """ Sync the Django ORM with the configured database """ def run(self, setup): - management.setup_environ(Bcfg2.settings) Bcfg2.Server.models.load_models() try: management.call_command("syncdb", interactive=False, @@ -911,9 +909,9 @@ if HAS_REPORTS: # this has to be imported after options are parsed, # because Django finalizes its settings as soon as it's # loaded, which means that if we import this before - # Bcfg2.settings has been populated, Django gets a null - # configuration, and subsequent updates to Bcfg2.settings - # won't help. + # Bcfg2.DBSettings has been populated, Django gets a null + # configuration, and subsequent updates to + # Bcfg2.DBSettings won't help. from django.db.transaction import commit_on_success self.run = commit_on_success(self.run) @@ -1011,7 +1009,7 @@ if HAS_REPORTS: self.logger.debug("Filtering by maxdate: %s" % maxdate) ipurge = ipurge.filter(timestamp__lt=maxdate) - if Bcfg2.settings.DATABASES['default']['ENGINE'] == \ + if django.conf.settings.DATABASES['default']['ENGINE'] == \ 'django.db.backends.sqlite3': grp_limit = 100 else: diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index e3a9f7fce..9174878b2 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -14,7 +14,7 @@ import lxml.etree import Bcfg2.Server import Bcfg2.Logger import Bcfg2.Options -import Bcfg2.settings +import Bcfg2.DBSettings import Bcfg2.Server.Statistics import Bcfg2.Server.FileMonitor from itertools import chain @@ -24,14 +24,20 @@ from Bcfg2.Server.Plugin.exceptions import * # pylint: disable=W0401,W0614 from Bcfg2.Server.Plugin.interfaces import * # pylint: disable=W0401,W0614 from Bcfg2.Server.Plugin import track_statistics +try: + from django.core.exceptions import ImproperlyConfigured + from django.core import management + import django.conf + HAS_DJANGO = True +except ImportError: + HAS_DJANGO = False + try: import psyco psyco.full() except ImportError: pass -os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings' - def exposed(func): """ Decorator that sets the ``exposed`` attribute of a function to @@ -198,10 +204,6 @@ class Core(object): #: RLock to be held on writes to the backend db self.db_write_lock = threading.RLock() - # generate Django ORM settings. this must be done _before_ we - # load plugins - Bcfg2.settings.read_config() - # mapping of group name => plugin name to record where groups # that are created by Connector plugins came from self._dynamic_groups = dict() @@ -232,9 +234,7 @@ class Core(object): #: Whether or not it's possible to use the Django database #: backend for plugins that have that capability self._database_available = False - if Bcfg2.settings.HAS_DJANGO: - from django.core.exceptions import ImproperlyConfigured - from django.core import management + if HAS_DJANGO: try: management.call_command("syncdb", interactive=False, verbosity=0) @@ -1343,7 +1343,7 @@ class NetworkCore(Core): self.ca = Bcfg2.Options.setup.ca if self._database_available: - db_settings = Bcfg2.settings.DATABASES['default'] + db_settings = django.conf.settings.DATABASES['default'] if (Bcfg2.Options.setup.daemon and Bcfg2.Options.setup.daemon_uid and db_settings['ENGINE'].endswith(".sqlite3") and diff --git a/src/lib/Bcfg2/Server/Reports/updatefix.py b/src/lib/Bcfg2/Server/Reports/updatefix.py index c3fbcd2e9..91c370994 100644 --- a/src/lib/Bcfg2/Server/Reports/updatefix.py +++ b/src/lib/Bcfg2/Server/Reports/updatefix.py @@ -1,5 +1,4 @@ -import Bcfg2.settings - +import Bcfg2.DBSettings from django.db import connection import django.core.management import sys diff --git a/src/lib/Bcfg2/Server/models.py b/src/lib/Bcfg2/Server/models.py index 51cc835dc..7150c245a 100644 --- a/src/lib/Bcfg2/Server/models.py +++ b/src/lib/Bcfg2/Server/models.py @@ -51,9 +51,9 @@ def load_models(plugins=None): """ load models from plugins specified in the config """ # this has to be imported after options are parsed, because Django # finalizes its settings as soon as it's loaded, which means that - # if we import this before Bcfg2.settings has been populated, + # if we import this before Bcfg2.DBSettings has been populated, # Django gets a null configuration, and subsequent updates to - # Bcfg2.settings won't help. + # Bcfg2.DBSettings won't help. from django.db import models global MODELS diff --git a/src/lib/Bcfg2/settings.py b/src/lib/Bcfg2/settings.py deleted file mode 100644 index 7ddf58aed..000000000 --- a/src/lib/Bcfg2/settings.py +++ /dev/null @@ -1,185 +0,0 @@ -""" Django settings for the Bcfg2 server """ - -import os -import Bcfg2.Options - -try: - import django - HAS_DJANGO = True -except ImportError: - HAS_DJANGO = False - -# required for reporting -try: - import south # pylint: disable=W0611 - HAS_SOUTH = True -except ImportError: - HAS_SOUTH = False - -DATABASES = dict(default=dict()) - -TIME_ZONE = None - -TEMPLATE_DEBUG = DEBUG = False - -ALLOWED_HOSTS = ['*'] - -MEDIA_URL = '/site_media/' - -MANAGERS = ADMINS = (('Root', 'root')) - -# Language code for this installation. All choices can be found here: -# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes -# http://blogs.law.harvard.edu/tech/stories/storyReader$15 -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# TODO - sanitize this -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.admin', - 'Bcfg2.Server', -) -if HAS_SOUTH: - INSTALLED_APPS = INSTALLED_APPS + ( - 'south', - 'Bcfg2.Reporting', - ) -if 'BCFG2_LEGACY_MODELS' in os.environ: - INSTALLED_APPS += ('Bcfg2.Server.Reports.reports',) - -# Imported from Bcfg2.Server.Reports -MEDIA_ROOT = '' - -# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a -# trailing slash. -STATIC_URL = '/media/' - -#TODO - make this unique -# Make this unique, and don't share it with anybody. -SECRET_KEY = 'eb5+y%oy-qx*2+62vv=gtnnxg1yig_odu0se5$h0hh#pc*lmo7' - -if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] < 3: - CACHE_BACKEND = 'locmem:///' -else: - CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - } - } - -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -) - -#TODO - review these. auth and sessions aren't really used -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.middleware.doc.XViewMiddleware', -) - -# TODO - move this to a higher root and dynamically import -ROOT_URLCONF = 'Bcfg2.Reporting.urls' - -# TODO - this isn't usable -# Authentication Settings -AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend') - -LOGIN_URL = '/login' - -SESSION_EXPIRE_AT_BROWSER_CLOSE = True - -TEMPLATE_DIRS = ( - # App loaders should take care of this.. not sure why this is here - '/usr/share/python-support/python-django/django/contrib/admin/templates/', -) - -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.request' -) - - -def read_config(): - """ read the config file and set django settings based on it """ - global DEBUG, TEMPLATE_DEBUG, TIME_ZONE, MEDIA_URL # pylint: disable=W0603 - - DATABASES['default'] = \ - dict(ENGINE="django.db.backends.%s" % Bcfg2.Options.setup.db_engine, - NAME=Bcfg2.Options.setup.db_name, - USER=Bcfg2.Options.setup.db_user, - PASSWORD=Bcfg2.Options.setup.db_password, - HOST=Bcfg2.Options.setup.db_host, - PORT=Bcfg2.Options.setup.db_port, - OPTIONS=Bcfg2.Options.setup.db_opts, - SCHEMA=Bcfg2.Options.setup.db_schema) - - TIME_ZONE = Bcfg2.Options.setup.timezone - - TEMPLATE_DEBUG = DEBUG = Bcfg2.Options.setup.web_debug - if DEBUG: - print("Warning: Setting web_debug to True causes extraordinary memory " - "leaks. Only use this setting if you know what you're doing.") - - if Bcfg2.Options.setup.web_prefix: - MEDIA_URL = Bcfg2.Options.setup.web_prefix.rstrip('/') + MEDIA_URL - - -class _OptionContainer(object): - """ Container for options loaded at import-time to configure - databases """ - options = [ - Bcfg2.Options.Common.repository, - Bcfg2.Options.PathOption( - '-W', '--web-config', cf=('reporting', 'config'), - default="/etc/bcfg2-web.conf", - action=Bcfg2.Options.ConfigFileAction, - help='Web interface configuration file'), - Bcfg2.Options.Option( - cf=('database', 'engine'), default='sqlite3', - help='Database engine', dest='db_engine'), - Bcfg2.Options.Option( - cf=('database', 'name'), default='/etc/bcfg2.sqlite', - help="Database name", dest="db_name"), - Bcfg2.Options.Option( - cf=('database', 'user'), help='Database username', dest='db_user'), - Bcfg2.Options.Option( - cf=('database', 'password'), help='Database password', - dest='db_password'), - Bcfg2.Options.Option( - cf=('database', 'host'), help='Database host', dest='db_host'), - Bcfg2.Options.Option( - cf=('database', 'port'), help='Database port', dest='db_port'), - Bcfg2.Options.Option( - cf=('database', 'schema'), help='Database schema', - dest='db_schema'), - Bcfg2.Options.Option( - cf=('database', 'options'), help='Database options', - dest='db_opts', type=Bcfg2.Options.Types.comma_dict, - default=dict()), - Bcfg2.Options.Option( - cf=('reporting', 'timezone'), help='Django timezone'), - Bcfg2.Options.BooleanOption( - cf=('reporting', 'web_debug'), help='Django debug'), - Bcfg2.Options.Option( - cf=('reporting', 'web_prefix'), help='Web prefix')] - - @staticmethod - def options_parsed_hook(): - """ initialize settings from /etc/bcfg2-web.conf or - /etc/bcfg2.conf, or set up basic defaults. this lets - manage.py work in all cases """ - read_config() - - -Bcfg2.Options.get_parser().add_component(_OptionContainer) -- cgit v1.2.3-1-g7c22