diff --git a/docs/appendices/0.30.0-migration-guide.md b/docs/appendices/0.30.0-migration-guide.md index 2944c4c140d..76b719564b1 100644 --- a/docs/appendices/0.30.0-migration-guide.md +++ b/docs/appendices/0.30.0-migration-guide.md @@ -1,5 +1,10 @@ # 0.30.0 Migration Guide +## Changes + +- The `port` management commands from the `proxy` plugin have been moved to a new `ports` plugin. +- The `proxy-configure-ports` plugin trigger was renamed to `ports-configure`. + ## Removals - Support for [SPDY](https://en.wikipedia.org/wiki/SPDY) has been removed. No major browser supports it as of 2021. Custom `nginx.conf.sigil` templates referencing spdy-related variables will continue to build until the 1.0.0 release. @@ -10,3 +15,7 @@ - `post-release-dockerfile` - `post-release-pack` - The ability to call `logs:failed` without specifying an app or `--all` flag has been removed. This was deprecated in 0.22.0. Please see the [logs:failed](/docs/deployment/logs.md#failed-deploy-logs). +- `proxy#is_app_proxy_enabled()` is removed in favor of `plugn trigger proxy-is-enabled`. +- `proxy#get_app_proxy_type()` is removed in favor of `plugn trigger proxy-type`. +- The `DOKKU_NGINX_PORT` env var is no longer migrated to `DOKKU_PROXY_PORT` on upgrade. +- The `DOKKU_NGINX_SSL_PORT` env var is no longer migrated to `DOKKU_PROXY_SSL_PORT` on upgrade. \ No newline at end of file diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index c4498062fe8..e48084557dd 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -116,7 +116,7 @@ The following config variables have special meanings and can be set in a variety | `DOKKU_PARALLEL_ARGUMENTS`. | none | `dokku config:set` | Allows passing custom arguments to parallel for `ps:*all` commands | | `DOKKU_PROXY_PORT` | automatically assigned | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*`
`dokku config:set` | | | `DOKKU_PROXY_SSL_PORT` | automatically assigned | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*`
`dokku config:set` | | -| `DOKKU_PROXY_PORT_MAP` | automatically assigned | `dokku proxy:ports-add`
`dokku proxy:ports-remove`, `dokku proxy:ports-clear` | | +| `DOKKU_PROXY_PORT_MAP` | automatically assigned | `dokku ports:add`
`dokku ports:remove`, `dokku ports:clear` | | | `DOKKU_SKIP_ALL_CHECKS` | none | `dokku config:set` | | | `DOKKU_SKIP_CLEANUP` | | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | When a deploy is triggered, if this is set to a non-empty value, then old docker containers and images will not be removed. | | `DOKKU_SKIP_DEFAULT_CHECKS` | | `dokku config:set` | | diff --git a/docs/configuration/ssl.md b/docs/configuration/ssl.md index 5402154cf25..761982c74ae 100644 --- a/docs/configuration/ssl.md +++ b/docs/configuration/ssl.md @@ -165,4 +165,4 @@ dokku nginx:set node-js-app x-forwarded-ssl ### SSL Port Exposure -When your app is served from port `80` then the `/home/dokku/APP/nginx.conf` file will automatically be updated to instruct nginx to respond to ssl on port 443 as a new cert is added. If your app uses a non-standard port (perhaps you have a dockerfile deploy exposing port `99999`) you may need to manually expose an ssl port via `dokku proxy:ports-add https:443:99999`. +When your app is served from port `80` then the `/home/dokku/APP/nginx.conf` file will automatically be updated to instruct nginx to respond to ssl on port 443 as a new cert is added. If your app uses a non-standard port (perhaps you have a dockerfile deploy exposing port `99999`) you may need to manually expose an ssl port via `dokku ports:add https:443:99999`. diff --git a/docs/deployment/builders/dockerfiles.md b/docs/deployment/builders/dockerfiles.md index f6f0e5a71d3..52fc2fde482 100644 --- a/docs/deployment/builders/dockerfiles.md +++ b/docs/deployment/builders/dockerfiles.md @@ -29,7 +29,7 @@ Dokku will only select the `dockerfile` builder if both the `herokuish` and `pac If an application was previously deployed via buildpacks, the following commands should be run before a Dockerfile deploy will succeed: ```shell -dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP +dokku ports:clear node-js-app ``` ### Changing the `Dockerfile` location diff --git a/docs/deployment/builders/herokuish-buildpacks.md b/docs/deployment/builders/herokuish-buildpacks.md index 31b9976b6a3..d917244947e 100644 --- a/docs/deployment/builders/herokuish-buildpacks.md +++ b/docs/deployment/builders/herokuish-buildpacks.md @@ -301,7 +301,7 @@ false If an application was previously deployed via Dockerfile, the following commands should be run before a buildpack deploy will succeed: ```shell -dokku config:unset --no-restart node-js-app DOKKU_PROXY_PORT_MAP +dokku ports:clear node-js-app ``` ### Using a specific buildpack version diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 9f3b2f098ca..05241476681 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -1210,6 +1210,36 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x nginx -t ``` +### `ports-clear` + +- Description: Clears the ports for a given app without triggering further restarts or rebuilds +- Invoked by: internally +- Arguments: `$APP` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +# TODO +``` + +### `ports-get` + +- Description: Returns the port map for a given application in newline-delimited format +- Invoked by: internally +- Arguments: `$APP` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +# TODO +``` + ### `post-app-clone` - Description: Allows you to run commands after an app was cloned. @@ -1480,10 +1510,10 @@ echo "clock: some-command" >> Procfile popd &>/dev/null ``` -### `post-proxy-ports-update` +### `post-ports-update` - Description: Allows you to run commands once the proxy port mappings for an app have been updated. It also sends the invoking command. This can be "add", "clear" or "remove". -- Invoked by: `dokku proxy:ports-add`, `dokku proxy:ports-clear`, `dokku proxy:ports-remove` +- Invoked by: `dokku ports:add`, `dokku ports:clear`, `dokku ports:remove` - Arguments: `$APP` `action name` - Example: @@ -1824,7 +1854,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x # TODO ``` -### `proxy-configure-ports` +### `ports-configure` - Description: Configures the proxy port mapping - Invoked by: `internally triggered by proxy plugins` diff --git a/docs/getting-started/troubleshooting.md b/docs/getting-started/troubleshooting.md index 9402c91e864..18612404e04 100644 --- a/docs/getting-started/troubleshooting.md +++ b/docs/getting-started/troubleshooting.md @@ -78,8 +78,8 @@ The proxy port mapping will be `http:8000:8000`. To avoid this issue, either of the following can be done: -- Remove `EXPOSE` directive: This will require respecting the `$PORT` environment variable (automatically set by Dokku). Once that change is deployed, the port mapping should be cleared via the `dokku proxy:ports-clear $APP` command (where `$APP` is your app name). -- Update the port mapping: Updating the port mapping to redirect port `80` to your app's exposed port via `dokku proxy:ports-set $APP http:80:$EXPOSED_PORT` can also fix the issue. This will also allow certificate management and the letsencrypt plugin to work correctly. +- Remove `EXPOSE` directive: This will require respecting the `$PORT` environment variable (automatically set by Dokku). Once that change is deployed, the port mapping should be cleared via the `dokku ports:clear $APP` command (where `$APP` is your app name). +- Update the port mapping: Updating the port mapping to redirect port `80` to your app's exposed port via `dokku ports:set $APP http:80:$EXPOSED_PORT` can also fix the issue. This will also allow certificate management and the letsencrypt plugin to work correctly. See the [port management documentation](/docs/networking/port-management.md) for more information on how Dokku exposes ports for applications and how you can configure these for your app. @@ -240,4 +240,4 @@ This could be a result of a bad proxy configuration (`http:5000:5000` may be inc Proxy type: nginx ``` -Set `dokku proxy:ports-set front http:80:5000` to get proxy correctly configured for http endpoint. +Set `dokku ports:set front http:80:5000` to get proxy correctly configured for http endpoint. diff --git a/docs/networking/port-management.md b/docs/networking/port-management.md index 61f3d66833c..28aff827c58 100644 --- a/docs/networking/port-management.md +++ b/docs/networking/port-management.md @@ -1,16 +1,16 @@ # Port Management -> New as of 0.5.0, Enhanced in 0.6.0 +> New as of 0.30.0 ``` -proxy:ports # List proxy port mappings for an app -proxy:ports-add :: [::...] # Add proxy port mappings to an app -proxy:ports-clear # Clear all proxy port mappings for an app -proxy:ports-remove [|::...] # Remove specific proxy port mappings from an app -proxy:ports-set :: [::...] # Set proxy port mappings for an app +ports:list # List port mappings for an app +ports:add :: [::...] # Add port mappings to an app +ports:clear # Clear all port mappings for an app +ports:remove [|::...] # Remove specific port mappings from an app +ports:set :: [::...] # Set port mappings for an app ``` -In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into the proxy plugin. Dokku 0.6.0 introduced the ability to map host ports to specific container ports. In the future this will allow other proxy software - such as HAProxy or Caddy - to be used in place of nginx. +The `ports` plugin can be used to map host ports to specific container ports. Proxy implementations can then consume those port mappings as necessary ## Usage @@ -18,20 +18,18 @@ In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into > > Users should also avoid setting the `PORT` environment variable. Dokku will use port mappings to set this value. Overriding this manually may cause issues in application routing. -> New as of 0.6.0 - -You can now configure `host -> container` port mappings with the `proxy:ports-*` commands. This mapping is currently supported by the built-in nginx-vhosts plugin. +You can now configure `host -> container` port mappings with the `ports:*` commands. This mapping is currently supported by the built-in nginx-vhosts plugin. By default, buildpack apps and dockerfile apps **without** explicitly exposed ports (i.e. using the `EXPOSE` directive) will be configured with a listener on port `80` (and additionally a listener on 443 if ssl is enabled) that will proxy to the application container on port `5000`. Dockerfile apps **with** explicitly exposed ports will be configured with a listener on each exposed port and will proxy to that same port of the deployed application container. -> Note: This default behavior **will not** be automatically changed on subsequent pushes and must be manipulated with the `proxy:ports-*` commands detailed below. +> Note: This default behavior **will not** be automatically changed on subsequent pushes and must be manipulated with the `ports:*` commands detailed below. ### Listing port mappings -To inspect the port mapping for a given application, use the `proxy:ports` command: +To inspect the port mapping for a given application, use the `ports:list` command: ```shell -dokku proxy:ports node-js-app +dokku ports:list node-js-app ``` ``` @@ -62,10 +60,10 @@ curl http://node-js-app.dokku.me:8080 curl: (7) Failed to connect to node-js-app.dokku.me port 8080: Connection refused ``` -However, we can use the `proxy:ports-add` command to add a second external port mapping - `8080` - to our application's port `5000`. +However, we can use the `ports:add` command to add a second external port mapping - `8080` - to our application's port `5000`. ```shell -dokku proxy:ports-add node-js-app http:8080:5000 +dokku ports:add node-js-app http:8080:5000 ``` ``` @@ -98,10 +96,10 @@ Hello World! ### Setting all port mappings at once -Port mappings can also be force set using the `proxy:ports-set` command. +Port mappings can also be force set using the `ports:set` command. ```shell -dokku proxy:ports-set node-js-app http:8080:5000 +dokku ports:set node-js-app http:8080:5000 ``` ``` @@ -114,21 +112,21 @@ dokku proxy:ports-set node-js-app http:8080:5000 ### Removing a port mapping -A port mapping can be removed using the `proxy:ports-remove` command if it no longer necessary: +A port mapping can be removed using the `ports:remove` command if it no longer necessary: ```shell -dokku proxy:ports-remove node-js-app http:80:5000 +dokku ports:remove node-js-app http:80:5000 ``` Ports may also be removed by specifying only the `host-port` value. This effectively acts as a wildcard and removes all mappings for that particular host port. ```shell -dokku proxy:ports-remove node-js-app http:80 +dokku ports:remove node-js-app http:80 ``` ## Port management by Deployment Method -> Warning: If you set a proxy port map but _do not have a global domain set_, Dokku will reset that map upon first deployment. +> Warning: If you set a port map but _do not have a global domain set_, Dokku will reset that map upon first deployment. ### Buildpacks @@ -136,8 +134,6 @@ For buildpack deployments, your application _must_ respect the `PORT` environmen ### Dockerfile -> Changed as of 0.5.0 - Dokku's default proxy implementation - nginx - supports HTTP and GRPC request proxying. At this time, we do not support proxying plain TCP or UDP ports. UDP ports can be exposed by disabling the nginx proxy with `dokku proxy:disable myapp`. If you would like to investigate alternative proxy methods, please refer to our [proxy management documentation](/docs/networking/proxy-management.md). #### Applications using EXPOSE @@ -156,10 +152,10 @@ The application would be exposed to the user at `node-js-app.dokku.me:1234`. If ```shell # add a port mapping to port 80 -dokku proxy:ports-add node-js-app http:80:1234 +dokku ports:add node-js-app http:80:1234 # remove the incorrect port mapping -dokku proxy:ports-remove node-js-app http:1234:1234 +dokku ports:remove node-js-app http:1234:1234 ``` #### Applications not using EXPOSE @@ -176,7 +172,7 @@ When switching between `EXPOSE` usage modes, it is important to reset your port ```shell # assuming your application is called `node-js-app` dokku config:unset --no-restart node-js-app DOKKU_DOCKERFILE_PORTS PORT -dokku proxy:ports-clear node-js-app +dokku ports:clear node-js-app ``` ### Docker Image @@ -186,7 +182,7 @@ When deploying an image, we will use `docker inspect` to extract the `ExposedPor ```shell # assuming your application is called `node-js-app` dokku config:set node-js-app DOKKU_DOCKERFILE_PORTS="1234/tcp 80/tcp" -dokku proxy:ports-clear node-js-app +dokku ports:clear node-js-app ``` All other port-related behavior is the same as when deploying via Dockerfile. diff --git a/docs/networking/proxies/nginx.md b/docs/networking/proxies/nginx.md index ae9806a2d98..e5523120693 100644 --- a/docs/networking/proxies/nginx.md +++ b/docs/networking/proxies/nginx.md @@ -337,8 +337,8 @@ Unsetting this value is the same as enabling custom nginx config usage. {{ .PROXY_PORT }} Non-SSL nginx listener port (same as `DOKKU_PROXY_PORT` config var) {{ .PROXY_SSL_PORT }} SSL nginx listener port (same as `DOKKU_PROXY_SSL_PORT` config var) {{ .NOSSL_SERVER_NAME }} List of non-SSL VHOSTS -{{ .PROXY_PORT_MAP }} List of port mappings (same as `DOKKU_PROXY_PORT_MAP` config var) -{{ .PROXY_UPSTREAM_PORTS }} List of configured upstream ports (derived from `DOKKU_PROXY_PORT_MAP` config var) +{{ .PROXY_PORT_MAP }} List of port mappings +{{ .PROXY_UPSTREAM_PORTS }} List of configured upstream ports (derived from port mappings) {{ .RAW_TCP_PORTS }} List of exposed tcp ports as defined by Dockerfile `EXPOSE` directive (**Dockerfile apps only**) {{ .SSL_INUSE }} Boolean set when an app is SSL-enabled {{ .SSL_SERVER_NAME }} List of SSL VHOSTS diff --git a/docs/networking/proxy-management.md b/docs/networking/proxy-management.md index a716952fb2b..3cb3bb106eb 100644 --- a/docs/networking/proxy-management.md +++ b/docs/networking/proxy-management.md @@ -11,7 +11,7 @@ proxy:report [] [] # Displays a proxy report fo proxy:set # Set proxy type for app ``` -In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into the proxy plugin. Dokku 0.6.0 introduced the ability to map host ports to specific container ports. In the future this will allow other proxy software - such as HAProxy or Caddy - to be used in place of nginx. +In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into the proxy plugin. In the future this will allow other proxy software - such as HAProxy or Caddy - to be used in place of nginx. ## Usage @@ -158,14 +158,14 @@ At this time, the following dokku commands are used to implement a complete prox - triggers: `proxy-disable` - `proxy:enable`: Enables the proxy configuration for an app. - triggers: `proxy-enable` -- `proxy:ports-add`: Adds one or more port mappings to an app - - triggers: `post-proxy-ports-update` -- `proxy:ports-clear`: Clears out all port mappings for an app. - - triggers: `post-proxy-ports-update` -- `proxy:ports-remove`: Removes one or more port mappings from an app. - - triggers: `post-proxy-ports-update` -- `proxy:ports-set`: Sets all port mappings for an app. - - triggers: `post-proxy-ports-update` +- `ports:add`: Adds one or more port mappings to an app + - triggers: `post-ports-update` +- `ports:clear`: Clears out all port mappings for an app. + - triggers: `post-ports-update` +- `ports:remove`: Removes one or more port mappings from an app. + - triggers: `post-ports-update` +- `ports:set`: Sets all port mappings for an app. + - triggers: `post-ports-update` Proxy implementations may decide to omit some functionality here, or use plugin triggers to supplement config with information from other plugins. diff --git a/plugins/20_events/post-proxy-ports-update b/plugins/20_events/ports-clear similarity index 100% rename from plugins/20_events/post-proxy-ports-update rename to plugins/20_events/ports-clear diff --git a/plugins/20_events/proxy-configure-ports b/plugins/20_events/ports-configure similarity index 100% rename from plugins/20_events/proxy-configure-ports rename to plugins/20_events/ports-configure diff --git a/plugins/20_events/ports-get b/plugins/20_events/ports-get new file mode 120000 index 00000000000..5178a749ff6 --- /dev/null +++ b/plugins/20_events/ports-get @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/20_events/post-ports-update b/plugins/20_events/post-ports-update new file mode 120000 index 00000000000..5178a749ff6 --- /dev/null +++ b/plugins/20_events/post-ports-update @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/caddy-vhosts/docker-args-process-deploy b/plugins/caddy-vhosts/docker-args-process-deploy index 4fe047894c3..65a9c97963c 100755 --- a/plugins/caddy-vhosts/docker-args-process-deploy +++ b/plugins/caddy-vhosts/docker-args-process-deploy @@ -8,7 +8,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() { declare desc="nginx-vhosts core-post-deploy plugin trigger" declare trigger="docker-args-process-deploy" declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3" PROC_TYPE="$4" CONTAINER_INDEX="$5" - local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_port_map proxy_scheme proxy_schemes scheme tls_internal + local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes scheme tls_internal local proxy_container_http_port proxy_container_http_port_candidate proxy_host_http_port_candidate local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate local STDIN=$(cat) @@ -30,15 +30,14 @@ trigger-caddy-vhosts-docker-args-process-deploy() { fi # ensure we have a port mapping - plugn trigger proxy-configure-ports "$APP" + plugn trigger ports-configure "$APP" # gather port mapping information # we only support proxying a single port for http and https listeners # so this block parses the port mappings and tries to find the correct # mapping to expose is_app_listening="false" - proxy_port_map="$(plugn trigger config-get "$APP" DOKKU_PROXY_PORT_MAP)" - for port_map in $proxy_port_map; do + while read -r port_map; do proxy_scheme="$(awk -F ':' '{ print $1 }' <<<"$port_map")" proxy_host_port="$(awk -F ':' '{ print $2 }' <<<"$port_map")" proxy_container_port="$(awk -F ':' '{ print $3 }' <<<"$port_map")" @@ -66,7 +65,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() { proxy_container_https_port="$proxy_container_port" fi fi - done + done < <(plugn trigger ports-get "$APP") letsencrypt_email="$(fn-caddy-letsencrypt-email)" if [[ -n "$letsencrypt_email" ]] && [[ -z "$proxy_container_https_port" ]]; then diff --git a/plugins/domains/internal-functions b/plugins/domains/internal-functions index 921ac9885bb..f897c444293 100755 --- a/plugins/domains/internal-functions +++ b/plugins/domains/internal-functions @@ -136,7 +136,7 @@ fn-domains-generate-urls() { fn-domains-generate-urls-from-config() { declare APP="$1" SCHEME="$2" VHOST="$3" DEFAULT_LISTEN_PORT="$4" - local DOKKU_PROXY_PORT_MAP=$(plugn trigger config-get "$APP" DOKKU_PROXY_PORT_MAP || true) + local APP_PORT_MAP="$(plugn trigger ports-get "$APP")" local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")" if [[ "$(plugn trigger proxy-is-enabled "$APP")" == "false" ]]; then @@ -155,13 +155,13 @@ fn-domains-generate-urls-from-config() { done shopt -u nullglob fi - elif [[ -n "$DOKKU_PROXY_PORT_MAP" ]]; then + elif [[ -n "$APP_PORT_MAP" ]]; then local port_map - for port_map in $DOKKU_PROXY_PORT_MAP; do + while IFS= read -r port_map; do local scheme="$(awk -F ':' '{ print $1 }' <<<"$port_map")" local listen_port="$(awk -F ':' '{ print $2 }' <<<"$port_map")" fn-domains-generate-url "$SCHEME" "$VHOST" "$listen_port" - done + done <<<"$APP_PORT_MAP" elif [[ -n "$RAW_TCP_PORTS" ]]; then for listen_port in $RAW_TCP_PORTS; do fn-domains-generate-url "$SCHEME" "$VHOST" "$listen_port" diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 25ccdd4e78e..a05cc0b2a0f 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -318,13 +318,12 @@ nginx_build_config() { fi # setup nginx listen ports - plugn trigger proxy-configure-ports "$APP" + plugn trigger ports-configure "$APP" local PROXY_PORT=$(config_get "$APP" DOKKU_PROXY_PORT) local PROXY_SSL_PORT=$(config_get "$APP" DOKKU_PROXY_SSL_PORT) - local PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP) - local PORT_MAP proxy_port_map - for PORT_MAP in $PROXY_PORT_MAP; do + local PORT_MAP PROXY_PORT_MAP proxy_port_map + while read -r PORT_MAP; do local PROXY_UPSTREAM_SCHEME="$(awk -F ':' '{ print $1 }' <<<"$PORT_MAP")" if [[ "$PROXY_UPSTREAM_SCHEME" == "https" ]] && [[ "$IS_SSL_ENABLED" == "false" ]]; then dokku_log_warn "Ignoring detected https port mapping without an accompanying ssl certificate (${PORT_MAP})" @@ -337,8 +336,8 @@ nginx_build_config() { if [[ "$(is_val_in_list "$PROXY_UPSTREAM_PORT" "$PROXY_UPSTREAM_PORTS" " ")" == "false" ]]; then local PROXY_UPSTREAM_PORTS+="$PROXY_UPSTREAM_PORT " fi - done - PROXY_PORT_MAP="$proxy_port_map" + done < <(plugn trigger ports-get "$APP") + PROXY_PORT_MAP=$(echo "$proxy_port_map" | xargs) # trailing spaces mess up default template local PROXY_UPSTREAM_PORTS="$(echo "$PROXY_UPSTREAM_PORTS" | xargs)" local SSL_INUSE= @@ -379,8 +378,6 @@ nginx_build_config() { HTTP2_PUSH_SUPPORTED="$(is_http2_push_enabled "$NGINX_VERSION")" GRPC_SUPPORTED="$(is_grpc_enabled "$NGINX_VERSION")" - PROXY_PORT_MAP=$(echo "$PROXY_PORT_MAP" | xargs) # trailing spaces mess up default template - local NGINX_LOG_ROOT="$(fn-nginx-log-root)" local NGINX_ACCESS_LOG_FORMAT="$(fn-nginx-access-log-format "$APP")" local NGINX_ACCESS_LOG_PATH="$(fn-nginx-access-log-path "$APP")" diff --git a/plugins/nginx-vhosts/install b/plugins/nginx-vhosts/install index e5f0e7af442..bf98d8cd539 100755 --- a/plugins/nginx-vhosts/install +++ b/plugins/nginx-vhosts/install @@ -3,32 +3,8 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions" -fn-nginx-vhosts-migrate-env-vars() { - # @TODO: Remove this after a few versions - for app in $(dokku_apps "false" 2>/dev/null); do - nginx_port="$(config_get "$app" DOKKU_NGINX_PORT || true)" - nginx_ssl_port="$(config_get "$app" DOKKU_NGINX_SSL_PORT || true)" - if [[ -n "$nginx_port" ]] || [[ -n "$nginx_ssl_port" ]]; then - dokku_log_info1 "Migrating DOKKU_NGINX env variables. The following variables will be migrated" - dokku_log_info2 "DOKKU_NGINX_PORT -> DOKKU_PROXY_PORT" - dokku_log_info2 "DOKKU_NGINX_SSL_PORT -> DOKKU_PROXY_SSL_PORT" - fi - if [[ -n "$nginx_port" ]]; then - dokku_log_info1 "Migrating DOKKU_NGINX_PORT to DOKKU_PROXY_PORT for $app" - DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$app" DOKKU_PROXY_PORT="$nginx_port" - DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" DOKKU_NGINX_PORT - fi - if [[ -n "$nginx_ssl_port" ]]; then - dokku_log_info1 "Migrating DOKKU_NGINX_SSL_PORT to DOKKU_PROXY_SSL_PORT for $app" - DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$app" DOKKU_PROXY_SSL_PORT="$nginx_ssl_port" - DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$app" DOKKU_NGINX_SSL_PORT - fi - done -} - fn-nginx-vhosts-migrate-nginx-conf-sigil() { if [[ "$(fn-plugin-property-get-default "nginx" "--global" "nginx-conf-sigil-migrated" "")" == "true" ]]; then return @@ -129,7 +105,6 @@ trigger-nginx-vhosts-install() { # patch broken nginx 1.8.0 logrotate [[ -f /etc/logrotate.d/nginx ]] && sed -i -e 's/invoke-rc.d/service/g' /etc/logrotate.d/nginx - fn-nginx-vhosts-migrate-env-vars fn-nginx-vhosts-migrate-nginx-conf-sigil if [[ -f "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" ]]; then diff --git a/plugins/nginx-vhosts/post-proxy-ports-update b/plugins/nginx-vhosts/post-ports-update similarity index 72% rename from plugins/nginx-vhosts/post-proxy-ports-update rename to plugins/nginx-vhosts/post-ports-update index 499377c9646..364f671849b 100755 --- a/plugins/nginx-vhosts/post-proxy-ports-update +++ b/plugins/nginx-vhosts/post-ports-update @@ -4,9 +4,9 @@ set -eo pipefail source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" -trigger-nginx-vhosts-post-proxy-ports-update() { +trigger-nginx-vhosts-post-ports-update() { declare desc="calls nginx build_config when domains are updated" - declare trigger="post-proxy-ports-update" + declare trigger="post-ports-update" declare APP="$1" ACTION="$2" if [[ "$(plugn trigger proxy-type "$APP")" == "nginx" ]]; then @@ -14,4 +14,4 @@ trigger-nginx-vhosts-post-proxy-ports-update() { fi } -trigger-nginx-vhosts-post-proxy-ports-update "$@" +trigger-nginx-vhosts-post-ports-update "$@" diff --git a/plugins/nginx-vhosts/pre-disable-vhost b/plugins/nginx-vhosts/pre-disable-vhost index e786e5322f0..ecfba935c82 100755 --- a/plugins/nginx-vhosts/pre-disable-vhost +++ b/plugins/nginx-vhosts/pre-disable-vhost @@ -10,7 +10,8 @@ trigger-nginx-vhosts-pre-disable-vhost() { declare APP="$1" if [[ "$(plugn trigger proxy-type "$APP")" == "nginx" ]]; then - DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$APP" DOKKU_PROXY_PORT DOKKU_PROXY_SSL_PORT DOKKU_PROXY_PORT_MAP + DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$APP" DOKKU_PROXY_PORT DOKKU_PROXY_SSL_PORT + plugn trigger ports-clear "$APP" fi } diff --git a/plugins/nginx-vhosts/pre-enable-vhost b/plugins/nginx-vhosts/pre-enable-vhost index bde11f963ac..64808eb3d40 100755 --- a/plugins/nginx-vhosts/pre-enable-vhost +++ b/plugins/nginx-vhosts/pre-enable-vhost @@ -10,7 +10,8 @@ trigger-nginx-vhosts-pre-enable-vhost() { declare APP="$1" if [[ "$(plugn trigger proxy-type "$APP")" == "nginx" ]]; then - DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$APP" DOKKU_PROXY_PORT DOKKU_PROXY_SSL_PORT DOKKU_PROXY_PORT_MAP + DOKKU_QUIET_OUTPUT=1 config_unset --no-restart "$APP" DOKKU_PROXY_PORT DOKKU_PROXY_SSL_PORT + plugn trigger ports-clear "$APP" fi } diff --git a/plugins/ports/.gitignore b/plugins/ports/.gitignore new file mode 100644 index 00000000000..83d7acd2c5b --- /dev/null +++ b/plugins/ports/.gitignore @@ -0,0 +1,9 @@ +/commands +/subcommands/* +/triggers/* +/triggers +/install +/post-* +/ports-* +/report +!/ports-configure \ No newline at end of file diff --git a/plugins/ports/Makefile b/plugins/ports/Makefile new file mode 100644 index 00000000000..09ef51751f3 --- /dev/null +++ b/plugins/ports/Makefile @@ -0,0 +1,6 @@ +SUBCOMMANDS = subcommands/list subcommands/add subcommands/clear subcommands/remove subcommands/set subcommands/report +TRIGGERS = triggers/ports-clear triggers/ports-get triggers/post-certs-remove triggers/post-certs-update triggers/report +BUILD = commands subcommands triggers +PLUGIN_NAME = ports + +include ../../common.mk diff --git a/plugins/ports/functions.go b/plugins/ports/functions.go new file mode 100644 index 00000000000..6829e3ddf3b --- /dev/null +++ b/plugins/ports/functions.go @@ -0,0 +1,192 @@ +package ports + +import ( + "errors" + "fmt" + "os" + "sort" + "strconv" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/config" + "github.com/ryanuber/columnize" +) + +func addPorts(appName string, portMap []PortMap) error { + allPortMaps := getPortMaps(appName) + allPortMaps = append(allPortMaps, portMap...) + + return setPorts(appName, allPortMaps) +} + +func clearPorts(appName string) error { + keys := []string{"DOKKU_PROXY_PORT_MAP"} + return config.UnsetMany(appName, keys, false) +} + +func filterAppPorts(appName string, scheme string, hostPort int) []PortMap { + var filteredMaps []PortMap + for _, portMap := range getPortMaps(appName) { + if portMap.Scheme == scheme && portMap.HostPort == hostPort { + filteredMaps = append(filteredMaps, portMap) + } + } + + return filteredMaps +} + +func getPortMaps(appName string) []PortMap { + value := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "") + portMaps, _ := parsePortMapString(value) + return portMaps +} + +func inRange(value int, min int, max int) bool { + return min < value && value < max +} + +func listAppPorts(appName string) error { + portMaps := getPortMaps(appName) + + if len(portMaps) == 0 { + return errors.New("No port mappings configured for app") + } + + var lines []string + if os.Getenv("DOKKU_QUIET_OUTPUT") == "" { + lines = append(lines, "-----> scheme:host port:container port") + } + + for _, portMap := range portMaps { + lines = append(lines, portMap.String()) + } + + sort.Strings(lines) + common.LogInfo1Quiet(fmt.Sprintf("Port mappings for %s", appName)) + config := columnize.DefaultConfig() + config.Delim = ":" + config.Prefix = " " + config.Empty = "" + fmt.Println(columnize.Format(lines, config)) + return nil +} + +func parsePortMapString(stringPortMap string) ([]PortMap, error) { + var portMap []PortMap + + for _, v := range strings.Split(strings.TrimSpace(stringPortMap), " ") { + parts := strings.SplitN(v, ":", 3) + if len(parts) == 1 { + hostPort, err := strconv.Atoi(v) + if err != nil { + return portMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) + } + + if !inRange(hostPort, 0, 65536) { + return portMap, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort) + } + + portMap = append(portMap, PortMap{ + HostPort: hostPort, + Scheme: "__internal__", + }) + continue + } + + if len(parts) != 3 { + return portMap, fmt.Errorf("Invalid port map %s [len=%d]", v, len(parts)) + } + + hostPort, err := strconv.Atoi(parts[1]) + if err != nil { + return portMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) + } + + containerPort, err := strconv.Atoi(parts[2]) + if err != nil { + return portMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) + } + + if !inRange(hostPort, 0, 65536) { + return portMap, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort) + } + + if !inRange(containerPort, 0, 65536) { + return portMap, fmt.Errorf("Invalid port map %s [containerPort=%d]", v, containerPort) + } + + portMap = append(portMap, PortMap{ + ContainerPort: containerPort, + HostPort: hostPort, + Scheme: parts[0], + }) + } + + return uniquePortMap(portMap), nil +} + +func removePorts(appName string, portMap []PortMap) error { + toRemove := map[string]bool{} + toRemoveByPort := map[int]bool{} + + for _, portMap := range portMap { + if portMap.AllowsPersistence() { + toRemoveByPort[portMap.HostPort] = true + continue + } + toRemove[portMap.String()] = true + } + + var toSet []PortMap + for _, portMap := range getPortMaps(appName) { + if toRemove[portMap.String()] { + continue + } + + if toRemoveByPort[portMap.HostPort] { + continue + } + + toSet = append(toSet, portMap) + } + + if len(toSet) == 0 { + return clearPorts(appName) + } + + return setPorts(appName, toSet) +} + +func setPorts(appName string, portMap []PortMap) error { + var value []string + for _, portMap := range uniquePortMap(portMap) { + if portMap.AllowsPersistence() { + continue + } + + value = append(value, portMap.String()) + } + + sort.Strings(value) + entries := map[string]string{ + "DOKKU_PROXY_PORT_MAP": strings.Join(value, " "), + } + return config.SetMany(appName, entries, false) +} + +func uniquePortMap(portMap []PortMap) []PortMap { + var unique []PortMap + existingPortMaps := map[string]bool{} + + for _, portMap := range portMap { + if existingPortMaps[portMap.String()] { + continue + } + + existingPortMaps[portMap.String()] = true + unique = append(unique, portMap) + } + + return unique +} diff --git a/plugins/ports/go.mod b/plugins/ports/go.mod new file mode 100644 index 00000000000..a980a7fea24 --- /dev/null +++ b/plugins/ports/go.mod @@ -0,0 +1,21 @@ +module github.com/dokku/dokku/plugins/ports + +go 1.19 + +require ( + github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 + github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000 + github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 + github.com/spf13/pflag v1.0.5 +) + +require ( + github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect + github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect + github.com/joho/godotenv v1.2.0 // indirect + golang.org/x/sync v0.1.0 // indirect +) + +replace github.com/dokku/dokku/plugins/common => ../common + +replace github.com/dokku/dokku/plugins/config => ../config diff --git a/plugins/ports/go.sum b/plugins/ports/go.sum new file mode 100644 index 00000000000..170b00f269b --- /dev/null +++ b/plugins/ports/go.sum @@ -0,0 +1,16 @@ +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= +github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= +github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc= +github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 h1:utdYOikI1XjNtTFGCwSM6OmFJblU4ld4gACoJsbadJg= +github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/plugins/ports/plugin.toml b/plugins/ports/plugin.toml new file mode 100644 index 00000000000..7694a9c275c --- /dev/null +++ b/plugins/ports/plugin.toml @@ -0,0 +1,4 @@ +[plugin] +description = "dokku core ports plugin" +version = "0.29.2" +[plugin.config] diff --git a/plugins/proxy/proxy-configure-ports b/plugins/ports/ports-configure similarity index 100% rename from plugins/proxy/proxy-configure-ports rename to plugins/ports/ports-configure diff --git a/plugins/ports/ports.go b/plugins/ports/ports.go new file mode 100644 index 00000000000..1918a8c531b --- /dev/null +++ b/plugins/ports/ports.go @@ -0,0 +1,21 @@ +package ports + +import ( + "fmt" +) + +// PortMap is a struct that contains a scheme:host-port:container-port mapping +type PortMap struct { + ContainerPort int + HostPort int + Scheme string +} + +func (p PortMap) String() string { + return fmt.Sprintf("%s:%d:%d", p.Scheme, p.HostPort, p.ContainerPort) +} + +// AllowsPersistence returns true if the port map is not to be persisted +func (p PortMap) AllowsPersistence() bool { + return p.Scheme == "__internal__" +} diff --git a/plugins/ports/report.go b/plugins/ports/report.go new file mode 100644 index 00000000000..63b53756d06 --- /dev/null +++ b/plugins/ports/report.go @@ -0,0 +1,37 @@ +package ports + +import ( + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +// ReportSingleApp is an internal function that displays the port report for one or more apps +func ReportSingleApp(appName string, format string, infoFlag string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + flags := map[string]common.ReportFunc{ + "--ports-map": reportPortMap, + } + + flagKeys := []string{} + for flagKey := range flags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + infoFlags := common.CollectReport(appName, infoFlag, flags) + return common.ReportSingleApp("ports", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + +func reportPortMap(appName string) string { + var portMap []string + for _, pm := range getPortMaps(appName) { + portMap = append(portMap, pm.String()) + } + + return strings.Join(portMap, " ") +} diff --git a/plugins/ports/src/commands/commands.go b/plugins/ports/src/commands/commands.go new file mode 100644 index 00000000000..9231d27bf29 --- /dev/null +++ b/plugins/ports/src/commands/commands.go @@ -0,0 +1,60 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +const ( + helpHeader = `Usage: dokku ports[:COMMAND] + +Manage ports for an app + +Additional commands:` + + helpContent = ` + ports:list , List port mappings for app + ports:add [::...], Add port mappings to an app + ports:clear , Clear all port mappings for an app + ports:remove [|::...], Remove specific port mappings from an app + ports:set [::...], Set port mappings for an app + ports:report [] [], Displays a ports report for one or more apps +` +) + +func main() { + flag.Usage = usage + flag.Parse() + + cmd := flag.Arg(0) + switch cmd { + case "ports", "ports:help": + usage() + case "help": + command := common.NewShellCmd(fmt.Sprintf("ps -o command= %d", os.Getppid())) + command.ShowOutput = false + output, err := command.Output() + + if err == nil && strings.Contains(string(output), "--all") { + fmt.Println(helpContent) + } else { + fmt.Print("\n ports, Manage ports for an app\n") + } + default: + dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT")) + if err != nil { + fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable") + dokkuNotImplementExitCode = 10 + } + os.Exit(dokkuNotImplementExitCode) + } +} + +func usage() { + common.CommandUsage(helpHeader, helpContent) +} diff --git a/plugins/ports/src/subcommands/subcommands.go b/plugins/ports/src/subcommands/subcommands.go new file mode 100644 index 00000000000..14f97ed9418 --- /dev/null +++ b/plugins/ports/src/subcommands/subcommands.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/ports" + + flag "github.com/spf13/pflag" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "list": + args := flag.NewFlagSet("ports:list", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + err = ports.CommandList(appName) + case "add": + args := flag.NewFlagSet("ports:add", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + _, portMaps := common.ShiftString(args.Args()) + err = ports.CommandAdd(appName, portMaps) + case "clear": + args := flag.NewFlagSet("ports:clear", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + err = ports.CommandClear(appName) + case "remove": + args := flag.NewFlagSet("ports:remove", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + _, portMaps := common.ShiftString(args.Args()) + err = ports.CommandRemove(appName, portMaps) + case "set": + args := flag.NewFlagSet("ports:set", flag.ExitOnError) + args.Parse(os.Args[2:]) + appName := args.Arg(0) + _, portMaps := common.ShiftString(args.Args()) + err = ports.CommandSet(appName, portMaps) + case "report": + args := flag.NewFlagSet("ports:report", flag.ExitOnError) + format := args.String("format", "stdout", "format: [ stdout | json ]") + osArgs, infoFlag, flagErr := common.ParseReportArgs("ports", os.Args[2:]) + if flagErr == nil { + args.Parse(osArgs) + appName := args.Arg(0) + err = ports.CommandReport(appName, *format, infoFlag) + } + default: + err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/ports/src/triggers/triggers.go b/plugins/ports/src/triggers/triggers.go new file mode 100644 index 00000000000..f199ba8da50 --- /dev/null +++ b/plugins/ports/src/triggers/triggers.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/ports" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + var err error + switch trigger { + case "ports-clear": + appName := flag.Arg(0) + err = ports.TriggerPortsClear(appName) + case "ports-get": + appName := flag.Arg(0) + err = ports.TriggerPortsGet(appName) + case "post-certs-remove": + appName := flag.Arg(0) + err = ports.TriggerPostCertsRemove(appName) + case "post-certs-update": + appName := flag.Arg(0) + err = ports.TriggerPostCertsUpdate(appName) + case "report": + appName := flag.Arg(0) + err = ports.ReportSingleApp(appName, "", "") + default: + err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/ports/subcommands.go b/plugins/ports/subcommands.go new file mode 100644 index 00000000000..942fe1e84ad --- /dev/null +++ b/plugins/ports/subcommands.go @@ -0,0 +1,114 @@ +package ports + +import ( + "errors" + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +// CommandList is a cmd wrapper to list port mappings for an app +func CommandList(appName string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + return listAppPorts(appName) +} + +// CommandAdd adds port mappings to an app +func CommandAdd(appName string, portMaps []string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + if len(portMaps) == 0 { + return errors.New("No port mapping specified") + } + + portMap, err := parsePortMapString(strings.Join(portMaps, " ")) + if err != nil { + return err + } + + if err := addPorts(appName, portMap); err != nil { + return err + } + + return common.PlugnTrigger("post-ports-update", []string{appName, "add"}...) +} + +// CommandClear clears all port mappings for an app +func CommandClear(appName string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + if err := clearPorts(appName); err != nil { + return err + } + + return common.PlugnTrigger("post-ports-update", []string{appName, "clear"}...) +} + +// CommandRemove removes specific port mappings from an app +func CommandRemove(appName string, portMaps []string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + if len(portMaps) == 0 { + return errors.New("No port mapping specified") + } + + portMap, err := parsePortMapString(strings.Join(portMaps, " ")) + if err != nil { + return err + } + + if err := removePorts(appName, portMap); err != nil { + return err + } + + return common.PlugnTrigger("post-ports-update", []string{appName, "remove"}...) +} + +// CommandSet sets port mappings for an app +func CommandSet(appName string, portMaps []string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + if len(portMaps) == 0 { + return errors.New("No port mapping specified") + } + + portMap, err := parsePortMapString(strings.Join(portMaps, " ")) + if err != nil { + return err + } + + if err := setPorts(appName, portMap); err != nil { + return err + } + + return common.PlugnTrigger("post-ports-update", []string{appName, "set"}...) +} + +// CommandReport displays a report for one or more apps +func CommandReport(appName string, format string, infoFlag string) error { + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return err + } + for _, appName := range apps { + if err := ReportSingleApp(appName, format, infoFlag); err != nil { + return err + } + } + return nil + } + + return ReportSingleApp(appName, format, infoFlag) +} diff --git a/plugins/ports/triggers.go b/plugins/ports/triggers.go new file mode 100644 index 00000000000..86623dd6492 --- /dev/null +++ b/plugins/ports/triggers.go @@ -0,0 +1,89 @@ +package ports + +import ( + "fmt" + + "github.com/dokku/dokku/plugins/config" +) + +// TriggerPortsClear removes all ports for the specified app +func TriggerPortsClear(appName string) error { + return clearPorts(appName) +} + +// TriggerPortsGet prints out the port mapping for a given app +func TriggerPortsGet(appName string) error { + for _, portMap := range getPortMaps(appName) { + if portMap.AllowsPersistence() { + continue + } + fmt.Println(portMap) + } + return nil +} + +// TriggerPostCertsRemove unsets port config vars after SSL cert is added +func TriggerPostCertsRemove(appName string) error { + keys := []string{"DOKKU_PROXY_SSL_PORT"} + if err := config.UnsetMany(appName, keys, false); err != nil { + return err + } + + return removePorts(appName, filterAppPorts(appName, "https", 443)) +} + +// TriggerPostCertsUpdate sets port config vars after SSL cert is added +func TriggerPostCertsUpdate(appName string) error { + port := config.GetWithDefault(appName, "DOKKU_PROXY_PORT", "") + sslPort := config.GetWithDefault(appName, "DOKKU_PROXY_SSL_PORT", "") + portMaps := getPortMaps(appName) + + toUnset := []string{} + if port == "80" { + toUnset = append(toUnset, "DOKKU_PROXY_PORT") + } + if sslPort == "443" { + toUnset = append(toUnset, "DOKKU_PROXY_SSL_PORT") + } + + if len(toUnset) > 0 { + if err := config.UnsetMany(appName, toUnset, false); err != nil { + return err + } + } + + var http80Ports []PortMap + for _, portMap := range portMaps { + if portMap.Scheme == "http" && portMap.HostPort == 80 { + http80Ports = append(http80Ports, portMap) + } + } + + if len(http80Ports) > 0 { + var https443Ports []PortMap + for _, portMap := range portMaps { + if portMap.Scheme == "https" && portMap.HostPort == 443 { + https443Ports = append(https443Ports, portMap) + } + } + + if err := removePorts(appName, https443Ports); err != nil { + return err + } + + var toAdd []PortMap + for _, portMap := range http80Ports { + toAdd = append(toAdd, PortMap{ + Scheme: "https", + HostPort: 443, + ContainerPort: portMap.ContainerPort, + }) + } + + if err := addPorts(appName, toAdd); err != nil { + return err + } + } + + return nil +} diff --git a/plugins/proxy/.gitignore b/plugins/proxy/.gitignore index 3b20f2e1cfc..3079acc9d7d 100644 --- a/plugins/proxy/.gitignore +++ b/plugins/proxy/.gitignore @@ -2,8 +2,7 @@ /subcommands/* /triggers/* /triggers -/proxy-* /install /post-* /report -!/proxy-configure-ports +/proxy-* diff --git a/plugins/proxy/Makefile b/plugins/proxy/Makefile index 21cc25c91fd..9ed4ffae5ff 100644 --- a/plugins/proxy/Makefile +++ b/plugins/proxy/Makefile @@ -1,5 +1,5 @@ -SUBCOMMANDS = subcommands/build-config subcommands/clear-config subcommands/disable subcommands/enable subcommands/ports subcommands/ports-add subcommands/ports-clear subcommands/ports-remove subcommands/ports-set subcommands/report subcommands/set -TRIGGERS = triggers/proxy-is-enabled triggers/proxy-type triggers/post-certs-remove triggers/post-certs-update triggers/report +SUBCOMMANDS = subcommands/build-config subcommands/clear-config subcommands/disable subcommands/enable subcommands/report subcommands/set +TRIGGERS = triggers/proxy-is-enabled triggers/proxy-type triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = proxy diff --git a/plugins/proxy/functions b/plugins/proxy/functions deleted file mode 100755 index 910a7a22e91..00000000000 --- a/plugins/proxy/functions +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_AVAILABLE_PATH/config/functions" - -is_app_proxy_enabled() { - declare desc="return true if proxy is enabled; otherwise return false" - declare APP="$1" - declare deprecated=true - dokku_log_warn "Deprecated: Use plugn#proxy-is-enabled" - - plugn trigger proxy-is-enabled "$APP" -} - -get_app_proxy_type() { - declare desc="return app proxy type" - declare APP="$1" - declare deprecated=true - dokku_log_warn "Deprecated: Use plugn#proxy-type" - - plugn trigger proxy-type "$APP" -} diff --git a/plugins/proxy/functions.go b/plugins/proxy/functions.go index bc12f32a9e6..4b5467f50e3 100644 --- a/plugins/proxy/functions.go +++ b/plugins/proxy/functions.go @@ -1,192 +1,9 @@ package proxy import ( - "errors" - "fmt" - "os" - "sort" - "strconv" - "strings" - - "github.com/dokku/dokku/plugins/common" "github.com/dokku/dokku/plugins/config" - "github.com/ryanuber/columnize" ) -func addProxyPorts(appName string, proxyPortMap []PortMap) error { - allPortMaps := getProxyPortMap(appName) - allPortMaps = append(allPortMaps, proxyPortMap...) - - return setProxyPorts(appName, allPortMaps) -} - -func filterAppProxyPorts(appName string, scheme string, hostPort int) []PortMap { - var filteredProxyMaps []PortMap - for _, portMap := range getProxyPortMap(appName) { - if portMap.Scheme == scheme && portMap.HostPort == hostPort { - filteredProxyMaps = append(filteredProxyMaps, portMap) - } - } - - return filteredProxyMaps -} - func getAppProxyType(appName string) string { return config.GetWithDefault(appName, "DOKKU_APP_PROXY_TYPE", "nginx") } - -func getProxyPortMap(appName string) []PortMap { - value := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "") - portMaps, _ := parseProxyPortMapString(value) - return portMaps -} - -func inRange(value int, min int, max int) bool { - return min < value && value < max -} - -func listAppProxyPorts(appName string) error { - proxyPortMap := getProxyPortMap(appName) - - if len(proxyPortMap) == 0 { - return errors.New("No port mappings configured for app") - } - - var lines []string - if os.Getenv("DOKKU_QUIET_OUTPUT") == "" { - lines = append(lines, "-----> scheme:host port:container port") - } - - for _, portMap := range proxyPortMap { - lines = append(lines, portMap.String()) - } - - sort.Strings(lines) - common.LogInfo1Quiet(fmt.Sprintf("Port mappings for %s", appName)) - config := columnize.DefaultConfig() - config.Delim = ":" - config.Prefix = " " - config.Empty = "" - fmt.Println(columnize.Format(lines, config)) - return nil -} - -func parseProxyPortMapString(stringPortMap string) ([]PortMap, error) { - var proxyPortMap []PortMap - - for _, v := range strings.Split(strings.TrimSpace(stringPortMap), " ") { - parts := strings.SplitN(v, ":", 3) - if len(parts) == 1 { - hostPort, err := strconv.Atoi(v) - if err != nil { - return proxyPortMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) - } - - if !inRange(hostPort, 0, 65536) { - return proxyPortMap, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort) - } - - proxyPortMap = append(proxyPortMap, PortMap{ - HostPort: hostPort, - Scheme: "__internal__", - }) - continue - } - - if len(parts) != 3 { - return proxyPortMap, fmt.Errorf("Invalid port map %s [len=%d]", v, len(parts)) - } - - hostPort, err := strconv.Atoi(parts[1]) - if err != nil { - return proxyPortMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) - } - - containerPort, err := strconv.Atoi(parts[2]) - if err != nil { - return proxyPortMap, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error()) - } - - if !inRange(hostPort, 0, 65536) { - return proxyPortMap, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort) - } - - if !inRange(containerPort, 0, 65536) { - return proxyPortMap, fmt.Errorf("Invalid port map %s [containerPort=%d]", v, containerPort) - } - - proxyPortMap = append(proxyPortMap, PortMap{ - ContainerPort: containerPort, - HostPort: hostPort, - Scheme: parts[0], - }) - } - - return uniqueProxyPortMap(proxyPortMap), nil -} - -func removeProxyPorts(appName string, proxyPortMap []PortMap) error { - toRemove := map[string]bool{} - toRemoveByPort := map[int]bool{} - - for _, portMap := range proxyPortMap { - if portMap.AllowsPersistence() { - toRemoveByPort[portMap.HostPort] = true - continue - } - toRemove[portMap.String()] = true - } - - var toSet []PortMap - for _, portMap := range getProxyPortMap(appName) { - if toRemove[portMap.String()] { - continue - } - - if toRemoveByPort[portMap.HostPort] { - continue - } - - toSet = append(toSet, portMap) - } - - if len(toSet) == 0 { - keys := []string{"DOKKU_PROXY_PORT_MAP"} - return config.UnsetMany(appName, keys, false) - } - - return setProxyPorts(appName, toSet) -} - -func setProxyPorts(appName string, proxyPortMap []PortMap) error { - var value []string - for _, portMap := range uniqueProxyPortMap(proxyPortMap) { - if portMap.AllowsPersistence() { - continue - } - - value = append(value, portMap.String()) - } - - sort.Strings(value) - entries := map[string]string{ - "DOKKU_PROXY_PORT_MAP": strings.Join(value, " "), - } - return config.SetMany(appName, entries, false) -} - -func uniqueProxyPortMap(proxyPortMap []PortMap) []PortMap { - var unique []PortMap - existingPortMaps := map[string]bool{} - - for _, portMap := range proxyPortMap { - if existingPortMaps[portMap.String()] { - continue - } - - existingPortMaps[portMap.String()] = true - unique = append(unique, portMap) - } - - return unique -} diff --git a/plugins/proxy/proxy.go b/plugins/proxy/proxy.go index ec87bf48c5e..26cfee2ffb4 100644 --- a/plugins/proxy/proxy.go +++ b/plugins/proxy/proxy.go @@ -1,8 +1,6 @@ package proxy import ( - "fmt" - "github.com/dokku/dokku/plugins/common" "github.com/dokku/dokku/plugins/config" ) @@ -11,22 +9,6 @@ import ( // and defaults to -1 (false) const RunInSerial = 0 -// PortMap is a struct that contains a scheme:host-port:container-port mapping -type PortMap struct { - ContainerPort int - HostPort int - Scheme string -} - -func (p PortMap) String() string { - return fmt.Sprintf("%s:%d:%d", p.Scheme, p.HostPort, p.ContainerPort) -} - -// AllowsPersistence returns true if the port map is not to be persisted -func (p PortMap) AllowsPersistence() bool { - return p.Scheme == "__internal__" -} - // BuildConfig rebuilds the proxy config for the specified app func BuildConfig(appName string) error { return common.PlugnTrigger("proxy-build-config", []string{appName}...) diff --git a/plugins/proxy/report.go b/plugins/proxy/report.go index bf4c5c917b4..5db7792a2f6 100644 --- a/plugins/proxy/report.go +++ b/plugins/proxy/report.go @@ -1,8 +1,6 @@ package proxy import ( - "strings" - "github.com/dokku/dokku/plugins/common" ) @@ -13,9 +11,8 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--proxy-enabled": reportEnabled, - "--proxy-type": reportType, - "--proxy-port-map": reportPortMap, + "--proxy-enabled": reportEnabled, + "--proxy-type": reportType, } flagKeys := []string{} @@ -41,12 +38,3 @@ func reportEnabled(appName string) string { func reportType(appName string) string { return getAppProxyType(appName) } - -func reportPortMap(appName string) string { - var proxyPortMap []string - for _, portMap := range getProxyPortMap(appName) { - proxyPortMap = append(proxyPortMap, portMap.String()) - } - - return strings.Join(proxyPortMap, " ") -} diff --git a/plugins/proxy/src/commands/commands.go b/plugins/proxy/src/commands/commands.go index e2f6c016a81..129cc282082 100644 --- a/plugins/proxy/src/commands/commands.go +++ b/plugins/proxy/src/commands/commands.go @@ -22,11 +22,6 @@ Additional commands:` proxy:clear-config [--all|], Clears config for a given app proxy:disable , Disable proxy for app proxy:enable , Enable proxy for app - proxy:ports , List proxy port mappings for app - proxy:ports-add [::...], Add proxy port mappings to an app - proxy:ports-clear , Clear all proxy port mappings for an app - proxy:ports-remove [|::...], Remove specific proxy port mappings from an app - proxy:ports-set [::...], Set proxy port mappings for an app proxy:report [] [], Displays a proxy report for one or more apps proxy:set , Set proxy type for app ` diff --git a/plugins/proxy/src/subcommands/subcommands.go b/plugins/proxy/src/subcommands/subcommands.go index c25db395ccb..d181068da7b 100644 --- a/plugins/proxy/src/subcommands/subcommands.go +++ b/plugins/proxy/src/subcommands/subcommands.go @@ -45,34 +45,6 @@ func main() { args.Parse(os.Args[2:]) appName := args.Arg(0) err = proxy.CommandEnable(appName, *allApps, *parallelCount) - case "ports": - args := flag.NewFlagSet("proxy:ports", flag.ExitOnError) - args.Parse(os.Args[2:]) - appName := args.Arg(0) - err = proxy.CommandPorts(appName) - case "ports-add": - args := flag.NewFlagSet("proxy:ports-add", flag.ExitOnError) - args.Parse(os.Args[2:]) - appName := args.Arg(0) - _, portMaps := common.ShiftString(args.Args()) - err = proxy.CommandPortsAdd(appName, portMaps) - case "ports-clear": - args := flag.NewFlagSet("proxy:ports-clear", flag.ExitOnError) - args.Parse(os.Args[2:]) - appName := args.Arg(0) - err = proxy.CommandPortsClear(appName) - case "ports-remove": - args := flag.NewFlagSet("proxy:ports-remove", flag.ExitOnError) - args.Parse(os.Args[2:]) - appName := args.Arg(0) - _, portMaps := common.ShiftString(args.Args()) - err = proxy.CommandPortsRemove(appName, portMaps) - case "ports-set": - args := flag.NewFlagSet("proxy:ports-set", flag.ExitOnError) - args.Parse(os.Args[2:]) - appName := args.Arg(0) - _, portMaps := common.ShiftString(args.Args()) - err = proxy.CommandPortsSet(appName, portMaps) case "report": args := flag.NewFlagSet("proxy:report", flag.ExitOnError) format := args.String("format", "stdout", "format: [ stdout | json ]") diff --git a/plugins/proxy/src/triggers/triggers.go b/plugins/proxy/src/triggers/triggers.go index 11c5bd277ab..713e1976d0c 100644 --- a/plugins/proxy/src/triggers/triggers.go +++ b/plugins/proxy/src/triggers/triggers.go @@ -24,12 +24,6 @@ func main() { case "proxy-type": appName := flag.Arg(0) err = proxy.TriggerProxyType(appName) - case "post-certs-remove": - appName := flag.Arg(0) - err = proxy.TriggerPostCertsRemove(appName) - case "post-certs-update": - appName := flag.Arg(0) - err = proxy.TriggerPostCertsUpdate(appName) case "report": appName := flag.Arg(0) err = proxy.ReportSingleApp(appName, "", "") diff --git a/plugins/proxy/subcommands.go b/plugins/proxy/subcommands.go index 1dcb66558a5..58a57a87029 100644 --- a/plugins/proxy/subcommands.go +++ b/plugins/proxy/subcommands.go @@ -2,7 +2,6 @@ package proxy import ( "errors" - "strings" "github.com/dokku/dokku/plugins/common" "github.com/dokku/dokku/plugins/config" @@ -60,95 +59,6 @@ func CommandEnable(appName string, allApps bool, parallelCount int) error { return Enable(appName) } -// CommandPorts is a cmd wrapper to list proxy port mappings for an app -func CommandPorts(appName string) error { - if err := common.VerifyAppName(appName); err != nil { - return err - } - - return listAppProxyPorts(appName) -} - -// CommandPortsAdd adds proxy port mappings to an app -func CommandPortsAdd(appName string, portMaps []string) error { - if err := common.VerifyAppName(appName); err != nil { - return err - } - - if len(portMaps) == 0 { - return errors.New("No port mapping specified") - } - - proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " ")) - if err != nil { - return err - } - - if err := addProxyPorts(appName, proxyPortMap); err != nil { - return err - } - - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "add"}...) -} - -// CommandPortsClear clears all proxy port mappings for an app -func CommandPortsClear(appName string) error { - if err := common.VerifyAppName(appName); err != nil { - return err - } - - keys := []string{"DOKKU_PROXY_PORT_MAP"} - if err := config.UnsetMany(appName, keys, false); err != nil { - return err - } - - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "clear"}...) -} - -// CommandPortsRemove removes specific proxy port mappings from an app -func CommandPortsRemove(appName string, portMaps []string) error { - if err := common.VerifyAppName(appName); err != nil { - return err - } - - if len(portMaps) == 0 { - return errors.New("No port mapping specified") - } - - proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " ")) - if err != nil { - return err - } - - if err := removeProxyPorts(appName, proxyPortMap); err != nil { - return err - } - - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "remove"}...) -} - -// CommandPortsSet sets proxy port mappings for an app -func CommandPortsSet(appName string, portMaps []string) error { - if err := common.VerifyAppName(appName); err != nil { - return err - } - - if len(portMaps) == 0 { - return errors.New("No port mapping specified") - } - - proxyPortMap, err := parseProxyPortMapString(strings.Join(portMaps, " ")) - if err != nil { - return err - } - - if err := setProxyPorts(appName, proxyPortMap); err != nil { - return err - } - - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "set"}...) -} - // CommandReport displays a proxy report for one or more apps func CommandReport(appName string, format string, infoFlag string) error { if len(appName) == 0 { diff --git a/plugins/proxy/triggers.go b/plugins/proxy/triggers.go index 626f95a3009..49c0fef0699 100644 --- a/plugins/proxy/triggers.go +++ b/plugins/proxy/triggers.go @@ -2,8 +2,6 @@ package proxy import ( "fmt" - - "github.com/dokku/dokku/plugins/config" ) // TriggerProxyIsEnabled prints true or false depending on whether the proxy is enabled @@ -24,69 +22,3 @@ func TriggerProxyType(appName string) error { return nil } - -// TriggerPostCertsRemove unsets port config vars after SSL cert is added -func TriggerPostCertsRemove(appName string) error { - keys := []string{"DOKKU_PROXY_SSL_PORT"} - if err := config.UnsetMany(appName, keys, false); err != nil { - return err - } - - return removeProxyPorts(appName, filterAppProxyPorts(appName, "https", 443)) -} - -// TriggerPostCertsUpdate sets port config vars after SSL cert is added -func TriggerPostCertsUpdate(appName string) error { - port := config.GetWithDefault(appName, "DOKKU_PROXY_PORT", "") - sslPort := config.GetWithDefault(appName, "DOKKU_PROXY_SSL_PORT", "") - proxyPortMap := getProxyPortMap(appName) - - toUnset := []string{} - if port == "80" { - toUnset = append(toUnset, "DOKKU_PROXY_PORT") - } - if sslPort == "443" { - toUnset = append(toUnset, "DOKKU_PROXY_SSL_PORT") - } - - if len(toUnset) > 0 { - if err := config.UnsetMany(appName, toUnset, false); err != nil { - return err - } - } - - var http80Ports []PortMap - for _, portMap := range proxyPortMap { - if portMap.Scheme == "http" && portMap.HostPort == 80 { - http80Ports = append(http80Ports, portMap) - } - } - - if len(http80Ports) > 0 { - var https443Ports []PortMap - for _, portMap := range proxyPortMap { - if portMap.Scheme == "https" && portMap.HostPort == 443 { - https443Ports = append(https443Ports, portMap) - } - } - - if err := removeProxyPorts(appName, https443Ports); err != nil { - return err - } - - var toAdd []PortMap - for _, portMap := range http80Ports { - toAdd = append(toAdd, PortMap{ - Scheme: "https", - HostPort: 443, - ContainerPort: portMap.ContainerPort, - }) - } - - if err := addProxyPorts(appName, toAdd); err != nil { - return err - } - } - - return nil -} diff --git a/plugins/traefik-vhosts/docker-args-process-deploy b/plugins/traefik-vhosts/docker-args-process-deploy index c81248ceaf1..f9d94ffa46b 100755 --- a/plugins/traefik-vhosts/docker-args-process-deploy +++ b/plugins/traefik-vhosts/docker-args-process-deploy @@ -8,7 +8,7 @@ trigger-traefik-vhosts-docker-args-process-deploy() { declare desc="nginx-vhosts core-post-deploy plugin trigger" declare trigger="docker-args-process-deploy" declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3" PROC_TYPE="$4" CONTAINER_INDEX="$5" - local app_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_port_map priority proxy_scheme proxy_schemes traefik_domains + local app_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map priority proxy_scheme proxy_schemes traefik_domains local proxy_container_http_port proxy_container_http_port_candidate proxy_host_http_port_candidate local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate local STDIN=$(cat) @@ -30,15 +30,14 @@ trigger-traefik-vhosts-docker-args-process-deploy() { fi # ensure we have a port mapping - plugn trigger proxy-configure-ports "$APP" + plugn trigger ports-configure "$APP" # gather port mapping information # we only support proxying a single port for http and https listeners # so this block parses the port mappings and tries to find the correct # mapping to expose is_app_listening="false" - proxy_port_map="$(plugn trigger config-get "$APP" DOKKU_PROXY_PORT_MAP)" - for port_map in $proxy_port_map; do + while read -r port_map; do proxy_scheme="$(awk -F ':' '{ print $1 }' <<<"$port_map")" proxy_host_port="$(awk -F ':' '{ print $2 }' <<<"$port_map")" proxy_container_port="$(awk -F ':' '{ print $3 }' <<<"$port_map")" @@ -66,7 +65,7 @@ trigger-traefik-vhosts-docker-args-process-deploy() { proxy_container_https_port="$proxy_container_port" fi fi - done + done < <(plugn trigger ports-get "$APP") letsencrypt_email="$(fn-traefik-letsencrypt-email)" if [[ -n "$letsencrypt_email" ]] && [[ -z "$proxy_container_https_port" ]]; then diff --git a/tests/unit/apps_2.bats b/tests/unit/apps_2.bats index 2afb61fa827..966bea44efb 100644 --- a/tests/unit/apps_2.bats +++ b/tests/unit/apps_2.bats @@ -108,13 +108,14 @@ teardown() { } @test "(apps) apps:clone ssl-app" { - run /bin/bash -c "dokku config:set --no-restart $TEST_APP DOKKU_PROXY_PORT_MAP=https:443:5000 DOKKU_PROXY_SSL_PORT=443" + run /bin/bash -c "dokku ports:set $TEST_APP https:443:5000" + run /bin/bash -c "dokku config:set --no-restart $TEST_APP DOKKU_PROXY_SSL_PORT=443" deploy_app run /bin/bash -c "dokku apps:clone $TEST_APP app-without-ssl" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku --quiet proxy:ports app-without-ssl | xargs" + run /bin/bash -c "dokku --quiet ports:list app-without-ssl | xargs" echo "output: $output" echo "status: $status" assert_output "http 80 5000" diff --git a/tests/unit/caddy.bats b/tests/unit/caddy.bats index 1ff68959c9e..e05da79185d 100644 --- a/tests/unit/caddy.bats +++ b/tests/unit/caddy.bats @@ -137,7 +137,7 @@ teardown() { assert_success assert_output "$TEST_APP.dokku.me" - run /bin/bash -c "dokku proxy:report $TEST_APP --proxy-port-map" + run /bin/bash -c "dokku ports:report $TEST_APP --ports-map" echo "output: $output" echo "status: $status" assert_output "http:80:5000" diff --git a/tests/unit/nginx-vhosts_3.bats b/tests/unit/nginx-vhosts_3.bats index babc690c5fd..0a7ad5fa7c2 100644 --- a/tests/unit/nginx-vhosts_3.bats +++ b/tests/unit/nginx-vhosts_3.bats @@ -18,14 +18,14 @@ teardown() { @test "(nginx-vhosts) grpc endpoint" { deploy_app gogrpc - dokku proxy:ports-add "$TEST_APP" "grpc:80:50051" + dokku ports:add "$TEST_APP" "grpc:80:50051" run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:80 -name grpc" assert_output "Greeting: Hello grpc" } @test "(nginx-vhosts) grpc endpoint on a port other than 80" { deploy_app gogrpc - dokku proxy:ports-add "$TEST_APP" "grpc:8080:50051" + dokku ports:add "$TEST_APP" "grpc:8080:50051" run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:8080 -name grpc8080" assert_output "Greeting: Hello grpc8080" } @@ -33,7 +33,7 @@ teardown() { @test "(nginx-vhosts) grpcs endpoint" { setup_test_tls deploy_app gogrpc - dokku proxy:ports-add "$TEST_APP" "grpcs:443:50051" + dokku ports:add "$TEST_APP" "grpcs:443:50051" run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:443 -name grpcs -tls" assert_output "Greeting: Hello grpcs" } diff --git a/tests/unit/nginx-vhosts_8.bats b/tests/unit/nginx-vhosts_8.bats index e1de6ab34ee..f85d56d7dab 100644 --- a/tests/unit/nginx-vhosts_8.bats +++ b/tests/unit/nginx-vhosts_8.bats @@ -125,7 +125,7 @@ teardown() { assert_output_contains "Ignoring detected https port mapping without an accompanying ssl certificate" 0 teardown_test_tls - run /bin/bash -c "dokku proxy:report $TEST_APP --proxy-port-map" + run /bin/bash -c "dokku ports:report $TEST_APP --ports-map" echo "output: $output" echo "status: $status" assert_output "http:80:5000 https:443:5000" @@ -135,7 +135,7 @@ teardown() { echo "status: $status" assert_output_contains "Ignoring detected https port mapping without an accompanying ssl certificate" 1 - run /bin/bash -c "dokku proxy:report $TEST_APP --proxy-port-map" + run /bin/bash -c "dokku ports:report $TEST_APP --ports-map" echo "output: $output" echo "status: $status" assert_output "http:80:5000 https:443:5000" diff --git a/tests/unit/ports.bats b/tests/unit/ports.bats new file mode 100644 index 00000000000..d982a36496a --- /dev/null +++ b/tests/unit/ports.bats @@ -0,0 +1,106 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + global_setup + [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" + create_app +} + +teardown() { + destroy_app 0 $TEST_APP + [[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST" + global_teardown +} + +@test "(ports) ports:help" { + run /bin/bash -c "dokku ports" + echo "output: $output" + echo "status: $status" + assert_output_contains "Manage ports for an app" + help_output="$output" + + run /bin/bash -c "dokku ports:help" + echo "output: $output" + echo "status: $status" + assert_output_contains "Manage ports for an app" + assert_output "$help_output" +} + +@test "(ports) list/add/set/remove/clear" { + run /bin/bash -c "dokku ports:set $TEST_APP http:1234:5001" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "http 1234 5001" + + run /bin/bash -c "dokku ports:add $TEST_APP http:8080:5002 https:8443:5003" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "http 1234 5001 http 8080 5002 https 8443 5003" + + run /bin/bash -c "dokku ports:set $TEST_APP http:8080:5000 https:8443:5000 http:1234:5001" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "http 1234 5001 http 8080 5000 https 8443 5000" + + run /bin/bash -c "dokku ports:remove $TEST_APP 8080" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "http 1234 5001 https 8443 5000" + + run /bin/bash -c "dokku ports:remove $TEST_APP http:1234:5001" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "https 8443 5000" + + run /bin/bash -c "dokku ports:clear $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet ports:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "http 80 5000" +} + +@test "(ports) ports:add (post-deploy add)" { + deploy_app + run /bin/bash -c "dokku ports:add $TEST_APP http:8080:5000 http:8081:5000" + echo "output: $output" + echo "status: $status" + assert_success + + URLS="$(dokku --quiet urls "$TEST_APP")" + for URL in $URLS; do + assert_http_success $URL + done + assert_http_success "http://$TEST_APP.dokku.me:8080" + assert_http_success "http://$TEST_APP.dokku.me:8081" +} diff --git a/tests/unit/proxied-app.bats b/tests/unit/proxied-app.bats index e16928634dd..3d4ed454842 100644 --- a/tests/unit/proxied-app.bats +++ b/tests/unit/proxied-app.bats @@ -29,7 +29,7 @@ teardown() { echo "status: $status" assert_success - run /bin/bash -c "dokku proxy:ports-set $TEST_APP http:80:8080" + run /bin/bash -c "dokku ports:set $TEST_APP http:80:8080" echo "output: $output" echo "status: $status" assert_success diff --git a/tests/unit/proxy.bats b/tests/unit/proxy.bats index be69693fde1..1de3c9db0c4 100644 --- a/tests/unit/proxy.bats +++ b/tests/unit/proxy.bats @@ -113,80 +113,3 @@ teardown() { assert_not_external_port $(<$CID_FILE) done } - -@test "(proxy) proxy:ports (list/add/set/remove/clear)" { - run /bin/bash -c "dokku proxy:ports-set $TEST_APP http:1234:5001" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "http 1234 5001" - - run /bin/bash -c "dokku proxy:ports-add $TEST_APP http:8080:5002 https:8443:5003" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "http 1234 5001 http 8080 5002 https 8443 5003" - - run /bin/bash -c "dokku proxy:ports-set $TEST_APP http:8080:5000 https:8443:5000 http:1234:5001" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "http 1234 5001 http 8080 5000 https 8443 5000" - - run /bin/bash -c "dokku proxy:ports-remove $TEST_APP 8080" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "http 1234 5001 https 8443 5000" - - run /bin/bash -c "dokku proxy:ports-remove $TEST_APP http:1234:5001" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "https 8443 5000" - - run /bin/bash -c "dokku proxy:ports-clear $TEST_APP" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku --quiet proxy:ports $TEST_APP | xargs" - echo "output: $output" - echo "status: $status" - assert_output "http 80 5000" -} - -@test "(proxy) proxy:ports (post-deploy add)" { - deploy_app - run /bin/bash -c "dokku proxy:ports-add $TEST_APP http:8080:5000 http:8081:5000" - echo "output: $output" - echo "status: $status" - assert_success - - URLS="$(dokku --quiet urls "$TEST_APP")" - for URL in $URLS; do - assert_http_success $URL - done - assert_http_success "http://$TEST_APP.dokku.me:8080" - assert_http_success "http://$TEST_APP.dokku.me:8081" -} diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 2c1f34a8b1c..a6a3aaa9560 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -288,7 +288,7 @@ assert_url() { echo "VHOST: $(cat $DOKKU_ROOT/$TEST_APP/VHOST | xargs)" echo "tls: $(ls $DOKKU_ROOT/$TEST_APP/tls || true)" echo "proxy-is-enabled: $(dokku plugin:trigger proxy-is-enabled "$TEST_APP")" - echo "port-map: $(dokku config:get "$TEST_APP" DOKKU_PROXY_PORT_MAP)" + echo "port-map: $(dokku ports:report "$TEST_APP" --ports-map)" echo "url: $(dokku urls $TEST_APP)" echo "output: $output" echo "status: $status" @@ -302,7 +302,7 @@ assert_urls() { echo "VHOST: $(cat $DOKKU_ROOT/$TEST_APP/VHOST | xargs)" echo "tls: $(ls $DOKKU_ROOT/$TEST_APP/tls || true)" echo "proxy-is-enabled: $(dokku plugin:trigger proxy-is-enabled "$TEST_APP")" - echo "port-map: $(dokku config:get "$TEST_APP" DOKKU_PROXY_PORT_MAP)" + echo "port-map: $(dokku ports:report "$TEST_APP" --ports-map)" echo "urls: $(dokku urls $TEST_APP)" echo "output: $output" echo "status: $status" diff --git a/tests/unit/traefik.bats b/tests/unit/traefik.bats index 4c3b0e82c57..d7cdb647e2d 100644 --- a/tests/unit/traefik.bats +++ b/tests/unit/traefik.bats @@ -177,7 +177,7 @@ teardown() { assert_success assert_output "5000" - run /bin/bash -c "dokku proxy:report $TEST_APP --proxy-port-map" + run /bin/bash -c "dokku ports:report $TEST_APP --ports-map" echo "output: $output" echo "status: $status" assert_output "http:80:5000"