From d975017fbd60637c5f295319c056d7c944d24c75 Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Tue, 26 Apr 2016 16:39:36 +0800 Subject: [PATCH] new: [apache] update to latests files from formanoo-charms. --- apache/build/etc/php/php.ini | 2 + apache/hooks/{install => install.old} | 4 + apache/hooks/publish_dir-relation-joined | 70 +-- apache/hooks/web_proxy-relation-joined | 48 +- apache/lib/common | 552 +++++++++++++++-------- apache/metadata.yml | 20 + apache/test/libtest | 166 +++++++ apache/test/vhost | 360 +++++++++++++++ apache/test/vhost_files | 243 ++++++++++ 9 files changed, 1166 insertions(+), 299 deletions(-) create mode 100644 apache/build/etc/php/php.ini rename apache/hooks/{install => install.old} (95%) create mode 100644 apache/metadata.yml create mode 100644 apache/test/libtest create mode 100755 apache/test/vhost create mode 100755 apache/test/vhost_files diff --git a/apache/build/etc/php/php.ini b/apache/build/etc/php/php.ini new file mode 100644 index 0000000..42c003f --- /dev/null +++ b/apache/build/etc/php/php.ini @@ -0,0 +1,2 @@ + +max_execution_time = 900 diff --git a/apache/hooks/install b/apache/hooks/install.old similarity index 95% rename from apache/hooks/install rename to apache/hooks/install.old index c4a1ec4..905416f 100755 --- a/apache/hooks/install +++ b/apache/hooks/install.old @@ -2,6 +2,10 @@ set -eux +## Old lxc script, might be used as a base for new docker Dockerfile generator. +## +## + apt-get -y install apache2 libapache2-mod-php5 libtidy-0.99-0 build-essential /dev/null | shyaml get-values 2>/dev/null) || true -LOCATION=$(relation-get location 2>/dev/null) || true -CREDS=$(relation-get creds 2>/dev/null) || true -SERVER_ALIAS=$(relation-get server-alias 2>/dev/null) || true +apache_publish_dir -export SERVER_ALIAS - -if SSL_CERT_LOCATION=$(relation-get ssl-cert-file 2>/dev/null); then - SSL_CERT=/etc/ssl/certs/${DOMAIN}.pem - config-add "\ -$MASTER_BASE_CHARM_NAME: - volumes: - - ${SSL_CERT_LOCATION}:${SSL_CERT} -" -fi - -if SSL_KEY_LOCATION=$(relation-get ssl-key-file 2>/dev/null); then - SSL_KEY=/etc/ssl/private/${DOMAIN}.key - config-add "\ -$MASTER_BASE_CHARM_NAME: - volumes: - - ${SSL_KEY_LOCATION}:${SSL_KEY} -" -fi - -if SSL_CA_CERT_LOCATION=$(relation-get ssl-ca-cert-file 2>/dev/null); then - SSL_CA_CERT=/etc/ssl/cert/${DOMAIN}-ca.pem - config-add "\ -$MASTER_BASE_CHARM_NAME: - volumes: - - ${SSL_CA_CERT_LOCATION}:${SSL_CA_CERT} -" -fi - -export CREDS -apache_ssl_add "$DOMAIN" - -if [ "$LOCATION" ]; then - if [ -d "$LOCATION" -a ! -d "$LOCATION/.git" ]; then - err "Hum, location '$LOCATION' does not seem to be a git directory." - exit 1 - fi - - if ! [ -d "$LOCATION/.git" ]; then - BRANCH=$(relation-get branch) - BRANCH=${BRANCH:-master} - - SOURCE=$(relation-get source) - parent="$(dirname "$LOCATION")" - ( - mkdir -p "$parent" && cd "$parent" - git clone -b "$BRANCH" "$SOURCE" "$(basename "$LOCATION")" - ) - fi - apache_code_dir "$DOMAIN" "$LOCATION" -else - mkdir -p "$SERVICE_DATASTORE/var/www/${DOMAIN}" || return 1 - config-add " -$MASTER_BASE_CHARM_NAME: - volumes: - - $DATASTORE/$BASE_CHARM_NAME/var/www/${DOMAIN}:/var/www/${DOMAIN} -" -fi - -if [ "$DATA_DIRS" ]; then - apache_data_dir "$DOMAIN" "$DATA_DIRS" +APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true +if [ "$APACHE_CORE_RULES" ]; then + apache_core_rules_add "$APACHE_CORE_RULES" fi diff --git a/apache/hooks/web_proxy-relation-joined b/apache/hooks/web_proxy-relation-joined index 6424810..58f1c6f 100755 --- a/apache/hooks/web_proxy-relation-joined +++ b/apache/hooks/web_proxy-relation-joined @@ -6,50 +6,10 @@ set -e -DOMAIN=$(relation-get domain) -TARGET=$(relation-get target) -APACHE_CUSTOM_RULES=$(relation-get apache-custom-rules 2>/dev/null) || true -CREDS=$(relation-get creds 2>/dev/null) || true -SERVER_ALIAS=$(relation-get server-alias 2>/dev/null) || true +apache_proxy_dir -export SERVER_ALIAS - - -if SSL_CERT_LOCATION=$(relation-get ssl-cert-file 2>/dev/null); then - SSL_CERT=/etc/ssl/certs/${DOMAIN}.pem - config-add "\ -$MASTER_TARGET_CHARM_NAME: - volumes: - - ${SSL_CERT_LOCATION}:${SSL_CERT} -" -fi - -if SSL_KEY_LOCATION=$(relation-get ssl-key-file 2>/dev/null); then - SSL_KEY=/etc/ssl/private/${DOMAIN}.key - config-add "\ -$MASTER_TARGET_CHARM_NAME: - volumes: - - ${SSL_KEY_LOCATION}:${SSL_KEY} -" -fi - -if SSL_CA_CERT_LOCATION=$(relation-get ssl-ca-cert-file 2>/dev/null); then - SSL_CA_CERT=/etc/ssl/cert/${DOMAIN}-ca.pem - config-add "\ -$MASTER_TARGET_CHARM_NAME: - volumes: - - ${SSL_CA_CERT_LOCATION}:${SSL_CA_CERT} -" +APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true +if [ "$APACHE_CORE_RULES" ]; then + apache_core_rules_add "$APACHE_CORE_RULES" fi -control=$(echo "$DOMAIN%$TARGET%$APACHE_CUSTOM_RULES%$CREDS%$SSL_CERT%$SSL_CA_CERT%$SSL_KEY" | md5_compat) - -[ "$control" == "$(relation-get control 2>/dev/null)" ] && exit 0 - -## XXXvlab: could probably figure target ourselves -apache_ssl_proxy_add "$DOMAIN" "$TARGET" "$APACHE_CUSTOM_RULES" "$CREDS" - -relation-set control "$control" - -info "Configured $DARKYELLOW$BASE_CHARM_NAME$NORMAL for proxy access." - diff --git a/apache/lib/common b/apache/lib/common index a63af3a..0cb9644 100644 --- a/apache/lib/common +++ b/apache/lib/common @@ -1,242 +1,196 @@ # -*- mode: shell-script -*- -export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" - -## XXXvlab: berk, sending conf via environment and args. -apache_ssl_proxy_config () { - local DOMAIN="$1" TARGET="$2" CUSTOM_RULES="$3" CREDS="$4" - ## target is meant to be a charm name - - PASSWORD_FILE=/etc/apache2/sites-enabled/${DOMAIN}.passwd - CRED_PART= - if [ "$CREDS" ]; then - CRED_PART=" - AuthType basic - AuthName "private" - AuthUserFile ${PASSWORD_FILE} - Require valid-user -" - rm -f "$SERVICE_CONFIGSTORE$PASSWORD_FILE" - include parse - first=c - while read-0 login password; do - debug "htpasswd -b$first ${PASSWORD_FILE} '$login' '$password'" - echo "htpasswd -b$first ${PASSWORD_FILE} '$login' '$password'" - [ "$first" ] && first= - done < <(echo "$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 - fi - if [ -z "$SSL_CERT" ]; then - SSL_CERT=/etc/ssl/certs/ssl-cert-snakeoil.pem - fi +apache_proxy_dir () { + DOMAIN=$(relation-get domain) || { + err "You must specify a ${WHITE}domain$NORMAL option in relation." + return 1 + } + proxy=yes apache_vhost_create + info "Added $DOMAIN as a proxy to $TARGET." +} +export -f apache_proxy_dir - if [ -z "$SSL_KEY" ]; then - SSL_KEY=/etc/ssl/private/ssl-cert-snakeoil.key - fi - cat < - - - ServerAdmin ${ADMIN_MAIL:-contact@$DOMAIN} - ServerName ${DOMAIN} -$( - while read-0 alias; do - echo " ServerAlias $alias" - done < <(echo "$SERVER_ALIAS" | shyaml get-values-0 2>/dev/null) -) - ServerSignature Off - CustomLog /var/log/apache2/s-${DOMAIN}_access.log combined - ErrorLog /var/log/apache2/s-${DOMAIN}_error.log - ErrorLog syslog:local2 - - - ProxyRequests Off - - Order deny,allow - Allow from all - - ProxyVia On - ProxyPass / http://$TARGET/ retry=0 - - ${CRED_PART} - ProxyPassReverse / - - - - ## Forbid any cache, this is only usefull on dev server. - #Header set Cache-Control "no-cache" - #Header set Access-Control-Allow-Origin "*" - #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" - #Header set Access-Control-Allow-Headers "origin, content-type, accept" - - RequestHeader set "X-Forwarded-Proto" "https" - - ## Fix IE problem (httpapache proxy dav error 408/409) - SetEnv proxy-nokeepalive 1 - #ServerSignature On - SSLProxyEngine On - SSLEngine On - - ## Full stance - SSLCertificateFile $SSL_CERT - SSLCertificateKeyFile $SSL_KEY - $([ "$SSL_CA_CERT" ] && echo "SSLCACertificateFile $SSL_CA_CERT") - SSLVerifyClient None - - $CUSTOM_RULES - - +apache_publish_dir () { + DOMAIN=$(relation-get domain) || { + err "You must specify a ${WHITE}domain$NORMAL option in relation." + return 1 + } + DOCKER_SITE_PATH="/var/www/${DOMAIN}" + LOCATION=$(relation-get location 2>/dev/null) || + LOCATION="$DATASTORE/$BASE_CHARM_NAME$DOCKER_SITE_PATH" - -EOF + apache_vhost_create || return 1 + info "Added $DOMAIN apache config." + apache_code_dir || return 1 + apache_data_dirs } -export -f apache_ssl_proxy_config +export -f apache_publish_dir -apache_ssl_config() { - local DOMAIN=$1 +apache_vhost_create () { + export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" + export PROTOCOLS=$(__vhost_cfg_normalize_protocol) || return 1 - if [ -z "$SSL_CERT" ]; then - SSL_CERT=/etc/ssl/certs/ssl-cert-snakeoil.pem + apache_vhost_statement "$PROTOCOLS" | + file_put "$APACHE_CONFIG_LOCATION/$prefix$DOMAIN.conf" || return 1 + + __vhost_cfg_creds_enabled=$(relation-get creds 2>/dev/null) || true + if [ "$__vhost_cfg_creds_enabled" ]; then + apache_passwd_file fi - if [ -z "$SSL_KEY" ]; then - SSL_KEY=/etc/ssl/private/ssl-cert-snakeoil.key + if is_protocol_enabled https; then + apache_ssl_files fi +} - PASSWORD_FILE=/etc/apache2/sites-enabled/${DOMAIN}.passwd - CRED_PART= - if [ "$CREDS" ]; then - CRED_PART=" - AuthType basic - AuthName \"private\" - AuthUserFile ${PASSWORD_FILE} - Require valid-user -" - include parse || true - first= - if ! [ -e "$CONFIGSTORE/$MASTER_TARGET_CHARM_NAME$PASSWORD_FILE" ]; then - debug "No file $CONFIGSTORE/$MASTER_TARGET_CHARM_NAME$PASSWORD_FILE, creating password file." || true - first=c - fi - while read-0 login password; do - debug "htpasswd -b$first ${PASSWORD_FILE} '$login' '$password'" || true - echo "htpasswd -b$first ${PASSWORD_FILE} '$login' '$password'" - if [ "$first" ]; then - first= - fi - done < <(echo "$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 + +is_protocol_enabled() { + local protocol=$1 + [[ "$PROTOCOLS" == *",$protocol,"* ]] +} +export -f is_protocol_enabled + + +__vhost_cfg_normalize_protocol() { + local protocol + + if ! protocol=$(relation-get protocol 2>/dev/null); then + protocol=auto else - CRED_PART="allow from all" + protocol=${protocol:-auto} fi - cat < + case "$protocol" in + auto) + if __vhost_cfg_ssl="$(relation-get ssl 2>/dev/null)"; then + protocol="https" + export __vhost_cfg_ssl + else + protocol="http" + fi + ;; + both) + protocol="https,http" + ;; + ssl|https) + protocol="https" + ;; + http) + protocol="http" + ;; + *) + err "Invalid value '$protocol' for ${WHITE}protocol$NORMAL option (use one of: http, https, both, auto)." + return 1 + esac + echo ",$protocol," +} - - ServerAdmin ${ADMIN_MAIL:-contact@$DOMAIN} - ServerName ${DOMAIN} -$( - while read-0 alias; do - echo " ServerAlias $alias" - done < <(echo "$SERVER_ALIAS" | shyaml get-values-0 2>/dev/null) -) - ServerSignature Off - CustomLog /var/log/apache2/s-${DOMAIN}_access.log combined - ErrorLog /var/log/apache2/s-${DOMAIN}_error.log - ErrorLog syslog:local2 +apache_ssl_files() { + local content + ## XXXvlab: called twice... no better way to do this ? + __vhost_ssl_statement > /dev/null + dst="$CONFIGSTORE/$BASE_CHARM_NAME" + volumes="" + for label in cert key ca_cert; do + content="$(eval echo "\"\$__vhost_cfg_ssl_$label\"")" + if [ "$content" ]; then + location="$(eval echo "\$__vhost_cfg_SSL_${label^^}_LOCATION")" + echo "$content" | file_put "$dst$location" + volumes="$volumes + - $dst$location:$location:ro" + fi + done - DocumentRoot /var/www/${DOMAIN} + if [ "$volumes" ]; then + config-add "\ +$MASTER_TARGET_CHARM_NAME: + volumes: +$volumes +" + fi - - Options FollowSymLinks - AllowOverride None - +} - - Options Indexes FollowSymLinks MultiViews - AllowOverride all - ${CRED_PART} - +apache_passwd_file() { + include parse || true - SSLEngine On + ## XXXvlab: called twice... no better way to do this ? + __vhost_creds_statement >/dev/null + first= + if ! [ -e "$CONFIGSTORE/$MASTER_TARGET_CHARM_NAME$password_file" ]; then + debug "No file $CONFIGSTORE/$MASTER_TARGET_CHARM_NAME$password_file, 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'" + if [ "$first" ]; then + first= + fi + done < <(echo "$__vhost_cfg_creds_enabled" | 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 +} - ## Full stance - SSLCertificateFile $SSL_CERT - SSLCertificateKeyFile $SSL_KEY - $([ "$SSL_CA_CERT" ] && echo "SSLCACertificateFile $SSL_CA_CERT") - SSLVerifyClient None +## Produce the full statements depending on relation-get informations +apache_vhost_statement() { + local vhost_statement + export PROTOCOLS="$1" - + if is_protocol_enabled http; then + __vhost_full_vhost_statement http + fi + if is_protocol_enabled https; then + cat < +$(__vhost_full_vhost_statement https | prefix " ") EOF - + fi } -export -f apache_ssl_config +export -f apache_vhost_statement -apache_ssl_add () { - local DOMAIN="$1" - DOCKER_SITE_PATH=/var/www/$DOMAIN - BASE=$DATASTORE/$BASE_CHARM_NAME - DST=$BASE$DOCKER_SITE_PATH - # [ -e "$APACHE_CONFIG_LOCATION/$DOMAIN.conf" ] && return 0 - mkdir -p "$APACHE_CONFIG_LOCATION" || return 1 - apache_ssl_config "$DOMAIN" > "$APACHE_CONFIG_LOCATION/$DOMAIN.conf" +apache_code_dir() { + local www_data_gid 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 } - mkdir -p "$DST" - setfacl -R -m g:"$www_data_gid":rx "$DST" - info "Added $DOMAIN apache config." -} -export -f apache_ssl_add - - -apache_ssl_proxy_add () { - local DOMAIN="$1" TARGET="$2" CUSTOM_RULES="$3" CREDS="$4" - - mkdir -p "$APACHE_CONFIG_LOCATION" || return 1 - apache_ssl_proxy_config "$DOMAIN" "$TARGET" "$CUSTOM_RULES" "$CREDS" > "$APACHE_CONFIG_LOCATION/$DOMAIN.conf" || return 1 - info "Added $DOMAIN as a proxy to $TARGET." -} -export -f apache_ssl_proxy_add + mkdir -p "$LOCATION" || return 1 + setfacl -R -m g:"$www_data_gid":rx "$LOCATION" + info "Set permission for read and traversal on '$LOCATION'." -apache_code_dir() { - local domain="$1" location="$2" config-add " $MASTER_BASE_CHARM_NAME: volumes: - - $location:/var/www/$domain + - $LOCATION:$DOCKER_SITE_PATH " } -apache_data_dir() { - local DOMAIN=$1 DATA_COMMA_SEPARATED=$2 +apache_data_dirs() { + + DATA_DIRS=$(relation-get data-dirs 2>/dev/null | shyaml get-values 2>/dev/null) || true + if [ -z "$DATA_DIRS" ]; then + return 0 + fi - DOCKER_SITE_PATH=/var/www/$DOMAIN - BASE=$DATASTORE/$BASE_CHARM_NAME - DST=$BASE$DOCKER_SITE_PATH + DST=$DATASTORE/$BASE_CHARM_NAME$DOCKER_SITE_PATH DATA=() while IFS="," read -ra ADDR; do for dir in "${ADDR[@]}"; do - mkdir -p "$DST/$dir" DATA+=($dir) done - done <<< "$DATA_COMMA_SEPARATED" + 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." @@ -249,7 +203,9 @@ apache_data_dir() { dirs+=("$DST/$d") done - chgrp "$www_data_gid" "${dirs[@]}" -R && chmod 775 "${dirs[@]}" -R + mkdir -p "${dirs[@]}" + setfacl -R -m g:"$www_data_gid":rwx "${dirs[@]}" + setfacl -R -d -m g:"$www_data_gid":rwx "${dirs[@]}" config-add " $MASTER_BASE_CHARM_NAME: @@ -275,3 +231,221 @@ deploy_files() { ) } export -f deploy_files + + +apache_core_rules_add() { + local conf="$1" dst="/etc/apache2/conf-enabled/$BASE_CHARM_NAME.conf" + debug "Adding core rule." + echo "$conf" | file_put "$CONFIGSTORE/$BASE_CHARM_NAME$dst" + config-add " +$MASTER_BASE_CHARM_NAME: + volumes: + - $CONFIGSTORE/$BASE_CHARM_NAME$dst:$dst:ro +" +} + + +__vhost_ssl_statement() { + local key cert ca_cert + + __vhost_cfg_ssl="$(relation-get ssl 2>/dev/null)" + if __vhost_cfg_ssl_cert=$(echo "$__vhost_cfg_ssl" | 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 "$__vhost_cfg_ssl" | 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 "$__vhost_cfg_ssl" | shyaml get-value ca-cert 2>/dev/null); then + __vhost_cfg_SSL_CA_CERT_LOCATION=/etc/ssl/certs/${DOMAIN}-ca.pem + fi + + if [ -z "$__vhost_cfg_SSL_CERT_LOCATION" ]; then + __vhost_cfg_SSL_CERT_LOCATION=/etc/ssl/certs/ssl-cert-snakeoil.pem + fi + + if [ -z "$__vhost_cfg_SSL_KEY_LOCATION" ]; then + __vhost_cfg_SSL_KEY_LOCATION=/etc/ssl/private/ssl-cert-snakeoil.key + fi + + cat </dev/null); then + echo "Allow from all" + return 0 + fi + + password_file=/etc/apache2/sites-enabled/${DOMAIN}.passwd + + cat </dev/null) || true + + if [ "$protocol" == "https" ]; then + prefix="s-" + else + prefix= + fi + + cat </dev/null) +) +ServerSignature Off +CustomLog /var/log/apache2/${prefix}${DOMAIN}_access.log combined +ErrorLog /var/log/apache2/${prefix}${DOMAIN}_error.log +ErrorLog syslog:local2 +EOF + +} + + +__vhost_custom_rules() { + local custom_rules + if custom_rules=$(relation-get apache-custom-rules 2>/dev/null); then + cat </dev/null) || true + if [ -z "$TARGET" ]; then + ## First exposed port: + base_image=$(service_base_docker_image "$BASE_CHARM_NAME") || return 1 + first_exposed_port=$(image_exposed_ports_0 "$base_image" | tr '\0' '\n' | head -n 1 | cut -f 1 -d /) || return 1 + TARGET=$MASTER_BASE_CHARM_NAME:$first_exposed_port + info "No target was specified, introspection found: $TARGET" + fi + + cat < + ProxyRequests Off + + Order deny,allow + Allow from all + + ProxyVia On + ProxyPass / http://$TARGET/ retry=0 + +$(__vhost_creds_statement | prefix " ") + ProxyPassReverse / + +$([ "$protocol" == "https" ] && echo " SSLProxyEngine On") + + +RequestHeader set "X-Forwarded-Proto" "https" + +## Fix IE problem (httpapache proxy dav error 408/409) +SetEnv proxy-nokeepalive 1 +EOF + +} + +__vhost_full_vhost_statement() { + local protocol="$1" + + case "$protocol" in + https) + PORT=443 + ;; + http) + PORT=80 + ;; + esac + + cat < + +$(__vhost_head_statement "$protocol" | prefix " ") + +$(__vhost_content_statement "$protocol" | prefix " ") + + ## Forbid any cache, this is only usefull on dev server. + #Header set Cache-Control "no-cache" + #Header set Access-Control-Allow-Origin "*" + #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" + #Header set Access-Control-Allow-Headers "origin, content-type, accept" +$([ "$protocol" == "https" ] && __vhost_ssl_statement | prefix " ") +$(__vhost_custom_rules | prefix " ") + +EOF + +} + +__vhost_publish_dir_statement() { + cat < + Options FollowSymLinks + AllowOverride None + + + + Options Indexes FollowSymLinks MultiViews + AllowOverride all +$(__vhost_creds_statement | prefix " ") + + +EOF +} diff --git a/apache/metadata.yml b/apache/metadata.yml new file mode 100644 index 0000000..ece28a7 --- /dev/null +++ b/apache/metadata.yml @@ -0,0 +1,20 @@ +description: "Apache Web Server" +maintainer: "Valentin Lab " +## XXXvlab: currently only used when building LXC along with hooks/install +## XXXvlab: docker uses the 'build' directory or the 'image:' option here. +inherit: base-0k +compatiblity: ## 'hooks/install' script was run on a these images without issues + - ubuntu/15.10 +docker-compose: + ## XXXvlab: should move to global lxc/docker compatible option + ports: + - "0.0.0.0:80:80" + - "0.0.0.0:443:443" +data-resources: + - /var/www/html + - /var/log/apache2 +config-resources: + - /etc/apache2/sites-enabled +provides: + web-proxy: + tech-dep: "reversed" diff --git a/apache/test/libtest b/apache/test/libtest new file mode 100644 index 0000000..2111cb2 --- /dev/null +++ b/apache/test/libtest @@ -0,0 +1,166 @@ +# -*- mode: shell-script -*- + +exname="$(basename $0)" + +if [ -t 1 ]; then + GRAY=$(echo -en "\e[1;30m") + RED=$(echo -en "\e[1;31m") + GREEN=$(echo -en "\e[1;32m") + YELLOW=$(echo -en "\e[1;33m") + BLUE=$(echo -en "\e[1;34m") + PINK=$(echo -en "\e[1;35m") + CYAN=$(echo -en "\e[1;36m") + WHITE=$(echo -en "\e[1;37m") + + DARKGRAY=$(echo -en "\e[0;30m") + DARKRED=$(echo -en "\e[0;31m") + DARKGREEN=$(echo -en "\e[0;32m") + DARKYELLOW=$(echo -en "\e[0;33m") + DARKBLUE=$(echo -en "\e[0;34m") + DARKPINK=$(echo -en "\e[0;35m") + DARKCYAN=$(echo -en "\e[0;36m") + + NORMAL=$(echo -en "\e[0m") +fi + +function out() { cat "$tmp_out"; } +function err() { cat "$tmp_err"; } +function errlvl() { cat "$tmp_errlvl"; } +function var() { echo "${$1}"; } + + +function time_note() { + echo "scale=1 ; l($1 - $empty_try_time) / l(10)" | bc -l +} + +function swallow_last_time() { + if test "$sum_time" == "0" -a -z "$cmd"; then ## catches first empty try '' + empty_try_time="$(echo "scale=0 ; $time_diff / 2" | bc -l )" + return 0 + fi + test -z "$test_counter" && test_counter=0 || test_counter=$[$test_counter + 1] + test -z "$sum_time" && sum_time=0 + test_name=${exname}_${test_counter} + if test "$time_diff"; then + test_time_note=$(time_note $time_diff) + profiler_info="$(echo -en "$profiler_info\n- $test_name\t$test_time_note")" + sum_time=$(echo "scale=3; $sum_time + $time_diff" | bc -l ) + fi + +} + +function time_exec() { + beg_exec=$(date +%s.%N) + ( echo "$*" | bash ) + errorlevel=$? + end_exec=$(date +%s.%N) + time_diff="$(echo "scale=3; ($end_exec - $beg_exec)*1000000" | bc | cut -f 1 -d ".")" + return $errorlevel +} + + +function try() { + swallow_last_time + cmd="$*" + desc=$(echo ; echo "$ $cmd" ) + time_exec "$prefix_cmd$cmd" 1> "$tmp_out" 2> "$tmp_err" + echo $? > "$tmp_errlvl" +} + +function apply_opt() { + code=$(cat -) + for opt in $*; do + code=$(echo "$code" | $opt) + done + echo "$code" +} + +function NOCOLOR() { + esc_char=$(echo -en "\e") + cat - | sed -r "s/$esc_char\[[0-9]+(;[0-9]+)*m//g" +} + +function NOPOS() { + esc_char=$(echo -en "\e\\[[0-9]\\+[GA]") + cat - | sed "s/$esc_char//g" +} + +function TRIM() { + cat - | sed -r "s/^ +//g" | sed -r "s/ +\$//g" +} + +function RTRIM() { + cat - | sed -r "s/ +\$//g" +} + +function SIZE() { + cat - | wc -c +} + +## usage: +## is ACTION [reg] CODE [OPTION ...] +is() { + local act="$1" type code msg + test -z "$total" && total=0 + shift + + case "$1" in + reg|part) + type="$1" + shift + ;; + *) + type="" + ;; + esac + + code="$1" + shift + #code=$(echo "$code" | apply_opt $*) + msg=$(echo "$type $code" | cut -c -30) + + output=$($act | apply_opt $*) + case "$type" in + "") + test "$code" == "$output" + ;; + "part") + [[ "$output" == *"$code"* ]] + ;; + ("reg") + echo -n "$output" | egrep -- "$code" >/dev/null 2>&1 + ;; + esac && total=$[$total + 1] && + echo "[v] is $act $msg" >/dev/null && return 0 + echo "$desc" + echo "[ ] is $act $msg" + echo "--- $*" + echo -n "$output" + echo + echo "--- DIFF" + diff -u <(echo "$code") <(echo "$output") | egrep -v '^(---|\+\+\+) /' + exit 1 + +} + +function summary() { + swallow_last_time + + echo "$profiler_info" + echo + echo "$total tests conducted in $(echo "scale=3;$sum_time/1000000" | bc) s ($(time_note $sum_time))" +} +function noerror() { + is err '' + is errlvl 0 +} + +pid=$$ +tmp_dir="/tmp" +tmp_out="$tmp_dir/test.$pid.out.tmp" +tmp_err="$tmp_dir/test.$pid.err.tmp" +tmp_errlvl="$tmp_dir/test.$pid.errlvl.tmp" + +try '' +try '' +try '' diff --git a/apache/test/vhost b/apache/test/vhost new file mode 100755 index 0000000..74efeca --- /dev/null +++ b/apache/test/vhost @@ -0,0 +1,360 @@ +#!/bin/bash + +exname=$(basename $0) + +prefix_cmd=" +. /etc/shlib + +include common +include parse + +. ../lib/common + +" +[ "$DEBUG" ] && echo "Loading testlib..." +if ! . ./libtest ; then + echo 'libtest failed to load.' + exit 1 +fi + +export COLUMNS=50 + + +test_pid_file="$tmp_dir/test.$$pid.tmp" +rm -f "$test_pid_file" + + +## +## print_bytes +## + +# mock +relation-get() { + local key="$1" + echo "$CFG" | shyaml get-value "$key" 2>/dev/null +} +export -f relation-get + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +apache_vhost_statement ,http," +noerror +is out ' + + ServerAdmin contact@www.example.com + ServerName www.example.com + + ServerSignature Off + CustomLog /var/log/apache2/www.example.com_access.log combined + ErrorLog /var/log/apache2/www.example.com_error.log + ErrorLog syslog:local2 + + ## + ## Publish directory /var/www/www.example.com + ## + + DocumentRoot /var/www/www.example.com + + + Options FollowSymLinks + AllowOverride None + + + + Options Indexes FollowSymLinks MultiViews + AllowOverride all + Allow from all + + + + ## Forbid any cache, this is only usefull on dev server. + #Header set Cache-Control "no-cache" + #Header set Access-Control-Allow-Origin "*" + #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" + #Header set Access-Control-Allow-Headers "origin, content-type, accept" + + +' RTRIM + +## +## Aliases +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +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=' +server-aliases: +- toto +- titi +' +apache_vhost_statement ,http," +noerror +is out reg 'ServerAlias toto' +is out reg 'ServerAlias titi' + + +## +## Creds +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG='' +apache_vhost_statement ,http," +noerror +is out reg 'Allow from all' + + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +creds: + toto: xxx + titi: yyy +' +apache_vhost_statement ,http," +noerror +is out reg 'AuthType basic' +is out reg 'Require valid-user' + + +## +## proxy +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +target: popo:3333 +creds: + toto: titi +' +proxy=yes apache_vhost_statement ,http," +noerror +is out reg 'ProxyPass / http://popo:3333/' +is out part ' + + AuthType basic + AuthName "private" + AuthUserFile /etc/apache2/sites-enabled/www.example.com.passwd + Require valid-user + ProxyPassReverse / + +' + +## +## ssl +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +ssl: true +target: popo:3333 +' +proxy=yes apache_vhost_statement ,https," +noerror +is out reg 'VirtualHost \*:443' +is out reg '' +is out reg 'SSLEngine On' +is out reg 'SSLProxyEngine On' +is out reg 'ssl-cert-snakeoil' +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=' +ssl: + ca-cert: a + key: b + cert: c +target: popo:3333 +' +proxy=yes apache_vhost_statement ,https," +noerror +is out reg 'SSLCertificateFile /etc/ssl/certs/www.example.com.pem' +is out reg 'SSLCertificateKeyFile /etc/ssl/private/www.example.com.key' +is out reg 'SSLCACertificateFile /etc/ssl/certs/www.example.com-ca.pem' + + +## +## CustomRules +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +ssl: + ca-cert: a + key: b + cert: c +apache-custom-rules: | + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ $1?skin=formanoo [L,QSA,R=302] +target: popo:3333 +' +proxy=yes apache_vhost_statement ,https," +noerror +is out reg 'RewriteEngine On' + + +## +## double def +## + +try " +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +ssl: + ca-cert: a + key: b + cert: c +apache-custom-rules: | + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ $1?skin=formanoo [L,QSA,R=302] +target: popo:3333 +' +proxy=yes apache_vhost_statement ,https,http," +noerror +is out ' + + ServerAdmin contact@www.example.com + ServerName www.example.com + + ServerSignature Off + CustomLog /var/log/apache2/www.example.com_access.log combined + ErrorLog /var/log/apache2/www.example.com_error.log + ErrorLog syslog:local2 + + ## + ## Proxy declaration towards popo:3333 + ## + + + ProxyRequests Off + + Order deny,allow + Allow from all + + ProxyVia On + ProxyPass / http://popo:3333/ retry=0 + + Allow from all + ProxyPassReverse / + + + + + RequestHeader set "X-Forwarded-Proto" "https" + + ## Fix IE problem (httpapache proxy dav error 408/409) + SetEnv proxy-nokeepalive 1 + + ## Forbid any cache, this is only usefull on dev server. + #Header set Cache-Control "no-cache" + #Header set Access-Control-Allow-Origin "*" + #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" + #Header set Access-Control-Allow-Headers "origin, content-type, accept" + + + + ## + ## Custom rules + ## + + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ ?skin=formanoo [L,QSA,R=302] + + + + + + + ServerAdmin contact@www.example.com + ServerName www.example.com + + ServerSignature Off + CustomLog /var/log/apache2/s-www.example.com_access.log combined + ErrorLog /var/log/apache2/s-www.example.com_error.log + ErrorLog syslog:local2 + + ## + ## Proxy declaration towards popo:3333 + ## + + + ProxyRequests Off + + Order deny,allow + Allow from all + + ProxyVia On + ProxyPass / http://popo:3333/ retry=0 + + Allow from all + ProxyPassReverse / + + SSLProxyEngine On + + + RequestHeader set "X-Forwarded-Proto" "https" + + ## Fix IE problem (httpapache proxy dav error 408/409) + SetEnv proxy-nokeepalive 1 + + ## Forbid any cache, this is only usefull on dev server. + #Header set Cache-Control "no-cache" + #Header set Access-Control-Allow-Origin "*" + #Header set Access-Control-Allow-Methods "POST, GET, OPTIONS" + #Header set Access-Control-Allow-Headers "origin, content-type, accept" + + ## + ## SSL Configuration + ## + + SSLEngine On + + SSLCertificateFile /etc/ssl/certs/www.example.com.pem + SSLCertificateKeyFile /etc/ssl/private/www.example.com.key + SSLCACertificateFile /etc/ssl/certs/www.example.com-ca.pem + SSLVerifyClient None + + + ## + ## Custom rules + ## + + RewriteEngine On + RewriteCond %{QUERY_STRING} !skin=formanoo + RewriteRule ^(/web/webclient/home.*)$ ?skin=formanoo [L,QSA,R=302] + + +' RTRIM + + +summary diff --git a/apache/test/vhost_files b/apache/test/vhost_files new file mode 100755 index 0000000..eb5fb0a --- /dev/null +++ b/apache/test/vhost_files @@ -0,0 +1,243 @@ +#!/bin/bash + +exname=$(basename $0) + +prefix_cmd=" +. /etc/shlib + +include common +include parse + +. ../lib/common + +" +[ "$DEBUG" ] && echo "Loading testlib..." +if ! . ./libtest ; then + echo 'libtest failed to load.' + exit 1 +fi + +export COLUMNS=50 + + +test_pid_file="$tmp_dir/test.$$pid.tmp" +rm -f "$test_pid_file" + +## +## Mocks +## + +relation-get() { + local key="$1" + echo "$CFG" | shyaml get-value "$key" 2>/dev/null +} +export -f relation-get + + +file_put() { + echo "file_put $1" + cat - | prefix " | " +} +export -f file_put + +docker() { + echo "docker" "$@" + echo stdin: + cat - | prefix " | " +} +export -f docker + +config-add() { + echo "config-add" + echo "$1" | prefix " | " +} +export -f config-add + +mkdir() { + echo "called: $FUNCNAME $@" >&2 +} +export -f mkdir + +setfacl() { + echo "called: $FUNCNAME $@" >&2 +} +export -f setfacl + +chgrp() { + echo "called: $FUNCNAME $@" >&2 +} +export -f chgrp + +chmod() { + echo "called: $FUNCNAME $@" >&2 +} +export -f chmod + + + +cached_cmd_on_base_image() { + echo "called: $FUNCNAME $@" >&2 + echo "stdout:" >&2 + echo "" | prefix " | " >&2 + echo "" +} +export -f cached_cmd_on_base_image + + +## +## apache_vhost_create +## + + +try " +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +apache_vhost_create" +noerror +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=' +ssl: true +' +apache_vhost_create" +noerror +is out reg '^file_put \$SERVICE_CONFIGSTORE/.*/www.example.com.conf' +is err '' + + +try " +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +CFG=' +ssl: + key: | + a + b + cert: c +' +apache_vhost_create" +noerror +is out part 'file_put $CONFIGSTORE/$BASE_CHARM_NAME/etc/ssl/certs/www.example.com.pem + | c' +is out part 'file_put $CONFIGSTORE/$BASE_CHARM_NAME/etc/ssl/private/www.example.com.key + | a + | b' +is out reg 'config-add' +is out reg ' - \$CONFIGSTORE/\$BASE_CHARM_NAME/etc/ssl/certs/www.example.com.pem:/etc/ssl/certs/www.example.com.pem:ro' +is out reg ' - \$CONFIGSTORE/\$BASE_CHARM_NAME/etc/ssl/private/www.example.com.key:/etc/ssl/private/www.example.com.key:ro' + + +try " +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +DOMAIN=www.example.com +DOCKER_SITE_PATH=/var/www/\$DOMAIN +export CFG=' +creds: + toto: xxx +' +apache_vhost_create" +noerror +is out reg "htpasswd -bc '/etc/apache2/sites-enabled/www.example.com.passwd' 'toto' 'xxx'" +is out reg 'docker run -i --entrypoint /bin/bash .* docker/apache' + + +## +## apache_proxy_dir +## + +try " +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +export CFG=' +creds: + toto: xxx +' +apache_publish_dir" +is errlvl 1 ## no domain + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +export CFG=' +domain: www.example.com +creds: + toto: xxx +' +apache_publish_dir" +is errlvl 0 +is err reg 'setfacl -R -m g::rx \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com' +is err reg 'cached_cmd_on_base_image apache id -g www-data' + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +export CFG=' +domain: www.example.com +creds: + toto: xxx +data-dirs: +- a +- b +- c +' +apache_publish_dir" +is errlvl 0 +is err reg 'setfacl -R -m g::rwx \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/a \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/b \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/c' +is err reg 'setfacl -R -d -m g::rwx \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/a \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/b \$DATASTORE/\$BASE_CHARM_NAME/var/www/www.example.com/c' + + +try " +export DATASTORE='\$DATASTORE' +export DOCKER_BASE_IMAGE=docker/apache +export SERVICE_CONFIGSTORE='\$SERVICE_CONFIGSTORE' +export CONFIGSTORE='\$CONFIGSTORE' +export BASE_CHARM_NAME='\$BASE_CHARM_NAME' +export MASTER_BASE_CHARM_NAME='\$MASTER_BASE_CHARM_NAME' +export MASTER_TARGET_CHARM_NAME='\$MASTER_TARGET_CHARM_NAME' +export CFG=' +domain: www.example.com +location: /opt/apps/newlocation +creds: + toto: xxx +data-dirs: +- a +- 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' +is out part ' | $MASTER_BASE_CHARM_NAME: + | volumes: + | - /opt/apps/newlocation:/var/www/www.example.com' + + +summary +