@@ -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
9394docker_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
102104docker_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.
115119docker_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`
125257if [ " $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 " " $@ "
131262fi
132263
264+ docker_note " Entrypoint script for MySQL Server ${MYSQL_VERSION} started."
265+
133266if [ " $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
0 commit comments