#!/usr/bin/env bash set -euo pipefail if [[ $# -lt 2 || $# -gt 3 ]]; then echo "Usage: $0 [db_password]" echo "Example: $0 project1_db project1_user" echo "Example: $0 project1_db project1_user 'very-strong-password'" exit 1 fi DB_NAME="$1" DB_USER="$2" DB_PASSWORD="${3:-}" if [[ ! "${DB_NAME}" =~ ^[a-zA-Z0-9_]+$ ]]; then echo "Error: db_name must match [a-zA-Z0-9_]+" exit 1 fi if [[ ! "${DB_USER}" =~ ^[a-zA-Z0-9_]+$ ]]; then echo "Error: db_user must match [a-zA-Z0-9_]+" exit 1 fi if [[ -z "${DB_PASSWORD}" ]]; then # Generate a random URL-safe password if none was provided. DB_PASSWORD="$(openssl rand -base64 24 | tr -d '\n' | tr '/+' '_-')" fi POSTGRES_ADMIN_USER="${POSTGRES_USER:-admin}" POSTGRES_ADMIN_DB="${POSTGRES_DB:-app}" POSTGRES_CONTAINER="${POSTGRES_CONTAINER_NAME:-postgres}" sql_escape() { printf "%s" "$1" | sed "s/'/''/g" } DB_NAME_ESCAPED="$(sql_escape "${DB_NAME}")" DB_USER_ESCAPED="$(sql_escape "${DB_USER}")" DB_PASSWORD_ESCAPED="$(sql_escape "${DB_PASSWORD}")" echo "Creating database user and database in container '${POSTGRES_CONTAINER}'..." ROLE_EXISTS="$(docker exec "${POSTGRES_CONTAINER}" psql -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER_ESCAPED}'" || true)" if [[ "${ROLE_EXISTS}" == "1" ]]; then docker exec "${POSTGRES_CONTAINER}" psql -v ON_ERROR_STOP=1 -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" \ -c "ALTER ROLE \"${DB_USER}\" WITH LOGIN PASSWORD '${DB_PASSWORD_ESCAPED}' NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;" else docker exec "${POSTGRES_CONTAINER}" psql -v ON_ERROR_STOP=1 -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" \ -c "CREATE ROLE \"${DB_USER}\" LOGIN PASSWORD '${DB_PASSWORD_ESCAPED}' NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;" fi DB_EXISTS="$(docker exec "${POSTGRES_CONTAINER}" psql -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME_ESCAPED}'" || true)" if [[ "${DB_EXISTS}" == "1" ]]; then echo "Database '${DB_NAME}' already exists." else docker exec "${POSTGRES_CONTAINER}" psql -v ON_ERROR_STOP=1 -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" \ -c "CREATE DATABASE \"${DB_NAME}\" OWNER \"${DB_USER}\";" fi docker exec "${POSTGRES_CONTAINER}" psql -v ON_ERROR_STOP=1 -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" \ -c "REVOKE CONNECT, TEMP ON DATABASE \"${DB_NAME}\" FROM PUBLIC;" docker exec "${POSTGRES_CONTAINER}" psql -v ON_ERROR_STOP=1 -U "${POSTGRES_ADMIN_USER}" -d "${POSTGRES_ADMIN_DB}" \ -c "GRANT CONNECT, TEMP ON DATABASE \"${DB_NAME}\" TO \"${DB_USER}\";" cat <