blob: 76268e9c1292b76bffe383afe862a66825bbfca9 [file] [log] [blame]
Thomas Psota0bc7d0d2019-11-15 11:53:26 +01001#!/usr/bin/env bash
2set -Eeo pipefail
3# TODO swap to -Eeuo pipefail above (after handling all potentially-unset variables)
4
5# usage: file_env VAR [DEFAULT]
6# ie: file_env 'XYZ_DB_PASSWORD' 'example'
7# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
8# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
9file_env() {
10 local var="$1"
11 local fileVar="${var}_FILE"
12 local def="${2:-}"
13 if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
14 echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
15 exit 1
16 fi
17 local val="$def"
18 if [ "${!var:-}" ]; then
19 val="${!var}"
20 elif [ "${!fileVar:-}" ]; then
21 val="$(< "${!fileVar}")"
22 fi
23 export "$var"="$val"
24 unset "$fileVar"
25}
26
27if [ "${1:0:1}" = '-' ]; then
28 set -- postgres "$@"
29fi
30
31# allow the container to be started with `--user`
32if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
33 mkdir -p "$PGDATA"
34 chown -R postgres "$PGDATA"
35 chmod 700 "$PGDATA"
36
37 mkdir -p /var/run/postgresql
38 chown -R postgres /var/run/postgresql
39 chmod 775 /var/run/postgresql
40
41 # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
42 if [ "$POSTGRES_INITDB_WALDIR" ]; then
43 mkdir -p "$POSTGRES_INITDB_WALDIR"
44 chown -R postgres "$POSTGRES_INITDB_WALDIR"
45 chmod 700 "$POSTGRES_INITDB_WALDIR"
46 fi
47
48 exec gosu postgres "$BASH_SOURCE" "$@"
49fi
50
51if [ "$1" = 'postgres' ]; then
52 mkdir -p "$PGDATA"
53 chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
54 chmod 700 "$PGDATA" 2>/dev/null || :
55
56 # look specifically for PG_VERSION, as it is expected in the DB dir
57 if [ ! -s "$PGDATA/PG_VERSION" ]; then
58 # "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
59 # see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
60 if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
61 export LD_PRELOAD='/usr/lib/libnss_wrapper.so'
62 export NSS_WRAPPER_PASSWD="$(mktemp)"
63 export NSS_WRAPPER_GROUP="$(mktemp)"
64 echo "postgres:x:$(id -u):$(id -g):PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD"
65 echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
66 fi
67
68 file_env 'POSTGRES_USER' 'postgres'
69 file_env 'POSTGRES_PASSWORD'
70
71 file_env 'POSTGRES_INITDB_ARGS'
72 if [ "$POSTGRES_INITDB_WALDIR" ]; then
73 export POSTGRES_INITDB_ARGS="$POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR"
74 fi
75 eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"
76
77 # unset/cleanup "nss_wrapper" bits
78 if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
79 rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
80 unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
81 fi
82
83 # check password first so we can output the warning before postgres
84 # messes it up
85 if [ -n "$POSTGRES_PASSWORD" ]; then
86 authMethod=md5
87
88 if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
89 cat >&2 <<-'EOWARN'
90
91 WARNING: The supplied POSTGRES_PASSWORD is 100+ characters.
92
93 This will not work if used via PGPASSWORD with "psql".
94
95 https://www.postgresql.org/message-id/flat/E1Rqxp2-0004Qt-PL%40wrigleys.postgresql.org (BUG #6412)
96 https://github.com/docker-library/postgres/issues/507
97
98 EOWARN
99 fi
100 else
101 # The - option suppresses leading tabs but *not* spaces. :)
102 cat >&2 <<-'EOWARN'
103 ****************************************************
104 WARNING: No password has been set for the database.
105 This will allow anyone with access to the
106 Postgres port to access your database. In
107 Docker's default configuration, this is
108 effectively any other container on the same
109 system.
110
111 Use "-e POSTGRES_PASSWORD=password" to set
112 it in "docker run".
113 ****************************************************
114 EOWARN
115
116 authMethod=trust
117 fi
118
119 {
120 echo
121 echo "host all all all $authMethod"
122 } >> "$PGDATA/pg_hba.conf"
123
124 # internal start of server in order to allow set-up using psql-client
125 # does not listen on external TCP/IP and waits until start finishes
126 PGUSER="${PGUSER:-$POSTGRES_USER}" \
127 pg_ctl -D "$PGDATA" \
128 -o "-c listen_addresses=''" \
129 -w start
130
131 file_env 'POSTGRES_DB' "$POSTGRES_USER"
132
133 export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
134 psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
135
136 if [ "$POSTGRES_DB" != 'postgres' ]; then
137 "${psql[@]}" --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
138 CREATE DATABASE :"db" ;
139 EOSQL
140 echo
141 fi
142 psql+=( --dbname "$POSTGRES_DB" )
143
144 echo
145 for f in ./ci/sql/*; do
146 case "$f" in
147 *.sh)
148 # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
149 # https://github.com/docker-library/postgres/pull/452
150 if [ -x "$f" ]; then
151 echo "$0: running $f"
152 "$f"
153 else
154 echo "$0: sourcing $f"
155 . "$f"
156 fi
157 ;;
158 *.sql) echo "$0: running $f"; "${psql[@]}" -f "$f"; echo ;;
159 *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${psql[@]}"; echo ;;
160 *) echo "$0: ignoring $f" ;;
161 esac
162 echo
163 done
164
165 PGUSER="${PGUSER:-$POSTGRES_USER}" \
166 pg_ctl -D "$PGDATA" -m fast -w stop
167
168 unset PGPASSWORD
169
170 echo
171 echo 'PostgreSQL init process complete; ready for start up.'
172 echo
173 fi
174fi