root: auto-migrate on startup, lock database using pg_advisory_lock

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-04-18 14:47:50 +02:00
parent caa5dc1d14
commit 7b8e5c4272
3 changed files with 36 additions and 39 deletions

View File

@ -43,29 +43,6 @@ spec:
values: values:
- web - web
topologyKey: "kubernetes.io/hostname" 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: containers:
- name: {{ .Chart.Name }} - name: {{ .Chart.Name }}
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}" image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"

View File

@ -2,13 +2,13 @@
python -m lifecycle.wait_for_db python -m lifecycle.wait_for_db
printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr printf '{"event": "Bootstrap completed", "level": "info", "logger": "bootstrap", "command": "%s"}\n' "$@" > /dev/stderr
if [[ "$1" == "server" ]]; then if [[ "$1" == "server" ]]; then
python -m lifecycle.migrate
gunicorn -c /lifecycle/gunicorn.conf.py authentik.root.asgi:application gunicorn -c /lifecycle/gunicorn.conf.py authentik.root.asgi:application
elif [[ "$1" == "worker" ]]; then 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 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 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 lifecycle.migrate
python -m manage migrate
elif [[ "$1" == "backup" ]]; then elif [[ "$1" == "backup" ]]; then
python -m manage dbbackup --clean python -m manage dbbackup --clean
elif [[ "$1" == "restore" ]]; then elif [[ "$1" == "restore" ]]; then

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
"""System Migration handler""" """System Migration handler"""
import os
from importlib.util import module_from_spec, spec_from_file_location from importlib.util import module_from_spec, spec_from_file_location
from inspect import getmembers, isclass from inspect import getmembers, isclass
from pathlib import Path from pathlib import Path
@ -11,6 +12,7 @@ from structlog.stdlib import get_logger
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
LOGGER = get_logger() LOGGER = get_logger()
ADV_LOCK_UID = 1000
class BaseMigration: class BaseMigration:
@ -40,8 +42,13 @@ if __name__ == "__main__":
host=CONFIG.y("postgresql.host"), host=CONFIG.y("postgresql.host"),
) )
curr = conn.cursor() curr = conn.cursor()
# lock an advisory lock to prevent multiple instances from migrating at once
for migration in Path(__file__).parent.absolute().glob("system_migrations/*.py"): 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) spec = spec_from_file_location("lifecycle.system_migrations", migration)
mod = module_from_spec(spec) mod = module_from_spec(spec)
# pyright: reportGeneralTypeIssues=false # pyright: reportGeneralTypeIssues=false
@ -55,3 +62,16 @@ if __name__ == "__main__":
LOGGER.info("Migration needs to be applied", migration=sub) LOGGER.info("Migration needs to be applied", migration=sub)
migration.run() migration.run()
LOGGER.info("Migration finished applying", migration=sub) 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,))