From 3bf728e895b9c949d755ff6cb77123da746066ec Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Wed, 13 Feb 2019 14:11:52 +0100 Subject: [PATCH] chg: dev: [apache] rewrite internal library to avoid global vars. --- apache/hooks/publish_dir-relation-joined | 3 +- apache/hooks/web_proxy-relation-joined | 3 +- apache/lib/common | 363 ++++++++++++++--------- apache/test/vhost | 95 +++--- apache/test/vhost_cert_provider | 185 +++++++++++- apache/test/vhost_files | 107 +++++-- 6 files changed, 533 insertions(+), 223 deletions(-) diff --git a/apache/hooks/publish_dir-relation-joined b/apache/hooks/publish_dir-relation-joined index 57a7940..1d0202a 100755 --- a/apache/hooks/publish_dir-relation-joined +++ b/apache/hooks/publish_dir-relation-joined @@ -6,7 +6,8 @@ set -e -apache_publish_dir +cfg=$(relation-get) +apache_publish_dir "$cfg" APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true if [ "$APACHE_CORE_RULES" ]; then diff --git a/apache/hooks/web_proxy-relation-joined b/apache/hooks/web_proxy-relation-joined index 4e8bb86..fc90dc5 100755 --- a/apache/hooks/web_proxy-relation-joined +++ b/apache/hooks/web_proxy-relation-joined @@ -5,7 +5,8 @@ set -e . lib/common -apache_proxy_dir || exit 1 +cfg=$(relation-get) +apache_proxy_dir "$cfg" APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true if [ "$APACHE_CORE_RULES" ]; then diff --git a/apache/lib/common b/apache/lib/common index 82eb87c..b81decf 100644 --- a/apache/lib/common +++ b/apache/lib/common @@ -1,10 +1,10 @@ # -*- mode: shell-script -*- -config_hash= +get_domain() { + local cfg="$1" -get_domain () { - relation-get domain 2>/dev/null && return 0 + e "$cfg" | cfg-get-value domain 2>/dev/null && return 0 ## is service name a regex ? if [[ "$BASE_SERVICE_NAME" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then @@ -12,64 +12,71 @@ get_domain () { return 0 fi - err "You must specify a ${WHITE}domain$NORMAL option in relation." + err "You must specify a ${WHITE}domain$NORMAL option in relation. (${FUNCNAME[@]})" return 1 } -apache_proxy_dir () { - DOMAIN=$(get_domain) || return 1 - relation-set domain "$DOMAIN" - proxy=yes apache_vhost_create || return 1 - info "Added $DOMAIN as a proxy to $TARGET." -} -export -f apache_proxy_dir +## +## Master entrypoints +## -apache_publish_dir () { - DOMAIN=$(get_domain) || return 1 - relation-set domain "$DOMAIN" - DOCKER_SITE_PATH="/var/www/${DOMAIN}" - LOCATION=$(relation-get location 2>/dev/null) || - LOCATION="$DATASTORE/$BASE_SERVICE_NAME$DOCKER_SITE_PATH" +apache_proxy_dir() { + local cfg="$1" domain + apache_vhost_create web_proxy "$cfg" || return 1 +} +export -f apache_proxy_dir - apache_vhost_create || return 1 - info "Added $DOMAIN apache config." - apache_code_dir || return 1 - apache_data_dirs +apache_publish_dir() { + local cfg="$1" domain + apache_vhost_create publish_dir "$cfg" || return 1 + apache_code_dir "$cfg" || return 1 + apache_data_dirs "$cfg" } export -f apache_publish_dir -apache_vhost_create () { - local custom_rules - export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" vhost_statement - SERVER_ALIAS=$(relation-get server-aliases 2>/dev/null) || true - PROTOCOLS=$(__vhost_cfg_normalize_protocol) || return 1 +## +## Simple functions +## + + - export SERVER_ALIAS PROTOCOLS SSL_PLUGIN_FUN SSL_CFG_{VALUE,OPTION} +apache_vhost_create() { + local type="$1" cfg="$2" custom_rules vhost_statement creds - if is_protocol_enabled https; then - read-0 SSL_PLUGIN_FUN SSL_CFG_VALUE SSL_CFG_OPTIONS < <(ssl_get_plugin_fun) || return 1 - "$SSL_PLUGIN_FUN"_vars "$SSL_CFG_OPTIONS" "$SSL_CFG_VALUE" || return 1 - redirect=$(relation-get 'redirect-to-ssl' 2>/dev/null) || true - if is_protocol_enabled http; then + export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" + + protocols=$(__vhost_cfg_normalize_protocol "$cfg") || return 1 + + if is_protocol_enabled https "$protocols"; then + read-0 ssl_plugin_fun ssl_cfg_value ssl_cfg_options < <(ssl_get_plugin_fun "$cfg") || return 1 + "$ssl_plugin_fun"_vars "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" || return 1 + redirect=$(e "$cfg" | cfg-get-value 'redirect-to-ssl' 2>/dev/null) || true + if is_protocol_enabled http "$protocols"; then redirect=${redirect:-true} else redirect=false fi if [ "$redirect" == "true" ]; then - custom_rules=$(_get_custom_rules) || return 1 + custom_rules=$(_get_custom_rules "$cfg") || return 1 if [[ "$custom_rules" != *"## Auto-redirection from http to https"* ]]; then - relation-set apache-custom-rules "- | + redirect_rule="- | ## Auto-redirection from http to https RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] +" + relation-set apache-custom-rules "$redirect_rule $(if [ "$custom_rules" ]; then echo "- |"$'\n'"$(echo "$custom_rules" | prefix " ")" fi)" + cfg=$(merge_yaml_str "$cfg" "$(yaml_key_val_str "apache-custom-rules" "$redirect_rule +$(if [ "$custom_rules" ]; then + echo "- |"$'\n'"$(echo "$custom_rules" | prefix " ")" + fi)")") fi relation-set protocol https else @@ -80,30 +87,36 @@ $(if [ "$custom_rules" ]; then else relation-set protocol http fi - vhost_statement=$(apache_vhost_statement "$PROTOCOLS") || return 1 - echo "$vhost_statement"| file_put "$APACHE_CONFIG_LOCATION/$prefix$DOMAIN.conf" || return 1 + vhost_statement=$(apache_vhost_statement "$type" "$protocols" "$cfg") || { + err "Failed to get vhost statement for type $type on ${protocols:1:-1}" + return 1 + } + domain=$(get_domain "$cfg") || return 1 + relation-set domain "$domain" - __vhost_cfg_creds_enabled=$(relation-get creds 2>/dev/null) || true - if [ "$__vhost_cfg_creds_enabled" ]; then - apache_passwd_file || return 1 + echo "$vhost_statement"| file_put "$APACHE_CONFIG_LOCATION/$prefix$domain.conf" || return 1 + + creds=$(e "$cfg" | cfg-get-value creds 2>/dev/null) || true + if [ "$creds" ]; then + apache_passwd_file "$cfg" || return 1 fi - if is_protocol_enabled https; then - "$SSL_PLUGIN_FUN"_prepare "$SSL_CFG_OPTIONS" "$SSL_CFG_VALUE" || return 1 + if is_protocol_enabled https "$protocols"; then + "$ssl_plugin_fun"_prepare "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" || return 1 fi } is_protocol_enabled() { - local protocol=$1 - [[ "$PROTOCOLS" == *",$protocol,"* ]] + local protocol="$1" protocols="$2" + [[ "$protocols" == *",$protocol,"* ]] } export -f is_protocol_enabled _get_ssl_option_value() { - local target_relation rn ts rc td - relation-get ssl 2>/dev/null && return 0 + local cfg="$1" target_relation rn ts rc td + e "$cfg" | cfg-get-value ssl 2>/dev/null && return 0 target_relation="cert-provider" while read-0 rn ts rc td; do @@ -118,19 +131,29 @@ _get_ssl_option_value() { __vhost_cfg_normalize_protocol() { - local protocol - - if ! protocol=$(relation-get protocol 2>/dev/null); then - protocol=auto - else + local cfg="$1" protocol + ## XXXvlab: can't cache if libcharm is not able to give me some checksums + ## indeed, ``_get_ssl_option_value`` depends on relations calculations... + + # local cfg="$1" cache_file="$CACHEDIR/$FUNCNAME.cache.$(p0 "$@" | md5_compat)" \ + # protocol + # if [ -e "$cache_file" ]; then + # #debug "$FUNCNAME: STATIC cache hit $1" + # cat "$cache_file" && + # touch "$cache_file" || return 1 + # return 0 + # fi + + if protocol=$(e "$cfg" | cfg-get-value protocol 2>/dev/null); then protocol=${protocol:-auto} + else + protocol=auto fi case "$protocol" in auto) - if __vhost_cfg_ssl="$(_get_ssl_option_value)"; then + if _get_ssl_option_value "$cfg" >/dev/null 2>&1; then protocol="http,https" - export __vhost_cfg_ssl else protocol="http" fi @@ -149,24 +172,22 @@ __vhost_cfg_normalize_protocol() { return 1 esac echo ",$protocol," + #| tee "$cache_file" } ## ssl_plugin_* and ssl_fallback should : -## - do anything to ensure that +## - do anything to ensure that ## - issue config-add to add volumes if necessary ## - output 3 vars of where to find the 3 files from within the docker apache ssl_get_plugin_fun() { # from ssl conf, return the function that should manage SSL code creation - local cfg type keys - cfg=$(_get_ssl_option_value) - if [ -z "$cfg" ]; then - return 0 - else - type="$(echo "$cfg" | shyaml -y get-type 2>/dev/null)" || return 1 - fi + local master_cfg="$1" cfg type keys + cfg=$(_get_ssl_option_value "$master_cfg") + [ "$cfg" ] || return 0 + type="$(echo "$cfg" | shyaml -y get-type 2>/dev/null)" || return 1 if [[ "$type" == "bool" ]]; then printf "%s\0" "ssl_fallback" "" "$cfg" echo ssl_fallback @@ -216,18 +237,19 @@ ssl_get_plugin_fun() { ssl_fallback_vars() { - local cfg="$1" cert key ca_cert + local cfg="$1" ssl_cfg="$2" cert key ca_cert domain + domain=$(get_domain "$cfg") || return 1 - if __vhost_cfg_ssl_cert=$(echo "$cfg" | shyaml get-value cert 2>/dev/null); then - __vhost_cfg_SSL_CERT_LOCATION=/etc/ssl/certs/${DOMAIN}.pem + if __vhost_cfg_ssl_cert=$(echo "$ssl_cfg" | shyaml get-value cert 2>/dev/null); then + __vhost_cfg_SSL_CERT_LOCATION=/etc/ssl/certs/${domain}.pem fi - if __vhost_cfg_ssl_key=$(echo "$cfg" | shyaml get-value key 2>/dev/null); then - __vhost_cfg_SSL_KEY_LOCATION=/etc/ssl/private/${DOMAIN}.key + if __vhost_cfg_ssl_key=$(echo "$ssl_cfg" | shyaml get-value key 2>/dev/null); then + __vhost_cfg_SSL_KEY_LOCATION=/etc/ssl/private/${domain}.key fi - if __vhost_cfg_ssl_ca_cert=$(echo "$cfg" | shyaml get-value ca-cert 2>/dev/null); then - __vhost_cfg_SSL_CA_CERT_LOCATION=/etc/ssl/certs/${DOMAIN}-ca.pem + if __vhost_cfg_ssl_ca_cert=$(echo "$ssl_cfg" | shyaml get-value ca-cert 2>/dev/null); then + __vhost_cfg_SSL_CA_CERT_LOCATION=/etc/ssl/certs/${domain}-ca.pem fi } @@ -259,19 +281,30 @@ $volumes } ssl_plugin_cert-provider_vars() { + local cfg="$1" ssl_cfg="$2" + domain=$(get_domain "$cfg") || return 1 - __vhost_cfg_SSL_CERT_LOCATION=/etc/letsencrypt/live/${DOMAIN}/cert.pem - __vhost_cfg_SSL_KEY_LOCATION=/etc/letsencrypt/live/${DOMAIN}/privkey.pem - __vhost_cfg_SSL_CHAIN=/etc/letsencrypt/live/${DOMAIN}/chain.pem + __vhost_cfg_SSL_CERT_LOCATION=/etc/letsencrypt/live/${domain}/cert.pem + __vhost_cfg_SSL_KEY_LOCATION=/etc/letsencrypt/live/${domain}/privkey.pem + __vhost_cfg_SSL_CHAIN=/etc/letsencrypt/live/${domain}/chain.pem } ssl_plugin_cert-provider_prepare() { - local cfg="$1" service="$2" options + local cfg="$1" ssl_cfg="$2" service="$3" options domain server_aliases + + domain=$(get_domain "$cfg") || return 1 - options=$(yaml_key_val_str "options" "$cfg") || return 1 + options=$(yaml_key_val_str "options" "$ssl_cfg") || return 1 service_config=$(yaml_key_val_str "$service" "$options") + server_aliases=$(e "$cfg" | cfg-get-value server-aliases 2>/dev/null) || true + [ "$server_aliases" == None ] && server_aliases="" + if [ "$server_aliases" ]; then + server_aliases=($(echo "$server_aliases" | shyaml get-values)) || return 1 + else + server_aliases=() + fi compose --debug --add-compose-content "$service_config" run --rm --service-ports "$service" \ - crt create "$DOMAIN" $(echo "$SERVER_ALIAS" | shyaml get-values 2>/dev/null) || { + crt create "$domain" "${server_aliases[@]}" || { err "Failed to launch letsencrypt for certificate creation." return 1 } @@ -286,22 +319,24 @@ services: apache_passwd_file() { + local cfg="$1" creds include parse || true ## XXXvlab: called twice... no better way to do this ? - __vhost_creds_statement >/dev/null + creds=$(e "$cfg" | cfg-get-value creds 2>/dev/null) || true + password_path=$(password-path-get "$cfg") first= - if ! [ -e "$CONFIGSTORE/$MASTER_TARGET_SERVICE_NAME$password_file" ]; then - debug "No file $CONFIGSTORE/$MASTER_TARGET_SERVICE_NAME$password_file, creating password file." || true + if ! [ -e "$CONFIGSTORE/$MASTER_TARGET_SERVICE_NAME$password_path" ]; then + debug "No file $CONFIGSTORE/$MASTER_TARGET_SERVICE_NAME$password_path, creating password file." || true first=c fi while read-0 login password; do - debug "htpasswd -b$first '${password_file}' '$login' '$password'" - echo "htpasswd -b$first '${password_file}' '$login' '$password'" + debug "htpasswd -b$first '${password_path}' '$login' '$password'" + echo "htpasswd -b$first '${password_path}' '$login' '$password'" if [ "$first" ]; then first= fi - done < <(echo "$__vhost_cfg_creds_enabled" | shyaml key-values-0 2>/dev/null) | + done < <(e "$creds" | shyaml key-values-0 2>/dev/null) | docker run -i --entrypoint "/bin/bash" \ -v "$APACHE_CONFIG_LOCATION:/etc/apache2/sites-enabled" \ "$DOCKER_BASE_IMAGE" || return 1 @@ -309,16 +344,16 @@ apache_passwd_file() { ## Produce the full statements depending on relation-get informations apache_vhost_statement() { - local vhost_statement - export SERVER_ALIAS=$(relation-get server-aliases 2>/dev/null) || true - export PROTOCOLS="$1" + local type="$1" protocols="$2" cfg="$3" \ + vhost_statement - if is_protocol_enabled http; then - __vhost_full_vhost_statement http || return 1 + if is_protocol_enabled http "$protocols"; then + __vhost_full_vhost_statement "$type" http "$cfg" || return 1 fi - if is_protocol_enabled https; then - "$SSL_PLUGIN_FUN"_vars "$(_get_ssl_option_value 2>/dev/null)" || return 1 - vhost_statement=$(__vhost_full_vhost_statement https) || return 1 + if is_protocol_enabled https "$protocols"; then + read-0 ssl_plugin_fun ssl_cfg_value ssl_cfg_options < <(ssl_get_plugin_fun "$cfg") || return 1 + "$ssl_plugin_fun"_vars "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" || return 1 + vhost_statement=$(__vhost_full_vhost_statement "$type" https "$cfg") || return 1 cat < @@ -331,37 +366,42 @@ export -f apache_vhost_statement apache_code_dir() { - local www_data_gid + local cfg="$1" www_data_gid local_path www_data_gid=$(cached_cmd_on_base_image apache 'id -g www-data') || { debug "Failed to query for www-data gid in ${DARKYELLOW}apache${NORMAL} base image." return 1 } + domain=$(get_domain "$cfg") || return 1 + local_path="/var/www/${domain}" + host_path=$(e "$cfg" | cfg-get-value location 2>/dev/null) || + host_path="$DATASTORE/$BASE_SERVICE_NAME${local_path}" - mkdir -p "$LOCATION" || return 1 - setfacl -R -m g:"$www_data_gid":rx "$LOCATION" - info "Set permission for read and traversal on '$LOCATION'." + mkdir -p "$host_path" || return 1 + setfacl -R -m g:"$www_data_gid":rx "$host_path" + info "Set permission for read and traversal on '$host_path'." config-add " $MASTER_BASE_SERVICE_NAME: volumes: - - $LOCATION:$DOCKER_SITE_PATH + - $host_path:$local_path " } apache_data_dirs() { - - DATA_DIRS=$(relation-get data-dirs 2>/dev/null | shyaml get-values 2>/dev/null) || true - if [ -z "$DATA_DIRS" ]; then + local cfg="$1" data_dirs dst data dirs + data_dirs=$(e "$cfg" | cfg-get-value data-dirs 2>/dev/null | shyaml get-values 2>/dev/null) || true + if [ -z "$data_dirs" ]; then return 0 fi - - DST=$DATASTORE/$BASE_SERVICE_NAME$DOCKER_SITE_PATH - DATA=() - while IFS="," read -ra ADDR; do - for dir in "${ADDR[@]}"; do - DATA+=($dir) + domain=$(get_domain "$cfg") || return 1 + local_path="/var/www/${domain}" + dst=$DATASTORE/$BASE_SERVICE_NAME$local_path + data=() + while IFS="," read -ra addr; do + for dir in "${addr[@]}"; do + data+=($dir) done - done <<< "$DATA_DIRS" + done <<< "$data_dirs" www_data_gid=$(cached_cmd_on_base_image apache 'id -g www-data') || { debug "Failed to query for www-data gid in ${DARKYELLOW}apache${NORMAL} base image." @@ -370,8 +410,8 @@ apache_data_dirs() { info "www-data gid from ${DARKYELLOW}apache${NORMAL} is '$www_data_gid'" dirs=() - for d in "${DATA[@]}"; do - dirs+=("$DST/$d") + for d in "${data[@]}"; do + dirs+=("$dst/$d") done mkdir -p "${dirs[@]}" @@ -382,8 +422,8 @@ apache_data_dirs() { $MASTER_BASE_SERVICE_NAME: volumes: $( - for d in "${DATA[@]}"; do - echo " - $DST/$d:$DOCKER_SITE_PATH/$d" + for d in "${data[@]}"; do + echo " - $dst/$d:$local_path/$d" done )" @@ -443,18 +483,24 @@ EOF } +password-path-get() { + local cfg="$1" domain + domain=$(get_domain "$cfg") || return 1 + echo /etc/apache2/sites-enabled/${domain}.passwd +} + __vhost_creds_statement() { - if ! __vhost_cfg_creds_enabled=$(relation-get creds 2>/dev/null); then + local cfg="$1" password_path + password_path=$(password-path-get "$cfg") || return 1 + if ! e "$cfg" | cfg-get-value creds >/dev/null 2>&1; then echo "Allow from all" return 0 fi - password_file=/etc/apache2/sites-enabled/${DOMAIN}.passwd - cat </dev/null) || true + server_aliases=$(e "$cfg" | cfg-get-value server-aliases 2>/dev/null) || true + [ "$server_aliases" == None ] && server_aliases="" + if [ "$server_aliases" ]; then + server_aliases=($(e "$server_aliases" | shyaml get-values)) || return 1 + if [ -z "$domain" ]; then + err "You can't specify server aliases if you don't have a domain." + return 1 + fi + else + server_aliases=() + fi if [ "$protocol" == "https" ]; then prefix="s-" @@ -471,16 +530,17 @@ __vhost_head_statement() { fi cat </dev/null) + done ) ServerSignature Off -CustomLog /var/log/apache2/${prefix}${DOMAIN}_access.log combined -ErrorLog /var/log/apache2/${prefix}${DOMAIN}_error.log +CustomLog /var/log/apache2/${prefix}${domain}_access.log combined +ErrorLog /var/log/apache2/${prefix}${domain}_error.log ErrorLog syslog:local2 EOF @@ -488,8 +548,8 @@ EOF _get_custom_rules() { - local custom_rules type elt value first - custom_rules=$(relation-get apache-custom-rules 2>/dev/null) || true + local cfg="$1" custom_rules type elt value first + custom_rules=$(e "$cfg" | cfg-get-value apache-custom-rules 2>/dev/null) || true if [ -z "$custom_rules" ]; then return 0 fi @@ -527,8 +587,8 @@ _get_custom_rules() { __vhost_custom_rules() { - local custom_rules - custom_rules=$(_get_custom_rules) || return 1 + local cfg="$1" custom_rules + custom_rules=$(_get_custom_rules "$cfg") || return 1 if [ "$custom_rules" ]; then cat </dev/null) || true - if [ -z "$TARGET" ]; then +target-get() { + local cfg="$1" target first_exposed_port base_image + target=$(e "$cfg" | cfg-get-value target 2>/dev/null) || true + if [ -z "$target" ]; then ## First exposed port: base_image=$(service_base_docker_image "$BASE_SERVICE_NAME") || return 1 if ! docker_has_image "$base_image"; then @@ -568,15 +632,22 @@ __vhost_proxy_statement() { err "Failed to get first exposed port of image '$base_image'." return 1 fi - TARGET=$MASTER_BASE_SERVICE_NAME:$first_exposed_port - info "No target was specified, introspection found: $TARGET" + target=$MASTER_BASE_SERVICE_NAME:$first_exposed_port + info "No target was specified, introspection found: $target" fi + echo "$target" +} + +__vhost_proxy_statement() { + local protocol="$1" cfg="$2" + + target=$(target-get "$cfg") || return 1 cat < @@ -586,9 +657,9 @@ __vhost_proxy_statement() { Allow from all ProxyVia On - ProxyPass / http://$TARGET/ retry=0 + ProxyPass / http://$target/ retry=0 -$(__vhost_creds_statement | prefix " ") +$(__vhost_creds_statement "$cfg" | prefix " ") ProxyPassReverse / $([ "$protocol" == "https" ] && echo " SSLProxyEngine On") @@ -603,11 +674,11 @@ EOF } __vhost_full_vhost_statement() { - local protocol="$1" head_statement custom_rules content_statement + local type="$1" protocol="$2" cfg="$3" head_statement custom_rules content_statement - head_statement=$(__vhost_head_statement "$protocol") || return 1 - custom_rules=$(__vhost_custom_rules) || return 1 - content_statement=$(__vhost_content_statement "$protocol") || return 1 + head_statement=$(__vhost_head_statement "$cfg" "$protocol") || return 1 + custom_rules=$(__vhost_custom_rules "$cfg") || return 1 + content_statement=$(__vhost_content_statement "$type" "$protocol" "$cfg") || return 1 case "$protocol" in https) @@ -637,22 +708,26 @@ EOF } __vhost_publish_dir_statement() { + local protocol="$1" cfg="$2" + domain=$(get_domain "$cfg") || return 1 + local_path="/var/www/${domain}" + cat < Options FollowSymLinks AllowOverride None - + Options Indexes FollowSymLinks MultiViews AllowOverride all -$(__vhost_creds_statement | prefix " ") +$(__vhost_creds_statement "$cfg" | prefix " ") EOF diff --git a/apache/test/vhost b/apache/test/vhost index a2d6287..5f7bc4d 100644 --- a/apache/test/vhost +++ b/apache/test/vhost @@ -12,11 +12,6 @@ include parse " - -## -## print_bytes -## - # mock relation-get() { local key="$1" @@ -24,10 +19,27 @@ relation-get() { } export -f relation-get +cfg-get-value() { + local key="$1" + shyaml get-value "$key" 2>/dev/null +} +export -f cfg-get-value + +get_service_relations() { + printf "%s\0" "${RELATIONS[@]}" +} +export -f get_service_relations + + + +## +## Tests +## + try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -apache_vhost_statement ,http," +apache_vhost_statement publish_dir ,http, '\ +domain: www.example.com +'" noerror is out ' @@ -69,26 +81,22 @@ is out ' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement publish_dir ,http, ' +domain: www.example.com server-aliases: - toto -' -apache_vhost_statement ,http," +'" noerror is out reg 'ServerAlias toto' try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement publish_dir ,http, ' +domain: www.example.com server-aliases: - toto - titi -' -apache_vhost_statement ,http," +'" noerror is out reg 'ServerAlias toto' is out reg 'ServerAlias titi' @@ -99,23 +107,22 @@ is out reg 'ServerAlias titi' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG='' -apache_vhost_statement ,http," "credentials allow all" +apache_vhost_statement publish_dir ,http, ' +domain: www.example.com +' +" "credentials allow all" noerror is out reg 'Allow from all' try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement publish_dir ,http, ' +domain: www.example.com creds: toto: xxx titi: yyy ' -apache_vhost_statement ,http," "credentials with basic auth user/pass" +" "credentials with basic auth user/pass" noerror is out reg 'AuthType basic' is out reg 'Require valid-user' @@ -126,14 +133,13 @@ is out reg 'Require valid-user' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement web_proxy ,http, ' +domain: www.example.com target: popo:3333 creds: toto: titi ' -proxy=yes apache_vhost_statement ,http," "proxy explicit target" +" "proxy explicit target" noerror is out reg 'ProxyPass / http://popo:3333/' is out part ' @@ -151,13 +157,12 @@ is out part ' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement web_proxy ,https, ' +domain: www.example.com ssl: true target: popo:3333 ' -SSL_PLUGIN_FUN=ssl_fallback proxy=yes apache_vhost_statement ,https," "ssl default generation (ssl-cert-snakeoil)" +" "ssl default generation (ssl-cert-snakeoil)" noerror is out reg 'VirtualHost \*:443' is out reg '' @@ -168,16 +173,16 @@ is out reg 'CustomLog /var/log/apache2/s-www.example.com_access.log combined' try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +RELATIONS=() +apache_vhost_statement web_proxy ,https, ' +domain: www.example.com ssl: ca-cert: a key: b cert: c target: popo:3333 ' -SSL_PLUGIN_FUN=ssl_fallback proxy=yes apache_vhost_statement ,https," "ssl providing keys inline" +" "ssl providing keys inline" noerror is out reg 'SSLCertificateFile /etc/ssl/certs/www.example.com.pem' is out reg 'SSLCertificateKeyFile /etc/ssl/private/www.example.com.key' @@ -189,9 +194,8 @@ is out reg 'SSLCACertificateFile /etc/ssl/certs/www.example.com-ca.pem' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement web_proxy ,https, ' +domain: www.example.com ssl: ca-cert: a key: b @@ -202,7 +206,7 @@ apache-custom-rules: | RewriteRule ^(/web/webclient/home.*)$ $1?skin=formanoo [L,QSA,R=302] target: popo:3333 ' -SSL_PLUGIN_FUN=ssl_fallback proxy=yes apache_vhost_statement ,https," "custom rules" +" "custom rules" noerror is out reg 'RewriteEngine On' @@ -212,9 +216,8 @@ is out reg 'RewriteEngine On' ## try " -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +apache_vhost_statement web_proxy ,https,http, ' +domain: www.example.com ssl: ca-cert: a key: b @@ -225,7 +228,7 @@ apache-custom-rules: | RewriteRule ^(/web/webclient/home.*)$ $1?skin=formanoo [L,QSA,R=302] target: popo:3333 ' -SSL_PLUGIN_FUN=ssl_fallback proxy=yes apache_vhost_statement ,https,http," "both http and https" +" "both http and https" noerror is out ' diff --git a/apache/test/vhost_cert_provider b/apache/test/vhost_cert_provider index 2224394..6970a3a 100644 --- a/apache/test/vhost_cert_provider +++ b/apache/test/vhost_cert_provider @@ -31,12 +31,35 @@ relation-set() { } export -f relation-set +cfg-get-value() { + local key="$1" + shyaml get-value "$key" 2>/dev/null +} +export -f cfg-get-value + get_service_relations() { printf "%s\0" "${RELATIONS[@]}" } export -f get_service_relations merge_yaml_str() { + local arg_hash="$(H "$@" | cut -c -16)" + local i + echo "Calling: merge_yaml_str" >&2 + ((i=0)) + for arg in "$@"; do + echo " arg$((i++)):" + echo "$arg" | prefix " | " + done >&2 + echo " H> $arg_hash" >&2 + while read-0 h res; do + if [[ "$arg_hash" == "$h" ]]; then + echo "Mock hash matched, returning:" >&2 + echo "$res" | prefix " | " >&2 + echo "$res" + return 0 + fi + done < <(e "$MERGE_YAML_STR" | shyaml key-values-0) printf "" @@ -55,6 +78,12 @@ yaml_key_val_str() { } export -f yaml_key_val_str + +yaml_get_interpret() { + shyaml get-value +} +export -f yaml_get_interpret + file_put() { echo "file_put $1" cat - | prefix " | " @@ -114,16 +143,15 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -CFG=' +RELATIONS=() +apache_vhost_create publish_dir ' +domain: www.example.com ssl: foo: | a b ' -RELATIONS=() -apache_vhost_create" "unknown cert key" +" "unknown cert key" is errlvl 1 is err reg 'Error: .*cert-provider.*' @@ -134,14 +162,26 @@ export CONFIGSTORE='\$CONFIGSTORE' export DATASTORE='\$DATASTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN CFG=' +domain: www.example.com ssl: foo: 12 ' +ADDITION=' +apache-custom-rules: + - | + ## Auto-redirection from http to https + RewriteEngine On + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA]' +MERGE_YAML_STR=\" +3e417c2db15450f3: | +\$(echo \"\$CFG\" | prefix ' ') +\$(echo \"\$ADDITION\" | prefix ' ') +\" RELATIONS=(cert-provider foo a True) -apache_vhost_create" "known cert key" +apache_vhost_create publish_dir \"\$CFG\" +" "known cert key" is errlvl 0 is err part "\ relation-set apache-custom-rules: @@ -157,3 +197,132 @@ is out part 'config-add | $MASTER_TARGET_SERVICE_NAME: | volumes: | - $DATASTORE/foo/etc/letsencrypt:/etc/letsencrypt:ro' +is out part ' + | ## Auto-redirection from http to https + | RewriteEngine On + | RewriteCond %{HTTPS} off + | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] +' + + + +try " +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export DATASTORE='\$DATASTORE' +export SERVICE_NAME='\$SERVICE_NAME' +export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' +export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' +RELATIONS=(cert-provider foo a True) +CFG=' +domain: www.example.com +server-aliases: +ssl: + foo: 12 +' +ADDITION=' +apache-custom-rules: + - | + ## Auto-redirection from http to https + RewriteEngine On + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA]' +MERGE_YAML_STR=\" +d186e0ae74640f6d: | +\$(echo \"\$CFG\" | prefix ' ') +\$(echo \"\$ADDITION\" | prefix ' ') +\" +apache_vhost_create publish_dir \"\$CFG\" +" "known cert key - empty server-aliases" +is errlvl 0 +is err part "\ +relation-set apache-custom-rules: + | - | + | ## Auto-redirection from http to https + | RewriteEngine On + | RewriteCond %{HTTPS} off + | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] + |" +is out reg 'Calling: compose .*foo: options: .*run --rm --service-ports foo crt create www.example.com\s* +' RTRIM +is out part 'config-add + | services: + | $MASTER_TARGET_SERVICE_NAME: + | volumes: + | - $DATASTORE/foo/etc/letsencrypt:/etc/letsencrypt:ro' +is out part 'file_put $SERVICE_CONFIGSTORE/etc/apache2/sites-enabled/www.example.com.conf + | + | + | ServerAdmin contact@www.example.com + | ServerName www.example.com + | + | ServerSignature Off' RTRIM +is out part ' + | ## Auto-redirection from http to https + | RewriteEngine On + | RewriteCond %{HTTPS} off + | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] +' + + +try " +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export DATASTORE='\$DATASTORE' +export SERVICE_NAME='\$SERVICE_NAME' +export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' +export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' +RELATIONS=(cert-provider foo a True) +CFG=' +domain: www.example.com +server-aliases: + - example.fr + - example.de +ssl: + foo: 12 +' +ADDITION=' +apache-custom-rules: + - | + ## Auto-redirection from http to https + RewriteEngine On + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA]' +MERGE_YAML_STR=\" +fcab3acadc661133: | +\$(echo \"\$CFG\" | prefix ' ') +\$(echo \"\$ADDITION\" | prefix ' ') +\" +apache_vhost_create publish_dir \"\$CFG\" + +" "known cert key - multiple server-aliases" +is errlvl 0 +is err part "\ +relation-set apache-custom-rules: + | - | + | ## Auto-redirection from http to https + | RewriteEngine On + | RewriteCond %{HTTPS} off + | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] + |" +is out reg 'Calling: compose .*foo: options: .*run --rm --service-ports foo crt create www.example.com example.fr example.de\s+ +' +is out part 'config-add + | services: + | $MASTER_TARGET_SERVICE_NAME: + | volumes: + | - $DATASTORE/foo/etc/letsencrypt:/etc/letsencrypt:ro' +is out part 'file_put $SERVICE_CONFIGSTORE/etc/apache2/sites-enabled/www.example.com.conf + | + | + | ServerAdmin contact@www.example.com + | ServerName www.example.com + | ServerAlias example.fr + | ServerAlias example.de + | ServerSignature Off' RTRIM +is out part ' + | ## Auto-redirection from http to https + | RewriteEngine On + | RewriteCond %{HTTPS} off + | RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA] +' diff --git a/apache/test/vhost_files b/apache/test/vhost_files index 2b4d5fe..039cd8f 100644 --- a/apache/test/vhost_files +++ b/apache/test/vhost_files @@ -29,6 +29,12 @@ relation-set() { } export -f relation-set +cfg-get-value() { + local key="$1" + shyaml get-value "$key" 2>/dev/null +} +export -f cfg-get-value + get_service_relations() { printf "%s\0" "${RELATIONS[@]}" } @@ -73,7 +79,39 @@ chmod() { } export -f chmod +merge_yaml_str() { + local arg_hash="$(H "$@" | cut -c -16)" + local i + echo "Calling: merge_yaml_str" >&2 + ((i=0)) + for arg in "$@"; do + echo " arg$((i++)):" + echo "$arg" | prefix " | " + done >&2 + echo " H> $arg_hash" >&2 + while read-0 h res; do + if [[ "$arg_hash" == "$h" ]]; then + echo "Mock hash matched, returning:" >&2 + echo "$res" | prefix " | " >&2 + echo "$res" + return 0 + fi + done < <(e "$MERGE_YAML_STR" | shyaml key-values-0) + printf "" +} +export -f merge_yaml_str + +yaml_get_interpret() { + shyaml get-value +} +export -f yaml_get_interpret +yaml_key_val_str() { + printf "%s: %s" "$1" "$2" +} +export -f yaml_key_val_str cached_cmd_on_base_image() { echo "called: $FUNCNAME $@" >&2 @@ -91,9 +129,9 @@ export -f cached_cmd_on_base_image try " export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -apache_vhost_create" +apache_vhost_create publish_dir ' +domain: www.example.com +'" is errlvl 0 is err part "\ relation-set protocol: @@ -102,12 +140,24 @@ is out reg '^file_put \$SERVICE_CONFIGSTORE/.*/www.example.com.conf' try " export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN CFG=' +domain: www.example.com ssl: true ' -apache_vhost_create" +ADDITION=' +apache-custom-rules: + - | + ## Auto-redirection from http to https + RewriteEngine On + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA]' +MERGE_YAML_STR=\" +6b92a84e9d93e4a1: | +\$(echo \"\$CFG\" | prefix ' ') +\$(echo \"\$ADDITION\" | prefix ' ') +\" +apache_vhost_create publish_dir \"\$CFG\" +" is errlvl 0 is err part "## Auto-redirection from http to https" is err part "\ @@ -121,16 +171,28 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN CFG=' +domain: www.example.com ssl: key: | a b cert: c ' -apache_vhost_create" +ADDITION=' +apache-custom-rules: + - | + ## Auto-redirection from http to https + RewriteEngine On + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L,QSA]' +MERGE_YAML_STR=\" +3b76349cfba9d3f2: | +\$(echo \"\$CFG\" | prefix ' ') +\$(echo \"\$ADDITION\" | prefix ' ') +\" +apache_vhost_create publish_dir \"\$CFG\" +" is errlvl 0 is err part "## Auto-redirection from http to https" is err part "\ @@ -152,13 +214,13 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -DOMAIN=www.example.com -DOCKER_SITE_PATH=/var/www/\$DOMAIN -export CFG=' +CFG=' +domain: www.example.com creds: toto: xxx ' -apache_vhost_create" +apache_vhost_create publish_dir \"\$CFG\" +" is errlvl 0 is err part "\ relation-set protocol: @@ -168,7 +230,7 @@ is out reg 'docker run -i --entrypoint /bin/bash .* docker/apache' ## -## apache_proxy_dir +## apache_publish_dir ## try " @@ -177,11 +239,10 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -export CFG=' +apache_publish_dir ' creds: toto: xxx -' -apache_publish_dir" +'" "missing domain" is errlvl 1 ## no domain @@ -192,12 +253,12 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -export CFG=' +apache_publish_dir ' domain: www.example.com creds: toto: xxx ' -apache_publish_dir" +" is errlvl 0 is err reg 'setfacl -R -m g::rx \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com' is err reg 'cached_cmd_on_base_image apache id -g www-data' @@ -210,7 +271,7 @@ export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -export CFG=' +apache_publish_dir ' domain: www.example.com creds: toto: xxx @@ -219,7 +280,7 @@ data-dirs: - b - c ' -apache_publish_dir" +" is errlvl 0 is err reg 'setfacl -R -m g::rwx \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/a \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/b \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/c' is err reg 'setfacl -R -d -m g::rwx \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/a \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/b \$DATASTORE/\$BASE_SERVICE_NAME/var/www/www.example.com/c' @@ -233,7 +294,7 @@ export CONFIGSTORE='\$CONFIGSTORE' export BASE_SERVICE_NAME='\$BASE_SERVICE_NAME' export MASTER_BASE_SERVICE_NAME='\$MASTER_BASE_SERVICE_NAME' export MASTER_TARGET_SERVICE_NAME='\$MASTER_TARGET_SERVICE_NAME' -export CFG=' +apache_publish_dir ' domain: www.example.com location: /opt/apps/newlocation creds: @@ -243,7 +304,7 @@ data-dirs: - b - c ' -apache_publish_dir" +" is errlvl 0 is err reg 'mkdir -p /opt/apps/newlocation' is err reg 'setfacl -R -m g::rx /opt/apps/newlocation'