Files
dokku/plugins/nginx-vhosts/functions
Jose Diaz-Gonzalez 2474c87bbd Pull the deploying app image name where necessary
All of these commands should execute against the image that is in use versus the "latest" that dokku provides the system with.
2016-07-29 12:49:29 -04:00

304 lines
12 KiB
Bash
Executable File

#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/certs/functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
source "$PLUGIN_AVAILABLE_PATH/domains/functions"
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
validate_nginx() {
declare desc="validate entire nginx config"
set +e
sudo /usr/sbin/nginx -t > /dev/null 2>&1
local exit_code=$?
set -e
if [[ "$exit_code" -ne "0" ]]; then
sudo /usr/sbin/nginx -t
shopt -s nullglob
local conf_file
for conf_file in $DOKKU_ROOT/*/nginx.conf; do
dokku_log_verbose "validate_nginx failed. contents of $conf_file below..."
cat "$conf_file"
done
exit "$exit_code"
fi
}
restart_nginx() {
declare desc="restart nginx for given distros"
case "$DOKKU_DISTRO" in
debian)
sudo /usr/sbin/invoke-rc.d nginx reload > /dev/null
;;
ubuntu)
sudo /etc/init.d/nginx reload > /dev/null
;;
opensuse)
sudo /sbin/service nginx reload > /dev/null
;;
arch)
sudo /usr/bin/systemctl reload nginx
;;
esac
}
nginx_logs() {
declare desc="display app nginx logs"
local APP="$2"; verify_app_name "$APP"
local NGINX_LOGS_TYPE=${1#nginx:}
local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log"
if [[ $3 == "-t" ]]; then
local NGINX_LOGS_ARGS="-F"
else
local NGINX_LOGS_ARGS="-n 20"
fi
tail "$NGINX_LOGS_ARGS" "$NGINX_LOGS_PATH"
}
configure_nginx_ports() {
declare desc="configure nginx listening ports"
local APP=$1; verify_app_name "$APP"
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
local DOKKU_NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
local DOKKU_NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)
local DOKKU_PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP)
local IS_APP_VHOST_ENABLED="$(is_app_vhost_enabled "$APP")"
local UPSTREAM_PORT="5000"
if [[ -z "$DOKKU_NGINX_PORT" ]] && [[ -z "$RAW_TCP_PORTS" ]]; then
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
dokku_log_info1 "no nginx port set. setting to random open high port"
local NGINX_PORT=$(get_available_port)
else
local NGINX_PORT=80
fi
config_set --no-restart "$APP" DOKKU_NGINX_PORT="$NGINX_PORT"
fi
if [[ -z "$DOKKU_NGINX_SSL_PORT" ]]; then
if (is_ssl_enabled "$APP") && [[ -z "$RAW_TCP_PORTS" ]]; then
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
dokku_log_info1 "no nginx ssl port set. setting to random open high port"
local NGINX_SSL_PORT=$(get_available_port)
else
local NGINX_SSL_PORT=443
fi
config_set --no-restart "$APP" DOKKU_NGINX_SSL_PORT="$NGINX_SSL_PORT"
fi
fi
if [[ -z "$DOKKU_PROXY_PORT_MAP" ]]; then
if [[ -n "$RAW_TCP_PORTS" ]]; then
local RAW_TCP_PORT
for RAW_TCP_PORT in $RAW_TCP_PORTS; do
local PROXY_PORT_MAP+=" http:${RAW_TCP_PORT}:${RAW_TCP_PORT} "
done
else
local NGINX_PORT=${NGINX_PORT:-$DOKKU_NGINX_PORT}
local NGINX_SSL_PORT=${NGINX_SSL_PORT:-$DOKKU_NGINX_SSL_PORT}
[[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ]] && local UPSTREAM_PORT="$(< "$DOKKU_ROOT/$APP/PORT.web.1")"
if [[ -n "$NGINX_PORT" ]] && [[ -n "$NGINX_SSL_PORT" ]]; then
local PROXY_PORT_MAP+=" http:${NGINX_PORT}:$UPSTREAM_PORT https:${NGINX_SSL_PORT}:$UPSTREAM_PORT "
elif [[ -n "$NGINX_PORT" ]]; then
local PROXY_PORT_MAP+=" http:${NGINX_PORT}:$UPSTREAM_PORT "
fi
fi
if [[ -n "$PROXY_PORT_MAP" ]]; then
local PROXY_PORT_MAP="$(echo "$PROXY_PORT_MAP" | xargs)"
local PROXY_PORT_MAP+=" $(merge_dedupe_list "$(remove_val_from_list "$PORT_MAP" "$DOKKU_PROXY_PORT_MAP" " ")" " ") "
config_set --no-restart "$APP" DOKKU_PROXY_PORT_MAP="$PROXY_PORT_MAP"
fi
fi
}
validate_ssl_domains() {
declare desc="check configured domains against SSL cert contents and show warning if mismatched"
local APP=$1; verify_app_name "$APP"
local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')
if ! (egrep -q "^${SSL_HOSTNAME_REGEX}$" "$VHOST_PATH" &> /dev/null); then
dokku_log_info1 "No matching configured domains for $APP found in SSL certificate. Your app will show as insecure in a browser if accessed via SSL"
dokku_log_info1 "Please add appropriate domains via the dokku domains command"
[[ -n "$NONSSL_VHOSTS" ]] && dokku_log_info1 "Configured domains for app:"
local domain
for domain in $(echo "$NONSSL_VHOSTS"| xargs); do
dokku_log_info2 "$domain"
done
[[ -n "$SSL_HOSTNAME" ]] && dokku_log_info1 "Domains found in SSL certificate:"
for domain in $(echo "$SSL_HOSTNAME" | xargs); do
dokku_log_info2 "$domain"
done
fi
}
get_custom_nginx_template() {
declare desc="attempts to copy custom nginx template from app image"
local APP="$1"; verify_app_name "$APP"
local DESTINATION="$2"
local IMAGE_TAG="$(get_running_image_tag "$APP")"
local IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
local NGINX_TEMPLATE_NAME="nginx.conf.sigil"
copy_from_image "$IMAGE" "$NGINX_TEMPLATE_NAME" "$DESTINATION" 2>/dev/null || true
}
is_spdy_enabled() {
declare desc="detects whether the installed nginx version has spdy or http2 support"
local NGINX_VERSION="$1"
local MAJOR_VERSION MINOR_VERSION PATCH_VERSION
local HAS_SUPPORT=true
if ! which nginx > /dev/null 2>&1; then
echo $HAS_SUPPORT
return
fi
MAJOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[1]}')
MINOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[2]}')
PATCH_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[3]}')
if [[ "$MAJOR_VERSION" -ge "2" ]]; then
HAS_SUPPORT=false
elif [[ "$MAJOR_VERSION" -eq "1" ]]; then
if [[ "$MINOR_VERSION" -ge "10" ]]; then
HAS_SUPPORT=false
elif [[ "$MINOR_VERSION" -ge "9" ]] && [[ "$PATCH_VERSION" -ge "5" ]]; then
HAS_SUPPORT=false
fi
fi
echo $HAS_SUPPORT
}
nginx_build_config() {
declare desc="build nginx config to proxy app containers using sigil"
local APP="$1"; verify_app_name "$APP"
local DOKKU_APP_LISTEN_PORT="$2"; local DOKKU_APP_LISTEN_IP="$3"
local VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local URLS_PATH="$DOKKU_ROOT/$APP/URLS"
local NGINX_TEMPLATE_NAME="nginx.conf.sigil"
local DEFAULT_NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/$NGINX_TEMPLATE_NAME"
local NGINX_TEMPLATE="$DEFAULT_NGINX_TEMPLATE"; local SCHEME=http
local NGINX_TEMPLATE_SOURCE="built-in"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls"
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
local DOKKU_DISABLE_PROXY=$(config_get "$APP" DOKKU_DISABLE_PROXY)
local IS_APP_VHOST_ENABLED=$(is_app_vhost_enabled "$APP")
if [[ -z "$DOKKU_DISABLE_PROXY" ]]; then
if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then
shopt -s nullglob
local DOKKU_APP_IP_FILE
for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do
local DOKKU_APP_PORT_FILE="${DOKKU_APP_IP_FILE//IP/PORT}"
local DOKKU_APP_LISTENER_IP=$(< "$DOKKU_APP_IP_FILE")
local DOKKU_APP_LISTENER_PORT=$(< "$DOKKU_APP_PORT_FILE")
local DOKKU_APP_LISTENERS+="$DOKKU_APP_LISTENER_IP:$DOKKU_APP_LISTENER_PORT "
done
local DOKKU_APP_LISTENERS="$(echo "$DOKKU_APP_LISTENERS" | xargs)"
shopt -u nullglob
elif [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then
local PASSED_LISTEN_IP_PORT=true
fi
# setup nginx listen ports
configure_nginx_ports "$APP"
local NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
local NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)
local PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP)
local PORT_MAP
for PORT_MAP in $PROXY_PORT_MAP; do
local PROXY_UPSTREAM_PORT="$(awk -F ':' '{ print $3 }' <<< "$PORT_MAP")"
if [[ "$(is_val_in_list "$PROXY_UPSTREAM_PORT" "$PROXY_UPSTREAM_PORTS" " ")" == "false" ]]; then
local PROXY_UPSTREAM_PORTS+="$PROXY_UPSTREAM_PORT "
fi
done
local PROXY_UPSTREAM_PORTS="$(echo "$PROXY_UPSTREAM_PORTS" | xargs)"
local NGINX_BUILD_CONFIG_TMP_WORK_DIR=$(mktemp -d /tmp/dokku_nginx_template.XXXXX)
local NGINX_CONF=$(mktemp --tmpdir="${NGINX_BUILD_CONFIG_TMP_WORK_DIR}" "nginx.conf.XXXXXX")
local CUSTOM_NGINX_TEMPLATE="$NGINX_BUILD_CONFIG_TMP_WORK_DIR/$NGINX_TEMPLATE_NAME"
# shellcheck disable=SC2086
trap 'rm -rf $NGINX_CONF $NGINX_BUILD_CONFIG_TMP_WORK_DIR > /dev/null' RETURN INT TERM EXIT
get_custom_nginx_template "$APP" "$CUSTOM_NGINX_TEMPLATE"
if [[ -f "$CUSTOM_NGINX_TEMPLATE" ]]; then
dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.sigil'
local NGINX_TEMPLATE="$CUSTOM_NGINX_TEMPLATE"
local NGINX_TEMPLATE_SOURCE="app-supplied"
fi
local NONSSL_VHOSTS=$(get_app_domains "$APP")
local NOSSL_SERVER_NAME=$(echo "$NONSSL_VHOSTS" | xargs)
if is_ssl_enabled "$APP"; then
local SSL_INUSE=true; local SCHEME=https
validate_ssl_domains "$APP"
local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')
if [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
local SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" "$VHOST_PATH" || true)
else
local SSL_VHOSTS=$(< "$DOKKU_ROOT/HOSTNAME")
fi
local SSL_SERVER_NAME=$(echo "$SSL_VHOSTS" | xargs)
fi
local NGINX_VERSION="$(nginx -v 2>&1 | cut -d'/' -f 2)"
local SPDY_SUPPORTED="$(is_spdy_enabled "$NGINX_VERSION")"
eval "$(config_export app "$APP")"
local SIGIL_PARAMS=(-f $NGINX_TEMPLATE APP="$APP" DOKKU_ROOT="$DOKKU_ROOT"
NOSSL_SERVER_NAME="$NOSSL_SERVER_NAME"
DOKKU_APP_LISTENERS="$DOKKU_APP_LISTENERS"
PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT"
SPDY_SUPPORTED="$SPDY_SUPPORTED"
DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP"
APP_SSL_PATH="$APP_SSL_PATH" SSL_INUSE="$SSL_INUSE" SSL_SERVER_NAME="$SSL_SERVER_NAME"
NGINX_PORT="$NGINX_PORT" NGINX_SSL_PORT="$NGINX_SSL_PORT" RAW_TCP_PORTS="$RAW_TCP_PORTS"
PROXY_PORT_MAP="$PROXY_PORT_MAP" PROXY_UPSTREAM_PORTS="$PROXY_UPSTREAM_PORTS")
# execute sigil template processing
xargs -i echo "-----> Configuring {}...(using $NGINX_TEMPLATE_SOURCE template)" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)"
# echo "sigil ${SIGIL_PARAMS[@]}"
sigil "${SIGIL_PARAMS[@]}" | cat -s > "$NGINX_CONF"
if is_deployed "$APP"; then
dokku_log_info1 "Creating $SCHEME nginx.conf"
mv "$NGINX_CONF" "$DOKKU_ROOT/$APP/nginx.conf"
else
dokku_log_info1 "App $APP has not been deployed. Skipping nginx config creation"
rm -f "$NGINX_CONF"
fi
if is_deployed "$APP"; then
dokku_log_info1 "Running nginx-pre-reload"
plugn trigger nginx-pre-reload "$APP" "$DOKKU_APP_LISTEN_PORT" "$DOKKU_APP_LISTEN_IP"
dokku_log_verbose "Reloading nginx"
validate_nginx && restart_nginx
fi
if ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > "$URLS_PATH"
xargs -i echo "$SCHEME://{}" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)" >> "$URLS_PATH"
fi
else
# note because this clause is long. if $DOKKU_DISABLE_PROXY is set:
dokku_log_info1 "nginx support is disabled for app ($APP)."
if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
dokku_log_info1 "deleting nginx.conf"
rm "$DOKKU_ROOT/$APP/nginx.conf"
if is_deployed "$APP"; then
dokku_log_info1 "reloading nginx after nginx.conf deletion"
validate_nginx && restart_nginx
fi
fi
fi
}