refactor: deprecate proxy-configure-ports plugin trigger in favor of ports-configure

This also rewrites the logic to be in golang, which will make it easier to refactor portions of it to use the property system going forward.
This commit is contained in:
Jose Diaz-Gonzalez
2023-07-02 19:29:05 -04:00
parent 192f7cf768
commit 48d5820b8c
13 changed files with 203 additions and 64 deletions

View File

@@ -7,12 +7,13 @@
- The `traefik` integration now mounts config to `/data` instead of the path `/acme.json`, fixing permissions issues under certain architectures. To take advantage of the new functionality, the traefik container should be stopped (via `dokku traefik:stop`) and then started (via `dokku traefik:start`).
- Users no longer need to clear the `source-image` git property when transitioning from image-based deploys (`git:from-image` and `git:load-image`) to other deployment methods (git push, `git:from-archive`, `git:sync`).
- For deploys via the `git:from-image` and `git:load-image` commands, the `CHECKS` file is now extracted from the configured `WORKDIR` property of the image. For all other deploys - git push, `git:from-archive`, `git:sync` - will have the `CHECKS` extracted directly from the source code. The filename in both cases is `CHECKS` and cannot be modified.
- The `common#get_app_raw_tcp_ports()` function has been deprecated and will be removed in the next release. Users should avoid interacting with this function for dockerfile ports and instead use the `ports-get` plugin trigger for fetching ports for an app.
- The `common#get_available_port()` function has been deprecated and will be removed in the next release. Users should avoid interacting with this function and instead use the `ports-get-available` plugin trigger for fetching an available port.
## Deprecations
- 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.
- The `common#get_app_raw_tcp_ports()` function has been deprecated and will be removed in the next release. Users should avoid interacting with this function for dockerfile ports and instead use the `ports-get` plugin trigger for fetching ports for an app.
- The `common#get_available_port()` function has been deprecated and will be removed in the next release. Users should avoid interacting with this function and instead use the `ports-get-available` plugin trigger for fetching an available port.
- The `proxy-configure-ports` plugin trigger has been deprecated and will be removed in the next release. Users should instead trigger the `ports-configure` plugin trigger.
## Un-Deprecations

View File

