#!/usr/bin/env bash # PANELS · aplica los changelogs de Liquibase contra Postgres. # # Requiere las credenciales del rol "_owner" de cada módulo (nunca el rol # "_app" -- ese es solo para runtime, sin privilegios de DDL). Se leen de # variables de entorno con el mismo nombre que usan los secrets de la app: # DATABASE_URL_PLATFORM_OWNER (jdbc: panels_platform) # DATABASE_URL_IAM_OWNER (jdbc: panels_product, schema iam) # DATABASE_URL_CORE_OWNER (jdbc: panels_product, schema core) # # Formato esperado: postgresql://usuario:password@host:puerto/basededatos # (también se acepta postgres://). El host NO puede ser un CONTAINER ID. # # Uso: # set -a && source .env.dev-local && set +a && ./db/update.sh all # ./db/update.sh core --context-filter=dev # ./db/update.sh all --context-filter='!dev' -- updateSQL # dry-run (CI) set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" "$ROOT/db/bootstrap-tools.sh" LIQUIBASE="$ROOT/db/tools/liquibase/liquibase" PG_JDBC="$ROOT/db/tools/postgresql-jdbc.jar" TARGET="${1:-all}" shift || true LB_COMMAND="update" EXTRA_ARGS=() while [[ $# -gt 0 ]]; do if [[ "$1" == "--" ]]; then shift LB_COMMAND="${1:-update}" shift || true else EXTRA_ARGS+=("$1") shift fi done # postgresql://user:pass@host:port/db -> jdbc:postgresql://host:port/db + user/pass parse_url() { local url="$1" url="${url#"${url%%[![:space:]]*}"}" url="${url%"${url##*[![:space:]]}"}" url="${url#\'}"; url="${url%\'}" url="${url#\"}"; url="${url%\"}" if [[ "$url" == postgres://* ]]; then url="postgresql://${url#postgres://}" fi if [[ "$url" != postgresql://* ]]; then echo "ERROR: la URL debe empezar por postgresql:// o postgres://" >&2 exit 1 fi local rest="${url#postgresql://}" local userinfo="${rest%%@*}" local hostpart="${rest#*@}" if [[ "$userinfo" == "$rest" || -z "$hostpart" ]]; then echo "ERROR: URL sin host (falta user:pass@host)" >&2 exit 1 fi PARSED_USER="${userinfo%%:*}" PARSED_PASS="${userinfo#*:}" PARSED_JDBC="jdbc:postgresql://${hostpart}" local hp="${hostpart%%\?*}" hp="${hp%%/*}" PARSED_HOST="${hp%%:*}" } preflight_host() { echo "==> host JDBC: ${PARSED_HOST}" if [[ "$PARSED_HOST" =~ ^[0-9a-f]{12}$ ]]; then echo "ERROR: '${PARSED_HOST}' es un CONTAINER ID de Docker, no un hostname." >&2 echo "En Coolify copia Postgres URL (internal): el texto entre @ y :5432." >&2 echo "Pon ese hostname en las 6 DATABASE_URL_* (mismo host) y conecta el" >&2 echo "compose a la red predefined 'coolify'." >&2 exit 1 fi if [[ "$PARSED_HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then return 0 fi if command -v getent >/dev/null 2>&1; then if ! getent hosts "$PARSED_HOST" >/dev/null 2>&1; then echo "ERROR: no se resuelve el host '${PARSED_HOST}' (DNS)." >&2 echo "Usa el hostname de Postgres URL (internal), no el ID del contenedor." >&2 echo "El stack PANELS debe estar en la misma red Docker que Postgres (coolify)." >&2 exit 1 fi fi } run_one() { local name="$1" local var="DATABASE_URL_${name^^}_OWNER" local url="${!var:-}" if [[ -z "$url" ]]; then echo "Falta la variable de entorno $var (credenciales del rol _owner de $name)" >&2 exit 1 fi parse_url "$url" echo "==> Liquibase $LB_COMMAND: $name ($PARSED_JDBC)" preflight_host ( cd "$ROOT/db/$name" "$LIQUIBASE" \ --defaultsFile=liquibase.properties \ --classpath="$PG_JDBC" \ --url="$PARSED_JDBC" \ --username="$PARSED_USER" \ --password="$PARSED_PASS" \ "$LB_COMMAND" "${EXTRA_ARGS[@]}" ) } case "$TARGET" in platform) run_one platform ;; iam) run_one iam ;; core) run_one core ;; all) run_one platform run_one iam run_one core ;; *) echo "Usage: $0 [all|platform|iam|core] [-- liquibase-args...]" >&2 exit 1 ;; esac echo "Liquibase OK"