Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ if [ "$1" = 'postgres' ]; then
if [ "x$REPLICATE_FROM" == "x" ]; then
eval "gosu postgres initdb $POSTGRES_INITDB_ARGS"
else
until /bin/ping -c 1 -W 1 ${REPLICATE_FROM}
until ping -c 1 -W 1 "${REPLICATE_FROM}"
do
echo "Waiting for master to ping..."
sleep 1s
done
until gosu postgres pg_basebackup -h ${REPLICATE_FROM} -D ${PGDATA} -U ${POSTGRES_USER} -vP -w
until gosu postgres pg_basebackup -h "${REPLICATE_FROM}" -D "${PGDATA}" -U "${POSTGRES_USER}" -vP -w
do
echo "Waiting for master to connect..."
sleep 1s
Expand Down Expand Up @@ -84,10 +84,13 @@ if [ "$1" = 'postgres' ]; then
-o "-c listen_addresses='localhost'" \
-w start

# shellcheck disable=SC2086
: ${POSTGRES_USER:=postgres}
# shellcheck disable=SC2086
: ${POSTGRES_DB:=$POSTGRES_USER}
export POSTGRES_USER POSTGRES_DB

# shellcheck disable=SC2191
psql=( psql -v ON_ERROR_STOP=1 )

if [ "$POSTGRES_DB" != 'postgres' ]; then
Expand All @@ -112,6 +115,7 @@ if [ "$1" = 'postgres' ]; then
psql+=( --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" )

echo
# shellcheck disable=SC1090
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sh) echo "$0: running $f"; . "$f" ;;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/bash

if [ "x$REPLICATE_FROM" == "x" ]; then
if [[ -z "$REPLICATE_FROM" ]]; then

cat >> ${PGDATA}/postgresql.conf <<EOF
cat >> "${PGDATA}/postgresql.conf" <<EOF
wal_level = hot_standby
max_wal_senders = $PG_MAX_WAL_SENDERS
wal_keep_segments = $PG_WAL_KEEP_SEGMENTS
Expand All @@ -11,12 +11,12 @@ EOF

else

cat > ${PGDATA}/recovery.conf <<EOF
cat > "${PGDATA}/recovery.conf" <<EOF
standby_mode = on
primary_conninfo = 'host=${REPLICATE_FROM} port=5432 user=${POSTGRES_USER} password=${POSTGRES_PASSWORD}'
trigger_file = '/tmp/touch_me_to_promote_to_me_master'
EOF
chown postgres ${PGDATA}/recovery.conf
chmod 600 ${PGDATA}/recovery.conf
chown postgres "${PGDATA}/recovery.conf"
chmod 600 "${PGDATA}/recovery.conf"

fi
219 changes: 122 additions & 97 deletions cmd/postgres_exporter/tests/test-smoke
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,89 @@
# Basic integration tests with postgres. Requires docker to work.

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
METRICS_DIR=$(pwd)

# resolve $SOURCE until the file is no longer a symlink
while [[ -h "${SOURCE}" ]]; do
DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
SOURCE="$(readlink "${SOURCE}")"

