diff --git a/dokku b/dokku index 9374b6e6f..f59d247f0 100755 --- a/dokku +++ b/dokku @@ -82,8 +82,20 @@ case "$1" in # start the app DOCKER_ARGS=$(: | pluginhook docker-args $APP deploy) - id=$(docker run -d -p 5000 -e PORT=5000 $DOCKER_ARGS $IMAGE /bin/bash -c "/start web") - port=$(docker port $id 5000 | sed 's/[0-9.]*://') + BIND_EXTERNAL=$(pluginhook bind-external-ip $APP) + + if [[ "$BIND_EXTERNAL" = "false" ]];then + port=5000 + id=$(docker run -d -e PORT=$port $DOCKER_ARGS $IMAGE /bin/bash -c "/start web") + ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $id) + + echo $ipaddr > "$DOKKU_ROOT/$APP/IP" + else + id=$(docker run -d -p 5000 -e PORT=5000 $DOCKER_ARGS $IMAGE /bin/bash -c "/start web") + port=$(docker port $id 5000 | sed 's/[0-9.]*://') + + [[ -f "$DOKKU_ROOT/$APP/IP" ]] && rm -f "$DOKKU_ROOT/$APP/IP" + fi # if we can't post-deploy successfully, kill new container function kill_new { @@ -95,7 +107,7 @@ case "$1" in # run checks first, then post-deploy hooks, which switches Nginx traffic trap kill_new INT TERM EXIT echo "-----> Running pre-flight checks" - pluginhook check-deploy $id $APP $port + pluginhook check-deploy $id $APP $port ${ipaddr:-localhost} # now using the new container echo $id > "$DOKKU_ROOT/$APP/CONTAINER" @@ -103,7 +115,7 @@ case "$1" in echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$port" > "$DOKKU_ROOT/$APP/URL" echo "-----> Running post-deploy" - pluginhook post-deploy $APP $port + pluginhook post-deploy $APP $port $ipaddr trap - INT TERM EXIT # kill the old container diff --git a/plugins/nginx-vhosts/bind-external-ip b/plugins/nginx-vhosts/bind-external-ip new file mode 100755 index 000000000..55159289e --- /dev/null +++ b/plugins/nginx-vhosts/bind-external-ip @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +APP="$1" + +set +e; NO_VHOST=$(dokku config:get $APP NO_VHOST); set -e +if [[ -f "$DOKKU_ROOT/VHOST" ]];then + GLOBAL_VHOST=$(< "$DOKKU_ROOT/VHOST") +else + GLOBAL_VHOST=$(< "$DOKKU_ROOT/HOSTNAME") +fi + +if [[ -n "$NO_VHOST" ]]; then + echo true # bind to external ip. VHOST is disabled for this app +elif [[ "$GLOBAL_VHOST" =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]];then + echo true # bind to external ip. GLOBAL_VHOST is somehow an IP +elif [[ -f "$DOKKU_ROOT/$APP/VHOST" ]]; then + echo false # bind to docker ip. this app has a vhost defined +else + echo false +fi diff --git a/plugins/nginx-vhosts/commands b/plugins/nginx-vhosts/commands index bb85ca607..8434f21ae 100755 --- a/plugins/nginx-vhosts/commands +++ b/plugins/nginx-vhosts/commands @@ -15,7 +15,7 @@ restart_nginx () { case "$1" in nginx:build-config) - APP="$2"; PORT="$3" + APP="$2"; PORT="$3"; IP="${4:-127.0.0.1}" [[ -z "$PORT" ]] && PORT=$(< "$DOKKU_ROOT/$APP/PORT") VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" WILDCARD_SSL="$DOKKU_ROOT/tls" @@ -68,7 +68,7 @@ EOF NOSSL_SERVER_NAME=$(echo $NONSSL_VHOSTS $SSL_VHOSTS| tr '\n' ' ') echo "-----> Creating $SCHEME nginx.conf" - echo "upstream $APP { server 127.0.0.1:$PORT; }" > $DOKKU_ROOT/$APP/nginx.conf + echo "upstream $APP { server $IP:$PORT; }" > $DOKKU_ROOT/$APP/nginx.conf eval "cat <<< \"$(< $NGINX_CONF)\" >> $DOKKU_ROOT/$APP/nginx.conf" echo "-----> Running nginx-pre-reload" diff --git a/plugins/nginx-vhosts/post-deploy b/plugins/nginx-vhosts/post-deploy index cdf81d452..72516694b 100755 --- a/plugins/nginx-vhosts/post-deploy +++ b/plugins/nginx-vhosts/post-deploy @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -APP="$1"; PORT="$2" +APP="$1"; PORT="$2"; IP="$3" set +e; NO_VHOST=$(dokku config:get $APP NO_VHOST); set -e @@ -11,4 +11,4 @@ elif [[ ! -f "$DOKKU_ROOT/$APP/VHOST" ]]; then dokku domains:setup $APP fi -dokku nginx:build-config $APP $PORT +dokku nginx:build-config $APP $PORT $IP diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats new file mode 100644 index 000000000..76166ea53 --- /dev/null +++ b/tests/unit/ports.bats @@ -0,0 +1,57 @@ +#!/usr/bin/env bats + +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() { + 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 "port exposure (with global VHOST)" { + echo "dokku.me" > "$DOKKU_ROOT/VHOST" + deploy_app + 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 +} + +@test "port exposure (without global VHOST and real HOSTNAME)" { + rm "$DOKKU_ROOT/VHOST" + echo "dokku.me" > "$DOKKU_ROOT/HOSTNAME" + deploy_app + 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 +} + +@test "port exposure (with NO_VHOST set)" { + deploy_app + dokku config:set $TEST_APP NO_VHOST=1 + 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_success +} + +@test "port exposure (without global VHOST and ip as HOSTNAME)" { + rm "$DOKKU_ROOT/VHOST" + echo "127.0.0.1" > "$DOKKU_ROOT/HOSTNAME" + deploy_app + 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_success +} diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index d671ae1b6..d2b10dd47 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -1,6 +1,7 @@ #!/usr/bin/env bash # constants +DOKKU_ROOT=${DOKKU_ROOT:=~dokku} TEST_APP=my-cool-guy-test-app # test functions