#!/bin/bash # # postgresql-setup - Initialization and upgrade operations for PostgreSQL # For SELinux we need to use 'runuser' not 'su' if [ -x /sbin/runuser ]; then SU=runuser else SU=su fi if test "$(id -u)" -eq 0; then cmd= for v in PGSETUP_DEBUG PGSETUP_INITDB_OPTIONS PGSETUP_PGUPGRADE_OPTIONS; do eval var_content=\$$v test -z "$var_content" && continue cmd+=$v="$(printf %q "$var_content") " done cmd+=$(printf %q "$(readlink -f "$0")") for arg; do cmd+=" $(printf %q "$arg")" ; done # Drop root privileges asap. It's not recommended to run postgresql-setup # script under root nowadays; so we take the liberty to switch to the # PostgreSQL admin user (by default 'postgres') without any other option. exec $SU -s /bin/sh postgres -c "$cmd" fi die () { echo >&2 "$*"; exit 1; } test "$(id -u)" -eq 0 && exit 1 # ensure privacy umask 0077 : ${RESTORECON=/sbin/restorecon} test -x $RESTORECON || RESTORECON=: test x"$PGSETUP_DEBUG" != x && set -x # PGVERSION is the full package version, e.g., 9.0.2 # Note: the specfile inserts the correct value during package build PGVERSION=xxxx # PGMAJORVERSION is the major version, e.g. 9.0 PGMAJORVERSION=xxxx # PGENGINE is the directory containing the postmaster executable PGENGINE=xxxx # PREVMAJORVERSION is the previous major version, e.g., 8.4, for upgrades PREVMAJORVERSION=xxxx # PREVPGENGINE is the directory containing the previous postmaster executable PREVPGENGINE=xxxx USER=postgres # Absorb configuration settings from the specified systemd service file, # or the default "postgresql" service if not specified SERVICE_NAME="$2" if [ x"$SERVICE_NAME" = x ]; then SERVICE_NAME=postgresql fi # Pathname of the RPM distribution README README_RPM_DIST=xxxx USAGE_STRING=$" Usage: $0 {initdb|upgrade} [SERVICE_NAME] Script is aimed to help sysadmin with basic database cluster administration. The SERVICE_NAME is used for selection of proper unit configuration file; For more info and howto/when use this script please look at the docu file $README_RPM_DIST. The 'postgresql' string is used when no SERVICE_NAME is explicitly passed. Available operation mode: initdb Create a new PostgreSQL database cluster. This is usually the first action you perform after PostgreSQL server installation. upgrade Upgrade PostgreSQL database cluster to be usable with new server. Use this if you upgraded your PostgreSQL server to newer major version (currently from $PREVMAJORVERSION \ to $PGMAJORVERSION). Environment: PGSETUP_INITDB_OPTIONS Options carried by this variable are passed to subsequent call of \`initdb\` binary (see man initdb(1)). This variable is used also during 'upgrade' mode because the new cluster is actually re-initialized from the old one. PGSETUP_PGUPGRADE_OPTIONS Options in this variable are passed next to the subsequent call of \`pg_upgrade\`. For more info about possible options please look at man pg_upgrade(1). PGSETUP_DEBUG Set to '1' if you want to see debugging output." # note that these options are useful at least for help2man processing case "$1" in --version) echo "postgresql-setup $PGVERSION" exit 0 ;; --help|--usage) echo "$USAGE_STRING" exit 0 ;; esac # this parsing technique fails for PGDATA pathnames containing spaces, # but there's not much I can do about it given systemctl's output format... PGDATA=`systemctl show -p Environment "${SERVICE_NAME}.service" | sed 's/^Environment=//' | tr ' ' '\n' | sed -n 's/^PGDATA=//p' | tail -n 1` if [ x"$PGDATA" = x ]; then echo "failed to find PGDATA setting in ${SERVICE_NAME}.service" exit 1 fi PGPORT=`systemctl show -p Environment "${SERVICE_NAME}.service" | sed 's/^Environment=//' | tr ' ' '\n' | sed -n 's/^PGPORT=//p' | tail -n 1` if [ x"$PGPORT" = x ]; then echo "failed to find PGPORT setting in ${SERVICE_NAME}.service" exit 1 fi # Log file for initdb PGLOG=/var/lib/pgsql/initdb.log # Log file for pg_upgrade PGUPLOG=/var/lib/pgsql/pgupgrade.log export PGDATA export PGPORT script_result=0 test -w /var/lib/pgsql || { echo >&2 $"The /var/lib/pgsql directory has wrong permissions." echo >&2 $"Please make sure the directory is writable by postgres." exit 1 } # code shared between initdb and upgrade actions perform_initdb(){ if [ ! -e "$PGDATA" ]; then mkdir "$PGDATA" || return 1 fi $RESTORECON "$PGDATA" test -w "$PGDATA" || die "$PGDATA is not writeable by $USER" # Create the initdb log file if needed if [ ! -e "$PGLOG" ]; then touch "$PGLOG" || return 1 fi $RESTORECON "$PGLOG" test -w "$PGLOG" || echo "$PGLOG is not writeable by $USER" # Initialize the database initdbcmd=( "$PGENGINE/initdb" --pgdata="$PGDATA" --auth=ident ) eval "initdbcmd+=( $PGSETUP_INITDB_OPTIONS )" "${initdbcmd[@]}" >> "$PGLOG" 2>&1 < /dev/null mkdir "$PGDATA/pg_log" $RESTORECON "$PGDATA/pg_log" if [ -f "$PGDATA/PG_VERSION" ]; then return 0 fi return 1 } initdb(){ if [ -f "$PGDATA/PG_VERSION" ]; then echo $"Data directory is not empty!" echo script_result=1 else echo -n $"Initializing database ... " if perform_initdb; then echo $"OK" else echo $"failed, see $PGLOG" script_result=1 fi echo fi } upgrade(){ # must see previous version in PG_VERSION if [ ! -f "$PGDATA/PG_VERSION" -o \ x`cat "$PGDATA/PG_VERSION"` != x"$PREVMAJORVERSION" ] then echo echo $"Cannot upgrade because the database in $PGDATA is not of" echo $"compatible previous version $PREVMAJORVERSION." echo exit 1 fi if [ ! -x "$PGENGINE/pg_upgrade" ]; then echo echo $"Please install the postgresql-upgrade RPM." echo exit 5 fi # Set up log file for pg_upgrade rm -f "$PGUPLOG" touch "$PGUPLOG" || exit 1 $RESTORECON "$PGUPLOG" # Move old DB to PGDATAOLD PGDATAOLD="${PGDATA}-old" rm -rf "$PGDATAOLD" mv "$PGDATA" "$PGDATAOLD" || exit 1 # Create configuration file for upgrade process HBA_CONF_BACKUP="$PGDATAOLD/pg_hba.conf.postgresql-setup.`date +%s`" HBA_CONF_BACKUP_EXISTS=0 if [ ! -f $HBA_CONF_BACKUP ]; then mv "$PGDATAOLD/pg_hba.conf" "$HBA_CONF_BACKUP" HBA_CONF_BACKUP_EXISTS=1 # For fluent upgrade 'postgres' user should be able to connect # to any database without password. Temporarily, no other type # of connection is needed. echo "local all postgres ident" > "$PGDATAOLD/pg_hba.conf" fi echo -n $"Upgrading database: " # Create empty new-format database if perform_initdb; then eval "add_options=( $PGSETUP_PGUPGRADE_OPTIONS )" # Do the upgrade ( cd # pg_upgrade writes to $PWD "$PGENGINE/pg_upgrade" \ --old-bindir="$PREVPGENGINE" \ --new-bindir="$PGENGINE" \ --old-datadir="$PGDATAOLD" \ --new-datadir="$PGDATA" \ --link \ --old-port="$PGPORT" \ --new-port="$PGPORT" \ --user=postgres \ "${add_options[@]}" \ >> "$PGUPLOG" 2>&1 < /dev/null ) if [ $? -ne 0 ]; then # pg_upgrade failed script_result=1 fi else # initdb failed script_result=1 fi # Move back the backed-up pg_hba.conf regardless of the script_result. if [ x$HBA_CONF_BACKUP_EXISTS = x1 ]; then mv -f "$HBA_CONF_BACKUP" "$PGDATAOLD/pg_hba.conf" fi if [ $script_result -eq 0 ]; then echo $"OK" echo echo $"The configuration files were replaced by default configuration." echo $"The previous configuration and data are stored in folder" echo $PGDATAOLD. else # Clean up after failure rm -rf "$PGDATA" mv "$PGDATAOLD" "$PGDATA" echo $"failed" fi echo echo $"See $PGUPLOG for details." } # See how we were called. case "$1" in initdb) initdb ;; upgrade) upgrade ;; *) echo >&2 "$USAGE_STRING" exit 2 esac exit $script_result