From da465a61dde67553382debee14035632f62bf172 Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Thu, 8 Jan 2015 15:58:08 -0800 Subject: [PATCH 1/2] disable VHOST deployment if global VHOST file is missing --- docs/nginx.md | 2 +- plugins/domains/commands | 4 ++-- plugins/nginx-vhosts/bind-external-ip | 10 +++------- tests/unit/ports.bats | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/nginx.md b/docs/nginx.md index d309e2298..1f2688b97 100644 --- a/docs/nginx.md +++ b/docs/nginx.md @@ -141,7 +141,7 @@ dokku domains:remove myapp example.com > New as of 0.3.13 -The deployed docker container running your app's web process will bind to either the internal docker network interface (i.e. `docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID`) or an external interface (i.e. 0.0.0.0) depending on dokku's VHOST configuration. Dokku will attempt to bind to the internal docker network interface unless you specifically set NO_VHOST for the given app or your dokku installation is not setup to use VHOSTS (i.e. $DOKKU_ROOT/VHOST or $DOKKU_ROOT/HOSTNAME is set to an IPv4 or IPv6 address) +The deployed docker container running your app's web process will bind to either the internal docker network interface (i.e. `docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID`) or an external interface (i.e. 0.0.0.0) depending on dokku's VHOST configuration. Dokku will attempt to bind to the internal docker network interface unless you specifically set NO_VHOST for the given app or your dokku installation is not setup to use VHOSTS (i.e. $DOKKU_ROOT/VHOST is missing or $DOKKU_ROOT/HOSTNAME is set to an IPv4 or IPv6 address) ```shell # container bound to docker interface diff --git a/plugins/domains/commands b/plugins/domains/commands index 9ae7bec38..cfbd5a859 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -38,8 +38,8 @@ case "$1" in else VHOST=$(< "$DOKKU_ROOT/HOSTNAME") fi - if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]];then - echo "ip found as hostname. disabling vhost support" + if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]] || [[ ! -f "$DOKKU_ROOT/VHOST" ]];then + echo "unsupported vhost config found. disabling vhost support" [[ ! $(grep -q NO_VHOST "$DOKKU_ROOT/$APP/ENV") ]] && echo "export NO_VHOST='1'" >> "$DOKKU_ROOT/$APP/ENV" else echo "-----> Creating new $VHOST_PATH..." diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index 636bc894c..7cfc2a54d 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -19,14 +19,10 @@ RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: f RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 -if [[ -f "$DOKKU_ROOT/VHOST" ]];then - GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") -else - GLOBAL_VHOST=$(< "$DOKKU_ROOT/HOSTNAME") -fi +[[ -f "$DOKKU_ROOT/VHOST" ]] && GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") -if [[ -n "$NO_VHOST" ]]; then - echo true # bind to external ip. VHOST is disabled for this app +if [[ -n "$NO_VHOST" ]] || [[ -z "$GLOBAL_VHOST" ]]; then + echo true # bind to external ip. VHOST is disabled elif [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then echo true # bind to external ip. GLOBAL_VHOST is somehow an IPv4 or IPv6 address elif [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats index 9e641eed3..a1fbe8333 100644 --- a/tests/unit/ports.bats +++ b/tests/unit/ports.bats @@ -32,7 +32,7 @@ teardown() { run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" echo "output: "$output echo "status: "$status - assert_failure + assert_success } @test "port exposure (with NO_VHOST set)" { From 80d13c00053d402ae24a07e8e7f2c4ffde4dfc5b Mon Sep 17 00:00:00 2001 From: Michael Hobbs Date: Sun, 11 Jan 2015 14:35:02 -0800 Subject: [PATCH 2/2] allow users to add a domain to an app if there is no global vhost --- plugins/domains/commands | 39 +++++++++++++++++++-------- plugins/nginx-vhosts/bind-external-ip | 4 ++- plugins/nginx-vhosts/commands | 8 +++--- tests/unit/nginx-vhosts.bats | 20 ++++++++++++++ tests/unit/ports.bats | 32 ++++++++++++++++++++-- 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/plugins/domains/commands b/plugins/domains/commands index cfbd5a859..e3a9825f6 100755 --- a/plugins/domains/commands +++ b/plugins/domains/commands @@ -16,6 +16,19 @@ RE_IPV6="${RE_IPV6}fe08:(:[0-9a-fA-F]{1,4}){2,2}%[0-9a-zA-Z]{1,}|" # TEST: f RE_IPV6="${RE_IPV6}::(ffff(:0{1,4}){0,1}:){0,1}${RE_IPV4}|" # TEST: ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 +domains_restart_app() { + APP="$1"; + + if [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]]; then + echo "-----> Releasing $APP ..." + dokku release $APP + echo "-----> Release complete!" + echo "-----> Deploying $APP ..." + dokku deploy $APP + echo "-----> Deploy complete!" + fi +} + case "$1" in domains) [[ -z $2 ]] && echo "Please specify an app to run the command on" && exit 1 @@ -38,22 +51,24 @@ case "$1" in else VHOST=$(< "$DOKKU_ROOT/HOSTNAME") fi - if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]] || [[ ! -f "$DOKKU_ROOT/VHOST" ]];then + if [[ "$VHOST" =~ $RE_IPV4 ]] || [[ "$VHOST" =~ $RE_IPV6 ]];then echo "unsupported vhost config found. disabling vhost support" [[ ! $(grep -q NO_VHOST "$DOKKU_ROOT/$APP/ENV") ]] && echo "export NO_VHOST='1'" >> "$DOKKU_ROOT/$APP/ENV" else - echo "-----> Creating new $VHOST_PATH..." - SUBDOMAIN=${APP/%\.${VHOST}/} - hostname=$(: | pluginhook nginx-hostname $APP $SUBDOMAIN $VHOST) - if [[ ! -n $hostname ]]; then - if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then - hostname="${APP/\//-}" - else - hostname="${APP/\//-}.$VHOST" + if [[ -f "$DOKKU_ROOT/VHOST" ]]; then + echo "-----> Creating new $VHOST_PATH..." + SUBDOMAIN=${APP/%\.${VHOST}/} + hostname=$(: | pluginhook nginx-hostname $APP $SUBDOMAIN $VHOST) + if [[ ! -n $hostname ]]; then + if [[ "$APP" == *.* ]] && [[ "$SUBDOMAIN" == "$APP" ]]; then + hostname="${APP/\//-}" + else + hostname="${APP/\//-}.$VHOST" + fi fi - fi - echo "$hostname" > $VHOST_PATH + echo "$hostname" > $VHOST_PATH + fi fi fi ;; @@ -76,6 +91,8 @@ case "$1" in dokku domains:setup $APP echo "$3" >> "$DOKKU_ROOT/$APP/VHOST" + # we need to restart the app to make sure we're binding to the appropriate network interface + domains_restart_app $APP pluginhook post-domains-update $APP echo "-----> Added $3 to $APP" diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip index 7cfc2a54d..d4582b3cd 100755 --- a/plugins/nginx-vhosts/bind-external-ip +++ b/plugins/nginx-vhosts/bind-external-ip @@ -21,10 +21,12 @@ RE_IPV6="${RE_IPV6}([0-9a-fA-F]{1,4}:){1,4}:${RE_IPV4}" # TEST: 2 [[ -f "$DOKKU_ROOT/VHOST" ]] && GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") -if [[ -n "$NO_VHOST" ]] || [[ -z "$GLOBAL_VHOST" ]]; then +if [[ -n "$NO_VHOST" ]]; then echo true # bind to external ip. VHOST is disabled elif [[ "$GLOBAL_VHOST" =~ $RE_IPV4 ]] || [[ "$GLOBAL_VHOST" =~ $RE_IPV6 ]]; then echo true # bind to external ip. GLOBAL_VHOST is somehow an IPv4 or IPv6 address +elif [[ -z "$GLOBAL_VHOST" ]] && [[ ! -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + echo true # bind to external ip. no GLOBAL_VHOST and no app vhost elif [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then echo false # bind to docker ip. this app has a vhost defined else diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index b9ef3cf02..c66d6c939 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -29,7 +29,7 @@ case "$1" in [[ -f "$DOKKU_ROOT/$APP/ENV" ]] && source $DOKKU_ROOT/$APP/ENV - if [[ ! -n "$NO_VHOST" ]]; then + if [[ ! -n "$NO_VHOST" ]] && [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then NONSSL_VHOSTS=$(cat $VHOST_PATH) if [[ -e "$SSL/server.crt" ]] && [[ -e "$SSL/server.key" ]]; then SSL_INUSE="$SSL" @@ -86,14 +86,14 @@ EOF fi else if [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then - echo "-----> NO_VHOST set, deleting $APP/VHOST" + echo "-----> VHOST support disabled, deleting $APP/VHOST" rm "$DOKKU_ROOT/$APP/VHOST" fi if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then - echo "-----> NO_VHOST set, deleting nginx.conf" + echo "-----> VHOST support disabled, deleting nginx.conf" rm "$DOKKU_ROOT/$APP/nginx.conf" - echo "-----> NO_VHOST set, reloading nginx after nginx.conf deletion" + echo "-----> VHOST support disabled, reloading nginx after nginx.conf deletion" restart_nginx fi fi diff --git a/tests/unit/nginx-vhosts.bats b/tests/unit/nginx-vhosts.bats index db00a7ce5..bd1b1f285 100644 --- a/tests/unit/nginx-vhosts.bats +++ b/tests/unit/nginx-vhosts.bats @@ -3,11 +3,15 @@ load test_helper setup() { + [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -f "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" + [[ -f "$DOKKU_ROOT/HOSTNAME" ]] && cp -f "$DOKKU_ROOT/HOSTNAME" "$DOKKU_ROOT/HOSTNAME.bak" create_app } teardown() { destroy_app + [[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" + [[ -f "$DOKKU_ROOT/HOSTNAME.bak" ]] && mv "$DOKKU_ROOT/HOSTNAME.bak" "$DOKKU_ROOT/HOSTNAME" } @test "nginx (no server tokens)" { @@ -26,3 +30,19 @@ teardown() { echo "status: "$status assert_output "node-js-app.dokku.me" } + +@test "nginx:build-config (no global VHOST and domains:add)" { + destroy_app + rm "$DOKKU_ROOT/VHOST" + create_app + run dokku domains:add $TEST_APP www.test.app.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + deploy_app + sleep 5 # wait for nginx to reload + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" + echo "output: "$output + echo "status: "$status + assert_success +} diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats index a1fbe8333..bace5c786 100644 --- a/tests/unit/ports.bats +++ b/tests/unit/ports.bats @@ -5,7 +5,6 @@ load test_helper setup() { [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -f "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" [[ -f "$DOKKU_ROOT/HOSTNAME" ]] && cp -f "$DOKKU_ROOT/HOSTNAME" "$DOKKU_ROOT/HOSTNAME.bak" - } teardown() { @@ -67,14 +66,43 @@ teardown() { assert_success } -@test "port exposure (domains:add)" { +@test "port exposure (pre-deploy domains:add)" { create_app run dokku domains:add $TEST_APP www.test.app.dokku.me echo "output: "$output echo "status: "$status assert_success + deploy_app sleep 5 # wait for nginx to reload + + CONTAINER_ID=$(docker ps --no-trunc| grep dokku/$TEST_APP | grep "start web" | awk '{ print $1 }') + run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" + echo "output: "$output + echo "status: "$status + assert_failure + + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" + echo "output: "$output + echo "status: "$status + assert_success +} + +@test "port exposure (no global VHOST and domains:add post deploy)" { + rm "$DOKKU_ROOT/VHOST" + deploy_app + + run dokku domains:add $TEST_APP www.test.app.dokku.me + echo "output: "$output + echo "status: "$status + assert_success + + CONTAINER_ID=$(docker ps --no-trunc| grep dokku/$TEST_APP | grep "start web" | awk '{ print $1 }') + run bash -c "docker port $CONTAINER_ID | sed 's/[0-9.]*://' | egrep '[0-9]*'" + echo "output: "$output + echo "status: "$status + assert_failure + run bash -c "response=\"$(curl -s -S www.test.app.dokku.me)\"; echo \$response; test \"\$response\" == \"nodejs/express\"" echo "output: "$output echo "status: "$status