# if $SOURCE was a relative symlink, we need to resolve it relative
# to the path where the symlink file was located
[[ ${SOURCE} != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"

METRICS_DIR=$(pwd)
DIR=$( cd -P "$( dirname "${SOURCE}" )" && pwd )
cd "${DIR}" || {
echo "unable to cd to ${DIR}" ;
exit 1 ;
}

# Read the absolute path to the exporter
postgres_exporter="$1"
test_binary="$2"
postgres_exporter=$(readlink -f "$1")

# $2 is actually multiple space-separated values,
# we avoid quoting it here to allow argument expansion.
#
# readlink outputs one line per argument
#
# echo removes the newlines
#
# shellcheck disable=SC2086,SC2046,SC2005
test_binary=$(echo $(readlink -f $2))

# Confirm that the first arg is a binary we can run:
[[ -x "${test_binary%% *}" ]] || {
echo "${test_binary%% *} is not an executable file" ;
exit 1 ;
}

export POSTGRES_PASSWORD=postgres
exporter_port=9187

echo "Exporter Binary: $postgres_exporter" 1>&2
echo "Test Binary: $test_binary" 1>&2

[ -z "$postgres_exporter" ] && echo "Missing exporter binary" && exit 1
[ -z "$test_binary" ] && echo "Missing test binary" && exit 1

cd $DIR

VERSIONS=( \
9.1 \
9.2 \
9.3 \
9.4 \
9.5 \
9.6 \
10 \
declare -a VERSIONS=(
9.1
9.2
9.3
9.4
9.5
9.6
10
)

# START OF FUNCTIONS

wait_for_postgres(){
local ip=$1
local port=$2
if [ -z $ip ]; then
if [[ -z ${ip} ]]; then
echo "No IP specified." 1>&2
exit 1
fi
if [ -z $port ]; then

if [[ -z ${port} ]]; then
echo "No port specified." 1>&2
exit 1
fi


# shellcheck disable=SC2155
local wait_start=$(date +%s)
echo "Waiting for postgres to start listening..."
while ! pg_isready --host=$ip --port=$port &> /dev/null; do
if [ $(( $(date +%s) - $wait_start )) -gt $TIMEOUT ]; then
while ! pg_isready --host="${ip}" --port="${port}" &> /dev/null; do
if [[ $(( $(date +%s) - wait_start )) -gt ${TIMEOUT} ]]; then
echo "Timed out waiting for postgres to start!" 1>&2
exit 1
exit 1
fi
sleep 1
done
}

wait_for_exporter() {
# shellcheck disable=SC2155
local wait_start=$(date +%s)
echo "Waiting for exporter to start..."
while ! nc -z localhost $exporter_port ; do
if [ $(( $(date +%s) - $wait_start )) -gt $TIMEOUT ]; then
while ! nc -z localhost ${exporter_port} ; do
if [[ $(( $(date +%s) - wait_start )) -gt ${TIMEOUT} ]]; then
echo "Timed out waiting for exporter!" 1>&2
exit 1
fi
Expand All @@ -76,101 +97,105 @@ smoketest_postgres() {
local CONTAINER_NAME=postgres_exporter-test-smoke
local TIMEOUT=30
local IMAGE_NAME=postgres
local CUR_IMAGE=$IMAGE_NAME:$version

local CUR_IMAGE=${IMAGE_NAME}:${version}

echo "#######################"
echo "Standalone Postgres $version"
echo "#######################"
local docker_cmd="docker run -d -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD $CUR_IMAGE"
echo "Docker Cmd: $docker_cmd"

CONTAINER_NAME=$($docker_cmd)
standalone_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER_NAME)
trap "docker logs $CONTAINER_NAME ; docker kill $CONTAINER_NAME ; docker rm -v $CONTAINER_NAME; exit 1" EXIT INT TERM
wait_for_postgres $standalone_ip 5432
local docker_cmd="docker run -d -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD} -p 127.0.0.1:55432:5432 ${CUR_IMAGE}"
echo "Docker Cmd: ${docker_cmd}"

CONTAINER_NAME=$( ${docker_cmd} )
trap 'docker logs ${CONTAINER_NAME} ;
docker kill ${CONTAINER_NAME} ;
docker rm -v ${CONTAINER_NAME}; exit 1' EXIT INT TERM
wait_for_postgres localhost 55432

# Run the test binary.
DATA_SOURCE_NAME="postgresql://postgres:$POSTGRES_PASSWORD@$standalone_ip:5432/?sslmode=disable" $test_binary || exit $?
DATA_SOURCE_NAME="postgresql://postgres:${POSTGRES_PASSWORD}@localhost:55432/?sslmode=disable" \
${test_binary} --log.level=debug || exit $?

# Extract a raw metric list.
DATA_SOURCE_NAME="postgresql://postgres:$POSTGRES_PASSWORD@$standalone_ip:5432/?sslmode=disable" $postgres_exporter --log.level=debug --web.listen-address=:$exporter_port &
DATA_SOURCE_NAME="postgresql://postgres:${POSTGRES_PASSWORD}@localhost:55432/?sslmode=disable" \
${postgres_exporter} --log.level=debug --web.listen-address=:${exporter_port} &
exporter_pid=$!
# shellcheck disable=SC2064
trap "docker logs $CONTAINER_NAME ; docker kill $CONTAINER_NAME ; docker rm -v $CONTAINER_NAME; kill $exporter_pid; exit 1" EXIT INT TERM
wait_for_exporter

# Dump the metrics to a file.
wget -q -O - http://localhost:$exporter_port/metrics 1> $METRICS_DIR/.metrics.single.$version.prom
if [ "$?" != "0" ]; then
echo "Failed on postgres $version ($DOCKER_IMAGE)" 1>&2
kill $exporter_pid
exit 1
fi

# HACK test: check pg_up is a 1 - TODO: expand integration tests to include metric consumption
if ! grep 'pg_up.* 1' $METRICS_DIR/.metrics.single.$version.prom ; then
echo "pg_up metric was not 1 despite exporter and database being up"
kill $exporter_pid
exit 1
fi

kill $exporter_pid
docker kill $CONTAINER_NAME
docker rm -v $CONTAINER_NAME
wget -q -O - \
http://localhost:${exporter_port}/metrics \
1>"${METRICS_DIR}/.metrics.single.${version}.prom" ||
{
echo "Failed on postgres ${version} (${DOCKER_IMAGE})" 1>&2
kill ${exporter_pid}
exit 1
}

kill ${exporter_pid}
docker kill "${CONTAINER_NAME}"
docker rm -v "${CONTAINER_NAME}"
trap - EXIT INT TERM

echo "#######################"
echo "Replicated Postgres $version"
echo "Replicated Postgres ${version}"
echo "#######################"
old_pwd=$(pwd)
cd docker-postgres-replication
cd docker-postgres-replication || exit 1


VERSION=$version p2 -t Dockerfile.p2 -o Dockerfile
if [ "$?" != "0" ]; then
echo "Templating failed" 1>&2
exit 1
fi
VERSION=${version} p2 -t Dockerfile.p2 -o Dockerfile || {
echo "Templating failed" 1>&2 ;
exit 1 ;
}

trap "docker-compose logs; docker-compose down ; docker-compose rm -v; exit 1" EXIT INT TERM
local compose_cmd="POSTGRES_PASSWORD=$POSTGRES_PASSWORD docker-compose up -d --force-recreate --build"
echo "Compose Cmd: $compose_cmd"
eval $compose_cmd
local compose_cmd="POSTGRES_PASSWORD=${POSTGRES_PASSWORD} docker-compose up -d --force-recreate --build"
echo "Compose Cmd: ${compose_cmd}"
eval "${compose_cmd}"

master_container=$(docker-compose ps -q pg-master)
slave_container=$(docker-compose ps -q pg-slave)
master_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $master_container)
slave_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $slave_container)
echo "Got master IP: $master_ip"
wait_for_postgres $master_ip 5432
wait_for_postgres $slave_ip 5432
DATA_SOURCE_NAME="postgresql://postgres:$POSTGRES_PASSWORD@$master_ip:5432/?sslmode=disable" $test_binary || exit $?
DATA_SOURCE_NAME="postgresql://postgres:$POSTGRES_PASSWORD@$master_ip:5432/?sslmode=disable" $postgres_exporter --log.level=debug --web.listen-address=:$exporter_port &
master_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${master_container}")
slave_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${slave_container}")
echo "Got master IP: ${master_ip}"
wait_for_postgres "${master_ip}" 5432
wait_for_postgres "${slave_ip}" 5432

DATA_SOURCE_NAME="postgresql://postgres:${POSTGRES_PASSWORD}@${master_ip}:5432/?sslmode=disable" ${test_binary} --log.level=debug || exit $?

DATA_SOURCE_NAME="postgresql://postgres:${POSTGRES_PASSWORD}@${master_ip}:5432/?sslmode=disable" ${postgres_exporter} --log.level=debug --web.listen-address=:${exporter_port} &
exporter_pid=$!
trap "docker-compose logs; docker-compose down ; docker-compose rm -v ; kill $exporter_pid; exit 1" EXIT INT TERM
# shellcheck disable=SC2064
trap "docker-compose logs; docker-compose down ; docker-compose rm -v ; kill ${exporter_pid}; exit 1" EXIT INT TERM
wait_for_exporter

wget -q -O - http://localhost:$exporter_port/metrics 1> $METRICS_DIR/.metrics.replicated.$version.prom
if [ "$?" != "0" ]; then
echo "Failed on postgres $version ($DOCKER_IMAGE)" 1>&2
exit 1
fi
wget -q -O - \
http://localhost:${exporter_port}/metrics \
1>"${METRICS_DIR}/.metrics.replicated.${version}.prom" ||
{
echo "Failed on postgres ${version} (${DOCKER_IMAGE})" 1>&2 ;
exit 1 ;
}

kill $exporter_pid
kill ${exporter_pid}
docker-compose down
docker-compose rm -v
trap - EXIT INT TERM
cd $old_pwd

cd "${old_pwd}" || exit 1
}

### START OF MAIN PROGRAM

# Start pulling the docker images in advance
for version in ${VERSIONS[@]}; do
docker pull postgres:$version > /dev/null &
for version in "${VERSIONS[@]}"; do
docker pull "postgres:${version}" > /dev/null &
done

for version in ${VERSIONS[@]}; do
echo "Testing postgres version $version"
smoketest_postgres $version
for version in "${VERSIONS[@]}"; do
echo "Testing postgres version ${version}"
smoketest_postgres "${version}"
done
8 changes: 4 additions & 4 deletions postgres_exporter_integration_test_script
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ shift
echo "Test Binary: $test_binary" 1>&2
echo "Coverage File: $output_cov" 1>&2

echo "mode: count" > $output_cov
echo "mode: count" > "${output_cov}"

test_cov=$(mktemp)
$test_binary -test.coverprofile=$test_cov $@ || exit 1
tail -n +2 $test_cov >> $output_cov
rm -f $test_cov
${test_binary} -test.coverprofile="${test_cov}" "$@"
tail -n +2 "${test_cov}" >> "${output_cov}"
rm -f "${test_cov}"
4 changes: 2 additions & 2 deletions postgres_metrics_added_and_removed
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ version=$2
old_version=$3
new_version=$4

comm -23 $old_version $new_version > .metrics.${type}.${version}.removed
comm -13 $old_version $new_version > .metrics.${type}.${version}.added
comm -23 "${old_version}" "${new_version}" > ".metrics.${type}.${version}.removed"
comm -13 "${old_version}" "${new_version}" > ".metrics.${type}.${version}.added"
5 changes: 2 additions & 3 deletions postgres_metrics_parse_script
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@

for raw_prom in $(echo .*.prom) ; do
# Strip, sort and deduplicate the label names
cat $raw_prom | grep -v '#' | \
grep -v "#" "${raw_prom}" | \
rev | cut -d' ' -f2- | \
rev | cut -d'{' -f1 | \
sort | \
uniq > ${raw_prom}.unique

uniq > "${raw_prom}.unique"
done