From d1c6d54a2235c9655b7aa5a5139f777b75efc80f Mon Sep 17 00:00:00 2001 From: Kevin Baensch Date: Tue, 13 Dec 2022 17:04:48 +0100 Subject: [PATCH] [WIP] Docker Templater --- .gitignore | 4 +- script/docker-templater.sh | 122 +++++++++++++++++++++++++++++++++++++ templates/caddy.sh | 16 +++++ templates/hosts.sh | 40 ++++++++++++ templates/sqlproxy.sh | 6 ++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100755 script/docker-templater.sh create mode 100644 templates/caddy.sh create mode 100644 templates/hosts.sh create mode 100644 templates/sqlproxy.sh diff --git a/.gitignore b/.gitignore index 55c916e..d483373 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/etc/ssh/*key* -/etc/ssh/.ssh +etc/ssh/*key* +etc/ssh/.ssh/ diff --git a/script/docker-templater.sh b/script/docker-templater.sh new file mode 100755 index 0000000..a3081f8 --- /dev/null +++ b/script/docker-templater.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# Export Variables so they can be picked up by envsubst +set -ae +TEMPLATE_SRC=$1; +DOCKER_DATA=$2; + +NETWORK_NAME="${NETWORK_NAME:-proxy}" + +# "NetworkSettings" + +# Import Template +# Required Variables: +# - TEMPLATE :: The template string which will be read by envsubst +# Optional Variables: +# - WRAP_START :: String to prepend in front of the mapped template result +# - WRAP_END :: String to append to the mapped template result +# - SEPARATOR :: String/Charater to separate TEMPLATE lines (DEFAULT: \n) +# - OUT :: if set the result will be written to $OUT instead of stdout +# Optional Functions: +# - label_hook :: modify/override label query results +# - template_hook :: hook to verify/modify template rsults (0 => OK; 1 => SKIP) + +if [ -f "${TEMPLATE_SRC}" ] +then + source "${TEMPLATE_SRC}" + if [ -z "${TEMPLATE}" ] + then + echo "[ERR]: Template \"${TEMPLATE_SRC}\" does define a template string." + exit 1 + fi +else + echo "[ERR]: No such File \"${TEMPLATE_SRC}\"."; + exit 1 +fi + +# Check Hooks +if type label_hook 2>/dev/null | grep -q "label_hook is a function" +then + RUN_LABEL_HOOK=true +else + RUN_LABEL_HOOK=false +fi + +if type template_hook 2>/dev/null | grep -q "template_hook is a function" +then + RUN_TEMPLATE_HOOK=true +else + RUN_TEMPLATE_HOOK=false +fi + +if [ -z "${SEPARATOR+.}" ] +then + SEPARATOR='\n' +fi + +for row in $(jq -r '.[] | @base64' <<< "${DOCKER_DATA}") +do + CONTAINER_DATA=$(base64 --decode <<< "${row}"); + # Set non Label values + if [ -z "${LOCAL_IP}" ] + then + LOCAL_IP=$(jq -r '.NetworkSettings.Networks | if has($ENV.NETWORK_NAME) then .[$ENV.NETWORK_NAME].IPAddress else first(.[].IPAddress) end' <<< "${CONTAINER_DATA}"); + fi + # export LOCAL_IP + + # Read Label values + CONTAINER_LABELS=$(jq '.Labels' <<< "${CONTAINER_DATA}"); + for var in $(envsubst -v "${TEMPLATE}") + do + if [ -z "${!var}" ] + then + VAR_LABEL=$(tr '[:upper:]_' '[:lower:].' <<< "${var}") + LABEL_VAL=$(jq --arg KEY "${VAR_LABEL}" -r 'if has($KEY) then .[$KEY] else "" end' <<< "${CONTAINER_LABELS}") + + if [ -n "${LABEL_VAL}" ] + then + declare "${var}"="${LABEL_VAL}"; + fi + fi + done + + if ${RUN_LABEL_HOOK} + then + label_hook + fi + + PARTIAL_RESULT="$(envsubst <<< "${TEMPLATE}")"; + # Verify template result if check_template is defined + if ${RUN_TEMPLATE_HOOK} + then + if template_hook + then + # FIX with printf + RESULT+="${PARTIAL_RESULT}" + fi + else + RESULT=$(printf '%s' "${RESULT}" "${RESULT:+$SEPARATOR}" "${PARTIAL_RESULT}") + fi + + # Unset label-environment variables for next container + for var in $(envsubst -v "${TEMPLATE}") + do + if [ "${var}" != "LOCAL_IP" ] + then + unset "${!var}" + fi + done +done + +RESULT="${WRAP_START}${RESULT}${WRAP_END}" + + +if [ -z "${OUT}" ] +then + printf "%b\n" "${RESULT}"; +else + if ! diff --brief "${OUT}" - > /dev/null 2>&1 <<< "${RESULT}" + then + printf "Template Task: '%s' has been written to: '%s'\n" "${TEMPLATE_SRC}" "${OUT}" + printf "%b\n" "${RESULT}" > "${OUT}"; + fi +fi diff --git a/templates/caddy.sh b/templates/caddy.sh new file mode 100644 index 0000000..7d5dc52 --- /dev/null +++ b/templates/caddy.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -e + +TEMPLATE='reverse_proxy $LOCAL_WEB_HOST ${LOCAL_IP}:$LOCAL_WEB_PORT' + +label_hook() { + LOCAL_WEB_PORT="${LOCAL_WEB_PORT:-80}" +} + +template_hook() { + if grep -q '^reverse_proxy [^\s] [:.0-9a-e]\+:\d+$' <<< "${PARTIAL_RESULT}" + then + return 0; + fi + return 1; +} diff --git a/templates/hosts.sh b/templates/hosts.sh new file mode 100644 index 0000000..2a04f5b --- /dev/null +++ b/templates/hosts.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -e +HOST_CONF_PATH="${HOST_CONF_PATH:-/tmp/hosts}" +RESOLVE_DOCKERHOST="${RESOLVE_DOCKERHOST:-false}" +DOCKER_HOSTNAME_VAR="${DOCKER_HOSTNAME_VAR:-LOCAL_WEB_HOST}" + +if [ -f "${HOST_CONF_PATH}" ] +then + WRAP_START=$(grep -ve "# Added by hostman$" "${HOST_CONF_PATH}") + WRAP_START+="\n" +else + printf "[WARN]: No such file or directory: %s\n" "${HOST_CONF_PATH}" + printf "Creating %s" "${HOST_CONF_PATH}" + touch "${HOST_CONF_PATH}" +fi + +if ! $RESOLVE_DOCKERHOST +then + TEMPLATE='127.0.0.1 ' +else + TEMPLATE='$LOCAL_IP ' +fi + +TEMPLATE="${TEMPLATE}\${${DOCKER_HOSTNAME_VAR}} # Added by hostman" + +# Allow overriding out for debugging and testing purposs +if [ -z "${HOST_CONF_OUT+.}" ] +then + OUT="${HOST_CONF_PATH}" +else + OUT="${HOST_CONF_OUT}" +fi + +check_template() { + if grep -q '^[:.0-9a-e]\+ [^\s]\+ # Added by hostman$' <<< "${PARTIAL_RESULT}" + then + return 0; + fi + return 1; +} diff --git a/templates/sqlproxy.sh b/templates/sqlproxy.sh new file mode 100644 index 0000000..614064a --- /dev/null +++ b/templates/sqlproxy.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -e +WRAP_START='[\n' +TEMPLATE=' { type: "${LOCAL_DB_TYPE}", user: "${LOCAL_DB_USER}", password: "${LOCAL_DB_PASSWORD}", host: "${LOCAL_DB_HOST}", port: "${LOCAL_DB_PORT}" }' +SEPARATOR=',\n' +WRAP_END='\n]'