Skip to content

Commit 7c84645

Browse files
committed
Apply update.sh for new entrypoint
1 parent d1cc089 commit 7c84645

12 files changed

+2616
-1404
lines changed

10/alpine/docker-entrypoint.sh

+218-117
Original file line numberDiff line numberDiff line change
@@ -24,153 +24,254 @@ file_env() {
2424
unset "$fileVar"
2525
}
2626

27-
if [ "${1:0:1}" = '-' ]; then
28-
set -- postgres "$@"
29-
fi
27+
# check to see if this file is being run or sourced from another script
28+
_is_sourced() {
29+
# https://unix.stackexchange.com/a/215279
30+
[ "${#FUNCNAME[@]}" -ge 2 ] \
31+
&& [ "${FUNCNAME[0]}" = '_is_sourced' ] \
32+
&& [ "${FUNCNAME[1]}" = 'source' ]
33+
}
34+
35+
# used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
36+
docker_create_db_directories() {
37+
local user="$(id -u)"
3038

31-
# allow the container to be started with `--user`
32-
if [ "$1" = 'postgres' ] && [ "$(id -u)" = '0' ]; then
3339
mkdir -p "$PGDATA"
34-
chown -R postgres "$PGDATA"
3540
chmod 700 "$PGDATA"
3641

37-
mkdir -p /var/run/postgresql
38-
chown -R postgres /var/run/postgresql
39-
chmod 775 /var/run/postgresql
42+
# ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
43+
mkdir -p /var/run/postgresql || :
44+
chmod 775 /var/run/postgresql || :
4045

41-
# Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
46+
# Create the transaction log directory before initdb is run so the directory is owned by the correct user
4247
if [ "$POSTGRES_INITDB_WALDIR" ]; then
4348
mkdir -p "$POSTGRES_INITDB_WALDIR"
44-
chown -R postgres "$POSTGRES_INITDB_WALDIR"
49+
[ "$user" = '0' ] && find "$POSTGRES_INITDB_WALDIR" \! -user postgres - exec chown postgres '{}' +
4550
chmod 700 "$POSTGRES_INITDB_WALDIR"
4651
fi
4752

48-
exec su-exec postgres "$BASH_SOURCE" "$@"
49-
fi
50-
51-
if [ "$1" = 'postgres' ]; then
52-
mkdir -p "$PGDATA"
53-
chown -R "$(id -u)" "$PGDATA" 2>/dev/null || :
54-
chmod 700 "$PGDATA" 2>/dev/null || :
53+
# allow the container to be started with `--user`
54+
if [ "$user" = '0' ]; then
55+
find "$PGDATA" \! -user postgres -exec chown postgres '{}' +
56+
find /var/run/postgresql \! -user postgres -exec chown postgres '{}' +
57+
fi
58+
}
5559

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
60+
# initialize empty PGDATA directory with new database via 'initdb'
61+
# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
62+
# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
63+
# this is also where the database user is created, specified by `POSTGRES_USER` env
64+
docker_init_database_dir() {
65+
# "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
66+
# see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
67+
if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
68+
export LD_PRELOAD='/usr/lib/libnss_wrapper.so'
69+
export NSS_WRAPPER_PASSWD="$(mktemp)"
70+
export NSS_WRAPPER_GROUP="$(mktemp)"
71+
echo "postgres:x:$(id -u):$(id -g):PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD"
72+
echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
73+
fi
6774

68-
file_env 'POSTGRES_USER' 'postgres'
69-
file_env 'POSTGRES_PASSWORD'
75+
if [ "$POSTGRES_INITDB_WALDIR" ]; then
76+
set -- --waldir "$POSTGRES_INITDB_WALDIR" "$@"
77+
fi
7078

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"
79+
eval 'initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") '"$POSTGRES_INITDB_ARGS"' "$@"'
7680

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
81+
# unset/cleanup "nss_wrapper" bits
82+
if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
83+
rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
84+
unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
85+
fi
86+
}
8287

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
88+
# print large warning if POSTGRES_PASSWORD is empty
89+
docker_verify_minimum_env() {
90+
# check password first so we can output the warning before postgres
91+
# messes it up
92+
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
93+
cat >&2 <<-'EOWARN'
8794
88-
if [ "${#POSTGRES_PASSWORD}" -ge 100 ]; then
89-
cat >&2 <<-'EOWARN'
95+
WARNING: The supplied POSTGRES_PASSWORD is 100+ characters.
9096
91-
WARNING: The supplied POSTGRES_PASSWORD is 100+ characters.
97+
This will not work if used via PGPASSWORD with "psql".
9298
93-
This will not work if used via PGPASSWORD with "psql".
99+
https://www.postgresql.org/message-id/flat/E1Rqxp2-0004Qt-PL%40wrigleys.postgresql.org (BUG #6412)
100+
https://github.com/docker-library/postgres/issues/507
94101
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
102+
EOWARN
103+
fi
104+
if [ -z "$POSTGRES_PASSWORD" ]; then
105+
# The - option suppresses leading tabs but *not* spaces. :)
106+
cat >&2 <<-'EOWARN'
107+
****************************************************
108+
WARNING: No password has been set for the database.
109+
This will allow anyone with access to the
110+
Postgres port to access your database. In
111+
Docker's default configuration, this is
112+
effectively any other container on the same
113+
system.
97114
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
115+
Use "-e POSTGRES_PASSWORD=password" to set
116+
it in "docker run".
117+
****************************************************
118+
EOWARN
118119

119-
{
120-
echo
121-
echo "host all all all $authMethod"
122-
} >> "$PGDATA/pg_hba.conf"
120+
fi
121+
}
123122

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
123+
# usage: docker_process_init_files [file [file [...]]]
124+
# ie: docker_process_init_files /always-initdb.d/*
125+
# process initializer files, based on file extensions and permissions
126+
docker_process_init_files() {
127+
# psql here for backwards compatiblilty "${psql[@]}"
128+
psql=( docker_process_sql )
130129

131-
file_env 'POSTGRES_DB' "$POSTGRES_USER"
130+
echo
131+
local f
132+
for f; do
133+
case "$f" in
134+
*.sh)
135+
# https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
136+
# https://github.com/docker-library/postgres/pull/452
137+
if [ -x "$f" ]; then
138+
echo "$0: running $f"
139+
"$f"
140+
else
141+
echo "$0: sourcing $f"
142+
. "$f"
143+
fi
144+
;;
145+
*.sql) echo "$0: running $f"; docker_process_sql -f "$f"; echo ;;
146+
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | docker_process_sql; echo ;;
147+
*) echo "$0: ignoring $f" ;;
148+
esac
149+
echo
150+
done
151+
}
132152

133-
export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
134-
psql=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
153+
# Execute sql script, passed via stdin (or -f flag of pqsl)
154+
# usage: docker_process_sql [psql-cli-args]
155+
# ie: docker_process_sql --dbname=mydb <<<'INSERT ...'
156+
# ie: docker_process_sql -f my-file.sql
157+
# ie: docker_process_sql <my-file.sql
158+
docker_process_sql() {
159+
local query_runner=( psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --no-password )
160+
if [ -n "$POSTGRES_DB" ]; then
161+
query_runner+=( --dbname "$POSTGRES_DB" )
162+
fi
135163

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" )
164+
"${query_runner[@]}" "$@"
165+
}
143166

167+
# create initial database
168+
# uses environment variables for input: POSTGRES_DB
169+
docker_setup_db() {
170+
if [ "$POSTGRES_DB" != 'postgres' ]; then
171+
POSTGRES_DB= docker_process_sql --dbname postgres --set db="$POSTGRES_DB" <<-'EOSQL'
172+
CREATE DATABASE :"db" ;
173+
EOSQL
144174
echo
145-
for f in /docker-entrypoint-initdb.d/*; 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
175+
fi
176+
}
164177

165-
PGUSER="${PGUSER:-$POSTGRES_USER}" \
166-
pg_ctl -D "$PGDATA" -m fast -w stop
178+
# Loads various settings that are used elsewhere in the script
179+
# This should be called before any other functions
180+
docker_setup_env() {
181+
file_env 'POSTGRES_PASSWORD'
167182

168-
unset PGPASSWORD
183+
file_env 'POSTGRES_USER' 'postgres'
184+
file_env 'POSTGRES_DB' "$POSTGRES_USER"
185+
file_env 'POSTGRES_INITDB_ARGS'
169186

187+
declare -g DATABASE_ALREADY_EXISTS
188+
# look specifically for PG_VERSION, as it is expected in the DB dir
189+
if [ -s "$PGDATA/PG_VERSION" ]; then
190+
DATABASE_ALREADY_EXISTS='true'
191+
fi
192+
}
193+
194+
# append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
195+
pg_setup_hba_conf() {
196+
local authMethod
197+
if [ "$POSTGRES_PASSWORD" ]; then
198+
authMethod='md5'
199+
else
200+
authMethod='trust'
201+
fi
202+
203+
{
170204
echo
171-
echo 'PostgreSQL init process complete; ready for start up.'
172-
echo
205+
echo "host all all all $authMethod"
206+
} >> "$PGDATA/pg_hba.conf"
207+
}
208+
209+
# start socket-only postgresql server for setting up or running scripts
210+
# all arguments will be passed along as arguments to `postgres` (via pg_ctl)
211+
docker_temp_server_start() {
212+
if [ "$1" = 'postgres' ]; then
213+
shift
173214
fi
174-
fi
215+
# internal start of server in order to allow setup using psql client
216+
# does not listen on external TCP/IP and waits until start finishes (can be overridden via args)
217+
PGUSER="${PGUSER:-$POSTGRES_USER}" \
218+
pg_ctl -D "$PGDATA" \
219+
-o "-c listen_addresses='' $([ "$#" -gt 0 ] && printf '%q ' "$@")" \
220+
-w start
221+
}
222+
223+
# stop postgresql server after done setting up user and running scripts
224+
docker_temp_server_stop() {
225+
PGUSER="${PGUSER:-postgres}" \
226+
pg_ctl -D "$PGDATA" -m fast -w stop
227+
}
228+
229+
_main() {
230+
# if first arg looks like a flag, assume we want to run postgres server
231+
if [ "${1:0:1}" = '-' ]; then
232+
set -- postgres "$@"
233+
fi
234+
235+
236+
if [ "$1" = 'postgres' ]; then
237+
docker_setup_env
238+
# setup data directories and permissions (when run as root)
239+
docker_create_db_directories
240+
if [ "$(id -u)" = '0' ]; then
241+
# then restart script as postgres user
242+
exec su-exec postgres "$BASH_SOURCE" "$@"
243+
fi
244+
245+
# only run initialization on an empty data directory
246+
if [ -z "$DATABASE_ALREADY_EXISTS" ]; then
247+
docker_verify_minimum_env
248+
docker_init_database_dir
249+
pg_setup_hba_conf
250+
251+
# PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
252+
# e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
253+
export PGPASSWORD="${PGPASSWORD:-$POSTGRES_PASSWORD}"
254+
docker_temp_server_start "$@"
255+
256+
docker_setup_db
257+
docker_process_init_files /docker-entrypoint-initdb.d/*
258+
259+
docker_temp_server_stop
260+
unset PGPASSWORD
261+
262+
echo
263+
echo 'PostgreSQL init process complete; ready for start up.'
264+
echo
265+
else
266+
echo
267+
echo 'PostgreSQL Database directory appears to contain a database; Skipping initialization'
268+
echo
269+
fi
270+
fi
271+
272+
exec "$@"
273+
}
175274

176-
exec "$@"
275+
if ! _is_sourced; then
276+
_main "$@"
277+
fi

0 commit comments

Comments
 (0)