@@ -1256,6 +1256,21 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
# TODO
```
### `ports-configure`
- Description: Configures the port mapping
- Invoked by: `internally triggered by proxy plugins`
- Arguments: `$APP`
- Example:
```shell
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
# TODO
```
### `ports-dockerfile-raw-tcp-ports`
> Warning: This trigger is for internal use and will be removed in a future release. Do not use it in your codebase.
@@ -1934,6 +1949,8 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
### `proxy-configure-ports`
> Warning: Deprecated, please use `ports-configure` instead
- Description: Configures the port mapping
- Invoked by: `internally triggered by proxy plugins`
- Arguments: `$APP`

View File

@@ -0,0 +1 @@
hook

View File

@@ -30,7 +30,7 @@ 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

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
get_available_port "$@"

View File

@@ -33,7 +33,7 @@ trigger-haproxy-vhosts-docker-args-process-deploy() {
plugn trigger domains-setup "$APP" >/dev/null
# 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

View File

@@ -318,7 +318,7 @@ 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=$(plugn trigger ports-get "$APP")

View File

@@ -1,5 +1,5 @@
SUBCOMMANDS = subcommands/list subcommands/add subcommands/clear subcommands/remove subcommands/set subcommands/report
TRIGGERS = triggers/ports-clear triggers/ports-dockerfile-raw-tcp-ports triggers/ports-get triggers/ports-get-available triggers/post-certs-remove triggers/post-certs-update triggers/report
TRIGGERS = triggers/ports-clear triggers/ports-configure triggers/ports-dockerfile-raw-tcp-ports triggers/ports-get triggers/ports-get-available triggers/post-certs-remove triggers/post-certs-update triggers/report
BUILD = commands subcommands triggers
PLUGIN_NAME = ports

View File

@@ -28,6 +28,12 @@ func clearPorts(appName string) error {
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
}
func doesCertExist(appName string) bool {
b, _ := common.PlugnTriggerOutput("certs-exists", []string{appName}...)
certsExists := strings.TrimSpace(string(b[:]))
return certsExists == "true"
}
func filterAppPortMaps(appName string, scheme string, hostPort int) []PortMap {
var filteredPortMaps []PortMap
for _, portMap := range getPortMaps(appName) {
@@ -90,12 +96,59 @@ func getDockerfileRawTCPPorts(appName string) []int {
return ports
}
func getGlobalProxyPort() int {
port := 0
b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_PORT"}...)
if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil {
port = intVar
}
return port
}
func getGlobalProxySSLPort() int {
port := 0
b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_SSL_PORT"}...)
if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil {
port = intVar
}
return port
}
func getPortMaps(appName string) []PortMap {
value := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "")
portMaps, _ := parsePortMapString(value)
return portMaps
}
func getProxyPort(appName string) int {
port := 0
b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_PORT"}...)
if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil {
port = intVar
}
return port
}
func getProxySSLPort(appName string) int {
port := 0
b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_SSL_PORT"}...)
if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil {
port = intVar
}
return port
}
func isAppVhostEnabled(appName string) bool {
if err := common.PlugnTrigger("domains-vhost-enabled", []string{appName}...); err != nil {
return false
}
return true
}
func inRange(value int, min int, max int) bool {
return min < value && value < max
}
@@ -223,11 +276,13 @@ func setPortMaps(appName string, portMaps []PortMap) error {
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)
return common.EnvWrap(func() error {
sort.Strings(value)
entries := map[string]string{
"DOKKU_PROXY_PORT_MAP": strings.Join(value, " "),
}
return config.SetMany(appName, entries, false)
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
}
func uniquePortMaps(portMaps []PortMap) []PortMap {

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
@@ -8,58 +7,9 @@ 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="$(plugn trigger ports-dockerfile-raw-tcp-ports "$APP" | xargs)"
local DOKKU_PROXY_PORT=$(config_get "$APP" DOKKU_PROXY_PORT)
local DOKKU_PROXY_SSL_PORT=$(config_get "$APP" DOKKU_PROXY_SSL_PORT)
local DOKKU_PROXY_PORT_MAP=$(config_get "$APP" DOKKU_PROXY_PORT_MAP)
local IS_APP_VHOST_ENABLED=true
local UPSTREAM_PORT="5000"
plugn trigger domains-vhost-enabled "$APP" 2>/dev/null || IS_APP_VHOST_ENABLED=false
if [[ -z "$DOKKU_PROXY_PORT" ]] && [[ -z "$RAW_TCP_PORTS" ]]; then
if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
dokku_log_info1 "No port set, setting to random open high port"
local PROXY_PORT=$(plugn trigger ports-get-available)
else
local PROXY_PORT=$(config_get --global DOKKU_PROXY_PORT)
PROXY_PORT=${PROXY_PORT:=80}
fi
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_PROXY_PORT="$PROXY_PORT"
fi
if [[ -z "$DOKKU_PROXY_SSL_PORT" ]]; then
if [[ "$(plugn trigger certs-exists "$APP")" == "true" ]]; then
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 ssl port set, setting to random open high port"
PROXY_SSL_PORT=$(plugn trigger ports-get-available)
fi
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_PROXY_SSL_PORT="$PROXY_SSL_PORT"
fi
fi
if [[ -z "$DOKKU_PROXY_PORT_MAP" ]]; then
if [[ -n "$RAW_TCP_PORTS" ]]; then
local RAW_TCP_PORT
for RAW_TCP_PORT in $RAW_TCP_PORTS; do
local PROXY_PORT_MAP+=" http:${RAW_TCP_PORT}:${RAW_TCP_PORT} "
done
else
local PROXY_PORT=${PROXY_PORT:-$DOKKU_PROXY_PORT}
local PROXY_SSL_PORT=${PROXY_SSL_PORT:-$DOKKU_PROXY_SSL_PORT}
[[ -f "$DOKKU_ROOT/$APP/PORT.web.1" ]] && local UPSTREAM_PORT="$(<"$DOKKU_ROOT/$APP/PORT.web.1")"
if [[ -n "$PROXY_PORT" ]] && [[ -n "$PROXY_SSL_PORT" ]]; then
local PROXY_PORT_MAP+=" http:${PROXY_PORT}:$UPSTREAM_PORT https:${PROXY_SSL_PORT}:$UPSTREAM_PORT "
elif [[ -n "$PROXY_PORT" ]]; then
local PROXY_PORT_MAP+=" http:${PROXY_PORT}:$UPSTREAM_PORT "
fi
fi
if [[ -n "$PROXY_PORT_MAP" ]]; then
local PROXY_PORT_MAP="$(echo "$PROXY_PORT_MAP" | xargs)"
local PROXY_PORT_MAP+=" $(merge_dedupe_list "$(remove_val_from_list "$PORT_MAP" "$DOKKU_PROXY_PORT_MAP" " ")" " ") "
DOKKU_QUIET_OUTPUT=1 config_set --no-restart "$APP" DOKKU_PROXY_PORT_MAP="$PROXY_PORT_MAP"
fi
fi
dokku_log_warn "Deprecated: please use the 'ports-configure' plugin trigger instead"
plugn trigger ports-configure "$APP"
}
trigger-ports-proxy-configure-ports "$@"

View File

@@ -21,6 +21,9 @@ func main() {
case "ports-clear":
appName := flag.Arg(0)
err = ports.TriggerPortsClear(appName)
case "ports-configure":
appName := flag.Arg(0)
err = ports.TriggerPortsConfigure(appName)
case "ports-dockerfile-raw-tcp-ports":
appName := flag.Arg(0)
err = ports.TriggerPortsDockerfileRawTCPPorts(appName)

View File

@@ -2,6 +2,8 @@ package ports
import (
"fmt"
"path/filepath"
"strconv"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/config"
@@ -12,6 +14,110 @@ func TriggerPortsClear(appName string) error {
return clearPorts(appName)
}
// TriggerPortsConfigure ensures we have a port mapping
func TriggerPortsConfigure(appName string) error {
rawTCPPorts := getDockerfileRawTCPPorts(appName)
dokkuProxyPort := getProxyPort(appName)
dokkuProxySSLPort := getProxySSLPort(appName)
portMaps := getPortMaps(appName)
vhostEnabled := isAppVhostEnabled(appName)
if dokkuProxyPort == 0 && len(rawTCPPorts) == 0 {
proxyPort := 80
if !vhostEnabled {
common.LogInfo1("No port set, setting to random open high port")
proxyPort = getAvailablePort()
} else {
proxyPort = getGlobalProxyPort()
}
if proxyPort == 0 {
proxyPort = 80
}
dokkuProxyPort = proxyPort
err := common.EnvWrap(func() error {
entries := map[string]string{
"DOKKU_PROXY_PORT": fmt.Sprint(proxyPort),
}
return config.SetMany(appName, entries, false)
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
if err != nil {
return err
}
}
if dokkuProxySSLPort == 0 {
if doesCertExist(appName) {
proxySSLPort := getGlobalProxySSLPort()
if proxySSLPort == 0 {
proxySSLPort = 443
}
if len(rawTCPPorts) == 0 && !vhostEnabled {
common.LogInfo1("No ssl port set, setting to random open high port")
proxySSLPort = getAvailablePort()
}
dokkuProxySSLPort = proxySSLPort
err := common.EnvWrap(func() error {
entries := map[string]string{
"DOKKU_PROXY_SSL_PORT": fmt.Sprint(proxySSLPort),
}
return config.SetMany(appName, entries, false)
}, map[string]string{"DOKKU_QUIET_OUTPUT": "1"})
if err != nil {
return err
}
}
}
if len(portMaps) == 0 {
if len(rawTCPPorts) > 0 {
for _, rawTcpPort := range rawTCPPorts {
portMaps = append(portMaps, PortMap{
ContainerPort: rawTcpPort,
HostPort: rawTcpPort,
Scheme: "http",
})
}
} else {
upstreamPort := 5000
portFile := filepath.Join(common.AppRoot(appName), "PORT.web.1")
if common.FileExists(portFile) {
if port, err := strconv.Atoi(common.ReadFirstLine(portFile)); err == nil {
upstreamPort = port
}
}
if dokkuProxyPort != 0 {
portMaps = append(portMaps, PortMap{
ContainerPort: upstreamPort,
HostPort: dokkuProxyPort,
Scheme: "http",
})
}
if dokkuProxySSLPort != 0 {
portMaps = append(portMaps, PortMap{
ContainerPort: upstreamPort,
HostPort: dokkuProxySSLPort,
Scheme: "https",
})
}
}
if len(portMaps) > 0 {
return setPortMaps(appName, portMaps)
}
return nil
}
return nil
}
// TriggerRawTCPPorts extracts raw tcp port numbers from DOCKERFILE_PORTS config variable
func TriggerPortsDockerfileRawTCPPorts(appName string) error {
ports := getDockerfileRawTCPPorts(appName)

View File

@@ -30,7 +30,7 @@ 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