Skip to content

Commit f9c185f

Browse files
ltangvaldyosifkit
authored andcommitted
entrypoint: Move more logic into functions
Almost all logic in the entrypoint script is now separated into various functions
1 parent db12713 commit f9c185f

File tree

2 files changed

+162
-99
lines changed

2 files changed

+162
-99
lines changed

.template.Debian/docker-entrypoint.sh

+158-95
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,17 @@ docker_get_config() {
9090
# match "datadir /some/path with/spaces in/it here" but not "--xyz=abc\n datadir (xyz)"
9191
}
9292

93+
# Do a temporary startup of the MySQL server, for init purposes
9394
docker_start_server() {
94-
local socket=$1; shift
9595
result=0
9696
%%SERVERSTARTUP%%
9797
if [ ! "$result" = "0" ];then
9898
docker_error "Unable to start server. Status code $result."
9999
fi
100100
}
101101

102+
# Wait for the temporary server to be ready for connections.
103+
# It is only used for versions older than 5.7
102104
docker_wait_for_server() {
103105
local mysql=( "$@" )
104106
for i in {30..0}; do
@@ -112,141 +114,202 @@ docker_wait_for_server() {
112114
fi
113115
}
114116

117+
# Stop the server. When using a local socket file mysqladmin will block until
118+
# the shutdown is complete.
115119
docker_stop_server() {
116-
local passfile=$1
117-
local socket=$2
118120
result=0
119-
mysqladmin --defaults-extra-file="${passfile}" shutdown -uroot --socket="${socket}" || result=$?
121+
mysqladmin --defaults-extra-file="${PASSFILE}" shutdown -uroot --socket="${SOCKET}" || result=$?
120122
if [ ! "$result" = "0" ]; then
121123
docker_error "Unable to shut down server. Status code $result."
122124
fi
123125
}
126+
127+
# Verify that the minimally required password settings are set for new databases.
128+
docker_verify_env() {
129+
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
130+
docker_error "Database is uninitialized and password option is not specified \n\tYou need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD"
131+
fi
132+
}
133+
134+
# Creates and initializes the database directory
135+
docker_init_database_dir() {
136+
mkdir -p "$DATADIR"
137+
138+
docker_note "Initializing database files"
139+
%%DATABASEINIT%%
140+
docker_note "Database files initialized"
141+
142+
if command -v mysql_ssl_rsa_setup > /dev/null && [ ! -e "$DATADIR/server-key.pem" ]; then
143+
# https://github.com/mysql/mysql-server/blob/23032807537d8dd8ee4ec1c4d40f0633cd4e12f9/packaging/deb-in/extra/mysql-systemd-start#L81-L84
144+
docker_note "Initializing certificates"
145+
mysql_ssl_rsa_setup --datadir="$DATADIR"
146+
docker_note "Certificates initialized"
147+
fi
148+
}
149+
150+
# Loads various settings that are used elsewhere in the script
151+
docker_init_env() {
152+
# Get config
153+
DATADIR="$(docker_get_config 'datadir' "$@")"
154+
SOCKET="$(docker_get_config 'socket' "$@")"
155+
156+
# We create a file to store the root password in so we don''t use it on the command line
157+
TMPDIR="$(mktemp -d)"
158+
PASSFILE="$(mktemp ${TMPDIR}/XXXXXXXXXX)"
159+
160+
# Initialize values that might be stored in a file
161+
docker_file_env 'MYSQL_ROOT_HOST' '%'
162+
docker_file_env 'MYSQL_DATABASE'
163+
docker_file_env 'MYSQL_USER'
164+
docker_file_env 'MYSQL_PASSWORD'
165+
docker_file_env 'MYSQL_ROOT_PASSWORD'
166+
}
167+
168+
# Define the client command that's used in various places
169+
docker_init_client_command() {
170+
mysql=( mysql --defaults-file="${PASSFILE}" --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
171+
}
172+
173+
# Store root password in a file for use with the client command
174+
docker_write_password_file() {
175+
# Write the password to the file the client uses
176+
if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
177+
cat >"${PASSFILE}" <<EOF
178+
[client]
179+
password="${MYSQL_ROOT_PASSWORD}"
180+
EOF
181+
fi
182+
}
183+
184+
# Sets root password and creates root users for non-localhost hosts
185+
docker_init_root_user() {
186+
rootCreate=
187+
# default root to listen for connections from anywhere
188+
if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
189+
# no, we don't care if read finds a terminating character in this heredoc
190+
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
191+
read -r -d '' rootCreate <<-EOSQL || true
192+
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
193+
GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
194+
EOSQL
195+
fi
196+
197+
"${mysql[@]}" <<-EOSQL
198+
-- What's done in this file shouldn't be replicated
199+
-- or products like mysql-fabric won't work
200+
SET @@SESSION.SQL_LOG_BIN=0;
201+
202+
%%PASSWORDSET%%
203+
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
204+
${rootCreate}
205+
DROP DATABASE IF EXISTS test ;
206+
FLUSH PRIVILEGES ;
207+
EOSQL
208+
}
209+
210+
# Creates a custom database and user if specified
211+
docker_init_database_user() {
212+
if [ "$MYSQL_DATABASE" ]; then
213+
docker_note "Creating database ${MYSQL_DATABASE}"
214+
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
215+
mysql+=( "$MYSQL_DATABASE" )
216+
fi
217+
218+
if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
219+
docker_note "Creating user ${MYSQL_USER}"
220+
echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
221+
222+
if [ "$MYSQL_DATABASE" ]; then
223+
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
224+
fi
225+
226+
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
227+
fi
228+
}
229+
230+
# Mark root user as expired so the password must be changed before anything
231+
# else can be done (only supported for 5.6+)
232+
docker_expire_root_user() {
233+
if [ "${MYSQL_MAJOR}" = "5.5" ]; then
234+
_warn "MySQL 5.5 does not support PASSWORD EXPIRE (required for MYSQL_ONETIME_PASSWORD)"
235+
else
236+
"${mysql[@]}" <<-EOSQL
237+
ALTER USER 'root'@'%' PASSWORD EXPIRE;
238+
EOSQL
239+
fi
240+
}
241+
242+
# Generate a random root password
243+
docker_generate_root_password() {
244+
export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
245+
docker_note "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
246+
}
247+
248+
# Load timezone info into database
249+
docker_load_tzinfo() {
250+
# sed is for https://bugs.mysql.com/bug.php?id=20545
251+
mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql
252+
}
253+
254+
docker_init_env "$@"
255+
124256
# allow the container to be started with `--user`
125257
if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
126258
docker_check_config "$@"
127-
DATADIR="$(docker_get_config 'datadir' "$@")"
128259
mkdir -p "$DATADIR"
129260
chown -R mysql:mysql "$DATADIR"
130261
exec gosu mysql "$BASH_SOURCE" "$@"
131262
fi
132263

264+
docker_note "Entrypoint script for MySQL Server ${MYSQL_VERSION} started."
265+
133266
if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
134267
# still need to check config, container may have started with --user
135268
docker_check_config "$@"
136-
# Get config
137-
DATADIR="$(docker_get_config 'datadir' "$@")"
138269

270+
# If this is true then there's no database, and it needs to be initialized
139271
if [ ! -d "$DATADIR/mysql" ]; then
140-
docker_file_env 'MYSQL_ROOT_PASSWORD'
141-
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
142-
docker_error "Database is uninitialized and password option is not specified \n\tYou need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD"
143-
fi
144-
145-
mkdir -p "$DATADIR"
146-
147-
docker_note "Initializing database"
148-
%%DATABASEINIT%%
149-
docker_note "Database initialized"
150-
151-
if command -v mysql_ssl_rsa_setup > /dev/null && [ ! -e "$DATADIR/server-key.pem" ]; then
152-
# https://github.com/mysql/mysql-server/blob/23032807537d8dd8ee4ec1c4d40f0633cd4e12f9/packaging/deb-in/extra/mysql-systemd-start#L81-L84
153-
docker_note "Initializing certificates"
154-
mysql_ssl_rsa_setup --datadir="$DATADIR"
155-
docker_note "Certificates initialized"
156-
fi
157-
158-
SOCKET="$(docker_get_config 'socket' "$@")"
159-
# We create a file to store the root password in so we don''t use it on the command line
160-
TMPDIR="$(mktemp -d)"
161-
PASSFILE="$(mktemp ${TMPDIR}/XXXXXXXXXX)"
272+
docker_verify_env
273+
docker_init_database_dir "$@"
274+
docker_init_client_command
162275

163-
mysql=( mysql --defaults-file="${PASSFILE}" --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
164-
docker_note "Starting server"
165-
docker_start_server "${SOCKET}" "$@"
276+
docker_note "Starting temporary server"
277+
docker_start_server "$@"
278+
# For 5.7+ the server is ready for use as soon as startup command unblocks
166279
if [ "${MYSQL_MAJOR}" = "5.5" ] || [ "${MYSQL_MAJOR}" = "5.6" ]; then
167280
docker_note "Waiting for server startup"
168281
docker_wait_for_server "${mysql[@]}"
169282
fi
170-
docker_note "Server started."
283+
docker_note "Temporary server started."
171284

172285

173286
if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
174-
# sed is for https://bugs.mysql.com/bug.php?id=20545
175-
mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql
287+
docker_load_tzinfo
176288
fi
177289

178290
if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
179-
export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
180-
docker_note "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
181-
fi
182-
183-
rootCreate=
184-
# default root to listen for connections from anywhere
185-
docker_file_env 'MYSQL_ROOT_HOST' '%'
186-
if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
187-
# no, we don't care if read finds a terminating character in this heredoc
188-
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
189-
read -r -d '' rootCreate <<-EOSQL || true
190-
CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
191-
GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
192-
EOSQL
193-
fi
194-
195-
"${mysql[@]}" <<-EOSQL
196-
-- What's done in this file shouldn't be replicated
197-
-- or products like mysql-fabric won't work
198-
SET @@SESSION.SQL_LOG_BIN=0;
199-
200-
%%PASSWORDSET%%
201-
GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
202-
${rootCreate}
203-
DROP DATABASE IF EXISTS test ;
204-
FLUSH PRIVILEGES ;
205-
EOSQL
206-
207-
# Write the password to the file the client uses
208-
if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
209-
cat >"${PASSFILE}" <<EOF
210-
[client]
211-
password="${MYSQL_ROOT_PASSWORD}"
212-
EOF
291+
docker_generate_root_password
213292
fi
293+
294+
docker_init_root_user
214295

215-
docker_file_env 'MYSQL_DATABASE'
216-
if [ "$MYSQL_DATABASE" ]; then
217-
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
218-
mysql+=( "$MYSQL_DATABASE" )
219-
fi
296+
docker_write_password_file
220297

221-
docker_file_env 'MYSQL_USER'
222-
docker_file_env 'MYSQL_PASSWORD'
223-
if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
224-
echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
225-
226-
if [ "$MYSQL_DATABASE" ]; then
227-
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
228-
fi
229-
230-
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
231-
fi
298+
docker_init_database_user
232299

233300
echo
234301
for f in /docker-entrypoint-initdb.d/*; do
235302
docker_process_init_file "$f" "${mysql[@]}"
236303
done
237304

238305
if [ ! -z "$MYSQL_ONETIME_PASSWORD" ]; then
239-
if [ "${MYSQL_MAJOR}" = "5.5" ]; then
240-
_warn "MySQL 5.5 does not support PASSWORD EXPIRE (required for MYSQL_ONETIME_PASSWORD)"
241-
else
242-
"${mysql[@]}" <<-EOSQL
243-
ALTER USER 'root'@'%' PASSWORD EXPIRE;
244-
EOSQL
245-
fi
306+
docker_expire_root_user
246307
fi
247-
docker_note "Stopping server"
248-
docker_stop_server "${PASSFILE}" "${SOCKET}"
249-
docker_note "Server stopped"
308+
docker_note "Stopping temporary server"
309+
docker_stop_server
310+
docker_note "Temporary server stopped"
311+
312+
# Remove the password file now that initialization is complete
250313
rm -f "${PASSFILE}"
251314
unset PASSFILE
252315
echo

update.sh

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ database_init["5.6"]="mysql_install_db --user=mysql --datadir=\"\$DATADIR\" --rp
2727
database_init["5.7"]="\"\$@\" --initialize-insecure"
2828
database_init["8.0"]="\"\$@\" --initialize-insecure"
2929
declare -A server_startup
30-
server_startup["5.5"]="\"\$@\" --skip-networking --basedir=\/usr\/local\/mysql --socket=\"\${socket}\" \&"
31-
server_startup["5.6"]="\"\$@\" --skip-networking --socket=\"\${socket}\" \&"
32-
server_startup["5.7"]="\"\$@\" --daemonize --skip-networking --socket=\"\${socket}\" || result=$?"
33-
server_startup["8.0"]="\"\$@\" --daemonize --skip-networking --socket=\"\${socket}\" || result=$?"
30+
server_startup["5.5"]="\"\$@\" --skip-networking --basedir=\/usr\/local\/mysql --socket=\"\${SOCKET}\" \&"
31+
server_startup["5.6"]="\"\$@\" --skip-networking --socket=\"\${SOCKET}\" \&"
32+
server_startup["5.7"]="\"\$@\" --daemonize --skip-networking --socket=\"\${SOCKET}\" || result=$?"
33+
server_startup["8.0"]="\"\$@\" --daemonize --skip-networking --socket=\"\${SOCKET}\" || result=$?"
3434
for version in ${templateVersions}; do
3535
cp ".template.Debian/docker-entrypoint.sh" "${version}/"
3636
sed -e 's/%%PASSWORDSET%%/'"${passwordset["$version"]}"'/g' \

0 commit comments

Comments
 (0)