Browse Source

new: [apache] improve domain specification and provide service to domain mapping facility

rallly
Valentin Lab 10 months ago
parent
commit
8b46dce6cb
  1. 188
      apache/README.org
  2. 29
      apache/README.rst
  3. 4
      apache/hooks/publish_dir-relation-joined
  4. 4
      apache/hooks/web_proxy-relation-joined
  5. 308
      apache/lib/common
  6. 316
      apache/test/get_domains
  7. 11
      apache/test/vhost
  8. 2
      apache/test/vhost_cert_provider

188
apache/README.org

@ -0,0 +1,188 @@
* Usage
Other services will often require a service managed with this charm to
act as a HTTP/HTTPS front-end. It can provide certificates with HTTPS.
** Domain assignment
Services using relation =web-proxy= or =publish-dir= will be required
to be assigned a domain name for the virtual host that will be
created.
*** Domain sources
This domain name can be set (in order of priority), the first source
giving a name will be taken.
- *Relation's options* (=web-proxy= or =publish-dir=)
Using =domain= option, and optionally the deprecated
=server-aliases= for additional names.
#+begin_src yaml
myservice:
# ...
relations:
web-proxy:
apache:
domain: mydomain.org
#server-aliases:
# - www.mydomain.org
# - pro.mydomain.org
#+end_src
- *Apache service's options*, using a =service-domain-name= mapping:
#+begin_src yaml
myservice:
# ...
apache:
options:
service-domain-map:
# ...
myservice:
- mydomain.org
- www.mydomain.org
- pro.mydomain.org
# ...
#+end_src
- *the service name* itself if is a domain name:
#+begin_src yaml
www.mydomain.org:
# ...
#+end_src
Please note that this is not recommended, and will be deprecated.
*** Domain and alternate domains
Every source (except the one coming out from the domain name), can use
several ways to provide *more than one domain name*.
Please remember:
- At least one domain name needs to be provided
- and the first domain can't use wildcards and will be considered the main domain name.
If other domains are specified, they will be used as aliases, and
wildcard (using ~*~) is supported.
Additionally, bash braces expansion and regex matching are
available. Space separated YAML string or YAML sequences are
supported, also as mix of both.
As examples, notice the following are equivalent and will serve
=myservice= on the exact same set of domain names:
#+begin_src yaml
myservice:
relations:
web-proxy:
domain:
## A yaml list
- myservice.home.org
- mydomain.org
- www.mydomain.org
- pro.mydomain.org
- *.myservice.hop.org
#+end_src
#+begin_src yaml
myservice:
# ... no domain set in relation
apache:
options:
service-domain-map:
## A yaml list as a mapping value
myservice:
- myservice.home.org
- {,www.,pro.}mydomain.org ## bash braces expansion used
- *.myservice.hop.org
#+end_src
#+begin_src yaml
myservice:
# ...
apache:
options:
service-domain-map:
## space separated YAML string and bash braces expansion
myservice: myservice.home.org {,www.,pro.}mydomain.org *.myservice.hop.org
#+end_src
#+begin_src yaml
myservice:
# ...
apache:
options:
service-domain-map:
## Leveraging bash braces expansion and regex replacement
.*: {$0.home,{,www.,pro.}mydomain,*.$0.hop}.org
#+end_src
** Domain mapping
You can automatically assign a domain to services in relation
=web-proxy= or =publish-dir= with services managed by this charm using
the =service-domain-name= option. For instance:
#+begin_src yaml
apache:
options:
service-domain-map:
.*: $0.mydomain.org
#+end_src
Where ~mydomain.org~ stands for the domain where most of your services
will be served. You can override this behavior for some services:
- by adding a matching rule *before* the given rule.
- by specifying a =domain= in the relation's options.
first rule matching will end the mapping:
#+begin_src yaml
apache:
options:
service-domain-map:
foo: www.mydomain.org
bar: beta.myotherdomain.com
#+end_src
Allows to distribute services to domains quite freely.
* SSH Tunnel
On the server side, you can configure your compose file::
#+begin_src yaml
apache:
options:
ssh-tunnel:
domain: ssh.domain.com ## required
#ssh: ... ## required, but automatically setup if you
## provide a ``cert-provider`` to ``apache``.
#+end_src
On the client side you should add this to your ``~/.ssh/config``::
#+begin_src conf-space
Host ssh.domain.com
Port 443
ProxyCommand proxytunnel -q -E -p ssh.domain.com:443 -d ssh.domain.com:22
DynamicForward 1080
ServerAliveInterval 60
#+end_src
If it doesn't work, you can do some checks thanks to this command::
#+begin_example
$ proxytunnel -E -p ssh.domain.com:443 -d ssh.domain.com:22 -v \
-H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n"
#+end_example

