Skip to content
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

Update docker-library images #2398

Merged
merged 1 commit into from
Nov 28, 2016

Conversation

tianon
Copy link
Member

@tianon tianon commented Nov 28, 2016

- `haproxy`: add 1.7 (docker-library/haproxy#35)
- `httpd`: add `mod_http2`, `mod_lua`, `mod_proxy_html`, and `mod_xml2enc` (docker-library/httpd#34)
- `mariadb`: add `file_env` support (MariaDB/mariadb-docker#89)
- `percona`: add `file_env` support (docker-library/percona#34); 5.6.34-79.1-1.jessie
- `piwik`: remove `ssmtp`
@tianon
Copy link
Member Author

tianon commented Nov 28, 2016

diff --git a/haproxy_alpine/Dockerfile b/haproxy_1.6-alpine/Dockerfile
similarity index 100%
copy from haproxy_alpine/Dockerfile
copy to haproxy_1.6-alpine/Dockerfile
diff --git a/haproxy_latest/docker-entrypoint.sh b/haproxy_1.6-alpine/docker-entrypoint.sh
similarity index 100%
copy from haproxy_latest/docker-entrypoint.sh
copy to haproxy_1.6-alpine/docker-entrypoint.sh
diff --git a/haproxy_latest/Dockerfile b/haproxy_1.6/Dockerfile
similarity index 100%
copy from haproxy_latest/Dockerfile
copy to haproxy_1.6/Dockerfile
diff --git a/haproxy_latest/docker-entrypoint.sh b/haproxy_1.6/docker-entrypoint.sh
similarity index 100%
copy from haproxy_latest/docker-entrypoint.sh
copy to haproxy_1.6/docker-entrypoint.sh
diff --git a/haproxy_alpine/Dockerfile b/haproxy_alpine/Dockerfile
index 12f54a7..5ca52e5 100644
--- a/haproxy_alpine/Dockerfile
+++ b/haproxy_alpine/Dockerfile
@@ -1,8 +1,8 @@
 FROM alpine:3.4
 
-ENV HAPROXY_MAJOR 1.6
-ENV HAPROXY_VERSION 1.6.10
-ENV HAPROXY_MD5 6d47461c008b823a0088d19ec30dbe4e
+ENV HAPROXY_MAJOR 1.7
+ENV HAPROXY_VERSION 1.7.0
+ENV HAPROXY_MD5 ab6e169aeb1b53364aacda80c904398a
 
 # see http://sources.debian.net/src/haproxy/1.5.8-1/debian/rules/ for some helpful navigation of the possible "make" arguments
 RUN set -x \
diff --git a/haproxy_latest/Dockerfile b/haproxy_latest/Dockerfile
index 7bb81f9..70398d3 100644
--- a/haproxy_latest/Dockerfile
+++ b/haproxy_latest/Dockerfile
@@ -2,9 +2,9 @@ FROM debian:jessie
 
 RUN apt-get update && apt-get install -y libssl1.0.0 libpcre3 --no-install-recommends && rm -rf /var/lib/apt/lists/*
 
-ENV HAPROXY_MAJOR 1.6
-ENV HAPROXY_VERSION 1.6.10
-ENV HAPROXY_MD5 6d47461c008b823a0088d19ec30dbe4e
+ENV HAPROXY_MAJOR 1.7
+ENV HAPROXY_VERSION 1.7.0
+ENV HAPROXY_MD5 ab6e169aeb1b53364aacda80c904398a
 
 # see http://sources.debian.net/src/haproxy/1.5.8-1/debian/rules/ for some helpful navigation of the possible "make" arguments
 RUN buildDeps='curl gcc libc6-dev libpcre3-dev libssl-dev make' \
diff --git a/httpd_2.2-alpine/Dockerfile b/httpd_2.2-alpine/Dockerfile
index 8bd56c2..233095f 100644
--- a/httpd_2.2-alpine/Dockerfile
+++ b/httpd_2.2-alpine/Dockerfile
@@ -23,6 +23,7 @@ ENV HTTPD_BZ2_URL https://www.apache.org/dyn/closer.cgi?action=download&filename
 # not all the mirrors actually carry the .asc files :'(
 ENV HTTPD_ASC_URL https://www.apache.org/dist/httpd/httpd-$HTTPD_VERSION.tar.bz2.asc
 
+# see https://httpd.apache.org/docs/2.2/install.html#requirements
 RUN set -x \
 	&& runDeps=' \
 		apr-dev \
@@ -57,12 +58,14 @@ RUN set -x \
 	\
 	&& ./configure \
 		--prefix="$HTTPD_PREFIX" \
-		--enable-mods-shared=reallyall \
-	&& make -j"$(getconf _NPROCESSORS_ONLN)" \
+# https://httpd.apache.org/docs/2.2/programs/configure.html
+# Caveat: --enable-mods-shared=all does not actually build all modules. To build all modules then, one might use:
+		--enable-mods-shared='all ssl ldap cache proxy authn_alias mem_cache file_cache authnz_ldap charset_lite dav_lock disk_cache' \
+	&& make -j "$(getconf _NPROCESSORS_ONLN)" \
 	&& make install \
 	\
 	&& cd .. \
-	&& rm -r src \
+	&& rm -r src build man manual \
 	\
 	&& sed -ri \
 		-e 's!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g' \
diff --git a/httpd_2.2/Dockerfile b/httpd_2.2/Dockerfile
index f3743eb..b636436 100644
--- a/httpd_2.2/Dockerfile
+++ b/httpd_2.2/Dockerfile
@@ -30,6 +30,7 @@ ENV HTTPD_BZ2_URL https://www.apache.org/dyn/closer.cgi?action=download&filename
 # not all the mirrors actually carry the .asc files :'(
 ENV HTTPD_ASC_URL https://www.apache.org/dist/httpd/httpd-$HTTPD_VERSION.tar.bz2.asc
 
+# see https://httpd.apache.org/docs/2.2/install.html#requirements
 RUN set -x \
 	&& buildDeps=' \
 		bzip2 \
@@ -63,11 +64,11 @@ RUN set -x \
 # https://httpd.apache.org/docs/2.2/programs/configure.html
 # Caveat: --enable-mods-shared=all does not actually build all modules. To build all modules then, one might use:
 		--enable-mods-shared='all ssl ldap cache proxy authn_alias mem_cache file_cache authnz_ldap charset_lite dav_lock disk_cache' \
-	&& make -j"$(nproc)" \
+	&& make -j "$(nproc)" \
 	&& make install \
 	\
 	&& cd .. \
-	&& rm -r src \
+	&& rm -r src build man manual \
 	\
 	&& sed -ri \
 		-e 's!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g' \
diff --git a/httpd_alpine/Dockerfile b/httpd_alpine/Dockerfile
index 35ab8f0..39b8c10 100644
--- a/httpd_alpine/Dockerfile
+++ b/httpd_alpine/Dockerfile
@@ -36,11 +36,21 @@ RUN set -x \
 		gcc \
 		gnupg \
 		libc-dev \
+		# mod_proxy_html mod_xml2enc
+		libxml2-dev \
+		# mod_lua
+		lua-dev \
 		make \
+		# no mod_session_crypto: openssl-dev in alpine doesn't work, but libressl is edge only (and brings conflicts with edge packages)
 		openssl \
 		openssl-dev \
 		pcre-dev \
 		tar \
+		zlib-dev \
+	# https://bugs.alpinelinux.org/issues/6375
+	&& echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/main' >> /etc/apk/repositories \
+	# mod_http2
+	&& apk add --no-cache nghttp2-dev@edge \
 	\
 	&& wget -O httpd.tar.bz2 "$HTTPD_BZ2_URL" \
 	&& echo "$HTTPD_SHA1 *httpd.tar.bz2" | sha1sum -c - \
@@ -52,18 +62,18 @@ RUN set -x \
 	&& rm -r "$GNUPGHOME" httpd.tar.bz2.asc \
 	\
 	&& mkdir -p src \
-	&& tar -xvf httpd.tar.bz2 -C src --strip-components=1 \
+	&& tar -xf httpd.tar.bz2 -C src --strip-components=1 \
 	&& rm httpd.tar.bz2 \
 	&& cd src \
 	\
 	&& ./configure \
 		--prefix="$HTTPD_PREFIX" \
 		--enable-mods-shared=reallyall \
-	&& make -j"$(getconf _NPROCESSORS_ONLN)" \
+	&& make -j "$(getconf _NPROCESSORS_ONLN)" \
 	&& make install \
 	\
 	&& cd .. \
-	&& rm -r src \
+	&& rm -r src build man manual \
 	\
 	&& sed -ri \
 		-e 's!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g' \
@@ -77,8 +87,11 @@ RUN set -x \
 			| xargs -r apk info --installed \
 			| sort -u \
 	)" \
+	# `apk update` instead of --no-cache since `apk del` gets confused with `@edge` packages if there is no cache
+	&& apk update \
 	&& apk add --virtual .httpd-rundeps $runDeps \
-	&& apk del .build-deps
+	&& apk del .build-deps \
+	&& rm -rf /var/cache/apk/*
 
 COPY httpd-foreground /usr/local/bin/
 
diff --git a/httpd_latest/Dockerfile b/httpd_latest/Dockerfile
index 50dc081..84f7536 100644
--- a/httpd_latest/Dockerfile
+++ b/httpd_latest/Dockerfile
@@ -9,6 +9,24 @@ RUN mkdir -p "$HTTPD_PREFIX" \
 	&& chown www-data:www-data "$HTTPD_PREFIX"
 WORKDIR $HTTPD_PREFIX
 
+# library for mod_http2
+ENV NGHTTP2_VERSION 1.16.0-1
+RUN { \
+		echo 'deb http://deb.debian.org/debian stretch main'; \
+	} > /etc/apt/sources.list.d/stretch.list \
+	&& { \
+# add a negative "Pin-Priority" so that we never ever get packages from stretch unless we explicitly request them
+		echo 'Package: *'; \
+		echo 'Pin: release n=stretch'; \
+		echo 'Pin-Priority: -10'; \
+		echo; \
+# except nghttp2, which is the reason we're here
+		echo 'Package: libnghttp2*'; \
+		echo "Pin: version $NGHTTP2_VERSION"; \
+		echo 'Pin-Priority: 990'; \
+		echo; \
+	} > /etc/apt/preferences.d/unstable-nghttp2
+
 # install httpd runtime dependencies
 # https://httpd.apache.org/docs/2.4/install.html#requirements
 RUN apt-get update \
@@ -18,8 +36,11 @@ RUN apt-get update \
 		libaprutil1-ldap \
 		libapr1-dev \
 		libaprutil1-dev \
+		liblua5.2-0 \
+		libnghttp2-14=$NGHTTP2_VERSION \
 		libpcre++0 \
 		libssl1.0.0 \
+		libxml2 \
 	&& rm -r /var/lib/apt/lists/*
 
 ENV HTTPD_VERSION 2.4.23
@@ -32,17 +53,23 @@ ENV HTTPD_ASC_URL https://www.apache.org/dist/httpd/httpd-$HTTPD_VERSION.tar.bz2
 
 # see https://httpd.apache.org/docs/2.4/install.html#requirements
 RUN set -x \
-	&& buildDeps=' \
+	# mod_http2 mod_lua mod_proxy_html mod_xml2enc
+	# https://anonscm.debian.org/cgit/pkg-apache/apache2.git/tree/debian/control?id=adb6f181257af28ee67af15fc49d2699a0080d4c
+	&& buildDeps=" \
 		bzip2 \
 		ca-certificates \
 		gcc \
+		libnghttp2-dev=$NGHTTP2_VERSION \
+		liblua5.2-dev \
 		libpcre++-dev \
 		libssl-dev \
+		libxml2-dev \
+		zlib1g-dev \
 		make \
 		wget \
-	' \
+	" \
 	&& apt-get update \
-	&& apt-get install -y --no-install-recommends $buildDeps \
+	&& apt-get install -y --no-install-recommends -V $buildDeps \
 	&& rm -r /var/lib/apt/lists/* \
 	\
 	&& wget -O httpd.tar.bz2 "$HTTPD_BZ2_URL" \
@@ -55,18 +82,18 @@ RUN set -x \
 	&& rm -r "$GNUPGHOME" httpd.tar.bz2.asc \
 	\
 	&& mkdir -p src \
-	&& tar -xvf httpd.tar.bz2 -C src --strip-components=1 \
+	&& tar -xf httpd.tar.bz2 -C src --strip-components=1 \
 	&& rm httpd.tar.bz2 \
 	&& cd src \
 	\
 	&& ./configure \
 		--prefix="$HTTPD_PREFIX" \
 		--enable-mods-shared=reallyall \
-	&& make -j"$(nproc)" \
+	&& make -j "$(nproc)" \
 	&& make install \
 	\
 	&& cd .. \
-	&& rm -r src \
+	&& rm -r src build man manual \
 	\
 	&& sed -ri \
 		-e 's!^(\s*CustomLog)\s+\S+!\1 /proc/self/fd/1!g' \
diff --git a/mariadb_10.0/docker-entrypoint.sh b/mariadb_10.0/docker-entrypoint.sh
index 576e2a5..b4fb80c 100755
--- a/mariadb_10.0/docker-entrypoint.sh
+++ b/mariadb_10.0/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/mariadb_5/docker-entrypoint.sh b/mariadb_5/docker-entrypoint.sh
index 576e2a5..b4fb80c 100755
--- a/mariadb_5/docker-entrypoint.sh
+++ b/mariadb_5/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/mariadb_latest/docker-entrypoint.sh b/mariadb_latest/docker-entrypoint.sh
index 576e2a5..b4fb80c 100755
--- a/mariadb_latest/docker-entrypoint.sh
+++ b/mariadb_latest/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/percona_5.5/docker-entrypoint.sh b/percona_5.5/docker-entrypoint.sh
index 576e2a5..b4fb80c 100755
--- a/percona_5.5/docker-entrypoint.sh
+++ b/percona_5.5/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/percona_5.6/Dockerfile b/percona_5.6/Dockerfile
index 59a49c5..0f8100f 100644
--- a/percona_5.6/Dockerfile
+++ b/percona_5.6/Dockerfile
@@ -42,7 +42,7 @@ RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys \
 RUN echo 'deb https://repo.percona.com/apt jessie main' > /etc/apt/sources.list.d/percona.list
 
 ENV PERCONA_MAJOR 5.6
-ENV PERCONA_VERSION 5.6.33-79.0-1.jessie
+ENV PERCONA_VERSION 5.6.34-79.1-1.jessie
 
 # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql)
 # also, we set debconf keys to make APT a little quieter
diff --git a/percona_5.6/docker-entrypoint.sh b/percona_5.6/docker-entrypoint.sh
index 576e2a5..b4fb80c 100755
--- a/percona_5.6/docker-entrypoint.sh
+++ b/percona_5.6/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/percona_latest/docker-entrypoint.sh b/percona_latest/docker-entrypoint.sh
index 3201cc9..c14725d 100755
--- a/percona_latest/docker-entrypoint.sh
+++ b/percona_latest/docker-entrypoint.sh
@@ -18,6 +18,28 @@ for arg; do
 	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 )
 	if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
@@ -52,6 +74,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 	DATADIR="$(_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'
@@ -87,7 +110,7 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
 		fi
 
 		if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
-			MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+			export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
 			echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
 		fi
 		"${mysql[@]}" <<-EOSQL
@@ -106,11 +129,14 @@ if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; 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
 
+		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[@]}"
 
diff --git a/piwik_latest/Dockerfile b/piwik_latest/Dockerfile
index 7975691..08e9253 100644
--- a/piwik_latest/Dockerfile
+++ b/piwik_latest/Dockerfile
@@ -8,7 +8,6 @@ RUN apt-get update && apt-get install -y \
       libgeoip-dev \
       libpng12-dev \
       libldap2-dev \
-      ssmtp \
       zip \
  && rm -rf /var/lib/apt/lists/*
 
@@ -29,8 +28,7 @@ RUN curl -fsSL -o piwik.tar.gz \
  && gpg --batch --verify piwik.tar.gz.asc piwik.tar.gz \
  && rm -r "$GNUPGHOME" piwik.tar.gz.asc \
  && tar -xzf piwik.tar.gz -C /usr/src/ \
- && rm piwik.tar.gz \
- && chfn -f 'Piwik Admin' www-data
+ && rm piwik.tar.gz
 
 COPY php.ini /usr/local/etc/php/php.ini
 

@tianon
Copy link
Member Author

tianon commented Nov 28, 2016

Build test of #2398; ea5ac13 (haproxy, httpd, mariadb, percona, piwik):

$ bashbrew build haproxy:1.4.27
Using bashbrew/cache:c9965884723bee2e7e1ffc9b0d48885ed306477a07669fb817d818421784fcd4 (haproxy:1.4.27)
Tagging haproxy:1.4.27
Tagging haproxy:1.4

$ test/run.sh haproxy:1.4.27
testing haproxy:1.4.27
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.4.27-alpine
Using bashbrew/cache:3c7880c9ab0a6dec93599acd0c9fb80755cfc3f13005b76ab13494ee7fff0528 (haproxy:1.4.27-alpine)
Tagging haproxy:1.4.27-alpine
Tagging haproxy:1.4-alpine

$ test/run.sh haproxy:1.4.27-alpine
testing haproxy:1.4.27-alpine
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.5.18
Using bashbrew/cache:49671ce9d0012998a9779ca13bfd4af35f14899a6f3ed9a134bc8cb18f9ae0fd (haproxy:1.5.18)
Tagging haproxy:1.5.18
Tagging haproxy:1.5

$ test/run.sh haproxy:1.5.18
testing haproxy:1.5.18
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.5.18-alpine
Using bashbrew/cache:4e6a371defb0e259468527359dc825e46c92cb4e46ab8171dd62ed8da5ca86da (haproxy:1.5.18-alpine)
Tagging haproxy:1.5.18-alpine
Tagging haproxy:1.5-alpine

$ test/run.sh haproxy:1.5.18-alpine
testing haproxy:1.5.18-alpine
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.6.10
Using bashbrew/cache:33cb6fb23c768154db9a548368bafc0819b2eeed01283e0bf2fe92c6015fe6a5 (haproxy:1.6.10)
Tagging haproxy:1.6.10
Tagging haproxy:1.6

$ test/run.sh haproxy:1.6.10
testing haproxy:1.6.10
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.6.10-alpine
Using bashbrew/cache:fbc9f67fef0450b7102d6c4eec5541c4f75264eeb3420a5d937076741138aa13 (haproxy:1.6.10-alpine)
Tagging haproxy:1.6.10-alpine
Tagging haproxy:1.6-alpine

$ test/run.sh haproxy:1.6.10-alpine
testing haproxy:1.6.10-alpine
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.7.0
Building bashbrew/cache:58a2bfd374595ff43424651904f52cd30b01ab9afc30b0468548ee8cd98a5994 (haproxy:1.7.0)
Tagging haproxy:1.7.0
Tagging haproxy:1.7
Tagging haproxy:1
Tagging haproxy:latest

$ test/run.sh haproxy:1.7.0
testing haproxy:1.7.0
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed


$ bashbrew build haproxy:1.7.0-alpine
Building bashbrew/cache:a88680c5578fd601eb72df1a8da7317d87e22cd8adcd4fc912adfb6b718cea2c (haproxy:1.7.0-alpine)
Tagging haproxy:1.7.0-alpine
Tagging haproxy:1.7-alpine
Tagging haproxy:1-alpine
Tagging haproxy:alpine

$ test/run.sh haproxy:1.7.0-alpine
testing haproxy:1.7.0-alpine
	'utc' [1/5]...passed
	'cve-2014--shellshock' [2/5]...passed
	'no-hard-coded-passwords' [3/5]...passed
	'override-cmd' [4/5]...passed
	'haproxy-basics' [5/5]...passed
$ bashbrew build httpd:2.2.31
Building bashbrew/cache:383011386cdde0fbc2a39b3e97c3b4cc21ac67382126acd89941d2cb5d4e78e5 (httpd:2.2.31)
Tagging httpd:2.2.31
Tagging httpd:2.2

$ test/run.sh httpd:2.2.31
testing httpd:2.2.31
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build httpd:2.2.31-alpine
Building bashbrew/cache:62c390a5ba7fadb42a874a8b198f3207f2900c5a58e8ac209a19aeb75e517387 (httpd:2.2.31-alpine)
Tagging httpd:2.2.31-alpine
Tagging httpd:2.2-alpine

$ test/run.sh httpd:2.2.31-alpine
testing httpd:2.2.31-alpine
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build httpd:2.4.23
Building bashbrew/cache:62054447416bf65b6daf13412eda7892e242cfe46e344aaaf63046b057a46332 (httpd:2.4.23)
Tagging httpd:2.4.23
Tagging httpd:2.4
Tagging httpd:2
Tagging httpd:latest

$ test/run.sh httpd:2.4.23
testing httpd:2.4.23
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed


$ bashbrew build httpd:2.4.23-alpine
Building bashbrew/cache:648064121a309c69dbaa912950a86349bb825ee119d242e3e14a26bb0c1054d9 (httpd:2.4.23-alpine)
Tagging httpd:2.4.23-alpine
Tagging httpd:2.4-alpine
Tagging httpd:2-alpine
Tagging httpd:alpine

$ test/run.sh httpd:2.4.23-alpine
testing httpd:2.4.23-alpine
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed
$ bashbrew build mariadb:10.1.19
Building bashbrew/cache:8a2794f2fdb96589de3f686c50fb757eb9ab12eb6770bb9d92a6fef64f598bf7 (mariadb:10.1.19)
Tagging mariadb:10.1.19
Tagging mariadb:10.1
Tagging mariadb:10
Tagging mariadb:latest

$ test/run.sh mariadb:10.1.19
testing mariadb:10.1.19
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7]..........passed
	'mysql-initdb' [6/7].........passed
	'mysql-log-bin' [7/7].........passed


$ bashbrew build mariadb:10.0.28
Building bashbrew/cache:b54abbae9590a280fa69f3d76dd344ce6b62c6c79ccc8d9516c75000df3ff11b (mariadb:10.0.28)
Tagging mariadb:10.0.28
Tagging mariadb:10.0

$ test/run.sh mariadb:10.0.28
testing mariadb:10.0.28
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7]........passed
	'mysql-initdb' [6/7].......passed
	'mysql-log-bin' [7/7].......passed


$ bashbrew build mariadb:5.5.53
Building bashbrew/cache:1f1722af0bdafa86e20a196d5b8dc7562261290c7a3bea328cd6c03ff122ec61 (mariadb:5.5.53)
Tagging mariadb:5.5.53
Tagging mariadb:5.5
Tagging mariadb:5

$ test/run.sh mariadb:5.5.53
testing mariadb:5.5.53
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7].......passed
	'mysql-initdb' [6/7]......passed
	'mysql-log-bin' [7/7]......passed
$ bashbrew build percona:5.7.15
Building bashbrew/cache:8857f98f1df0cd59a3e0e6eede8b1a8786d58fda756677a4c6063f2994f873db (percona:5.7.15)
Tagging percona:5.7.15
Tagging percona:5.7
Tagging percona:5
Tagging percona:latest

$ test/run.sh percona:5.7.15
testing percona:5.7.15
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7].........passed
	'mysql-initdb' [6/7].........passed
	'mysql-log-bin' [7/7].........passed


$ bashbrew build percona:5.6.34
Building bashbrew/cache:846dde9a0b188cd02ab283ae2b6b45b6dc6e75453e2c3ec76a3fc3c3ffe88af4 (percona:5.6.34)
Tagging percona:5.6.34
Tagging percona:5.6

$ test/run.sh percona:5.6.34
testing percona:5.6.34
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7].......passed
	'mysql-initdb' [6/7].......passed
	'mysql-log-bin' [7/7]........passed


$ bashbrew build percona:5.5.53
Building bashbrew/cache:fff63a5a35aa6c71659c0f6b310180d9afed0d0f48ec9c42d0443cd0c6c8154b (percona:5.5.53)
Tagging percona:5.5.53
Tagging percona:5.5

$ test/run.sh percona:5.5.53
testing percona:5.5.53
	'utc' [1/7]...passed
	'cve-2014--shellshock' [2/7]...passed
	'no-hard-coded-passwords' [3/7]...passed
	'override-cmd' [4/7]...passed
	'mysql-basics' [5/7]......passed
	'mysql-initdb' [6/7]......passed
	'mysql-log-bin' [7/7].......passed
$ bashbrew build piwik:2.17.1
Building bashbrew/cache:d2bc230c6a6b9b344d9307a09502d0e9f6259a4b0b1731d9af8d515cdd38371b (piwik:2.17.1)
Tagging piwik:2.17.1
Tagging piwik:2.17
Tagging piwik:2
Tagging piwik:latest

$ test/run.sh piwik:2.17.1
testing piwik:2.17.1
	'utc' [1/4]...passed
	'cve-2014--shellshock' [2/4]...passed
	'no-hard-coded-passwords' [3/4]...passed
	'override-cmd' [4/4]...passed

@tianon
Copy link
Member Author

tianon commented Nov 28, 2016

This also includes docker-library/httpd#35 😇

@yosifkit yosifkit merged commit 77f8f04 into docker-library:master Nov 28, 2016
@yosifkit yosifkit deleted the update-docker-library branch November 28, 2016 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants