# -*- mode: shell-script -*- 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 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" apache_vhost_create || return 1 info "Added $DOMAIN apache config." apache_code_dir || return 1 apache_data_dirs } export -f apache_publish_dir apache_vhost_create () { export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" export PROTOCOLS=$(__vhost_cfg_normalize_protocol) || return 1 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 is_protocol_enabled https; then apache_ssl_files fi } 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 protocol=${protocol:-auto} fi 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," } 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 if [ "$volumes" ]; then config-add "\ $MASTER_TARGET_CHARM_NAME: volumes: $volumes " fi } apache_passwd_file() { include parse || true ## 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 } ## 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_vhost_statement 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 "$LOCATION" || return 1 setfacl -R -m g:"$www_data_gid":rx "$LOCATION" info "Set permission for read and traversal on '$LOCATION'." config-add " $MASTER_BASE_CHARM_NAME: volumes: - $LOCATION:$DOCKER_SITE_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 return 0 fi DST=$DATASTORE/$BASE_CHARM_NAME$DOCKER_SITE_PATH DATA=() while IFS="," read -ra ADDR; do for dir in "${ADDR[@]}"; do DATA+=($dir) done 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." return 1 } info "www-data gid from ${DARKYELLOW}apache${NORMAL} is '$www_data_gid'" dirs=() for d in "${DATA[@]}"; do dirs+=("$DST/$d") done 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: volumes: $( for d in "${DATA[@]}"; do echo " - $DST/$d:$DOCKER_SITE_PATH/$d" done )" } deploy_files() { local src="$1" dst="$2" if ! [ -d "$dst" ]; then err "Destination '$dst' does not exist or is not a directory" return 1 fi ( cd "$dst" && info "In $dst:" && get_file "$src" | tar xv ) } 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" "$protocol" ## 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 }