module: add compose
diff --git a/module/compose/holder.sh b/module/compose/holder.sh
new file mode 100644
index 0000000..bea5c6c
--- /dev/null
+++ b/module/compose/holder.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# compose - holder.sh
+#
+# Copyright 2019 Luigi Santivetti <luigi.santivetti@gmail.com>
+
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+_COMPOSE_API_VERSION_="3"
+_COMPOSE_HOST_HTTP_PORT_="80"
+_COMPOSE_HOST_HTTPS_PORT_="443"
+_COMPOSE_HOST_SSH_PORT_="29418"
+_COMPOSE_SUBNET_BIT_="16"
+_COMPOSE_SUBNET_FRONTEND_IP_="172.28.0.0"
+_COMPOSE_SUBNET_BACKEND_IP_="172.27.0.0"
+_COMPOSE_ENVIRONMENT_="${environment_f}"
diff --git a/module/compose/module.sh b/module/compose/module.sh
new file mode 100644
index 0000000..d7e397e
--- /dev/null
+++ b/module/compose/module.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# compose - module.sh
+#
+# Copyright 2019 Luigi Santivetti <luigi.santivetti@gmail.com>
+
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+declare -r module="compose"
+source $common_sh
+
+module_enable $module
+declare -ar depmod=( gerrit mysql apache )
+
+declare -r environment="common.env"
+declare -r environment_f="${instance_d}/${environment}"
+declare -r docker_compose_f="${instance_d}/docker-compose.yml"
+declare -r compose_cli_f="${instance_d}/compose-cli.sh"
+
+declare -ar mod_more_files=( $docker_compose_f $environment_f $compose_cli_f )
+declare -ar mod_more_trefs=( docker_compose_t environment_t compose_cli_bang_t )
+
+function tod_watch
+{
+	__watch_module_common || return $s_err
+}
+
+function tod_doall
+{
+	__doins_module_common || return $s_err
+}
+
+function tod_upins
+{
+	__upins_module_common || return $s_err
+}
+
+function tod_clins
+{
+	__clins_module_common || return $s_err
+}
diff --git a/module/compose/scheme.sh b/module/compose/scheme.sh
new file mode 100644
index 0000000..666d782
--- /dev/null
+++ b/module/compose/scheme.sh
@@ -0,0 +1,283 @@
+#!/bin/bash
+#
+# generate a new docker-compose.yml
+#
+# Copyright 2019 Luigi Santivetti <luigi.santivetti@gmail.com>
+
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+if [ "${_APACHE_HAS_MEDIA_}" -eq 1 ]; then
+	declare -r compose_has_mount_media="\
+      - ${_APACHE_HTML_PHOTOS_D_}:/var/www/html/photos
+      - ${_APACHE_HTML_VIDEOS_D_}:/var/www/html/videos"
+else
+	declare -r compose_has_mount_media=""
+fi
+
+if [ "${_GERRIT_HAS_HTTPS_}" -eq 1 ]; then
+	declare -r compose_has_secure_store="\
+      - ${_GERRIT_DKRC_KEYSTORE_F_}:${_GERRIT_KEYSTORE_}:ro
+      - ${_GERRIT_DKRC_SSLIB_F_}:${_GERRIT_SSLIB_}"
+else
+	declare -r compose_has_secure_store=""
+fi
+
+declare -r docker_compose_t="\
+version: '${_COMPOSE_API_VERSION_}'
+networks:
+  frontend:
+    driver: bridge
+    ipam:
+      config:
+        - subnet: ${_COMPOSE_SUBNET_FRONTEND_IP_}/${_COMPOSE_SUBNET_BIT_}
+  backend:
+    driver: bridge
+    ipam:
+      config:
+        - subnet: ${_COMPOSE_SUBNET_BACKEND_IP_}/${_COMPOSE_SUBNET_BIT_}
+services:
+  ${_GERRIT_DKRC_SERVICE_}:
+    image: ${_GERRIT_DKRC_IMAGE_}
+    build:
+      context: ${_GERRIT_DKRC_CONTEXT_}
+      dockerfile: ${_GERRIT_DKRC_DOCKERFILE_}
+    container_name: ${_GERRIT_DKRC_CONTAINER_}
+    expose:
+      - \"${_GERRIT_PROXY_PORT_}\"
+      - \"${_GERRIT_SSH_PORT_}\"
+    ports:
+      - \"${_COMPOSE_HOST_SSH_PORT_}:${_GERRIT_SSH_PORT_}\"
+    volumes:
+      - ${_GERRIT_DKRC_ROOTFS_}/index:/var/gerrit/index
+      - ${_GERRIT_DKRC_ROOTFS_}/cache:/var/gerrit/cache
+      - ${_GERRIT_DKRC_ROOTFS_}/git:/var/gerrit/git
+      - ${_GERRIT_DKRC_ETC_D_}:/var/gerrit/etc
+${compose_has_secure_store}
+    environment:
+      - CANONICAL_WEB_URL=${_GERRIT_CANON_URL_}
+      - LISTEN_URL=${_GERRIT_LISTEN_URL_}
+    depends_on:
+      - ${_APACHE_DKRC_SERVICE_}
+    networks:
+      frontend:
+        ipv4_address: ${_GERRIT_DKRC_FRONTEND_IP_}
+    entrypoint: /bin/bash -c \"/${_GERRIT_DKRC_ENTRYPOINT_} \${GERRIT_ENTRYPOINT_ARGS}\"
+  ${_APACHE_DKRC_SERVICE_}:
+    environment:
+      - HOST_PEPPER=\${_PASSWD_APACHE_HASH_HMAC_PEPPER_}
+      - MYSQL_PASSWORD=\${_PASSWD_MYSQL_DB_PASSWORD_}
+      - MYSQL_USER=\${_PASSWD_MYSQL_DB_USERNAME_}
+    env_file:
+      - ${_COMPOSE_ENVIRONMENT_}
+    image: ${_APACHE_DKRC_IMAGE_}
+    build:
+      context: ${_APACHE_DKRC_CONTEXT_}
+      dockerfile: ${_APACHE_DKRC_DOCKERFILE_}
+    container_name: ${_APACHE_DKRC_CONTAINER_}
+    ports:
+      - \"${_COMPOSE_HOST_HTTP_PORT_}:${_APACHE_HTTP_PORT_}\"
+      - \"${_COMPOSE_HOST_HTTPS_PORT_}:${_APACHE_HTTPS_PORT_}\"
+    volumes:
+      - ${_APACHE_DKRC_PORTS_F_}:/etc/apache2/ports.conf:ro
+      - ${_APACHE_DKRC_CONF_F_}:/etc/apache2/apache2.conf:ro
+      - ${_APACHE_DKRC_AVAILABLE_D_}:/etc/apache2/sites-available:ro
+      - ${_APACHE_DKRC_ENABLED_D_}:/etc/apache2/sites-enabled:ro
+      - ${_MYSQL_ROOTFS_SSL_D_}:${_APACHE_CON_SSL_MYSQL_D_}:ro
+      - ${_APACHE_DKRC_CERT_L_}:${_APACHE_CON_SSL_D_}:ro
+      - ${_APACHE_EXT_AUTH_F_}:${_APACHE_CON_EXT_AUTH_F_}:ro
+      - ${_APACHE_DKRC_LOG_D_}:/var/log/apache2
+      - ${_APACHE_DKRC_WWW_D_}:/var/www
+${compose_has_mount_media}
+    depends_on:
+      - ${_MYSQL_DKRC_SERVICE_}
+    networks:
+      frontend:
+        ipv4_address: ${_APACHE_DKRC_FRONTEND_IP_}
+      backend:
+        ipv4_address: ${_APACHE_DKRC_BACKEND_IP_}
+  ${_MYSQL_DKRC_SERVICE_}:
+    environment:
+      - MYSQL_ROOT_PASSWORD=\${_PASSWD_MYSQL_DB_PASSWORD_ROOT_}
+      - MYSQL_PASSWORD=\${_PASSWD_MYSQL_DB_PASSWORD_}
+      - MYSQL_USER=\${_PASSWD_MYSQL_DB_USERNAME_}
+    env_file:
+      - ${_COMPOSE_ENVIRONMENT_}
+    image: ${_MYSQL_DKRC_IMAGE_}
+    build:
+      context: ${_MYSQL_DKRC_CONTEXT_}
+      dockerfile: ${_MYSQL_DKRC_DOCKERFILE_}
+    container_name: ${_MYSQL_DKRC_CONTAINER_}
+    restart: always
+    networks:
+      backend:
+        ipv4_address: ${_MYSQL_DKRC_BACKEND_IP_}
+    expose:
+      - \"${_MYSQL_DB_PORT_}\"
+    volumes:
+      - ${_MYSQL_ROOTFS_SSL_D_}:${_MYSQL_CON_SSL_D_}
+      - ${_MYSQL_INITDB_F_}:/docker-entrypoint-initdb.d/initdb.sql
+      - ${_MYSQL_MYCONF_F_}:/etc/mysql/my.cnf:ro
+      - ${_MYSQL_MYSQL_D_}:/var/lib/mysql
+      - ${_MYSQL_LOG_D_}:${_MYSQL_CON_LOG_D_}"
+
+declare -r environment_t="\
+MYSQL_DATABASE=${_MYSQL_DB_NAME_}
+MYSQL_HOSTNAME=${_MYSQL_DKRC_BACKEND_IP_}
+MYSQL_SSL_CAPATH=${_APACHE_CON_SSL_MYSQL_D_}
+MYSQL_SSL_CERT=${_APACHE_CON_SSL_MYSQL_CERT_F_}
+MYSQL_SSL_KEY=${_APACHE_CON_SSL_MYSQL_KEY_F_}
+MYSQL_SSL_CA=${_APACHE_CON_SSL_MYSQL_CA_F_}
+HOST_NAME=${_APACHE_SERVER_NAME_}"
+
+declare -r compose_cli_bang_t="\
+#!/bin/bash
+
+if (return 0 2>/dev/null); then
+	echo \"You must run this script\" >&2
+	return 1
+fi
+
+function __help
+{
+	cat <<EOF; exit 0
+`printf \"\\033[1m%s\\033[0m\\n\" \"NAME\"`
+
+  \${BASH_SOURCE[0]//.\//} - docker-compose CLI for ${host_name}
+
+`printf \"\\033[1m%s\\033[0m\\n\" \"USAGE\"`
+
+  \$ \${BASH_SOURCE[0]} [ OPTION ] [ ARGS ... ]
+
+`printf \"\\033[1m%s\\033[0m\\n\" \"ENVIRONMENT\"`
+
+  PASSWD_F                    path to file containing runtime credentials
+
+`printf \"\\033[1m%s\\033[0m\\n\" \"OPTION\"`
+
+      --start [init]          start instance. If \\\`init\\\` is passed,
+                              then do entrypoint.sh initialization steps
+                              and run in the foreground not as a daemon
+      --stop                  stop instance
+  -pc|--prune-containers      delete all services container
+  -pn|--prune-networks        delete all services network
+  -ps|--prune-system          delete all images, containers, cache,
+                              networks and volumes
+  -bs|--build-services        build all services and networks
+   -h|--help                  show this help
+
+`printf \"\\033[1m%s\\033[0m\\n\" \"END\"`
+EOF
+}
+
+function source_passwd_file
+{
+	if [ ! -f \"\${PASSWD_F}\" ]; then
+		echo \"error: PASSWD file not found\" >&2
+		exit 1
+	fi
+
+	if ! source \"\${PASSWD_F}\"; then
+		echo \"error: PASSWD file not sourced\" >&2
+		exit 1
+	fi
+}
+
+function __dkrc_start
+{
+	local -i error
+
+	source_passwd_file
+	pushd \"${instance_d}\" >/dev/null || exit 1
+
+	if sudo systemctl is-active --quiet service apache2.service; then
+		echo \"warning: shutting down apache2.service\" >&2
+		sudo systemctl stop apache2.service
+	fi
+
+	case \"\$1\" in
+		init )
+			GERRIT_ENTRYPOINT_ARGS=init \\
+				_PASSWD_APACHE_HASH_HMAC_PEPPER_=\${_PASSWD_APACHE_HASH_HMAC_PEPPER_} \\
+				_PASSWD_MYSQL_DB_USERNAME_=\${_PASSWD_MYSQL_DB_USERNAME_} \\
+				_PASSWD_MYSQL_DB_PASSWORD_=\${_PASSWD_MYSQL_DB_PASSWORD_} \\
+				_PASSWD_MYSQL_DB_PASSWORD_ROOT_=\${_PASSWD_MYSQL_DB_PASSWORD_ROOT_} \\
+				sudo -E docker-compose up ;;
+		*     )
+			[ -z \"\$1\" ] || echo \"warning: input ignored: \$1\" >&2
+
+			_PASSWD_APACHE_HASH_HMAC_PEPPER_=\${_PASSWD_APACHE_HASH_HMAC_PEPPER_} \\
+				_PASSWD_MYSQL_DB_USERNAME_=\${_PASSWD_MYSQL_DB_USERNAME_} \\
+				_PASSWD_MYSQL_DB_PASSWORD_=\${_PASSWD_MYSQL_DB_PASSWORD_} \\
+				_PASSWD_MYSQL_DB_PASSWORD_ROOT_=\${_PASSWD_MYSQL_DB_PASSWORD_ROOT_} \\
+				sudo -E docker-compose up -d ;;
+	esac
+
+	error=\"\$?\"
+	popd >/dev/null
+
+	return \$error
+}
+
+function __dkrc_stop
+{
+	sudo docker stop \$(sudo docker ps -a -q)
+}
+
+function __dkrc_prune_containers
+{
+	sudo docker rm \$(sudo docker ps -a -q)
+}
+
+function __dkrc_prune_networks
+{
+	sudo docker network prune -f
+}
+
+function __dkrc_prune_system
+{
+	sudo docker system prune --all
+}
+
+function __dkrc_build_services
+{
+	local -i error
+
+	source_passwd_file
+	pushd \"${instance_d}\" >/dev/null || exit 1
+
+	_PASSWD_APACHE_HASH_HMAC_PEPPER_=\${_PASSWD_APACHE_HASH_HMAC_PEPPER_} \\
+		_PASSWD_MYSQL_DB_USERNAME_=\${_PASSWD_MYSQL_DB_USERNAME_} \\
+		_PASSWD_MYSQL_DB_PASSWORD_=\${_PASSWD_MYSQL_DB_PASSWORD_} \\
+		_PASSWD_MYSQL_DB_PASSWORD_ROOT_=\${_PASSWD_MYSQL_DB_PASSWORD_ROOT_} \\
+		sudo -E docker-compose build --force-rm --no-cache \$@
+	error=\"\$?\"
+	popd >/dev/null
+
+	return \$error
+}
+
+case \"\$1\" in
+      --start            ) __dkrc_start \"\$2\"    ;;
+      --stop             ) __dkrc_stop             ;;
+  -pc|--prune-containers ) __dkrc_prune_containers ;;
+  -pn|--prune-networks   ) __dkrc_prune_networks   ;;
+  -ps|--prune-system     ) __dkrc_prune_system     ;;
+  -bs|--build-services   ) __dkrc_build_services   ;;
+   -h|--help             ) __help                  ;;
+esac"