summaryrefslogtreecommitdiffstats
path: root/pg_virtualenv
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:02:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:02:19 +0000
commite308bcff5a610d6a3bbe33b3769f03f6d4533b16 (patch)
tree6a8ed4eb26cd55f3a24165bc1d9b9a1f0ab62e8c /pg_virtualenv
parentInitial commit. (diff)
downloadpostgresql-common-e308bcff5a610d6a3bbe33b3769f03f6d4533b16.tar.xz
postgresql-common-e308bcff5a610d6a3bbe33b3769f03f6d4533b16.zip
Adding upstream version 248.upstream/248upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rwxr-xr-xpg_virtualenv280
-rw-r--r--pg_virtualenv.pod122
2 files changed, 402 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}
diff --git a/pg_virtualenv.pod b/pg_virtualenv.pod
new file mode 100644
index 0000000..e1e05f0
--- /dev/null
+++ b/pg_virtualenv.pod
@@ -0,0 +1,122 @@
+=head1 NAME
+
+pg_virtualenv - Create a throw-away PostgreSQL environment for running regression tests
+
+=head1 SYNOPSIS
+
+B<pg_virtualenv> [I<OPTIONS>] [B<-v> 'I<version ...>'] [I<command>]
+
+=head1 DESCRIPTION
+
+B<pg_virtualenv> creates a virtual PostgreSQL server environment, and sets
+environment variables such that I<command> can access the PostgreSQL database
+server(s). The servers are destroyed when I<command> exits.
+
+The environment variables B<PGHOST>, B<PGDATABASE>, B<PGUSER>, and
+B<PGPASSWORD> will be set. Per default, a single new cluster is created,
+using the newest PostgreSQL server version installed. The cluster will use the
+first available port number starting from B<5432>, and B<PGPORT> will be set.
+B<PGVERSION> is set the the PostgreSQL major version number.
+
+When clusters for more than one versions are created, they will differ in the
+port number used, and B<PGPORT> and B<PGVERSION> are not set. The clusters are
+named I<version>/regress. To access a cluster, set
+B<PGCLUSTER=>I<version>B</regress>. For ease of access, the clusters are also
+registered in F</etc/postgresql-common/pg_service.conf>, with the version
+number as cluster name. Clusters can be accessed by passing the connection
+string "B<service=>I<version>", e.g. B<psql service=9.2>.
+
+When invoked as root, the clusters are created in F</etc/postgresql/> as usual;
+for other users, B<PG_CLUSTER_CONF_ROOT> and B<PGSYSCONFDIR> are
+set to a temporary directory where all files belonging to the clusters are
+created.
+
+If I<command> fails, the tail of the PostgreSQL server log is shown.
+Additionally, if B<gdb> is available, the backtrace from any PostgreSQL
+coredump is show.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-a>
+
+Use all PostgreSQL server versions installed.
+
+=item B<-v> I<version ...>
+
+Use these versions (space-separated list).
+
+=item B<-c> I<pg_createcluster options>
+
+Extra options to pass to B<pg_createcluster>.
+
+=item B<-i> I<initdb options>
+
+Extra initdb options to pass to B<pg_createcluster>.
+
+=item B<-o> I<guc>B<=>I<value>
+
+Configuration option to set in the C<postgresql.conf> file, passed to
+B<pg_createcluster>.
+
+=item B<-p> I<package>
+
+Set B<extension_destdir> and B<dynamic_library_path> in cluster to enable
+loading and testing extensions at build-time from B<debian/>I<package>B</>.
+
+This is a Debian-specific PostgreSQL patch.
+
+=item B<-s>
+
+Launch a shell inside the virtual environment when I<command> fails.
+
+=item B<-t>
+
+Install clusters in a temporary directory, even when running as root.
+
+=item B<-h>
+
+Show program help.
+
+=back
+
+=head1 EXAMPLE
+
+ # pg_virtualenv make check
+
+=head1 NOTES
+
+When run with fakeroot(1), B<pg_virtualenv> will fall back to the non-root mode
+of operation. Running "fakeroot pg_virtualenv" as root will fail, though.
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item B<PG_VIRTUALENV_NEWPID>=yes
+
+When non-empty, B<pg_virtualenv> will re-exec itself using newpid(1).
+
+=item B<PG_VIRTUALENV_UNSHARE>=I<flags>
+
+When non-empty, B<pg_virtualenv> will re-exec itself using unshare(1) using
+these flags.
+
+=item B<PGPORT>=I<n>
+
+When set, the value is used for the (single) cluster created.
+
+=back
+
+=head1 COMPATIBILITY
+
+B<PGVERSION> is set in postgresql-common (>= 219~).
+
+=head1 SEE ALSO
+
+initdb(1), pg_createcluster(1).
+
+=head1 AUTHOR
+
+Christoph Berg L<E<lt>myon@debian.orgE<gt>>