#!/usr/bin/env bash set -Eeo pipefail # A helper script which can create an empty database with a new user as specified by # the environment variables POSTGRES_DATABASE, POSTGRES_USER and POSTGRES_PASSWORD. docker_verify_minimum_env() { if [[ -z "$POSTGRES_USER" ]]; then echo "Must set POSTGRES_USER" 2>&1 exit 1; fi if [[ -z "$POSTGRES_DB" ]]; then echo "Must set POSTGRES_DB" 2>&1 exit 1; fi if [[ -z "$POSTGRES_PASSWORD" ]]; then echo "Must set POSTGRES_PASSWORD" 2>&1 exit 1; fi if [[ -z "$PGDATA" ]]; then echo "Must set PGDATA" 2>&1 exit 1; fi # check password first so we can output the warning before postgres # messes it up if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then cat >&2 <<-'EOWARN' WARNING: The supplied POSTGRES_PASSWORD is 100+ characters. This will not work if used via PGPASSWORD with "psql". https://www.postgresql.org/message-id/flat/E1Rqxp2-0004Qt-PL%40wrigleys.postgresql.org (BUG #6412) https://github.com/docker-library/postgres/issues/507 EOWARN fi } # Execute sql script docker_process_sql() { local query_runner=( psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc --dbname "$POSTGRES_DB" ) "${query_runner[@]}" "$@" } # create initial database # uses environment variables for input: POSTGRES_DB docker_setup_db() { local dbAlreadyExists dbAlreadyExists="$( docker_process_sql --dbname postgres --set db="$POSTGRES_DB" --tuples-only <<-'EOSQL' SELECT 1 FROM pg_database WHERE datname = :'db' ; EOSQL )" if [ -z "$dbAlreadyExists" ]; then docker_process_sql --dbname postgres \ --set db="$POSTGRES_DB" \ --set pass="$POSTGRES_PASSWORD" \ --set user="$POSTGRES_USER" \ <<-'EOSQL' CREATE DATABASE :"db"; create user :"user" with encrypted password :'pass'; grant all privileges on database :"db" to :"user"; alter database :"db" OWNER TO :"user"; EOSQL fi } # start postgresql server for setting up or running scripts docker_temp_server_start() { # internal start of server in order to allow setup using psql client PGUSER="${PGUSER:-$POSTGRES_USER}" \ pg_ctlcluster "$POSTGRES_VERSION" main start -- -w -o "-c listen_addresses=''" } # stop postgresql server after done setting up user and running scripts docker_temp_server_stop() { PGUSER="${PGUSER:-postgres}" \ pg_ctlcluster "$POSTGRES_VERSION" main stop -- -m fast -w } _main() { export PGDATA="$DATA_DIR/postgres/" export POSTGRES_USER=$DATABASE_USER export POSTGRES_PASSWORD=$DATABASE_PASSWORD export POSTGRES_DB=$DATABASE_NAME export PGAUTOUPGRADE_DIR="${DATA_DIR}/pg_upgrade" ALREADY_SETUP_INDICATOR_FILE="$PGDATA/baserow_db_setup" # This script will re-run itself as postgres user, so this part is reserved for the root user setup/teardown if [ "$(id -u)" = '0' ]; then # The upgrade script will run as postgres user, so we need to create a directory # where the postgres user can write to. if [ "$1" == "upgrade" ] && [ ! -d ${PGAUTOUPGRADE_DIR} ]; then mkdir -p "${PGAUTOUPGRADE_DIR}" chown postgres:postgres "${PGAUTOUPGRADE_DIR}" fi # restart script as postgres user echo "Becoming postgres superuser to run setup SQL commands:" su postgres -c "${BASH_SOURCE[0]} $*" EXIT_STATUS=$? # If the upgrade script was run, and it was successful, remove the upgrade directory. if [ "$1" == "upgrade" ]; then if [ $EXIT_STATUS = 0 ]; then rm -rf "${PGAUTOUPGRADE_DIR}" echo echo 'You can now run the official `baserow/baserow:1.30.0` image to start Baserow.' echo # We want to stop the execution here, so return an error code even if the upgrade was successful. exit 1 else exit $EXIT_STATUS fi fi # this part is reserved for the postgres user elif [ "$1" == "upgrade" ]; then if [ ! -f "$ALREADY_SETUP_INDICATOR_FILE" ]; then echo echo 'PostgreSQL Database directory does not contain a database; Skipping upgrade' echo exit 0 fi # Get the current data version from the PG_VERSION file (https://www.postgresql.org/docs/current/storage-file-layout.html) PGDATA_VERSION=$(cat "${PGDATA}/PG_VERSION") if [ "$PGDATA_VERSION" = "$POSTGRES_VERSION" ]; then echo echo "Your PostgreSQL data directory is already at version $PGDATA_VERSION." echo exit 0 fi echo echo "Your PostgreSQL data directory was initialized with version $PGDATA_VERSION, but this image is running version $POSTGRES_VERSION." echo if [ "$PGDATA_VERSION" = $POSTGRES_OLD_VERSION ]; then echo echo "Upgrading PostgreSQL data directory to version ${POSTGRES_VERSION}..." echo set +e ./docker-postgres-upgrade.sh UPGRADE_EXIT_STATUS=$? set -e if [ $UPGRADE_EXIT_STATUS -ne 0 ]; then echo echo "Upgrading to PostgreSQL ${POSTGRES_VERSION} failed with exit code ${UPGRADE_EXIT_STATUS}" echo exit 1 else echo echo '...PostgreSQL data directory upgrade complete.' echo fi else echo echo "Your PostgreSQL data directory is at version $PGDATA_VERSION, which cannot be upgraded automatically." echo "Please look into Baserow official documentation for more information on how to upgrade your database." echo exit 1 fi elif [ "$1" == "setup" ]; then shift if [ -f "$ALREADY_SETUP_INDICATOR_FILE" ]; then echo echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization' echo # Get the current data version from the PG_VERSION file (https://www.postgresql.org/docs/current/storage-file-layout.html) PGDATA_VERSION=$(cat "${PGDATA}/PG_VERSION") if [ "$PGDATA_VERSION" != "$POSTGRES_VERSION" ]; then echo echo "Your PostgreSQL data directory was initialized with version $PGDATA_VERSION, but this image is running version $POSTGRES_VERSION." echo "Please look into official Baserow documentation at https://baserow.io/docs/installation%2Finstall-with-docker#upgrading-postgresql-database-from-a-previous-version for more information on how to upgrade your database using a different Baserow image ('baserow/baserow-pgautoupgrade:1.30.0') or how to run Baserow using legacy PostgreSQL 11 image ('baserow/baserow-pg11:1.30.0')." echo exit 1 fi else docker_verify_minimum_env cp -pR "/var/lib/postgresql/$POSTGRES_VERSION/main/." "$DATA_DIR/postgres/" docker_temp_server_start "$@" docker_setup_db touch "$ALREADY_SETUP_INDICATOR_FILE" docker_temp_server_stop echo echo 'PostgreSQL init process complete; ready for start up.' echo fi elif [ "$1" == "run" ]; then shift if [[ $(pgrep -f "bin/postgres") ]]; then echo "PostgreSQL is already running. Directly running SQL." docker_process_sql "$@" else echo "No running postgresql found, starting one up..." docker_temp_server_start docker_process_sql "$@" docker_temp_server_stop fi else echo "Unknown argument $1 it must be either 'setup', 'upgrade' or 'run ...'" exit 1 fi } _main "$@"