Skip to content

Creation of several databases with new variable env MYSQL_DATABASES = "one two three" #165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
iperfex-team opened this issue May 6, 2018 · 1 comment

Comments

@iperfex-team
Copy link

iperfex-team commented May 6, 2018

Hello partners.
I had the need to modify the file /usr/local/bin/docker-entrypoint.sh in order to create several databases when I lifted the container with docker-compose, I hope someone can use it ...

And if the administrator thinks it is useful to add it to the file.

Greetings Federico Pereira [email protected]

Example docker-compose.yml for mariadb:

# Use root/example as user/password credentials
version: '3.6'

services:

  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASES: "one two three"
      MYSQL_USER: user1
      MYSQL_PASSWORD: password
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    volumes:
      - /xxx/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh

Important note: if you use this method and you want to use docker-entrypoint-initdb.d to import your tables it is advisable to use USE my_databases; each sql file.

Example: docker-entrypoint-initdb.d

# Use root/example as user/password credentials
version: '3.6'

services:

  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASES: "one two three"
      MYSQL_USER: user1
      MYSQL_PASSWORD: password
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
    volumes:
      - /xxx/example1.sql:/docker-entrypoint-initdb.d/1-init.sql
      - /xxx/example2.sql:/docker-entrypoint-initdb.d/2-init.sql
      - /xxx/docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh
cat /xxx/example1.sql
USE one;
...
...
...
cat /xxx/example2.sql
USE two;
...
...
...

Code

Add after file_env 'MYSQL_DATABASE' line: 157

		# create several databases using the MYSQL DATABASES env
		#example: export MYSQL_DATABASES = "one two three"
		file_env 'MYSQL_DATABASES'
		if [ "$MYSQL_DATABASES" ]; then
			for databaseName in $MYSQL_DATABASES; do
				echo "CREATE DATABASE IF NOT EXISTS \`$databaseName\` ;" | "${mysql[@]}"
			done

		fi

Modify if ["$ MYSQL_USER" -a "$ MYSQL_PASSWORD"] .... line: 167 approximate

		file_env 'MYSQL_USER'
		file_env 'MYSQL_PASSWORD'
		if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
			echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"

			if [ "$MYSQL_DATABASE" ]; then
				echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
			fi

			#create the permissions for the different databases created with the db user
			if [ "$MYSQL_DATABASES" ]; then
				for databaseName in $MYSQL_DATABASES; do
					echo "GRANT ALL ON \`$databaseName\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
				done
			fi	

			echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
		fi

Complete code file /usr/local/bin/docker-entrypoint.sh

#!/bin/bash
set -eo pipefail
shopt -s nullglob

# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
	set -- mysqld "$@"
fi

# skip setup if they want an option that stops mysqld
wantHelp=
for arg; do
	case "$arg" in
		-'?'|--help|--print-defaults|-V|--version)
			wantHelp=1
			break
			;;
	esac
done

# usage: file_env VAR [DEFAULT]
#    ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
#  "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
	local var="$1"
	local fileVar="${var}_FILE"
	local def="${2:-}"
	if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
		echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
		exit 1
	fi
	local val="$def"
	if [ "${!var:-}" ]; then
		val="${!var}"
	elif [ "${!fileVar:-}" ]; then
		val="$(< "${!fileVar}")"
	fi
	export "$var"="$val"
	unset "$fileVar"
}

_check_config() {
	toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" )
	if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
		cat >&2 <<-EOM

			ERROR: mysqld failed while attempting to check config
			command was: "${toRun[*]}"

			$errors
		EOM
		exit 1
	fi
}

# Fetch value from server config
# We use mysqld --verbose --help instead of my_print_defaults because the
# latter only show values present in config files, and not server defaults
_get_config() {
	local conf="$1"; shift
	"$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }'
}

# allow the container to be started with `--user`
if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
	_check_config "$@"
	DATADIR="$(_get_config 'datadir' "$@")"
	mkdir -p "$DATADIR"
	chown -R mysql:mysql "$DATADIR"
	exec gosu mysql "$BASH_SOURCE" "$@"
fi

