diff --git a/helm/templates/web-deployment.yaml b/helm/templates/web-deployment.yaml index 74a9ed979..109f5d3d5 100644 --- a/helm/templates/web-deployment.yaml +++ b/helm/templates/web-deployment.yaml @@ -43,29 +43,6 @@ spec: values: - web topologyKey: "kubernetes.io/hostname" - initContainers: - - name: authentik-database-migrations - image: "{{ .Values.image.name }}:{{ .Values.image.tag }}" - imagePullPolicy: "{{ .Values.image.pullPolicy }}" - args: [migrate] - envFrom: - - configMapRef: - name: {{ include "authentik.fullname" . }}-config - prefix: AUTHENTIK_ - - secretRef: - name: {{ include "authentik.fullname" . }}-secret-key - prefix: AUTHENTIK_ - env: - - name: AUTHENTIK_REDIS__PASSWORD - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-redis" - key: redis-password - - name: AUTHENTIK_POSTGRESQL__PASSWORD - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-postgresql" - key: postgresql-password containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.name }}:{{ .Values.image.tag }}" diff --git a/lifecycle/bootstrap.sh b/lifecycle/bootstrap.sh index 12eec0a6e..d4e318c1f 100755 --- a/lifecycle/bootstrap.sh +++ b/lifecycle/bootstrap.sh @@ -2,13 +2,13 @@ python -m lifecycle.wait_for_db printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr if [[ "$1" == "server" ]]; then + python -m lifecycle.migrate gunicorn -c /lifecycle/gunicorn.conf.py authentik.root.asgi:application elif [[ "$1" == "worker" ]]; then celery -A authentik.root.celery worker --autoscale 3,1 -E -B -s /tmp/celerybeat-schedule -Q authentik,authentik_scheduled,authentik_events elif [[ "$1" == "migrate" ]]; then - # Run system migrations first, run normal migrations after + printf "DEPERECATED: database migrations are now executed automatically on startup." python -m lifecycle.migrate - python -m manage migrate elif [[ "$1" == "backup" ]]; then python -m manage dbbackup --clean elif [[ "$1" == "restore" ]]; then diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 75ad665a0..3ce9c71ab 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -1,5 +1,6 @@ #!/usr/bin/env python """System Migration handler""" +import os from importlib.util import module_from_spec, spec_from_file_location from inspect import getmembers, isclass from pathlib import Path @@ -11,6 +12,7 @@ from structlog.stdlib import get_logger from authentik.lib.config import CONFIG LOGGER = get_logger() +ADV_LOCK_UID = 1000 class BaseMigration: @@ -40,18 +42,36 @@ if __name__ == "__main__": host=CONFIG.y("postgresql.host"), ) curr = conn.cursor() + # lock an advisory lock to prevent multiple instances from migrating at once + LOGGER.info("waiting to acquire database lock") + curr.execute("SELECT pg_advisory_lock(%s)", (ADV_LOCK_UID,)) + try: + for migration in ( + Path(__file__).parent.absolute().glob("system_migrations/*.py") + ): + spec = spec_from_file_location("lifecycle.system_migrations", migration) + mod = module_from_spec(spec) + # pyright: reportGeneralTypeIssues=false + spec.loader.exec_module(mod) - for migration in Path(__file__).parent.absolute().glob("system_migrations/*.py"): - spec = spec_from_file_location("lifecycle.system_migrations", migration) - mod = module_from_spec(spec) - # pyright: reportGeneralTypeIssues=false - spec.loader.exec_module(mod) - - for name, sub in getmembers(mod, isclass): - if name != "Migration": - continue - migration = sub(curr, conn) - if migration.needs_migration(): - LOGGER.info("Migration needs to be applied", migration=sub) - migration.run() - LOGGER.info("Migration finished applying", migration=sub) + for name, sub in getmembers(mod, isclass): + if name != "Migration": + continue + migration = sub(curr, conn) + if migration.needs_migration(): + LOGGER.info("Migration needs to be applied", migration=sub) + migration.run() + LOGGER.info("Migration finished applying", migration=sub) + LOGGER.info("applying django migrations") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(["", "migrate"]) + finally: + curr.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,))