29
apache/README.rst

@ -1,29 +0,0 @@
SSH Tunnel
----------
On the server side, you can configure your compose file::
apache:
options:
ssh-tunnel:
domain: ssh.domain.com ## required
#ssh: ... ## required, but automatically setup if you
## provide a ``cert-provider`` to ``apache``.
On the client side you should add this to your ``~/.ssh/config``::
Host ssh.domain.com
Port 443
ProxyCommand proxytunnel -q -E -p ssh.domain.com:443 -d ssh.domain.com:22
DynamicForward 1080
ServerAliveInterval 60
If it doesn't work, you can do some checks thanks to this command::
$ proxytunnel -E -p ssh.domain.com:443 -d ssh.domain.com:22 -v \
-H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n"

4
apache/hooks/publish_dir-relation-joined

@ -6,8 +6,10 @@
set -e set -e
service_def=$(get_compose_service_def "$SERVICE_NAME")
cfg=$(relation-get) cfg=$(relation-get)
apache_publish_dir "$cfg"
apache_publish_dir "$cfg" "$service_def"
APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true
if [ "$APACHE_CORE_RULES" ]; then if [ "$APACHE_CORE_RULES" ]; then

4
apache/hooks/web_proxy-relation-joined

@ -5,8 +5,10 @@ set -e
. lib/common . lib/common
service_def=$(get_compose_service_def "$SERVICE_NAME")
cfg=$(relation-get) cfg=$(relation-get)
apache_proxy_dir "$cfg"
apache_proxy_dir "$cfg" "$service_def"
APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true APACHE_CORE_RULES=$(relation-get apache-core-rules 2>/dev/null) || true
if [ "$APACHE_CORE_RULES" ]; then if [ "$APACHE_CORE_RULES" ]; then

308
apache/lib/common

