@@ -24,153 +24,237 @@ file_env() {
24
24
unset " $fileVar "
25
25
}
26
26
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[${#FUNCNAME[@]} - 1]}" == ' source' ]
31
+ }
32
+
33
+ # used to create initial posgres directories and if run as root, ensure ownership to the "postgres" user
34
+ create_postgres_dirs () {
35
+ local user=" $( id -u) "
30
36
31
- # allow the container to be started with `--user`
32
- if [ " $1 " = ' postgres' ] && [ " $( id -u) " = ' 0' ]; then
33
37
mkdir -p " $PGDATA "
34
- chown -R postgres " $PGDATA "
35
38
chmod 700 " $PGDATA "
36
39
37
- mkdir -p /var/run/postgresql
38
- chown -R postgres /var/run/postgresql
39
- chmod 775 /var/run/postgresql
40
+ # ignore failure since it will be fine when using the image provided directory; see also https://github.com/docker-library/postgres/pull/289
41
+ mkdir -p /var/run/postgresql || :
42
+ chmod 775 /var/run/postgresql || :
40
43
41
- # Create the transaction log directory before initdb is run (below) so the directory is owned by the correct user
44
+ # Create the transaction log directory before initdb is run so the directory is owned by the correct user
42
45
if [ " $POSTGRES_INITDB_WALDIR " ]; then
43
46
mkdir -p " $POSTGRES_INITDB_WALDIR "
44
- chown -R postgres " $POSTGRES_INITDB_WALDIR "
47
+ [ " $user " = ' 0 ' ] && find " $POSTGRES_INITDB_WALDIR " \! -user postgres - exec chown postgres ' {} ' +
45
48
chmod 700 " $POSTGRES_INITDB_WALDIR "
46
49
fi
47
50
48
- exec gosu postgres " $BASH_SOURCE " " $@ "
49
- fi
51
+ # allow the container to be started with `--user`
52
+ if [ " $user " = ' 0' ]; then
53
+ find " $PGDATA " \! -user postgres -exec chown postgres ' {}' +
54
+ find /var/run/postgresql \! -user postgres -exec chown postgres ' {}' +
55
+ fi
56
+ }
50
57
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 || :
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
58
+ # initialize empty PGDATA directory with new database via 'initdb'
59
+ init_pgdata () {
60
+ # "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
61
+ # see https://github.com/docker-library/postgres/pull/253, https://github.com/docker-library/postgres/issues/359, https://cwrap.org/nss_wrapper.html
62
+ if ! getent passwd " $( id -u) " & > /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
63
+ export LD_PRELOAD=' /usr/lib/libnss_wrapper.so'
64
+ export NSS_WRAPPER_PASSWD=" $( mktemp) "
65
+ export NSS_WRAPPER_GROUP=" $( mktemp) "
66
+ echo " postgres:x:$( id -u) :$( id -g) :PostgreSQL:$PGDATA :/bin/false" > " $NSS_WRAPPER_PASSWD "
67
+ echo " postgres:x:$( id -g) :" > " $NSS_WRAPPER_GROUP "
68
+ fi
67
69
68
- file_env ' POSTGRES_USER' ' postgres'
69
- file_env ' POSTGRES_PASSWORD'
70
+ file_env ' POSTGRES_INITDB_ARGS'
71
+ if [ " $POSTGRES_INITDB_WALDIR " ]; then
72
+ export POSTGRES_INITDB_ARGS=" $POSTGRES_INITDB_ARGS --waldir $POSTGRES_INITDB_WALDIR "
73
+ fi
70
74
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 "
75
+ eval ' initdb --username="$POSTGRES_USER" --pwfile=<(echo "$POSTGRES_PASSWORD") ' " $POSTGRES_INITDB_ARGS "
76
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
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
+ }
82
83
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
84
+ # print large warning if POSTGRES_PASSWORD is empty
85
+ print_password_warning () {
86
+ # check password first so we can output the warning before postgres
87
+ # messes it up
88
+ if [ " ${# POSTGRES_PASSWORD} " -ge 100 ]; then
89
+ cat >&2 << -'EOWARN '
87
90
88
- if [ " ${# POSTGRES_PASSWORD} " -ge 100 ]; then
89
- cat >&2 << -'EOWARN '
91
+ WARNING: The supplied POSTGRES_PASSWORD is 100+ characters.
90
92
91
- WARNING: The supplied POSTGRES_PASSWORD is 100+ characters .
93
+ This will not work if used via PGPASSWORD with "psql" .
92
94
93
- This will not work if used via PGPASSWORD with "psql".
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
94
97
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
98
+ EOWARN
99
+ fi
100
+ if [ -z " $POSTGRES_PASSWORD " ]; then
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.
97
110
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
111
+ Use "-e POSTGRES_PASSWORD=password" to set
112
+ it in "docker run".
113
+ ****************************************************
114
+ EOWARN
118
115
119
- {
120
- echo
121
- echo " host all all all $authMethod "
122
- } >> " $PGDATA /pg_hba.conf"
116
+ fi
117
+ }
123
118
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
119
+ # run, source, or read files from /docker-entrypoint-initdb.d (or specified directory)
120
+ process_init_files () {
121
+ # psql here for backwards compatiblilty "${psql[@]}"
122
+ psql=( psql_run )
130
123
131
- file_env ' POSTGRES_DB ' " $POSTGRES_USER "
124
+ local initDir= " ${1 :-/ docker-entrypoint-initdb.d} "
132
125
133
- export PGPASSWORD=" ${PGPASSWORD:- $POSTGRES_PASSWORD } "
134
- psql=( psql -v ON_ERROR_STOP=1 --username " $POSTGRES_USER " --no-password )
126
+ echo
127
+ for f in " ${initDir%/ } " /* ; do
128
+ case " $f " in
129
+ * .sh)
130
+ # https://github.com/docker-library/postgres/issues/450#issuecomment-393167936
131
+ # https://github.com/docker-library/postgres/pull/452
132
+ if [ -x " $f " ]; then
133
+ echo " $0 : running $f "
134
+ " $f "
135
+ else
136
+ echo " $0 : sourcing $f "
137
+ . " $f "
138
+ fi
139
+ ;;
140
+ * .sql) echo " $0 : running $f " ; psql_run -f " $f " ; echo ;;
141
+ * .sql.gz) echo " $0 : running $f " ; gunzip -c " $f " | psql_run; echo ;;
142
+ * ) echo " $0 : ignoring $f " ;;
143
+ esac
144
+ echo
145
+ done
146
+ }
135
147
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 " )
148
+ # run `psql` with proper arguments for user and db
149
+ psql_run () {
150
+ local query_runner=( psql -v ON_ERROR_STOP=1 --username " $POSTGRES_USER " --no-password )
151
+ if [ -n " $POSTGRES_DB " ]; then
152
+ query_runner+=( --dbname " $POSTGRES_DB " )
153
+ fi
154
+
155
+ " ${query_runner[@]} " " $@ "
156
+ }
143
157
158
+ # create initial postgresql superuser with password and database
159
+ # uses environment variables for input: POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
160
+ setup_database () {
161
+ if [ " $POSTGRES_DB " != ' postgres' ]; then
162
+ POSTGRES_DB= psql_run --dbname postgres --set db=" $POSTGRES_DB " << -'EOSQL '
163
+ CREATE DATABASE :"db" ;
164
+ EOSQL
144
165
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
166
+ fi
167
+ }
164
168
165
- PGUSER=" ${PGUSER:- $POSTGRES_USER } " \
166
- pg_ctl -D " $PGDATA " -m fast -w stop
169
+ # get user/pass and db from env vars or via file
170
+ setup_env_vars () {
171
+ file_env ' POSTGRES_PASSWORD'
167
172
168
- unset PGPASSWORD
173
+ file_env ' POSTGRES_USER' ' postgres'
174
+ file_env ' POSTGRES_DB' " $POSTGRES_USER "
175
+ }
169
176
177
+ # append md5 or trust auth to pg_hba.conf based on existence of POSTGRES_PASSWORD
178
+ setup_pg_hba () {
179
+ local authMethod
180
+ if [ " $POSTGRES_PASSWORD " ]; then
181
+ authMethod=' md5'
182
+ else
183
+ authMethod=' trust'
184
+ fi
185
+
186
+ {
170
187
echo
171
- echo ' PostgreSQL init process complete; ready for start up.'
172
- echo
188
+ echo " host all all all $authMethod "
189
+ } >> " $PGDATA /pg_hba.conf"
190
+ }
191
+
192
+ # start socket-only postgresql server for setting up user or running scripts
193
+ temporary_pgserver_start () {
194
+ # internal start of server in order to allow set-up using psql-client
195
+ # does not listen on external TCP/IP and waits until start finishes
196
+ PGUSER=" ${PGUSER:- $POSTGRES_USER } " \
197
+ pg_ctl -D " $PGDATA " \
198
+ -o " -c listen_addresses=''" \
199
+ -w start
200
+ # ??? "$@"
201
+ }
202
+
203
+ # stop postgresql server after done setting up user and running scripts
204
+ temporary_pgserver_stop () {
205
+ PGUSER=" ${PGUSER:- postgres} " \
206
+ pg_ctl -D " $PGDATA " -m fast -w stop
207
+ }
208
+
209
+ main () {
210
+ # if first arg looks like a flag, assume we want to run postgres server
211
+ if [ " ${1: 0: 1} " = ' -' ]; then
212
+ set -- postgres " $@ "
173
213
fi
174
- fi
175
214
176
- exec " $@ "
215
+ # setup data directories and permissions, then restart script as postgres user
216
+ if [ " $1 " = ' postgres' ] && [ " $( id -u) " = ' 0' ]; then
217
+ create_postgres_dirs
218
+ exec gosu postgres " $BASH_SOURCE " " $@ "
219
+ fi
220
+
221
+ if [ " $1 " = ' postgres' ]; then
222
+ create_postgres_dirs
223
+
224
+ # only run initialization on an empty data directory
225
+ # look specifically for PG_VERSION, as it is expected in the DB dir
226
+ if [ ! -s " $PGDATA /PG_VERSION" ]; then
227
+ init_pgdata
228
+
229
+ setup_env_vars
230
+ print_password_warning
231
+ setup_pg_hba
232
+
233
+ # PGPASSWORD is required for psql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
234
+ # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
235
+ export PGPASSWORD=" ${PGPASSWORD:- $POSTGRES_PASSWORD } "
236
+ temporary_pgserver_start
237
+
238
+ setup_database
239
+
240
+ process_init_files
241
+
242
+ temporary_pgserver_stop
243
+ unset PGPASSWORD
244
+
245
+ echo
246
+ echo ' PostgreSQL init process complete; ready for start up.'
247
+ echo
248
+ else
249
+ echo
250
+ echo ' PostgreSQL Database directory appears to contain a database; Skipping initialization'
251
+ echo
252
+ fi
253
+ fi
254
+
255
+ exec " $@ "
256
+ }
257
+
258
+ if ! _is_sourced; then
259
+ main " $@ "
260
+ fi
0 commit comments