postgresql/root/usr/share/container-scripts/postgresql/common.sh
2017-05-04 10:50:54 +02:00

220 lines
7.7 KiB
Bash

# Configuration settings.
export POSTGRESQL_MAX_CONNECTIONS=${POSTGRESQL_MAX_CONNECTIONS:-100}
export POSTGRESQL_MAX_PREPARED_TRANSACTIONS=${POSTGRESQL_MAX_PREPARED_TRANSACTIONS:-0}
# Perform auto-tuning based on the container cgroups limits (only when the
# limits are set).
# Users can still override this by setting the POSTGRESQL_SHARED_BUFFERS
# and POSTGRESQL_EFFECTIVE_CACHE_SIZE variables.
if [[ "${NO_MEMORY_LIMIT:-}" == "true" || -z "${MEMORY_LIMIT_IN_BYTES}" ]]; then
export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-32MB}
export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-128MB}
else
# Use 1/4 of given memory for shared buffers
shared_buffers_computed="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/4))MB"
# Setting effective_cache_size to 1/2 of total memory would be a normal conservative setting,
effective_cache="$(($MEMORY_LIMIT_IN_BYTES/1024/1024/2))MB"
export POSTGRESQL_SHARED_BUFFERS=${POSTGRESQL_SHARED_BUFFERS:-$shared_buffers_computed}
export POSTGRESQL_EFFECTIVE_CACHE_SIZE=${POSTGRESQL_EFFECTIVE_CACHE_SIZE:-$effective_cache}
fi
export POSTGRESQL_RECOVERY_FILE=$HOME/openshift-custom-recovery.conf
export POSTGRESQL_CONFIG_FILE=$HOME/openshift-custom-postgresql.conf
postinitdb_actions=
psql_identifier_regex='^[a-zA-Z_][a-zA-Z0-9_]*$'
psql_password_regex='^[a-zA-Z0-9_~!@#$%^&*()-=<>,.?;:|]+$'
# match . files when moving userdata below
shopt -s dotglob
# extglob enables the !(userdata) glob pattern below.
shopt -s extglob
function usage() {
if [ $# == 1 ]; then
echo >&2 "error: $1"
fi
cat >&2 <<EOF
You must either specify the following environment variables:
POSTGRESQL_USER (regex: '$psql_identifier_regex')
POSTGRESQL_PASSWORD (regex: '$psql_password_regex')
POSTGRESQL_DATABASE (regex: '$psql_identifier_regex')
Or the following environment variable:
POSTGRESQL_ADMIN_PASSWORD (regex: '$psql_password_regex')
Or both.
Optional settings:
POSTGRESQL_MAX_CONNECTIONS (default: 100)
POSTGRESQL_MAX_PREPARED_TRANSACTIONS (default: 0)
POSTGRESQL_SHARED_BUFFERS (default: 32MB)
For more information see /usr/share/container-scripts/postgresql/README.md
within the container or visit https://github.com/openshift/postgresql.
EOF
exit 1
}
function check_env_vars() {
if [[ -v POSTGRESQL_USER || -v POSTGRESQL_PASSWORD || -v POSTGRESQL_DATABASE ]]; then
# one var means all three must be specified
[[ -v POSTGRESQL_USER && -v POSTGRESQL_PASSWORD && -v POSTGRESQL_DATABASE ]] || usage
[[ "$POSTGRESQL_USER" =~ $psql_identifier_regex ]] || usage
[[ "$POSTGRESQL_PASSWORD" =~ $psql_password_regex ]] || usage
[[ "$POSTGRESQL_DATABASE" =~ $psql_identifier_regex ]] || usage
[ ${#POSTGRESQL_USER} -le 63 ] || usage "PostgreSQL username too long (maximum 63 characters)"
[ ${#POSTGRESQL_DATABASE} -le 63 ] || usage "Database name too long (maximum 63 characters)"
postinitdb_actions+=",simple_db"
fi
if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then
[[ "$POSTGRESQL_ADMIN_PASSWORD" =~ $psql_password_regex ]] || usage
postinitdb_actions+=",admin_pass"
fi
case ",$postinitdb_actions," in
*,admin_pass,*|*,simple_db,*) ;;
*) usage ;;
esac
}
# Make sure env variables don't propagate to PostgreSQL process.
function unset_env_vars() {
unset POSTGRESQL_{DATABASE,USER,PASSWORD,ADMIN_PASSWORD}
}
# postgresql_master_addr lookups the 'postgresql-master' DNS and get list of the available
# endpoints. Each endpoint is a PostgreSQL container with the 'master' PostgreSQL running.
function postgresql_master_addr() {
local service_name=${POSTGRESQL_MASTER_SERVICE_NAME:-postgresql-master}
local endpoints=$(dig ${service_name} A +search | grep ";${service_name}" | cut -d ';' -f 2 2>/dev/null)
# FIXME: This is for debugging (docker run)
if [ -v POSTGRESQL_MASTER_IP ]; then
endpoints=${POSTGRESQL_MASTER_IP:-}
fi
if [ -z "$endpoints" ]; then
>&2 echo "Failed to resolve PostgreSQL master IP address"
exit 3
fi
echo -n "$(echo $endpoints | cut -d ' ' -f 1)"
}
# New config is generated every time a container is created. It only contains
# additional custom settings and is included from $PGDATA/postgresql.conf.
function generate_postgresql_config() {
envsubst \
< "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql.conf.template" \
> "${POSTGRESQL_CONFIG_FILE}"
if [ "${ENABLE_REPLICATION}" == "true" ]; then
envsubst \
< "${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql-replication.conf.template" \
>> "${POSTGRESQL_CONFIG_FILE}"
fi
}
function generate_postgresql_recovery_config() {
envsubst \
< "${CONTAINER_SCRIPTS_PATH}/openshift-custom-recovery.conf.template" \
> "${POSTGRESQL_RECOVERY_FILE}"
}
# Generate passwd file based on current uid
function generate_passwd_file() {
export USER_ID=$(id -u)
export GROUP_ID=$(id -g)
grep -v ^postgres /etc/passwd > "$HOME/passwd"
echo "postgres:x:${USER_ID}:${GROUP_ID}:PostgreSQL Server:${HOME}:/bin/bash" >> "$HOME/passwd"
export LD_PRELOAD=libnss_wrapper.so
export NSS_WRAPPER_PASSWD=${HOME}/passwd
export NSS_WRAPPER_GROUP=/etc/group
}
function initialize_database() {
# Initialize the database cluster with utf8 support enabled by default.
# This might affect performance, see:
# http://www.postgresql.org/docs/9.5/static/locale.html
LANG=${LANG:-en_US.utf8} initdb
# PostgreSQL configuration.
cat >> "$PGDATA/postgresql.conf" <<EOF
# Custom OpenShift configuration:
include '${POSTGRESQL_CONFIG_FILE}'
EOF
# Access control configuration.
# FIXME: would be nice-to-have if we could allow connections only from
# specific hosts / subnet
cat >> "$PGDATA/pg_hba.conf" <<EOF
#
# Custom OpenShift configuration starting at this point.
#
# Allow connections from all hosts.
host all all all md5
# Allow replication connections from all hosts.
host replication all all md5
EOF
}
function create_users() {
if [[ ",$postinitdb_actions," = *,simple_db,* ]]; then
createuser "$POSTGRESQL_USER"
createdb --owner="$POSTGRESQL_USER" "$POSTGRESQL_DATABASE"
fi
if [ -v POSTGRESQL_MASTER_USER ]; then
createuser "$POSTGRESQL_MASTER_USER"
fi
}
function set_passwords() {
if [[ ",$postinitdb_actions," = *,simple_db,* ]]; then
psql --command "ALTER USER \"${POSTGRESQL_USER}\" WITH ENCRYPTED PASSWORD '${POSTGRESQL_PASSWORD}';"
fi
if [ -v POSTGRESQL_MASTER_USER ]; then
psql --command "ALTER USER \"${POSTGRESQL_MASTER_USER}\" WITH REPLICATION;"
psql --command "ALTER USER \"${POSTGRESQL_MASTER_USER}\" WITH ENCRYPTED PASSWORD '${POSTGRESQL_MASTER_PASSWORD}';"
fi
if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then
psql --command "ALTER USER \"postgres\" WITH ENCRYPTED PASSWORD '${POSTGRESQL_ADMIN_PASSWORD}';"
fi
}
function set_pgdata ()
{
# backwards compatibility case, we used to put the data here,
# move it into our new expected location (userdata)
if [ -e ${HOME}/data/PG_VERSION ]; then
mkdir -p "${HOME}/data/userdata"
pushd "${HOME}/data"
# move everything except the userdata directory itself, into the userdata directory.
mv !(userdata) "userdata"
popd
else
# create a subdirectory that the user owns
mkdir -p "${HOME}/data/userdata"
fi
export PGDATA=$HOME/data/userdata
# ensure sane perms for postgresql startup
chmod 700 "$PGDATA"
}
function wait_for_postgresql_master() {
while true; do
master_fqdn=$(postgresql_master_addr)
echo "Waiting for PostgreSQL master (${master_fqdn}) to accept connections ..."
if [ -v POSTGRESQL_ADMIN_PASSWORD ]; then
PGPASSWORD=${POSTGRESQL_ADMIN_PASSWORD} psql "postgresql://postgres@${master_fqdn}" -c "SELECT 1;" && return 0
else
PGPASSWORD=${POSTGRESQL_PASSWORD} psql "postgresql://${POSTGRESQL_USER}@${master_fqdn}/${POSTGRESQL_DATABASE}" -c "SELECT 1;" && return 0
fi
sleep 1
done
}