@ -1,22 +1,163 @@
# -*- mode: shell-script -*- # -*- mode: shell-script -*-
replace_by_rematch_pattern() {
local input="$1" output="" char next_char i
# Loop through each character in the string
for (( i=0; i<${#input}; i++ )); do
char="${input:$i:1}"
# If a dollar sign is found
if [[ "$char" == '$' ]]; then
next_char="${input:$((i+1)):1}"
# Check if next character is a digit
if [[ "$next_char" =~ [0-9] ]]; then
# Replace $N with ${rematch[N]}
output+='${rematch['"$next_char"']}'
((i++)) # Skip next character as it's already processed
continue
fi
fi
get_domain() {
local cfg="$1" cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$SERVICE_NAME" "$MASTER_BASE_SERVICE_NAME" "$@")" \
domain
output+="$char"
done
echo "$output"
}
export -f replace_by_rematch_pattern
get_domains() {
local cfg="$1" service_cfg="$2" cache_file="$state_tmpdir/$FUNCNAME.cache.$(H "$SERVICE_NAME" "$MASTER_BASE_SERVICE_NAME" "$@")" \
domains new_domains maps m regex rematch type value key domain
if [ -e "$cache_file" ]; then if [ -e "$cache_file" ]; then
cat "$cache_file" cat "$cache_file"
return 0 return 0
fi fi
domain=$(e "$cfg" | cfg-get-value domain 2>/dev/null) || true
if [ "$domain" ]; then
echo "$domain" | tee "$cache_file"
elif [[ "$BASE_SERVICE_NAME" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then
echo "$BASE_SERVICE_NAME" | tee "$cache_file"
else
err "You must specify a ${WHITE}domain$NORMAL option. (${FUNCNAME[*]})"
domains=()
for key in domain server-aliases; do
type=$(e "$cfg" | shyaml -q get-type "$key" 2>/dev/null) || true
value=$(e "$cfg" | shyaml -q get-value -y "$key" 2>/dev/null) || true
while true; do
case "$type" in
sequence)
while read-0 domain; do
if [[ "$domain" != "None" ]]; then
if [ "${#domains[@]}" == 0 ] && [ "$key" == "server-aliases" ]; then
err "You can't specify server aliases if you don't have a domain."
return 1
fi
domains+=("$domain")
fi
done < <(e "$value" | shyaml get-values-0)
;;
str)
if ! domain=$(e "$value" | shyaml get-value 2>/dev/null); then
err "Failed to get domain value from config."
return 1
fi
[[ "$domain" == "" ]] && break
if [ "${#domains[@]}" == 0 ] && [ "$key" == "server-aliases" ]; then
err "You can't specify server aliases if you don't have a domain."
return 1
fi
domains+=("$domain")
;;
NoneType|"")
:
;;
\!*)
value=$(e "$value" | cfg-get-value "$key" 2>/dev/null) || true
type=$(e "$value" | shyaml -q get-type) || true
continue
;;
esac
break
done
## check and expand domain
new_domains=()
for domain in "${domains[@]}"; do
if ! [[ "$domain" =~ ^[a-z0-9\{\}*\ \,.-]+$ ]]; then
err "Invalid domain value '$domain' expression in ${WHITE}$key$NORMAL option."
return 1
fi
new_domains+=($(eval echo "${domain//\*/\\*}"))
done
domains=("${new_domains[@]}")
done
## Fill with service-domain-map
if [ "${#domains[@]}" == 0 ] &&
service_domain_map=$(e "$service_cfg" | cfg-get-value 'options.service-domain-map' 2>/dev/null) &&
[ -n "$service_domain_map" ]; then
while read-0 regex map; do
if [[ "$BASE_SERVICE_NAME" =~ ^$regex$ ]]; then
rematch=("${BASH_REMATCH[@]}")
maps=()
type=$(e "$map" | shyaml -q get-type 2>/dev/null) || true
value=$(e "$map" | shyaml -q get-value -y 2>/dev/null) || true
case "$type" in
sequence)
while read-0 m; do
if [[ "$m" != "None" ]] && [ -n "$m" ]; then
maps+=("$m")
fi
done < <(e "$value" | shyaml get-values-0)
;;
str)
if ! m=$(e "$value" | shyaml get-value 2>/dev/null); then
err "Failed to get mapping value from config."
return 1
fi
[ -z "$m" ] && continue
maps+=("$m")
;;
NoneType|"")
:
;;
esac
for map in "${maps[@]}"; do
if ! [[ "$map" =~ ^([a-z0-9*\{\}\ \,.-]|\$[0-9])+$ ]]; then
err "Invalid mapping value '$map' in ${WHITE}service-domain-map$NORMAL option."
return 1
fi
map="${map//\*/\\*}" ## protect star from eval
map=$(replace_by_rematch_pattern "$map")
domains+=($(set -- "${BASH_REMATCH[@]}"; eval echo "${map//\*/\\*}"))
done
break
fi
done < <(e "$service_domain_map" | yq e -0 'to_entries | .[] | [.key, .value] |.[]')
fi
if [ "${#domains[@]}" == 0 ] &&
[[ "$BASE_SERVICE_NAME" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then
domains+=("$BASE_SERVICE_NAME")
fi
new_domains=()
## remove duplicates
for domain in "${domains[@]}"; do
if ! [[ " ${new_domains[*]} " == *" $domain "* ]]; then
new_domains+=("$domain")
fi
done
domains=("${new_domains[@]}")
if [ "${#domains[@]}" == 0 ]; then
err "No domain name set for your service ${YELLOW}$BASE_SERVICE_NAME${NORMAL}."
echo " You can specify a ${WHITE}domain$NORMAL option in the" \
"relation with ${YELLOW}$TARGET_SERVICE_NAME${NORMAL}." >&2
echo " Or you can specify a service to domain mapping in" \
"${WHITE}service-domain-map${NORMAL} option of ${YELLOW}$TARGET_SERVICE_NAME${NORMAL}." >&2
return 1 return 1
fi fi
## check that first domain should not have a wildcard
if [[ "${domains[0]}" == *"*"* ]]; then
err "First domain name '${domains[0]}' can't contain a wildcard."
return 1
fi
echo "${domains[@]}" | tee "$cache_file"
} }
@ -25,17 +166,17 @@ get_domain() {
## ##
apache_proxy_dir() { apache_proxy_dir() {
local cfg="$1" domain
apache_vhost_create web_proxy "$cfg" || return 1
local cfg="$1" service_cfg="$2"
apache_vhost_create web_proxy "$cfg" "$service_cfg" || return 1
} }
export -f apache_proxy_dir export -f apache_proxy_dir
apache_publish_dir() { 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"
local cfg="$1" service_cfg="$2"
apache_vhost_create publish_dir "$cfg" "$service_cfg" || return 1
apache_code_dir "$cfg" "$service_cfg" || return 1
apache_data_dirs "$cfg" "$service_cfg"
} }
export -f apache_publish_dir export -f apache_publish_dir
@ -51,7 +192,7 @@ apache_ssh_tunnel() {
err "${WHITE}ssl${NORMAL} must be valued in ${WHITE}ssh-tunnel${NORMAL} config." err "${WHITE}ssl${NORMAL} must be valued in ${WHITE}ssh-tunnel${NORMAL} config."
return 1 return 1
fi fi
apache_vhost_create ssh_tunnel "$cfg" ",https," "000-$domain" || return 1
apache_vhost_create ssh_tunnel "$cfg" "" ",https," "000-$domain" || return 1
} }
export -f apache_publish_dir export -f apache_publish_dir
@ -62,7 +203,7 @@ export -f apache_publish_dir
apache_vhost_create() { apache_vhost_create() {
local type="$1" cfg="$2" protocols="$3" dest="$4" custom_rules vhost_statement creds \
local type="$1" cfg="$2" service_cfg="$3" protocols="$4" dest="$5" custom_rules vhost_statement creds \
redirect domain ssl_plugin_fun ssl_cfg_value ssl_cfg_options redirect domain ssl_plugin_fun ssl_cfg_value ssl_cfg_options
export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled" export APACHE_CONFIG_LOCATION="$SERVICE_CONFIGSTORE/etc/apache2/sites-enabled"
@ -73,21 +214,21 @@ apache_vhost_create() {
protocols=$(__vhost_cfg_normalize_protocol "$cfg") || return 1 protocols=$(__vhost_cfg_normalize_protocol "$cfg") || return 1
fi fi
domain=$(get_domain "$cfg") && {
[ "$RELATION_DATA_FILE" ] && relation-set domain "$domain"
domains=($(get_domains "$cfg" "$service_cfg")) && {
[ "$RELATION_DATA_FILE" ] && relation-set domain "${domains[0]}"
} }
echo "Domains: ${domains[*]}" >&2
if is_protocol_enabled https "$protocols"; then if is_protocol_enabled https "$protocols"; then
[ "$RELATION_DATA_FILE" ] && { [ "$RELATION_DATA_FILE" ] && {
relation-set url "https://$domain"
relation-set url "https://${domains[0]}"
} }
if [ -z "$domain" ]; then
if [ "${#domains[@]}" == 0 ]; then
err "You must specify a domain for ssl to work." err "You must specify a domain for ssl to work."
return 1 return 1
fi fi
read-0 ssl_plugin_fun ssl_cfg_value ssl_cfg_options < <(ssl_get_plugin_fun "$cfg") || return 1 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" "$domain" || return 1
"$ssl_plugin_fun"_vars "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" "${domains[*]}" || return 1
redirect=$(e "$cfg" | cfg-get-value 'redirect-to-ssl' 2>/dev/null) || true redirect=$(e "$cfg" | cfg-get-value 'redirect-to-ssl' 2>/dev/null) || true
if is_protocol_enabled http "$protocols"; then if is_protocol_enabled http "$protocols"; then
redirect=${redirect:-true} redirect=${redirect:-true}
@ -116,15 +257,15 @@ $(if [ "$custom_rules" ]; then
fi fi
else else
[ "$RELATION_DATA_FILE" ] && { [ "$RELATION_DATA_FILE" ] && {
relation-set url "http://$domain"
relation-set url "http://${domains[0]}"
} }
fi fi
vhost_statement=$(apache_vhost_statement "$type" "$protocols" "$cfg" "$domain") || {
vhost_statement=$(apache_vhost_statement "$type" "$protocols" "$cfg" "${domains[*]}") || {
err "Failed to get vhost statement for type $type on ${protocols:1:-1}" err "Failed to get vhost statement for type $type on ${protocols:1:-1}"
return 1 return 1
} }
dest=${dest:-$domain}
dest=${dest:-${domains[0]}}
if [ -z "$dest" ]; then if [ -z "$dest" ]; then
err "Please set either a domain or set a destination file." err "Please set either a domain or set a destination file."
return 1 return 1
@ -137,7 +278,7 @@ $(if [ "$custom_rules" ]; then
fi fi
if is_protocol_enabled https "$protocols"; then if is_protocol_enabled https "$protocols"; then
"$ssl_plugin_fun"_prepare "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" || return 1
"$ssl_plugin_fun"_prepare "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" "${domains[*]}" || return 1
fi fi
} }
@ -296,18 +437,18 @@ ssl_get_plugin_fun() {
ssl_fallback_vars() { ssl_fallback_vars() {
local cfg="$1" ssl_cfg="$2" value="$3" domain="$4" cert key ca_cert domain
local cfg="$1" ssl_cfg="$2" value="$3" domains="$4" cert key ca_cert
domains=($domains)
if __vhost_cfg_ssl_cert=$(echo "$ssl_cfg" | shyaml get-value cert 2>/dev/null); then 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
__vhost_cfg_SSL_CERT_LOCATION=/etc/ssl/certs/${domains[0]}.pem
fi fi
if __vhost_cfg_ssl_key=$(echo "$ssl_cfg" | shyaml get-value key 2>/dev/null); then 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
__vhost_cfg_SSL_KEY_LOCATION=/etc/ssl/private/${domains[0]}.key
fi fi
if __vhost_cfg_ssl_ca_cert=$(echo "$ssl_cfg" | shyaml get-value ca-cert 2>/dev/null); then 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
__vhost_cfg_SSL_CA_CERT_LOCATION=/etc/ssl/certs/${domains[0]}-ca.pem
fi fi
} }
@ -338,29 +479,20 @@ $volumes
} }
ssl_plugin_cert-provider_vars() { ssl_plugin_cert-provider_vars() {
local cfg="$1" ssl_cfg="$2" value="$3" domain="$4"
__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
local cfg="$1" ssl_cfg="$2" value="$3" domains="$4"
domains=($domains)
__vhost_cfg_SSL_CERT_LOCATION=/etc/letsencrypt/live/${domains[0]}/cert.pem
__vhost_cfg_SSL_KEY_LOCATION=/etc/letsencrypt/live/${domains[0]}/privkey.pem
__vhost_cfg_SSL_CHAIN=/etc/letsencrypt/live/${domains[0]}/chain.pem
} }
ssl_plugin_cert-provider_prepare() { ssl_plugin_cert-provider_prepare() {
local cfg="$1" ssl_cfg="$2" service="$3" options domain server_aliases
domain=$(get_domain "$cfg") || return 1
local cfg="$1" ssl_cfg="$2" service="$3" domains="$4" options server_aliases
domains=($domains)
options=$(yaml_key_val_str "options" "$ssl_cfg") || return 1 options=$(yaml_key_val_str "options" "$ssl_cfg") || return 1
service_config=$(yaml_key_val_str "$service" "$options") 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" crt "$service" \ compose --debug --add-compose-content "$service_config" crt "$service" \
create "$domain" "${server_aliases[@]}" || {
create "${domains[@]}" || {
err "Failed to launch letsencrypt for certificate creation." err "Failed to launch letsencrypt for certificate creation."
return 1 return 1
} }
@ -399,16 +531,16 @@ apache_passwd_file() {
## Produce the full statements depending on relation-get informations ## Produce the full statements depending on relation-get informations
apache_vhost_statement() { apache_vhost_statement() {
local type="$1" protocols="$2" cfg="$3" domain="$4" \
local type="$1" protocols="$2" cfg="$3" domains="$4" \
vhost_statement vhost_statement
if is_protocol_enabled http "$protocols"; then if is_protocol_enabled http "$protocols"; then
__vhost_full_vhost_statement "$type" http "$cfg" "$domain" || return 1
__vhost_full_vhost_statement "$type" http "$cfg" "$domains" || return 1
fi fi
if is_protocol_enabled https "$protocols"; then 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 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" "$domain" || return 1
vhost_statement=$(__vhost_full_vhost_statement "$type" https "$cfg" "$domain") || return 1
"$ssl_plugin_fun"_vars "$cfg" "$ssl_cfg_options" "$ssl_cfg_value" "$domains" || return 1
vhost_statement=$(__vhost_full_vhost_statement "$type" https "$cfg" "$domains") || return 1
cat <<EOF cat <<EOF
<IfModule mod_ssl.c> <IfModule mod_ssl.c>
@ -421,13 +553,13 @@ export -f apache_vhost_statement
apache_code_dir() { apache_code_dir() {
local cfg="$1" www_data_gid local_path
local cfg="$1" service_cfg="$2" www_data_gid local_path
www_data_gid=$(cached_cmd_on_base_image "$TARGET_SERVICE_NAME" 'id -g www-data') || { www_data_gid=$(cached_cmd_on_base_image "$TARGET_SERVICE_NAME" 'id -g www-data') || {
debug "Failed to query for www-data gid in ${DARKYELLOW}$TARGET_SERVICE_NAME${NORMAL} base image." debug "Failed to query for www-data gid in ${DARKYELLOW}$TARGET_SERVICE_NAME${NORMAL} base image."
return 1 return 1
} }
domain=$(get_domain "$cfg") || return 1
local_path="/var/www/${domain}"
domains=($(get_domains "$cfg" "$service_cfg")) || return 1
local_path="/var/www/${domains[0]}"
host_path=$(e "$cfg" | cfg-get-value location 2>/dev/null) || host_path=$(e "$cfg" | cfg-get-value location 2>/dev/null) ||
host_path="$DATASTORE/$BASE_SERVICE_NAME${local_path}" host_path="$DATASTORE/$BASE_SERVICE_NAME${local_path}"
@ -455,13 +587,13 @@ $SERVICE_NAME:
} }
apache_data_dirs() { apache_data_dirs() {
local cfg="$1" data_dirs dst data fdir to_create
local cfg="$1" service_cfg="$2" data_dirs dst data fdir to_create
data_dirs=$(e "$cfg" | cfg-get-value data-dirs 2>/dev/null | shyaml get-values 2>/dev/null) || true data_dirs=$(e "$cfg" | cfg-get-value data-dirs 2>/dev/null | shyaml get-values 2>/dev/null) || true
if [ -z "$data_dirs" ]; then if [ -z "$data_dirs" ]; then
return 0 return 0
fi fi
domain=$(get_domain "$cfg") || return 1
local_path="/var/www/${domain}"
domains=($(get_domains "$cfg" "$service_cfg")) || return 1
local_path="/var/www/${domains[0]}"
dst=$DATASTORE/$BASE_SERVICE_NAME$local_path dst=$DATASTORE/$BASE_SERVICE_NAME$local_path
data=() data=()
while IFS="," read -ra addr; do while IFS="," read -ra addr; do
@ -577,26 +709,15 @@ EOF
__vhost_head_statement() { __vhost_head_statement() {
local cfg="$1" protocol="$2" domain="$3" server_aliases admin_mail prefix
local cfg="$1" protocol="$2" domains="$3" server_aliases admin_mail prefix
domains=($domains)
admin_mail=$(e "$1" | cfg-get-value "admin-mail" 2>/dev/null) || true admin_mail=$(e "$1" | cfg-get-value "admin-mail" 2>/dev/null) || true
if [ -z "$admin_mail" ]; then if [ -z "$admin_mail" ]; then
if [ -z "$domain" ]; then
if [ "${#domains[@]}" == 0 ]; then
admin_mail=webmaster@localhost admin_mail=webmaster@localhost
else else
admin_mail=${admin_mail:-contact@$domain}
fi
fi
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
admin_mail=${admin_mail:-contact@${domains[0]}}
fi fi
else
server_aliases=()
fi fi
if [ "$protocol" == "https" ]; then if [ "$protocol" == "https" ]; then
@ -605,8 +726,8 @@ __vhost_head_statement() {
prefix= prefix=
fi fi
if [ "$domain" ]; then
log_prefix="${prefix}${domain}_"
if [ "${#domains[@]}" != 0 ]; then
log_prefix="${prefix}${domains[0]}_"
else else
log_prefix="" log_prefix=""
fi fi
@ -614,8 +735,8 @@ __vhost_head_statement() {
cat <<EOF cat <<EOF
$( $(
echo "ServerAdmin ${admin_mail}" echo "ServerAdmin ${admin_mail}"
[ "$domain" ] && echo "ServerName ${domain}"
for alias in "${server_aliases[@]}"; do
[ "${#domains[@]}" != 0 ] && echo "ServerName ${domains[0]}"
for alias in "${domains[@]:1}"; do
[ "$alias" ] || continue [ "$alias" ] || continue
echo "ServerAlias $alias" echo "ServerAlias $alias"
done done
@ -693,14 +814,15 @@ target-get() {
} }
__vhost_proxy_statement() { __vhost_proxy_statement() {
local protocol="$1" cfg="$2" dest="$3" proxy_pass_options target
local protocol="$1" cfg="$2" domains="$3" proxy_pass_options target
domains=($domains)
target=$(target-get "$cfg") || return 1 target=$(target-get "$cfg") || return 1
proxy_pass_options=($(e "$cfg" | shyaml -y -q get-value apache-proxy-pass-options | yaml_get_values)) proxy_pass_options=($(e "$cfg" | shyaml -y -q get-value apache-proxy-pass-options | yaml_get_values))
if [ "${#proxy_pass_options[@]}" == 0 ]; then if [ "${#proxy_pass_options[@]}" == 0 ]; then
proxy_pass_options=(${proxy_pass_options:-"retry=0"}) proxy_pass_options=(${proxy_pass_options:-"retry=0"})
fi fi
dest=${domains[0]}
dest=${dest:-html}
cat <<EOF cat <<EOF
@ -733,11 +855,12 @@ EOF
} }
__vhost_full_vhost_statement() { __vhost_full_vhost_statement() {
local type="$1" protocol="$2" cfg="$3" domain="$4" head_statement custom_rules content_statement
local type="$1" protocol="$2" cfg="$3" domains="$4" head_statement custom_rules content_statement
head_statement=$(__vhost_head_statement "$cfg" "$protocol" "$domain") || return 1
domains=($domains)
head_statement=$(__vhost_head_statement "$cfg" "$protocol" "${domains[*]}") || return 1
custom_rules=$(__vhost_custom_rules "$cfg") || return 1 custom_rules=$(__vhost_custom_rules "$cfg") || return 1
content_statement=$(__vhost_content_statement "$type" "$protocol" "$cfg" "${domain:-html}") || return 1
content_statement=$(__vhost_content_statement "$type" "$protocol" "$cfg" "${domains[*]}") || return 1
case "$protocol" in case "$protocol" in
https) https)
@ -770,7 +893,10 @@ EOF
} }
__vhost_publish_dir_statement() { __vhost_publish_dir_statement() {
local protocol="$1" cfg="$2" dest="$3" location
local protocol="$1" cfg="$2" domains="$3" location
domains=($domains)
dest=${domains[0]}
dest=${dest:-html}
local_path="/var/www/${dest}" local_path="/var/www/${dest}"
cat <<EOF cat <<EOF
@ -798,7 +924,13 @@ EOF
__vhost_tunnel_ssh_statement() { __vhost_tunnel_ssh_statement() {
local protocol="$1" cfg="$2" dest="$3" custom_rules content_statement
local protocol="$1" cfg="$2" domains="$3" custom_rules content_statement
domains=($domains)
dest=${domains[0]}
if [ "${#domains[@]}" == 0 ]; then
err "You must specify a domain for ssh tunnel to work."
return 1
fi
cat <<EOF cat <<EOF
@ -820,7 +952,7 @@ AllowConnect 22
### Accept redirect only to same domain ### Accept redirect only to same domain
<Proxy $domain>
<Proxy ${domains[0]}>
Order deny,allow Order deny,allow
$(__vhost_creds_statement "$cfg" "$dest" | prefix " ") $(__vhost_creds_statement "$cfg" "$dest" | prefix " ")
</Proxy> </Proxy>

316
apache/test/get_domains

@ -0,0 +1,316 @@
#!/bin/bash
exname=$(basename $0)
compose_core=$(which compose-core) || {
echo "Requires compose-core executable to be in \$PATH." >&2
exit 1
}
fetch-def() {
local path="$1" fname="$2"
( . "$path" 1>&2 || {
echo "Failed to load '$path'." >&2
exit 1
}
declare -f "$fname"
)
}
prefix_cmd="
. /etc/shlib
include common
include parse
. ../lib/common
$(fetch-def "$compose_core" yaml_get_values)
$(fetch-def "$compose_core" yaml_get_interpret)
" || {
echo "Couldn't build prefix cmd" >&2
exit 1
}
# mock
cfg-get-value() {
local key="$1"
shyaml get-value "$key" 2>/dev/null
}
export -f cfg-get-value
yaml_get_interpret() {
shyaml get-value
}
export -f yaml_get_interpret
export state_tmpdir=$(mktemp -d -t tmp.XXXXXXXXXX)
trap "rm -rf \"$state_tmpdir\"" EXIT
##
## Tests
##
try "
get_domains '
'"
is errlvl 1
is err reg 'Error: .*domain option.*'
is out ''
try "
get_domains '
domain: toto
'"
noerror
is out 'toto
'
try "
get_domains '
domain: toto titi
'"
noerror
is out 'toto titi
'
try "
get_domains '
domain:
- toto
'"
noerror
is out 'toto
'
try "
get_domains '
server-aliases:
'"
is errlvl 1
is err part 'Error: '
is err part 'No domain name set'
try "
get_domains '
domain:
server-aliases:
'"
is errlvl 1
is err part 'Error: '
is err part 'No domain name set'
try "
get_domains '
domain:
server-aliases:
- toto
'"
is errlvl 1
is err part 'Error: '
is err part "You can't specify server aliases if you don't have a domain"
try "
get_domains '
domain: foo
server-aliases:
- bar
'"
noerror
is out 'foo bar
'
try "
get_domains '
domain: foo
server-aliases: bar
'"
noerror
is out 'foo bar
'
try "
get_domains '
domain:
- foo
server-aliases: bar
'"
noerror
is out 'foo bar
'
try "
get_domains '
domain:
- foo{1,2} bar
server-aliases: wiz
'"
noerror
is out 'foo1 foo2 bar wiz
'
try "
get_domains '
domain:
- foo{1,2} bar
server-aliases: foo1
'"
noerror
is out 'foo1 foo2 bar
'
try "
get_domains '
domain:
- foo{1,2} bar
- \"*.zoo\"
server-aliases: foo1
'"
noerror
is out 'foo1 foo2 bar *.zoo
'
try "
get_domains '
domain: foo+ bar
'"
is errlvl 1
is err part 'Error: '
is err part 'Invalid domain value'
try "
get_domains '
domain:
' '
options.service-domain-map:
'" "empty service-domain-map"
is errlvl 1
is err part 'Error: '
is err part 'No domain name set'
is err part 'service-domain-map'
try "
BASE_SERVICE_NAME=foo
get_domains '
domain:
' '
options:
service-domain-map:
wiz: bar
'" "no map matching in service-domain-map"
is errlvl 1
is err part 'Error: '
is err part 'No domain name set'
is err part 'service-domain-map'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
wiz: bar
'" "matching map in service-domain-map"
noerror
is out 'bar
'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
wiz?: bar
wiz: bar2
'" "only first matching map in service-domain-map"
noerror
is out 'bar
'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
\"[w]i?zz?\": bar
'" "map are regex in service-domain-map"
noerror
is out 'bar
'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
(w)i(z): bar\$1\$2
'" "regex capture in service-domain-map"
noerror
is out 'barwz
'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
.*: \$0.shrubbery
'" "regex capture 2 in service-domain-map"
noerror
is out 'wiz.shrubbery
'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
.*: \$x
'" "refuse other variables in service-domain-map"
is errlvl 1
is err part 'Error: '
is err part 'Invalid mapping value'
try "
export BASE_SERVICE_NAME=wiz
get_domains '
domain:
' '
options:
service-domain-map:
.*:
- \$0.example.com
- my-\$0.domain.org
'" "list is possible as value of service-domain-map"
noerror
is out 'wiz.example.com my-wiz.domain.org
'

11
apache/test/vhost

@ -107,20 +107,13 @@ is out '<VirtualHost *:80>
## ##
try " try "
apache_vhost_statement publish_dir ,http, '
server-aliases:
- toto
' www.example.com"
apache_vhost_statement publish_dir ,http, '' 'www.example.com toto'"
noerror noerror
is out reg 'ServerAlias toto' is out reg 'ServerAlias toto'
try " try "
apache_vhost_statement publish_dir ,http, '
server-aliases:
- toto
- titi
' www.example.com"
apache_vhost_statement publish_dir ,http, '' 'www.example.com toto titi'"
noerror noerror
is out reg 'ServerAlias toto' is out reg 'ServerAlias toto'
is out reg 'ServerAlias titi' is out reg 'ServerAlias titi'

2
apache/test/vhost_cert_provider

@ -182,7 +182,7 @@ ssl:
foo: | foo: |
a a
b b
'
' ''
" "unknown cert key" " "unknown cert key"
is errlvl 1 is errlvl 1
is err reg 'Error: .*cert-provider.*' is err reg 'Error: .*cert-provider.*'

Loading…
Cancel
Save