diff options
Diffstat (limited to 'src/lib/Bcfg2/DBSettings.py')
-rw-r--r-- | src/lib/Bcfg2/DBSettings.py | 154 |
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) |