summaryrefslogtreecommitdiffstats
path: root/pg_virtualenv
diff options
context:
space:
mode:
Diffstat (limited to 'pg_virtualenv')
-rwxr-xr-xpg_virtualenv275
1 files changed, 275 insertions, 0 deletions
diff --git a/pg_virtualenv b/pg_virtualenv
new file mode 100755
index 0000000..8057d52
--- /dev/null
+++ b/pg_virtualenv
@@ -0,0 +1,275 @@
+#!/bin/bash
+
+# Create a throw-away PostgreSQL environment for running regression tests.
+# This does not interfere with existing clusters.
+#
+# (C) 2005-2012 Martin Pitt <mpitt@debian.org>
+# (C) 2012-2020 Christoph Berg <myon@debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+set -e # no -u here as that breaks PGCONF_OPTS[@]
+
+# wrap ourselves in newpid if requested
+if [ "$PG_VIRTUALENV_NEWPID" ]; then
+ unset PG_VIRTUALENV_NEWPID
+ exec newpid $0 "$@"
+fi
+
+# wrap ourselves in unshare if requested
+if [ "$PG_VIRTUALENV_UNSHARE" ]; then
+ export _PG_VIRTUALENV_UNSHARE="$PG_VIRTUALENV_UNSHARE"
+ unset PG_VIRTUALENV_UNSHARE
+ exec unshare $_PG_VIRTUALENV_UNSHARE -- $0 "$@"
+fi
+if [ "$_PG_VIRTUALENV_UNSHARE" ]; then
+ unset _PG_VIRTUALENV_UNSHARE
+ # start localhost interface
+ if [ -x /bin/ip ]; then
+ ip link set dev lo up || true
+ else
+ ifconfig lo up || true
+ fi
+fi
+
+disable_fakeroot ()
+{
+ case ${LD_PRELOAD:-} in
+ *fakeroot*) LD_PRELOAD=$(echo "$LD_PRELOAD" | sed -e 's/[^ ]*fakeroot[^ ]*//g') ;;
+ esac
+}
+
+help ()
+{
+ echo "pg_virtualenv: Create throw-away PostgreSQL environment for regression tests"
+ echo "Syntax: $0 [options] [command]"
+ echo " -a use all installed server versions"
+ echo " -v 'version ...' list of PostgreSQL versions to run [default: latest]"
+ echo " -c 'options' extra options to pass to pg_createcluster"
+ echo " -i 'initdb opts' extra initdb options to pass to pg_createcluster"
+ echo " -o 'guc=value' postgresql.conf options to pass to pg_createcluster"
+ echo " -p 'package' set options to find extension files in debian/package/"
+ echo " -s open a shell when command fails"
+ echo " -t use a temporary cluster directory even as root"
+ exit ${1:-0}
+}
+
+# option parsing
+PGBINROOT="/usr/lib/postgresql/"
+#redhat# PGBINROOT="/usr/pgsql-"
+PG_VERSIONS=""
+PGCONF_OPTS=()
+while getopts "ac:i:ho:p:stv:" opt ; do
+ case $opt in
+ a) for d in $PGBINROOT*/bin/pg_ctl; do
+ # prepend version so latest ends up first (i.e. on port 5432)
+ dir=${d%%/bin/pg_ctl}
+ PG_VERSIONS="${dir#$PGBINROOT} ${PG_VERSIONS:-}"
+ done ;;
+ c) CREATE_OPTS="$OPTARG" ;;
+ i) INITDB_OPTS="$OPTARG" ;;
+ h) help ;;
+ o) PGCONF_OPTS+=("--pgoption" "$OPTARG") ;;
+ p) PACKAGE="$OPTARG" ;;
+ s) run_shell=1 ;;
+ t) NONROOT=1 ;;
+ v) PG_VERSIONS="$OPTARG" ;;
+ *) help 1 ;;
+ esac
+done
+if [ -z "$PG_VERSIONS" ]; then
+ # use latest version
+ d=$(ls -v $PGBINROOT*/bin/pg_ctl 2> /dev/null | tail -1)
+ if [ -z "$d" ]; then
+ echo "Could not determine PostgreSQL version, are any PostgreSQL server packages installed?" >&2
+ exit 2
+ fi
+ dir=${d%%/bin/pg_ctl}
+ PG_VERSIONS="${dir#$PGBINROOT}"
+fi
+# shift away args
+shift $(($OPTIND - 1))
+# if no command is given, open a shell
+[ "${1:-}" ] || set -- ${SHELL:-/bin/sh}
+
+# generate a password
+if [ -x /usr/bin/pwgen ]; then
+ export PGPASSWORD=$(pwgen 20 1)
+else
+ export PGPASSWORD=$(dd if=/dev/urandom bs=1k count=1 2>/dev/null | md5sum - | awk '{ print $1 }')
+fi
+
+# we are not root
+if [ "$(id -u)" != 0 ]; then
+ NONROOT=1
+fi
+# we aren't really root in fakeroot (but leave it enabled for commands spawned)
+case ${LD_PRELOAD:-} in
+ *fakeroot*) NONROOT=1 ;;
+esac
+
+# non-root operation: create a temp dir where we store everything
+if [ "${NONROOT:-}" ]; then
+ WORKDIR=$(mktemp -d -t pg_virtualenv.XXXXXX)
+ if [ $(id -u) = 0 ]; then
+ chown postgres:postgres $WORKDIR
+ umask 022
+ fi
+ export PG_CLUSTER_CONF_ROOT="$WORKDIR/postgresql"
+ export PGUSER="${USER:-${LOGNAME:-$(id -un)}}"
+ [ "$PGUSER" = "root" ] && PGUSER="postgres"
+ PGSYSCONFDIR="$WORKDIR/postgresql-common" # no export yet so pg_createcluster uses the original createcluster.conf
+ mkdir "$PGSYSCONFDIR" "$WORKDIR/log"
+ PWFILE="$PGSYSCONFDIR/pwfile"
+ LOGDIR="$WORKDIR/log"
+ echo "$PGPASSWORD" > "$PWFILE"
+ # stats_temp_directory in /var/run/postgresql needs root (or postgres), disable it
+ PGCONF_OPTS+=("--pgoption" "stats_temp_directory=")
+
+ cleanup () {
+ set +e
+ disable_fakeroot
+ for v in $PG_VERSIONS; do
+ # don't drop existing clusters named "regress"
+ [ -f $PG_CLUSTER_CONF_ROOT/$v/regress/.by_pg_virtualenv ] || continue
+ echo "Dropping cluster $v/regress ..."
+ pg_ctlcluster --mode immediate $v regress stop
+ pg_dropcluster $v regress
+ done
+ rm -rf $WORKDIR
+ }
+ trap cleanup 0 HUP INT QUIT ILL ABRT PIPE TERM
+
+# root: keep everything in the standard locations
+else
+ for v in $PG_VERSIONS; do
+ if [ -d /etc/postgresql/$v/regress ]; then
+ echo "Cluster $v/regress exists, refusing to overwrite" >&2
+ exit 2
+ fi
+ done
+
+ : ${PGSYSCONFDIR:=/etc/postgresql-common}
+ pg_service="$PGSYSCONFDIR/pg_service.conf"
+
+ export PGUSER="postgres"
+ PWFILE=$(mktemp -t pgpassword.XXXXXX)
+ echo "$PGPASSWORD" > "$PWFILE" # write password before chowning the file
+ chown postgres:postgres "$PWFILE"
+
+ cleanup () {
+ set +e
+ rm -f $PWFILE $pg_service
+ if [ -f $pg_service.pg_virtualenv-save.$$ ]; then
+ mv -f $pg_service.pg_virtualenv-save.$$ $pg_service
+ fi
+ for v in $PG_VERSIONS; do
+ # don't drop existing clusters named "regress"
+ [ -f /etc/postgresql/$v/regress/.by_pg_virtualenv ] || continue
+ echo "Dropping cluster $v/regress ..."
+ rm -f /etc/postgresql/$v/regress/.by_pg_virtualenv
+ pg_ctlcluster --mode immediate $v regress stop
+ pg_dropcluster $v regress
+ done
+ }
+ trap cleanup 0 HUP INT QUIT ILL ABRT PIPE TERM
+
+ if [ -f $pg_service ]; then
+ mv --no-clobber $pg_service $pg_service.pg_virtualenv-save.$$
+ fi
+fi
+
+# create postgres environments
+for v in $PG_VERSIONS; do
+ # create temporary cluster
+ if [ "${PACKAGE:-}" ]; then
+ if ! grep -q 'extension_destdir' /usr/share/postgresql/$v/postgresql.conf.sample; then
+ echo "$0: This PostgreSQL $v installation does not support 'extension_destdir', skipping this version"
+ [ "$PG_VERSIONS" = "$v" ] && exit 0 # only one version requested
+ continue
+ fi
+ PKGARGS="--pgoption extension_destdir=$PWD/debian/$PACKAGE --pgoption dynamic_library_path=$PWD/debian/$PACKAGE/usr/lib/postgresql/$v/lib:/usr/lib/postgresql/$v/lib"
+ fi
+ # we chdir to / so programs don't throw "could not change directory to ..."
+ (
+ cd /
+ case $v in
+ 8*|9.0|9.1|9.2) : ;;
+ *) NOSYNC="--nosync" ;;
+ esac
+ # disable fakeroot here because we really can't run as root
+ # (and still switch to postgres when using fakeroot as root user)
+ disable_fakeroot
+ pg_createcluster --quiet \
+ ${PGPORT:+-p "$PGPORT"} \
+ ${NONROOT:+-d "$WORKDIR/data/$v/regress"} \
+ ${NONROOT:+-l "$WORKDIR/log/postgresql-$v-regress.log"} \
+ ${CREATE_OPTS:-} --pgoption fsync=off ${PKGARGS:-} "${PGCONF_OPTS[@]}" \
+ $v regress -- \
+ --username="$PGUSER" --pwfile="$PWFILE" $NOSYNC ${INITDB_OPTS:-}
+ # in fakeroot, the username will likely default to "postgres" otherwise
+ echo "This is a temporary throw-away cluster" > ${PG_CLUSTER_CONF_ROOT:-/etc/postgresql}/$v/regress/.by_pg_virtualenv
+ # start cluster with coredumps enabled
+ [ $v != 8.2 ] && ENABLE_COREDUMPS="-c"
+ pg_ctlcluster $v regress start -- ${ENABLE_COREDUMPS:-}
+ )
+ port=$(pg_conftool -s $v regress show port)
+
+ # record cluster information in service file
+ cat >> $PGSYSCONFDIR/pg_service.conf <<EOF
+[$v]
+host=localhost
+port=$port
+dbname=postgres
+user=$PGUSER
+password=$PGPASSWORD
+
+EOF
+done
+
+export PGSYSCONFDIR
+export PGHOST="localhost"
+export PGDATABASE="postgres"
+case $PG_VERSIONS in
+ *\ *) ;; # multiple versions: do not set PGPORT because that breaks --cluster
+ *)
+ export PGPORT="$port"
+ export PG_CONFIG="$PGBINROOT$PG_VERSIONS/bin/pg_config"
+ export PGVERSION="$PG_VERSIONS"
+ ;;
+esac
+
+# run program
+"$@" || EXIT="$?"
+if [ ${EXIT:-0} -gt 0 ]; then
+ for log in ${LOGDIR:-/var/log/postgresql}/*.log; do
+ echo "*** $log (last 100 lines) ***"
+ tail -100 $log
+ done
+
+ if which gdb > /dev/null; then
+ for v in $PG_VERSIONS; do
+ PGDATA=$(pg_conftool -s $v regress show data_directory)
+ for core in $PGDATA/core*; do
+ [ -f "$core" ] || continue
+ echo "*** $core ***"
+ gdb -batch -ex "bt full" /usr/lib/postgresql/$v/bin/postgres "$core"
+ done
+ done
+ fi
+
+ if [ "${run_shell:-}" ]; then
+ echo "pg_virtualenv: command exited with status $EXIT, dropping you into a shell"
+ ${SHELL:-/bin/sh}
+ fi
+fi
+
+exit ${EXIT:-0}