diff options
Diffstat (limited to 'pg_virtualenv')
-rwxr-xr-x | pg_virtualenv | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/pg_virtualenv b/pg_virtualenv new file mode 100755 index 0000000..f4cfe03 --- /dev/null +++ b/pg_virtualenv @@ -0,0 +1,280 @@ +#!/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" + + 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 + if [ "${NONROOT:-}" ]; then + # stats_temp_directory in /var/run/postgresql needs root (or postgres), disable it + case $v in + 8.4|9.*|1[01234]) PGCONF_OPTS+=("--pgoption" "stats_temp_directory=") ;; + esac + fi + # 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" +unset PGHOSTADDR PGPORT PGSERVICE # unset variables that might interfere +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 command -v 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} |