summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/DBSettings.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Bcfg2/DBSettings.py')
-rw-r--r--src/lib/Bcfg2/DBSettings.py154
1 files changed, 125 insertions, 29 deletions
diff --git a/src/lib/Bcfg2/DBSettings.py b/src/lib/Bcfg2/DBSettings.py
index 5a83c25c3..172f88f24 100644
--- a/src/lib/Bcfg2/DBSettings.py
+++ b/src/lib/Bcfg2/DBSettings.py
@@ -21,8 +21,9 @@ try:
except ImportError:
HAS_SOUTH = False
-settings = dict( # pylint: disable=C0103
- TIME_ZONE=None,
+# pylint: disable=C0103
+settings = dict(
+ TIME_ZONE='UTC',
TEMPLATE_DEBUG=False,
DEBUG=False,
ALLOWED_HOSTS=['*'],
@@ -50,37 +51,66 @@ settings = dict( # pylint: disable=C0103
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.middleware.doc.XViewMiddleware'),
+ 'django.contrib.auth.middleware.AuthenticationMiddleware'),
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=(
+ DATABASE_ROUTERS=['Bcfg2.DBSettings.PerApplicationRouter'],
+ TEST_RUNNER='django.test.simple.DjangoTestSuiteRunner',
+ CACHES={
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ }
+ })
+
+if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] >= 6:
+ settings['MIDDLEWARE_CLASSES'] += \
+ ('django.contrib.admindocs.middleware.XViewMiddleware',)
+elif HAS_SOUTH:
+ settings['MIDDLEWARE_CLASSES'] += \
+ ('django.middleware.doc.XViewMiddleware',)
+
+if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] >= 7:
+ settings['INSTALLED_APPS'] += ('Bcfg2.Reporting',)
+elif HAS_SOUTH:
+ settings['INSTALLED_APPS'] += ('south', 'Bcfg2.Reporting')
+ settings['SOUTH_MIGRATION_MODULES'] = {
+ 'Reporting': 'Bcfg2.Reporting.south_migrations',
+ 'Server': 'Bcfg2.Server.south_migrations',
+ }
+if HAS_DJANGO and django.VERSION[0] == 1 and django.VERSION[1] >= 8:
+ settings['TEMPLATES'] = [{
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [
+ '/usr/share/python-support/python-django/' +
+ 'django/contrib/admin/templates/'
+ ],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.contrib.auth.context_processors.auth',
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.i18n',
+ 'django.template.context_processors.media',
+ 'django.template.context_processors.request',
+ ],
+ },
+ }]
+else:
+ settings['TEMPLATE_DIRS'] = ('/usr/share/python-support/python-django/' +
+ 'django/contrib/admin/templates/')
+ settings['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'),
- DATABASE_ROUTERS=['Bcfg2.DBSettings.PerApplicationRouter'])
+ '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 """
@@ -97,8 +127,8 @@ def finalize_django_config(opts=None, silent=False):
OPTIONS=opts.db_opts,
SCHEMA=opts.db_schema))
- if hasattr(opts, "reporting_db_engine") and \
- opts.reporting_db_engine is not None:
+ if (hasattr(opts, "reporting_db_engine") and
+ opts.reporting_db_engine is not None):
settings['DATABASES']['Reporting'] = dict(
ENGINE="django.db.backends.%s" % opts.reporting_db_engine,
NAME=opts.reporting_db_name,
@@ -123,6 +153,9 @@ def finalize_django_config(opts=None, silent=False):
opts.web_prefix.rstrip('/') + \
settings['MEDIA_URL']
+ if opts.django_settings:
+ settings.update(opts.django_settings)
+
logger = logging.getLogger()
logger.debug("Finalizing Django settings: %s" % settings)
@@ -131,6 +164,8 @@ def finalize_django_config(opts=None, silent=False):
setattr(module, name, value)
try:
django.conf.settings.configure(**settings)
+ if django.VERSION[0] == 1 and django.VERSION[1] >= 7:
+ django.setup() # pylint: disable=E1101
except RuntimeError:
if not silent:
logger.warning("Failed to finalize Django settings: %s" %
@@ -139,6 +174,10 @@ def finalize_django_config(opts=None, silent=False):
def sync_databases(**kwargs):
""" Synchronize all databases that we know about. """
+ if django.VERSION[0] == 1 and django.VERSION[1] >= 7:
+ # Nothing needed here, it's all handled with migrate
+ return
+
logger = logging.getLogger()
for database in settings['DATABASES']:
logger.debug("Syncing database %s" % (database))
@@ -146,11 +185,55 @@ def sync_databases(**kwargs):
**kwargs)
+def upgrade_to_django_migrations(database, logger):
+ """
+ Get the migration state from south and move django migrations to
+ the same state by fake applying the same migration.
+
+ Note: We cannot use south directly here, because this functions
+ runs on django-1.7 or higher, that is not supported by south.
+ """
+
+ last_migration = None
+ try:
+ # get latest south migration
+ cursor = django.db.connections[database].cursor()
+ cursor.cursor.execute('SELECT migration FROM south_migrationhistory')
+ applied_migrations = [name for (name,) in cursor.fetchall()]
+ last_migration = sorted(applied_migrations).pop()
+ # django.db.DatabaseError is not working here, because we are
+ # using the low level api to interact directly with the database
+ except: # pylint: disable=W0702
+ logger.debug("No south migration detected for database: %s." %
+ database)
+
+ if last_migration is not None:
+ # fake-apply matching django migrations
+ django.core.management.call_command(
+ "migrate", 'Reporting', last_migration,
+ database=database, fake=True)
+
+
+def initial_django_migration(database):
+ """ Check if we ever executed an initial django migration. """
+ from django.db.migrations import loader # pylint: disable=E0611
+ loader = loader.MigrationLoader(django.db.connections[database])
+ return len(loader.applied_migrations) == 0
+
+
def migrate_databases(**kwargs):
""" Do South migrations on all databases that we know about. """
logger = logging.getLogger()
for database in settings['DATABASES']:
logger.debug("Migrating database %s" % (database))
+ if django.VERSION[0] == 1 and django.VERSION[1] >= 7:
+ if initial_django_migration(database):
+ logger.warning(
+ "No applied django migrations found for database %s. "
+ "Trying to get the state from south migration in case "
+ "you just upgraded your django version." % database)
+ upgrade_to_django_migrations(database, logger)
+
django.core.management.call_command("migrate", database=database,
**kwargs)
@@ -193,7 +276,14 @@ class PerApplicationRouter(object):
def allow_syncdb(self, *_):
""" Called when Django wants to determine which models to sync to a
given database. Take the cowards way out and sync all models to all
- databases to allow for easy migrations. """
+ databases to allow for easy migrations. This method is replaced with
+ allow_migrate in django 1.7 and higher. """
+ return True
+
+ def allow_migrate(self, *_args, **_kwargs):
+ """ Called when Django wants to determine which migrations should
+ be run on a given database. Take the cowards way out and run all
+ migrations to all databases to allow for easy migrations. """
return True
@@ -229,7 +319,7 @@ class _OptionContainer(object):
dest='db_schema', default='public'),
Bcfg2.Options.Option(
cf=('database', 'options'), help='Database options',
- dest='db_opts', type=Bcfg2.Options.Types.comma_dict,
+ dest='db_opts', type=Bcfg2.Options.Types.literal_dict,
default=dict()),
# reporting database options
Bcfg2.Options.Option(
@@ -258,20 +348,25 @@ class _OptionContainer(object):
Bcfg2.Options.Option(
cf=('database', 'reporting_options'),
help='Reporting database options', dest='reporting_db_opts',
- type=Bcfg2.Options.Types.comma_dict, default=dict()),
+ type=Bcfg2.Options.Types.literal_dict, default=dict()),
# Django options
Bcfg2.Options.Option(
cf=('reporting', 'time_zone'), help='Django timezone'),
Bcfg2.Options.BooleanOption(
cf=('reporting', 'web_debug'), help='Django debug'),
Bcfg2.Options.Option(
- cf=('reporting', 'web_prefix'), help='Web prefix')]
+ cf=('reporting', 'web_prefix'), help='Web prefix'),
+ Bcfg2.Options.Option(
+ cf=('reporting', 'django_settings'),
+ help='Additional django settings',
+ type=Bcfg2.Options.Types.literal_dict, default=dict())]
@staticmethod
def component_parsed_hook(opts):
""" Finalize the Django config after this component's options
are parsed. """
- finalize_django_config(opts=opts)
+ if HAS_DJANGO:
+ finalize_django_config(opts=opts)
@staticmethod
def options_parsed_hook():
@@ -280,6 +375,7 @@ class _OptionContainer(object):
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)
+ if HAS_DJANGO:
+ finalize_django_config(silent=True)
Bcfg2.Options.get_parser().add_component(_OptionContainer)