From f3a2b211eda9edfe85a0f6b5232bb1a70a9e846c Mon Sep 17 00:00:00 2001 From: dvirlabs <114520947+dvirlabs@users.noreply.github.com> Date: Mon, 8 Dec 2025 14:33:01 +0200 Subject: [PATCH] Add admin user --- .../templates/admin-init-configmap.yaml | 99 +++++++++++++++++++ .../templates/admin-init-job.yaml | 75 ++++++++++++++ manifests/my-recipes/values.yaml | 10 ++ 3 files changed, 184 insertions(+) create mode 100644 charts/my-recipes-chart/templates/admin-init-configmap.yaml create mode 100644 charts/my-recipes-chart/templates/admin-init-job.yaml diff --git a/charts/my-recipes-chart/templates/admin-init-configmap.yaml b/charts/my-recipes-chart/templates/admin-init-configmap.yaml new file mode 100644 index 0000000..7bda3cd --- /dev/null +++ b/charts/my-recipes-chart/templates/admin-init-configmap.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-admin-init + namespace: {{ .Values.global.namespace }} +data: + create-admin.py: | + #!/usr/bin/env python3 + import os + import sys + import psycopg2 + import bcrypt + from time import sleep + + def wait_for_db(): + """Wait for database to be ready""" + max_retries = 30 + retry_count = 0 + + while retry_count < max_retries: + try: + conn = psycopg2.connect( + host=os.environ['DB_HOST'], + port=os.environ['DB_PORT'], + database=os.environ['DB_NAME'], + user=os.environ['DB_USER'], + password=os.environ['DB_PASSWORD'] + ) + conn.close() + print("✓ Database is ready") + return True + except Exception as e: + retry_count += 1 + print(f"Waiting for database... ({retry_count}/{max_retries})") + sleep(2) + + print("✗ Database connection timeout") + return False + + def create_admin_user(): + """Create admin user if not exists""" + try: + # Hash the password + password = os.environ.get('ADMIN_PASSWORD', 'admin123') + password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') + + # Connect to database + conn = psycopg2.connect( + host=os.environ['DB_HOST'], + port=os.environ['DB_PORT'], + database=os.environ['DB_NAME'], + user=os.environ['DB_USER'], + password=os.environ['DB_PASSWORD'] + ) + cur = conn.cursor() + + # Insert admin user + cur.execute(""" + INSERT INTO users (username, email, password_hash, first_name, last_name, display_name, is_admin) + VALUES (%s, %s, %s, %s, %s, %s, %s) + ON CONFLICT (username) DO UPDATE SET + email = EXCLUDED.email, + password_hash = EXCLUDED.password_hash, + first_name = EXCLUDED.first_name, + last_name = EXCLUDED.last_name, + display_name = EXCLUDED.display_name, + is_admin = EXCLUDED.is_admin + """, ( + os.environ.get('ADMIN_USERNAME', 'admin'), + os.environ.get('ADMIN_EMAIL', 'admin@myrecipes.local'), + password_hash, + os.environ.get('ADMIN_FIRST_NAME', 'Admin'), + os.environ.get('ADMIN_LAST_NAME', 'User'), + os.environ.get('ADMIN_DISPLAY_NAME', 'מנהל'), + True + )) + + conn.commit() + cur.close() + conn.close() + + print(f"✓ Admin user '{os.environ.get('ADMIN_USERNAME', 'admin')}' created/updated successfully") + return True + + except Exception as e: + print(f"✗ Error creating admin user: {e}") + return False + + if __name__ == "__main__": + print("Starting admin user initialization...") + + if not wait_for_db(): + sys.exit(1) + + if not create_admin_user(): + sys.exit(1) + + print("✓ Admin user initialization completed") + sys.exit(0) diff --git a/charts/my-recipes-chart/templates/admin-init-job.yaml b/charts/my-recipes-chart/templates/admin-init-job.yaml new file mode 100644 index 0000000..511ec36 --- /dev/null +++ b/charts/my-recipes-chart/templates/admin-init-job.yaml @@ -0,0 +1,75 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-admin-init-{{ .Release.Revision }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-admin-init + component: init + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + ttlSecondsAfterFinished: 300 + template: + metadata: + labels: + app: {{ .Release.Name }}-admin-init + spec: + restartPolicy: Never + containers: + - name: admin-init + image: python:3.12-slim + command: + - /bin/sh + - -c + - | + pip install --no-cache-dir psycopg2-binary bcrypt > /dev/null 2>&1 + python3 /scripts/create-admin.py + env: + - name: DB_HOST + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_HOST + - name: DB_PORT + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PORT + - name: DB_NAME + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_NAME + - name: DB_USER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PASSWORD + - name: ADMIN_USERNAME + value: {{ .Values.admin.username | quote }} + - name: ADMIN_EMAIL + value: {{ .Values.admin.email | quote }} + - name: ADMIN_PASSWORD + value: {{ .Values.admin.password | quote }} + - name: ADMIN_FIRST_NAME + value: {{ .Values.admin.firstName | quote }} + - name: ADMIN_LAST_NAME + value: {{ .Values.admin.lastName | quote }} + - name: ADMIN_DISPLAY_NAME + value: {{ .Values.admin.displayName | quote }} + volumeMounts: + - name: init-script + mountPath: /scripts + volumes: + - name: init-script + configMap: + name: {{ .Release.Name }}-admin-init + defaultMode: 0755 diff --git a/manifests/my-recipes/values.yaml b/manifests/my-recipes/values.yaml index 103ef24..4ef4ac7 100644 --- a/manifests/my-recipes/values.yaml +++ b/manifests/my-recipes/values.yaml @@ -75,6 +75,16 @@ frontend: - secretName: my-recipes-tls hosts: - my-recipes.dvirlabs.com + +# Admin user configuration +admin: + username: "admin" + email: "admin@myrecipes.local" + password: "admin123" # Change this password! + firstName: "Admin" + lastName: "User" + displayName: "מנהל" + # PostgreSQL configuration postgres: name: db