|
| 1 | +#!/bin/bash |
| 2 | +# percona-pgadmin4 container entrypoint. |
| 3 | +# |
| 4 | +# Prepares the container environment (secrets, first-run setup, servers.json / |
| 5 | +# preferences.json import, TLS validation, OpenShift random-UID tolerance) and |
| 6 | +# execs the RPM launcher /usr/bin/percona-pgadmin4-gunicorn, which owns the |
| 7 | +# gunicorn command line, PGADMIN_LISTEN_*/GUNICORN_* handling and TLS wiring |
| 8 | +# (PGADMIN_ENABLE_TLS=true -> /certs/server.cert + /certs/server.key). |
| 9 | +# |
| 10 | +# Environment honored here (upstream dpage/pgadmin4 names): |
| 11 | +# PGADMIN_DEFAULT_EMAIL, PGADMIN_DEFAULT_PASSWORD[_FILE] |
| 12 | +# PGADMIN_CONFIG_CONFIG_DATABASE_URI[_FILE] |
| 13 | +# PGADMIN_SERVER_JSON_FILE (default /pgadmin4/servers.json) |
| 14 | +# PGADMIN_PREFERENCES_JSON_FILE (default /pgadmin4/preferences.json) |
| 15 | +# PGADMIN_REPLACE_SERVERS_ON_STARTUP ("True" to re-import with --replace) |
| 16 | +# PGADMIN_ENABLE_TLS ("true"; certs must exist in /certs) |
| 17 | +set -euo pipefail |
| 18 | + |
| 19 | +PGADMIN_DIR=/usr/lib/python3.12/site-packages/pgadmin4 |
| 20 | +SQLITE_PATH="${PGADMIN_CONFIG_SQLITE_PATH:-/var/lib/pgadmin/pgadmin4.db}" |
| 21 | + |
| 22 | +# --- OpenShift random-UID fixup ------------------------------------------- |
| 23 | +# Under an arbitrary UID (gid 0) there is no passwd entry; some libraries need |
| 24 | +# one. /etc/passwd is group-0 writable (image build). |
| 25 | +if ! whoami >/dev/null 2>&1; then |
| 26 | + if [ -w /etc/passwd ]; then |
| 27 | + echo "pgadmin:x:$(id -u):0:pgadmin user:/var/lib/pgadmin:/sbin/nologin" >> /etc/passwd |
| 28 | + fi |
| 29 | +fi |
| 30 | + |
| 31 | +# --- Docker-secret _FILE variants ----------------------------------------- |
| 32 | +# file_env VAR: honor VAR_FILE by reading VAR's value from the file; VAR and |
| 33 | +# VAR_FILE together are an error (upstream semantics). |
| 34 | +file_env() { |
| 35 | + local var="$1" fileVar="$1_FILE" val="" |
| 36 | + if [ -n "${!var:-}" ] && [ -n "${!fileVar:-}" ]; then |
| 37 | + echo "error: both ${var} and ${fileVar} are set (but are exclusive)" >&2 |
| 38 | + exit 1 |
| 39 | + fi |
| 40 | + if [ -n "${!fileVar:-}" ]; then |
| 41 | + if [ ! -r "${!fileVar}" ]; then |
| 42 | + echo "error: ${fileVar} is set to '${!fileVar}' but the file is not readable" >&2 |
| 43 | + exit 1 |
| 44 | + fi |
| 45 | + val="$(< "${!fileVar}")" |
| 46 | + export "${var}"="${val}" |
| 47 | + unset "${fileVar}" |
| 48 | + fi |
| 49 | +} |
| 50 | +file_env PGADMIN_DEFAULT_PASSWORD |
| 51 | +file_env PGADMIN_CONFIG_CONFIG_DATABASE_URI |
| 52 | + |
| 53 | +# --- External configuration database -------------------------------------- |
| 54 | +# When CONFIG_DATABASE_URI points at an existing, initialised external config |
| 55 | +# DB, first-run setup must not run (and must not demand DEFAULT_EMAIL). |
| 56 | +external_config_db_exists="False" |
| 57 | +if [ -n "${PGADMIN_CONFIG_CONFIG_DATABASE_URI:-}" ]; then |
| 58 | + result=$(cd "${PGADMIN_DIR}/pgadmin/utils" && /usr/bin/python3.12 -c " |
| 59 | +import os, ast |
| 60 | +from check_external_config_db import check_external_config_db |
| 61 | +raw = os.environ['PGADMIN_CONFIG_CONFIG_DATABASE_URI'] |
| 62 | +try: |
| 63 | + uri = ast.literal_eval(raw) |
| 64 | +except (ValueError, SyntaxError): |
| 65 | + uri = raw |
| 66 | +print(check_external_config_db(uri)) |
| 67 | +" 2>/dev/null) || true |
| 68 | + if [ -n "${result:-}" ]; then |
| 69 | + external_config_db_exists="${result}" |
| 70 | + fi |
| 71 | +fi |
| 72 | + |
| 73 | +# --- First-run setup + one-time imports ------------------------------------ |
| 74 | +if [ ! -e "${SQLITE_PATH}" ] && [ "${external_config_db_exists}" = "False" ]; then |
| 75 | + if [ -z "${PGADMIN_DEFAULT_EMAIL:-}" ] || [ -z "${PGADMIN_DEFAULT_PASSWORD:-}" ]; then |
| 76 | + echo 'You need to define the PGADMIN_DEFAULT_EMAIL and PGADMIN_DEFAULT_PASSWORD or PGADMIN_DEFAULT_PASSWORD_FILE environment variables.' >&2 |
| 77 | + exit 1 |
| 78 | + fi |
| 79 | + |
| 80 | + # Same init the launcher would run; the launcher sees the DB afterwards |
| 81 | + # and skips its own first-run branch (no double-init). |
| 82 | + (cd "${PGADMIN_DIR}" && \ |
| 83 | + PGADMIN_SETUP_EMAIL="${PGADMIN_DEFAULT_EMAIL}" \ |
| 84 | + PGADMIN_SETUP_PASSWORD="${PGADMIN_DEFAULT_PASSWORD}" \ |
| 85 | + /usr/bin/python3.12 setup.py setup-db) |
| 86 | + |
| 87 | + server_json="${PGADMIN_SERVER_JSON_FILE:-/pgadmin4/servers.json}" |
| 88 | + if [ -f "${server_json}" ]; then |
| 89 | + /usr/bin/pgadmin4-cli load-servers "${server_json}" --user "${PGADMIN_DEFAULT_EMAIL}" |
| 90 | + fi |
| 91 | + |
| 92 | + prefs_json="${PGADMIN_PREFERENCES_JSON_FILE:-/pgadmin4/preferences.json}" |
| 93 | + if [ -f "${prefs_json}" ]; then |
| 94 | + /usr/bin/pgadmin4-cli set-prefs "${PGADMIN_DEFAULT_EMAIL}" --input-file "${prefs_json}" |
| 95 | + fi |
| 96 | +elif [ "${PGADMIN_REPLACE_SERVERS_ON_STARTUP:-}" = "True" ]; then |
| 97 | + server_json="${PGADMIN_SERVER_JSON_FILE:-/pgadmin4/servers.json}" |
| 98 | + if [ -f "${server_json}" ]; then |
| 99 | + /usr/bin/pgadmin4-cli load-servers "${server_json}" --user "${PGADMIN_DEFAULT_EMAIL}" --replace |
| 100 | + fi |
| 101 | +fi |
| 102 | + |
| 103 | +# --- TLS pre-flight --------------------------------------------------------- |
| 104 | +# The launcher wires the certs; fail early and clearly when they are missing. |
| 105 | +if [ "${PGADMIN_ENABLE_TLS:-}" = "true" ]; then |
| 106 | + if [ ! -r /certs/server.cert ] || [ ! -r /certs/server.key ]; then |
| 107 | + echo 'PGADMIN_ENABLE_TLS is set but /certs/server.cert and/or /certs/server.key are missing or unreadable.' >&2 |
| 108 | + exit 1 |
| 109 | + fi |
| 110 | +fi |
| 111 | + |
| 112 | +exec /usr/bin/percona-pgadmin4-gunicorn |
0 commit comments