if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
	# still need to check config, container may have started with --user
	_check_config "$@"
	# Get config
	DATADIR="$(_get_config 'datadir' "$@")"

	if [ ! -d "$DATADIR/mysql" ]; then
		file_env 'MYSQL_ROOT_PASSWORD'
		if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
			echo >&2 'error: database is uninitialized and password option is not specified '
			echo >&2 '  You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
			exit 1
		fi

		mkdir -p "$DATADIR"

		echo 'Initializing database'
		mysql_install_db --datadir="$DATADIR" --rpm
		echo 'Database initialized'

		SOCKET="$(_get_config 'socket' "$@")"
		"$@" --skip-networking --socket="${SOCKET}" &
		pid="$!"

		mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )

		for i in {30..0}; do
			if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
				break
			fi
			echo 'MySQL init process in progress...'
			sleep 1
		done
		if [ "$i" = 0 ]; then
			echo >&2 'MySQL init process failed.'
			exit 1
		fi

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

		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
		fi

		rootCreate=
		# default root to listen for connections from anywhere
		file_env 'MYSQL_ROOT_HOST' '%'
		if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
			# no, we don't care if read finds a terminating character in this heredoc
			# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
			read -r -d '' rootCreate <<-EOSQL || true
				CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
				GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
			EOSQL
		fi

		"${mysql[@]}" <<-EOSQL
			-- What's done in this file shouldn't be replicated
			--  or products like mysql-fabric won't work
			SET @@SESSION.SQL_LOG_BIN=0;

			DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
			SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
			GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
			${rootCreate}
			DROP DATABASE IF EXISTS test ;
			FLUSH PRIVILEGES ;
		EOSQL

		if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
			mysql+=( -p"${MYSQL_ROOT_PASSWORD}" )
		fi

		file_env 'MYSQL_DATABASE'
		if [ "$MYSQL_DATABASE" ]; then
			echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
			mysql+=( "$MYSQL_DATABASE" )
		fi

		# create several databases using the MYSQL DATABASES env
		#example: export MYSQL_DATABASES = "one two three"
		file_env 'MYSQL_DATABASES'
		if [ "$MYSQL_DATABASES" ]; then
			for databaseName in $MYSQL_DATABASES; do
				echo "CREATE DATABASE IF NOT EXISTS \`$databaseName\` ;" | "${mysql[@]}"
			done

		fi

		file_env 'MYSQL_USER'
		file_env 'MYSQL_PASSWORD'
		if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
			echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"

			if [ "$MYSQL_DATABASE" ]; then
				echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
			fi

			#create the permissions for the different databases created with the db user
			if [ "$MYSQL_DATABASES" ]; then
				for databaseName in $MYSQL_DATABASES; do
					echo "GRANT ALL ON \`$databaseName\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
				done
			fi	

			echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
		fi

		echo
		for f in /docker-entrypoint-initdb.d/*; do
			case "$f" in
				*.sh)     echo "$0: running $f"; . "$f" ;;
				*.sql)    echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
				*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
				*)        echo "$0: ignoring $f" ;;
			esac
			echo
		done

		if ! kill -s TERM "$pid" || ! wait "$pid"; then
			echo >&2 'MySQL init process failed.'
			exit 1
		fi

		echo
		echo 'MySQL init process done. Ready for start up.'
		echo
	fi
fi

exec "$@"

#check

MariaDB [one]>  select host, user, password from mysql.user;
+-----------+--------------+-------------------------------------------+
| host      | user         | password                                  |
+-----------+--------------+-------------------------------------------+
| localhost | root         | *877C76D244B4A8FCCC96EA5312273D31F6731354 |
| %         | user1        | *76855C0C4687945F39741CD2257F826AD6057501 |
| %         | root         | *877C76D244B4A8FCCC96EA5312273D31F6731354 |
+-----------+--------------+-------------------------------------------+
3 rows in set (0.00 sec)
MariaDB [one]> SHOW GRANTS FOR 'user1'@'%';
+-------------------------------------------------------------------------------------------------------------+
| Grants for user1@%                                                                                          |
+-------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'user1'@'%' IDENTIFIED BY PASSWORD '*76855C0C4687945F39741CD2257F826AD6057501'        |
| GRANT ALL PRIVILEGES ON `one`.* TO 'user1'@'%'                                                              |
| GRANT ALL PRIVILEGES ON `two`.* TO 'user1'@'%'                                                              |
| GRANT ALL PRIVILEGES ON `three`.* TO 'user1'@'%'                                                            | 
+-------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
@yosifkit
Copy link
Contributor

yosifkit commented May 7, 2018

Duplicate: #63

@yosifkit yosifkit closed this as completed May 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants