summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/development/option_parsing.txt10
-rw-r--r--misc/bcfg2.spec2
-rw-r--r--reports/reports.wsgi9
-rw-r--r--src/lib/Bcfg2/Client/__init__.py2
-rw-r--r--src/lib/Bcfg2/DBSettings.py178
-rw-r--r--src/lib/Bcfg2/Options/Parser.py41
-rw-r--r--src/lib/Bcfg2/Reporting/Storage/DjangoORM.py16
-rw-r--r--src/lib/Bcfg2/Reporting/migrations/0002_convert_perms_to_mode.py3
-rw-r--r--src/lib/Bcfg2/Server/Admin.py24
-rw-r--r--src/lib/Bcfg2/Server/Core.py22
-rw-r--r--src/lib/Bcfg2/Server/Reports/updatefix.py3
-rw-r--r--src/lib/Bcfg2/Server/models.py4
-rw-r--r--src/lib/Bcfg2/settings.py185
-rwxr-xr-xsrc/sbin/bcfg2-reports20
-rw-r--r--testsuite/common.py12
-rwxr-xr-xtools/upgrade/1.3/migrate_dbstats.py1
-rwxr-xr-xtools/upgrade/1.3/migrate_probe_groups_to_db.py27
17 files changed, 281 insertions, 278 deletions
diff --git a/doc/development/option_parsing.txt b/doc/development/option_parsing.txt
index 52da8fced..091f43cdd 100644
--- a/doc/development/option_parsing.txt
+++ b/doc/development/option_parsing.txt
@@ -67,9 +67,19 @@ There is no required interface for an option component. They may
* An ``options`` attribute that is a list of
:class:`Bcfg2.Options.Options.Option` objects or option groups.
+* A boolean ``parse_first`` attribute; if set to True, the options for
+ the component are parsed before all other options. This is useful
+ for, e.g., Django database settings, which must be parsed before
+ plugins that use Django can be loaded.
* A function or static method, ``options_parsed_hook``, that is called
when all options have been parsed. (This will be called again if
:func:`Bcfg2.Options.Parser.Parser.reparse` is called.)
+* A function or static method, ``component_parsed_hook``, that is
+ called when early option parsing for a given component has
+ completed. This is *only* called for components with
+ ``parse_first`` set to True. It is passed a single argument: a
+ :class:`argparse.Namespace` object containing the complete set of
+ early options.
Options are collected through two primary mechanisms:
diff --git a/misc/bcfg2.spec b/misc/bcfg2.spec
index 21516c0ed..fc997ebc0 100644
--- a/misc/bcfg2.spec
+++ b/misc/bcfg2.spec
@@ -712,7 +712,7 @@ sed "s@http://www.w3.org/2001/xml.xsd@file://$(pwd)/schemas/xml.xsd@" \
%config(noreplace) %{_sysconfdir}/sysconfig/bcfg2-server
%{_sbindir}/bcfg2-*
%dir %{_localstatedir}/lib/%{name}
-%{python_sitelib}/Bcfg2/settings.py*
+%{python_sitelib}/Bcfg2/DBSettings.py*
%{python_sitelib}/Bcfg2/Server
%{python_sitelib}/Bcfg2/Reporting
%{python_sitelib}/Bcfg2/manage.py*
diff --git a/reports/reports.wsgi b/reports/reports.wsgi
index 92401d763..c2a2be1ce 100644
--- a/reports/reports.wsgi
+++ b/reports/reports.wsgi
@@ -1,9 +1,10 @@
import os
-import Bcfg2.settings
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings'
+import Bcfg2.Options
+import Bcfg2.DBSettings
+
+Bcfg2.Options.get_parser().parse()
+
import django.core.handlers.wsgi
def application(environ, start_response):
- if 'BCFG2_CONFIG_FILE' in environ:
- Bcfg2.settings.read_config(cfile=environ['BCFG2_CONFIG_FILE'])
return django.core.handlers.wsgi.WSGIHandler()(environ, start_response)
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='<repository>/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 <repository>
+ # 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 <repository> macros
+ # phase 4: fix up <repository> 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("<repository>", 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
@@ -25,13 +25,19 @@ 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='<repository>/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)
diff --git a/src/sbin/bcfg2-reports b/src/sbin/bcfg2-reports
index bb45e0009..f38d99435 100755
--- a/src/sbin/bcfg2-reports
+++ b/src/sbin/bcfg2-reports
@@ -4,25 +4,9 @@
import os
import sys
import datetime
-from optparse import OptionParser, OptionGroup, make_option
+import Bcfg2.DBSettings
from Bcfg2.Compat import ConfigParser
-
-try:
- import Bcfg2.settings
-except ConfigParser.NoSectionError:
- print("Your bcfg2.conf is currently missing the [database] section which "
- "is necessary for the reporting interface. Please see bcfg2.conf(5) "
- "for more details.")
- sys.exit(1)
-
-project_directory = os.path.dirname(Bcfg2.settings.__file__)
-project_name = os.path.basename(project_directory)
-sys.path.append(os.path.join(project_directory, '..'))
-project_module = __import__(project_name, '', '', [''])
-sys.path.pop()
-# Set DJANGO_SETTINGS_MODULE appropriately.
-os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name
-
+from optparse import OptionParser, OptionGroup, make_option
from Bcfg2.Reporting.models import (Client, BaseEntry)
def hosts_by_entry_type(clients, etype, entryspec):
diff --git a/testsuite/common.py b/testsuite/common.py
index 49035a177..c0dd8b518 100644
--- a/testsuite/common.py
+++ b/testsuite/common.py
@@ -39,11 +39,9 @@ def set_setup_default(option, value=None):
setattr(Bcfg2.Options.setup, option, value)
try:
- from django.core.management import setup_environ
+ import django.conf
has_django = True
- os.environ['DJANGO_SETTINGS_MODULE'] = "Bcfg2.settings"
-
set_setup_default("db_engine", "sqlite3")
set_setup_default("db_name",
os.path.join(os.path.dirname(os.path.abspath(__file__)),
@@ -58,8 +56,8 @@ try:
set_setup_default("web_debug", False)
set_setup_default("web_prefix")
- import Bcfg2.settings
- Bcfg2.settings.read_config()
+ import Bcfg2.DBSettings
+ Bcfg2.DBSettings.finalize_django_config()
except ImportError:
has_django = False
@@ -163,12 +161,12 @@ class DBModelTestCase(Bcfg2TestCase):
def test_syncdb(self):
""" Create the test database and sync the schema """
if self.models:
- setup_environ(Bcfg2.settings)
import django.core.management
django.core.management.call_command("syncdb", interactive=False,
verbosity=0)
self.assertTrue(
- os.path.exists(Bcfg2.settings.DATABASES['default']['NAME']))
+ os.path.exists(
+ django.conf.settings.DATABASES['default']['NAME']))
@skipUnless(has_django, "Django not found, skipping")
def test_cleandb(self):
diff --git a/tools/upgrade/1.3/migrate_dbstats.py b/tools/upgrade/1.3/migrate_dbstats.py
index f52ccab08..ed514289a 100755
--- a/tools/upgrade/1.3/migrate_dbstats.py
+++ b/tools/upgrade/1.3/migrate_dbstats.py
@@ -2,7 +2,6 @@
import os
os.environ['BCFG2_LEGACY_MODELS'] = '1'
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings'
import sys
import logging
diff --git a/tools/upgrade/1.3/migrate_probe_groups_to_db.py b/tools/upgrade/1.3/migrate_probe_groups_to_db.py
index 73339e787..f9abbf982 100755
--- a/tools/upgrade/1.3/migrate_probe_groups_to_db.py
+++ b/tools/upgrade/1.3/migrate_probe_groups_to_db.py
@@ -4,16 +4,13 @@ and Probe plugins. Does not migrate individual probe return data. Assumes
migration to BOTH Metadata and Probe to database backends. """
import os
-os.environ['DJANGO_SETTINGS_MODULE'] = 'Bcfg2.settings'
-
-import lxml.etree
import sys
+import lxml.etree
import Bcfg2.Options
+import Bcfg2.DBSettings
-from Bcfg2.Server.Plugins.Metadata import MetadataClientModel
-from Bcfg2.Server.Plugins.Probes import ProbesGroupsModel
-def migrate(xclient):
+def migrate(xclient, MetadataClientModel, ProbesGroupsModel):
""" Helper to do the migration given a <Client/> XML element """
client_name = xclient.get('name')
try:
@@ -32,9 +29,11 @@ def migrate(xclient):
group_name = xgroup.get('name')
cgroups.append(group_name)
try:
- group = ProbesGroupsModel.objects.get(hostname=client_name, group=group_name)
+ group = ProbesGroupsModel.objects.get(hostname=client_name,
+ group=group_name)
except ProbesGroupsModel.DoesNotExist:
- group = ProbesGroupsModel(hostname=client_name, group=group_name)
+ group = ProbesGroupsModel(hostname=client_name,
+ group=group_name)
group.save()
ProbesGroupsModel.objects.filter(
@@ -46,6 +45,7 @@ def migrate(xclient):
return False
return True
+
def main():
""" Main """
opts = dict(repo=Bcfg2.Options.SERVER_REPOSITORY)
@@ -59,10 +59,15 @@ def main():
except lxml.etree.XMLSyntaxError:
err = sys.exc_info()[1]
print("Could not parse %s, skipping: %s" % (probefile, err))
-
+
+ # these must be loaded after option parsing is complete
+ from Bcfg2.Server.Plugins.Metadata import MetadataClientModel
+ from Bcfg2.Server.Plugins.Probes import ProbesGroupsModel
+
for xclient in xdata.findall('Client'):
- print "Migrating Metadata and Probe groups for %s" % xclient.get('name')
- migrate(xclient)
+ print("Migrating Metadata and Probe groups for %s" %
+ xclient.get('name'))
+ migrate(xclient, MetadataClientModel, ProbesGroupsModel)
if __name__ == '__main__':
sys.exit(main())