refactor: move all port management code to standalone ports plugin
This change makes interacting with port mappings more clear - folks might previously set the port mapping to the proxy type or vice-versa. The existing proxy:ports* commands still exist but will show a deprecation warning for a single minor release.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# 0.30.0 Migration Guide
|
||||
# 0.31.0 Migration Guide
|
||||
|
||||
## Changes
|
||||
|
||||
- Herokuish build cache is now mounted from a docker volume - eg. `cache-node-js-app` - instead of the local filesystem. All existing app cache will be cleared upon upgrading past 0.29.0.
|
||||
- The `proxy:ports*` commands have been replaced with the new `ports` plugin. Users will be able to use the old `proxy:ports*` commands for a single minor release, and they will be removed in the next minor release.
|
||||
|
||||
@@ -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` <br /> `~dokku/.dokkurc` <br /> `~dokku/.dokkurc/*` <br /> `dokku config:set` | |
|
||||
| `DOKKU_PROXY_SSL_PORT` | automatically assigned | `/etc/environment` <br /> `~dokku/.dokkurc` <br /> `~dokku/.dokkurc/*` <br /> `dokku config:set` | |
|
||||
| `DOKKU_PROXY_PORT_MAP` | automatically assigned | `dokku proxy:ports-add` <br /> `dokku proxy:ports-remove`, `dokku proxy:ports-clear` | |
|
||||
| `DOKKU_PROXY_PORT_MAP` | automatically assigned | `dokku ports:add` <br /> `dokku ports:remove`, `dokku ports:clear` | |
|
||||
| `DOKKU_SKIP_ALL_CHECKS` | none | `dokku config:set` | |
|
||||
| `DOKKU_SKIP_CLEANUP` | | `/etc/environment` <br /> `~dokku/.dokkurc` <br /> `~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` | |
|
||||
|
||||
@@ -134,7 +134,7 @@ Certain versions of nginx have bugs that prevent [HTTP/2](https://nginx.org/en/d
|
||||
|
||||
### 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 <APP> 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 <APP> https:443:99999`.
|
||||
|
||||
## Other
|
||||
|
||||
|
||||
@@ -1498,8 +1498,8 @@ popd &>/dev/null
|
||||
|
||||
### `post-proxy-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`
|
||||
- Description: Allows you to run commands once the port mappings for an app have been updated. It also sends the invoking command. This can be "add", "clear" or "remove".
|
||||
- Invoked by: `dokku ports:add`, `dokku ports:clear`, `dokku ports:remove`
|
||||
- Arguments: `$APP` `action name`
|
||||
- Example:
|
||||
|
||||
@@ -1842,7 +1842,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
### `proxy-configure-ports`
|
||||
|
||||
- Description: Configures the proxy port mapping
|
||||
- Description: Configures the port mapping
|
||||
- Invoked by: `internally triggered by proxy plugins`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
@@ -72,12 +72,12 @@ For example, if you have an `EXPOSE` directive like so:
|
||||
EXPOSE 8000
|
||||
```
|
||||
|
||||
The proxy port mapping will be `http:8000:8000`.
|
||||
The 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.
|
||||
|
||||
@@ -233,16 +233,14 @@ If this solves the issue temporarily, longer term you should consider [configuri
|
||||
|
||||
### My application deploys properly, but won't load in browser "connection refused"
|
||||
|
||||
This could be a result of a bad proxy configuration (`http:5000:5000` may be incorrect). Run `dokku proxy:report myapp` to check if your app has the correct proxy configuration. It should show something like the following.
|
||||
This could be a result of a bad proxy configuration (`http:5000:5000` may be incorrect). Run `dokku ports:report node-js-app` to check if your app has the correct proxy configuration. It should show something like the following.
|
||||
|
||||
```
|
||||
=====> myapp proxy information
|
||||
Proxy enabled: true
|
||||
Proxy port map: http:80:5000 https:443:5000
|
||||
Proxy type: nginx
|
||||
=====> node-js-app ports information
|
||||
Port map: http:80:5000 https:443:5000
|
||||
```
|
||||
|
||||
Set `dokku proxy:ports-set front http:80:5000` to get proxy correctly configured for http endpoint.
|
||||
Set `dokku ports:set node-js-app http:80:5000` to get proxy correctly configured for http endpoint.
|
||||
|
||||
### I deployed a new app but now subdomains are miss-routed
|
||||
|
||||
|
||||
@@ -1,37 +1,52 @@
|
||||
# Port Management
|
||||
|
||||
> New as of 0.5.0, Enhanced in 0.6.0
|
||||
> New as of 0.31.0, replaces the previous `proxy:ports*` commands
|
||||
|
||||
```
|
||||
proxy:ports <app> # List proxy port mappings for an app
|
||||
proxy:ports-add <app> <scheme>:<host-port>:<container-port> [<scheme>:<host-port>:<container-port>...] # Add proxy port mappings to an app
|
||||
proxy:ports-clear <app> # Clear all proxy port mappings for an app
|
||||
proxy:ports-remove <app> <host-port> [<host-port>|<scheme>:<host-port>:<container-port>...] # Remove specific proxy port mappings from an app
|
||||
proxy:ports-set <app> <scheme>:<host-port>:<container-port> [<scheme>:<host-port>:<container-port>...] # Set proxy port mappings for an app
|
||||
ports:list <app> # List port mappings for an app
|
||||
ports:add <app> <scheme>:<host-port>:<container-port> [<scheme>:<host-port>:<container-port>...] # Add port mappings to an app
|
||||
ports:clear <app> # Clear all port mappings for an app
|
||||
ports:remove <app> <host-port> [<host-port>|<scheme>:<host-port>:<container-port>...] # Remove specific port mappings from an app
|
||||
ports:set <app> <scheme>:<host-port>:<container-port> [<scheme>:<host-port>:<container-port>...] # 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.
|
||||
|
||||
## Usage
|
||||
|
||||
> Warning: Mapping alternative ports may conflict with the active firewall installed on your server or hosting provider. Such software includes - but is not limited to - AWS Security Groups, iptables, and UFW. Please consult the documentation for those softwares as applicable.
|
||||
>
|
||||
> 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.
|
||||
|
||||
### Port Scheme
|
||||
|
||||
The proxy port scheme is as follows:
|
||||
|
||||
- `SCHEME:HOST_PORT:CONTAINER_PORT`
|
||||
|
||||
The scheme metadata can be used by proxy implementations in order to properly handle proxying of requests. For example, the built-in `nginx-vhosts` proxy implementation supports the `http`, `https`, `grpc` and `grpcs` schemes.
|
||||
For the `grpc` and `grpcs` see [nginx blog post on grpc](https://www.nginx.com/blog/nginx-1-13-10-grpc/).
|
||||
|
||||
Developers of proxy implementations are encouraged to use whatever schemes make the most sense, and ignore configurations which they do not support. For instance, a `udp` proxy implementation can safely ignore `http` and `https` port mappings.
|
||||
|
||||
To change the proxy implementation in use for an application, use the `proxy:set` command:
|
||||
|
||||
```shell
|
||||
# no validation will be performed against
|
||||
# the specified proxy implementation
|
||||
dokku proxy:set node-js-app nginx
|
||||
```
|
||||
|
||||
### 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 +77,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 +113,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 +129,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
|
||||
|
||||
@@ -156,10 +171,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 +191,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 +201,41 @@ 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.
|
||||
|
||||
### Displaying ports reports for an app
|
||||
|
||||
You can get a report about the app's ports status using the `ports:report` command:
|
||||
|
||||
```shell
|
||||
dokku ports:report
|
||||
```
|
||||
|
||||
```
|
||||
=====> node-js-app ports information
|
||||
Port map: http:80:5000 https:443:5000
|
||||
=====> python-sample ports information
|
||||
Port map: http:80:5000
|
||||
=====> ruby-sample ports information
|
||||
Port map: http:80:5000
|
||||
```
|
||||
|
||||
You can run the command for a specific app also.
|
||||
|
||||
```shell
|
||||
dokku ports:report node-js-app
|
||||
```
|
||||
|
||||
```
|
||||
=====> node-js-app ports information
|
||||
Port map: http:80:5000 https:443:5000
|
||||
```
|
||||
|
||||
You can pass flags which will output only the value of the specific information you want. For example:
|
||||
|
||||
```shell
|
||||
dokku ports:report node-js-app --ports-map
|
||||
```
|
||||
|
||||
@@ -506,7 +506,7 @@ See the [proxy documentation](/docs/networking/proxy-management.md) for more inf
|
||||
|
||||
### Managing Proxy Port mappings
|
||||
|
||||
See the [proxy documentation](/docs/networking/proxy-management.md#proxy-port-mapping) for more information on how to manage ports proxied for your app.
|
||||
See the [ports documentation](/docs/networking/port-management.md) for more information on how to manage ports proxied for your app.
|
||||
|
||||
### Regenerating nginx config
|
||||
|
||||
|
||||
@@ -73,15 +73,12 @@ dokku proxy:report
|
||||
=====> node-js-app proxy information
|
||||
Proxy enabled: true
|
||||
Proxy type: nginx
|
||||
Proxy port map: http:80:5000 https:443:5000
|
||||
=====> python-sample proxy information
|
||||
Proxy enabled: true
|
||||
Proxy type: nginx
|
||||
Proxy port map: http:80:5000
|
||||
=====> ruby-sample proxy information
|
||||
Proxy enabled: true
|
||||
Proxy type: nginx
|
||||
Proxy port map: http:80:5000
|
||||
```
|
||||
|
||||
You can run the command for a specific app also.
|
||||
@@ -94,7 +91,6 @@ dokku proxy:report node-js-app
|
||||
=====> node-js-app proxy information
|
||||
Proxy enabled: true
|
||||
Proxy type: nginx
|
||||
Proxy port map: http:80:5000 https:443:5000
|
||||
```
|
||||
|
||||
You can pass flags which will output only the value of the specific information you want. For example:
|
||||
@@ -105,22 +101,7 @@ dokku proxy:report node-js-app --proxy-type
|
||||
|
||||
#### Proxy Port Scheme
|
||||
|
||||
The proxy port scheme is as follows:
|
||||
|
||||
- `SCHEME:HOST_PORT:CONTAINER_PORT`
|
||||
|
||||
The scheme metadata can be used by proxy implementations in order to properly handle proxying of requests. For example, the built-in `nginx-vhosts` proxy implementation supports the `http`, `https`, `grpc` and `grpcs` schemes.
|
||||
For the `grpc` and `grpcs` see [nginx blog post on grpc](https://www.nginx.com/blog/nginx-1-13-10-grpc/).
|
||||
|
||||
Developers of proxy implementations are encouraged to use whatever schemes make the most sense, and ignore configurations which they do not support. For instance, a `udp` proxy implementation can safely ignore `http` and `https` port mappings.
|
||||
|
||||
To change the proxy implementation in use for an application, use the `proxy:set` command:
|
||||
|
||||
```shell
|
||||
# no validation will be performed against
|
||||
# the specified proxy implementation
|
||||
dokku proxy:set node-js-app nginx
|
||||
```
|
||||
See the [port scheme documentation](/docs/networking/port-management.md#port-scheme) for more information on the port mapping scheme used by dokku.
|
||||
|
||||
### Proxy port mapping
|
||||
|
||||
@@ -136,7 +117,7 @@ From Dokku versions `0.5.0` until `0.11.0`, enabling or disabling an application
|
||||
|
||||
Custom plugins names _must_ have the suffix `-vhosts` or scheduler overriding via `proxy:set` may not function as expected.
|
||||
|
||||
At this time, the following dokku commands are used to implement a complete proxy implementation.
|
||||
At this time, the following dokku commands are used to interact with a complete proxy implementation.
|
||||
|
||||
- `domains:add`: Adds a given domain to an app.
|
||||
- triggers: `post-domains-update`
|
||||
@@ -158,13 +139,13 @@ 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
|
||||
- `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.
|
||||
- `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.
|
||||
- `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.
|
||||
- `ports:set`: Sets all port mappings for an app.
|
||||
- triggers: `post-proxy-ports-update`
|
||||
|
||||
Proxy implementations may decide to omit some functionality here, or use plugin triggers to supplement config with information from other plugins.
|
||||
|
||||
7
plugins/ports/.gitignore
vendored
Normal file
7
plugins/ports/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
/commands
|
||||
/subcommands/*
|
||||
/triggers/*
|
||||
/triggers
|
||||
/install
|
||||
/post-*
|
||||
/report
|
||||
6
plugins/ports/Makefile
Normal file
6
plugins/ports/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
SUBCOMMANDS = subcommands/list subcommands/add subcommands/clear subcommands/remove subcommands/set subcommands/report
|
||||
TRIGGERS = triggers/post-certs-remove triggers/post-certs-update triggers/report
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = ports
|
||||
|
||||
include ../../common.mk
|
||||
188
plugins/ports/functions.go
Normal file
188
plugins/ports/functions.go
Normal file
@@ -0,0 +1,188 @@
|
||||
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 addPortMaps(appName string, portMaps []PortMap) error {
|
||||
allPortMaps := getPortMaps(appName)
|
||||
allPortMaps = append(allPortMaps, portMaps...)
|
||||
|
||||
return setPortMaps(appName, allPortMaps)
|
||||
}
|
||||
|
||||
func filterAppPortMaps(appName string, scheme string, hostPort int) []PortMap {
|
||||
var filteredPortMaps []PortMap
|
||||
for _, portMap := range getPortMaps(appName) {
|
||||
if portMap.Scheme == scheme && portMap.HostPort == hostPort {
|
||||
filteredPortMaps = append(filteredPortMaps, portMap)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPortMaps
|
||||
}
|
||||
|
||||
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 listAppPortMaps(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 portMaps []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 portMaps, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error())
|
||||
}
|
||||
|
||||
if !inRange(hostPort, 0, 65536) {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort)
|
||||
}
|
||||
|
||||
portMaps = append(portMaps, PortMap{
|
||||
HostPort: hostPort,
|
||||
Scheme: "__internal__",
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) != 3 {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [len=%d]", v, len(parts))
|
||||
}
|
||||
|
||||
hostPort, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error())
|
||||
}
|
||||
|
||||
containerPort, err := strconv.Atoi(parts[2])
|
||||
if err != nil {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [err=%s]", v, err.Error())
|
||||
}
|
||||
|
||||
if !inRange(hostPort, 0, 65536) {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [hostPort=%d]", v, hostPort)
|
||||
}
|
||||
|
||||
if !inRange(containerPort, 0, 65536) {
|
||||
return portMaps, fmt.Errorf("Invalid port map %s [containerPort=%d]", v, containerPort)
|
||||
}
|
||||
|
||||
portMaps = append(portMaps, PortMap{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
Scheme: parts[0],
|
||||
})
|
||||
}
|
||||
|
||||
return uniquePortMaps(portMaps), nil
|
||||
}
|
||||
|
||||
func removePortMaps(appName string, portMaps []PortMap) error {
|
||||
toRemove := map[string]bool{}
|
||||
toRemoveByPort := map[int]bool{}
|
||||
|
||||
for _, portMap := range portMaps {
|
||||
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 {
|
||||
keys := []string{"DOKKU_PROXY_PORT_MAP"}
|
||||
return config.UnsetMany(appName, keys, false)
|
||||
}
|
||||
|
||||
return setPortMaps(appName, toSet)
|
||||
}
|
||||
|
||||
func setPortMaps(appName string, portMaps []PortMap) error {
|
||||
var value []string
|
||||
for _, portMap := range uniquePortMaps(portMaps) {
|
||||
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 uniquePortMaps(portMaps []PortMap) []PortMap {
|
||||
var unique []PortMap
|
||||
existingPortMaps := map[string]bool{}
|
||||
|
||||
for _, portMap := range portMaps {
|
||||
if existingPortMaps[portMap.String()] {
|
||||
continue
|
||||
}
|
||||
|
||||
existingPortMaps[portMap.String()] = true
|
||||
unique = append(unique, portMap)
|
||||
}
|
||||
|
||||
return unique
|
||||
}
|
||||
23
plugins/ports/go.mod
Normal file
23
plugins/ports/go.mod
Normal file
@@ -0,0 +1,23 @@
|
||||
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 v2.1.2+incompatible
|
||||
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
|
||||
github.com/otiai10/copy v1.12.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/dokku/dokku/plugins/common => ../common
|
||||
|
||||
replace github.com/dokku/dokku/plugins/config => ../config
|
||||
22
plugins/ports/go.sum
Normal file
22
plugins/ports/go.sum
Normal file
@@ -0,0 +1,22 @@
|
||||
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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
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.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||
github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY=
|
||||
github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
|
||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible/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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
4
plugins/ports/plugin.toml
Normal file
4
plugins/ports/plugin.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core ports plugin"
|
||||
version = "0.30.8"
|
||||
[plugin.config]
|
||||
@@ -4,8 +4,8 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
trigger-proxy-proxy-configure-ports() {
|
||||
declare desc="proxy proxy-configure-ports plugin trigger"
|
||||
trigger-ports-proxy-configure-ports() {
|
||||
declare desc="ports proxy-configure-ports plugin trigger"
|
||||
declare trigger="proxy-configure-ports"
|
||||
declare APP="$1"
|
||||
local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
|
||||
@@ -19,7 +19,7 @@ trigger-proxy-proxy-configure-ports() {
|
||||
|
||||
if [[ -z "$DOKKU_PROXY_PORT" ]] && [[ -z "$RAW_TCP_PORTS" ]]; then
|
||||
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
|
||||
dokku_log_info1 "No proxy port set, setting to random open high port"
|
||||
dokku_log_info1 "No port set, setting to random open high port"
|
||||
local PROXY_PORT=$(get_available_port)
|
||||
else
|
||||
local PROXY_PORT=$(config_get --global DOKKU_PROXY_PORT)
|
||||
@@ -32,7 +32,7 @@ trigger-proxy-proxy-configure-ports() {
|
||||
local PROXY_SSL_PORT=$(config_get --global DOKKU_PROXY_SSL_PORT)
|
||||
PROXY_SSL_PORT=${PROXY_SSL_PORT:=443}
|
||||
if [[ -z "$RAW_TCP_PORTS" ]] && [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
|
||||
dokku_log_info1 "No proxy ssl port set, setting to random open high port"
|
||||
dokku_log_info1 "No ssl port set, setting to random open high port"
|
||||
PROXY_SSL_PORT=$(get_available_port)
|
||||
fi
|
||||
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_PROXY_SSL_PORT="$PROXY_SSL_PORT"
|
||||
@@ -61,4 +61,5 @@ trigger-proxy-proxy-configure-ports() {
|
||||
fi
|
||||
fi
|
||||
}
|
||||
trigger-proxy-proxy-configure-ports "$@"
|
||||
|
||||
trigger-ports-proxy-configure-ports "$@"
|
||||
21
plugins/ports/proxy.go
Normal file
21
plugins/ports/proxy.go
Normal file
@@ -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__"
|
||||
}
|
||||
37
plugins/ports/report.go
Normal file
37
plugins/ports/report.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
// ReportSingleApp is an internal function that displays the ports 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 portMaps []string
|
||||
for _, portMap := range getPortMaps(appName) {
|
||||
portMaps = append(portMaps, portMap.String())
|
||||
}
|
||||
|
||||
return strings.Join(portMaps, " ")
|
||||
}
|
||||
60
plugins/ports/src/commands/commands.go
Normal file
60
plugins/ports/src/commands/commands.go
Normal file
@@ -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 <app>, List port mappings for app
|
||||
ports:add <app> [<scheme>:<host-port>:<container-port>...], Add port mappings to an app
|
||||
ports:clear <app>, Clear all port mappings for an app
|
||||
ports:remove <app> [<host-port>|<scheme>:<host-port>:<container-port>...], Remove specific port mappings from an app
|
||||
ports:set <app> [<scheme>:<host-port>:<container-port>...], Set port mappings for an app
|
||||
ports:report [<app>] [<flag>], 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)
|
||||
}
|
||||
65
plugins/ports/src/subcommands/subcommands.go
Normal file
65
plugins/ports/src/subcommands/subcommands.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
37
plugins/ports/src/triggers/triggers.go
Normal file
37
plugins/ports/src/triggers/triggers.go
Normal file
@@ -0,0 +1,37 @@
|
||||
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 "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)
|
||||
}
|
||||
}
|
||||
116
plugins/ports/subcommands.go
Normal file
116
plugins/ports/subcommands.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
// 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 listAppPortMaps(appName)
|
||||
}
|
||||
|
||||
// CommandAdd adds port mappings to an app
|
||||
func CommandAdd(appName string, portMapStrings []string) error {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(portMapStrings) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
portMaps, err := parsePortMapString(strings.Join(portMapStrings, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := addPortMaps(appName, portMaps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return common.PlugnTrigger("post-proxy-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
|
||||
}
|
||||
|
||||
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"}...)
|
||||
}
|
||||
|
||||
// CommandRemove removes specific port mappings from an app
|
||||
func CommandRemove(appName string, portMapStrings []string) error {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(portMapStrings) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
portMaps, err := parsePortMapString(strings.Join(portMapStrings, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := removePortMaps(appName, portMaps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "remove"}...)
|
||||
}
|
||||
|
||||
// CommandSet sets port mappings for an app
|
||||
func CommandSet(appName string, portMapStrings []string) error {
|
||||
if err := common.VerifyAppName(appName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(portMapStrings) == 0 {
|
||||
return errors.New("No port mapping specified")
|
||||
}
|
||||
|
||||
portMaps, err := parsePortMapString(strings.Join(portMapStrings, " "))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := setPortMaps(appName, portMaps); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "set"}...)
|
||||
}
|
||||
|
||||
// CommandReport displays a ports 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)
|
||||
}
|
||||
71
plugins/ports/triggers.go
Normal file
71
plugins/ports/triggers.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
// 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 removePortMaps(appName, filterAppPortMaps(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 := removePortMaps(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 := addPortMaps(appName, toAdd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
2
plugins/proxy/.gitignore
vendored
2
plugins/proxy/.gitignore
vendored
@@ -6,4 +6,4 @@
|
||||
/install
|
||||
/post-*
|
||||
/report
|
||||
!/proxy-configure-ports
|
||||
|
||||
|
||||
@@ -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
|
||||
TRIGGERS = triggers/proxy-is-enabled triggers/proxy-type triggers/report
|
||||
BUILD = commands subcommands triggers
|
||||
PLUGIN_NAME = proxy
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ 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 v2.1.2+incompatible
|
||||
github.com/dokku/dokku/plugins/ports v0.0.0-00010101000000-000000000000
|
||||
github.com/spf13/pflag v1.0.5
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ require (
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect
|
||||
github.com/joho/godotenv v1.2.0 // indirect
|
||||
github.com/otiai10/copy v1.12.0 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
)
|
||||
@@ -21,3 +22,5 @@ require (
|
||||
replace github.com/dokku/dokku/plugins/common => ../common
|
||||
|
||||
replace github.com/dokku/dokku/plugins/config => ../config
|
||||
|
||||
replace github.com/dokku/dokku/plugins/ports => ../ports
|
||||
|
||||
@@ -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}...)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
@@ -15,7 +13,6 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
|
||||
flags := map[string]common.ReportFunc{
|
||||
"--proxy-enabled": reportEnabled,
|
||||
"--proxy-type": reportType,
|
||||
"--proxy-port-map": reportPortMap,
|
||||
}
|
||||
|
||||
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, " ")
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ Additional commands:`
|
||||
proxy:clear-config [--all|<app>], Clears config for a given app
|
||||
proxy:disable <app>, Disable proxy for app
|
||||
proxy:enable <app>, Enable proxy for app
|
||||
proxy:ports <app>, List proxy port mappings for app
|
||||
proxy:ports-add <app> [<scheme>:<host-port>:<container-port>...], Add proxy port mappings to an app
|
||||
proxy:ports-clear <app>, Clear all proxy port mappings for an app
|
||||
proxy:ports-remove <app> [<host-port>|<scheme>:<host-port>:<container-port>...], Remove specific proxy port mappings from an app
|
||||
proxy:ports-set <app> [<scheme>:<host-port>:<container-port>...], Set proxy port mappings for an app
|
||||
proxy:report [<app>] [<flag>], Displays a proxy report for one or more apps
|
||||
proxy:set <app> <proxy-type>, Set proxy type for app
|
||||
`
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/dokku/dokku/plugins/ports"
|
||||
"github.com/dokku/dokku/plugins/proxy"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
@@ -49,30 +50,35 @@ func main() {
|
||||
args := flag.NewFlagSet("proxy:ports", flag.ExitOnError)
|
||||
args.Parse(os.Args[2:])
|
||||
appName := args.Arg(0)
|
||||
err = proxy.CommandPorts(appName)
|
||||
common.LogWarn("Deprecated: Use 'ports:list' instead")
|
||||
err = ports.CommandList(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)
|
||||
common.LogWarn("Deprecated: Use 'ports:add' instead")
|
||||
err = ports.CommandAdd(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)
|
||||
common.LogWarn("Deprecated: Use 'ports:clear' instead")
|
||||
err = ports.CommandClear(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)
|
||||
common.LogWarn("Deprecated: Use 'ports:remove' instead")
|
||||
err = ports.CommandRemove(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)
|
||||
common.LogWarn("Deprecated: Use 'ports:set' instead")
|
||||
err = ports.CommandSet(appName, portMaps)
|
||||
case "report":
|
||||
args := flag.NewFlagSet("proxy:report", flag.ExitOnError)
|
||||
format := args.String("format", "stdout", "format: [ stdout | json ]")
|
||||
|
||||
@@ -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, "", "")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@ 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/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
|
||||
github.com/otiai10/copy v1.12.0 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
|
||||
@@ -114,7 +114,7 @@ teardown() {
|
||||
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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -154,7 +154,7 @@ teardown() {
|
||||
assert_success
|
||||
assert_output "true"
|
||||
|
||||
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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
106
tests/unit/ports.bats
Normal file
106
tests/unit/ports.bats
Normal file
@@ -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) ports subcommands (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"
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -233,7 +233,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"
|
||||
|
||||
Reference in New Issue
Block a user