diff --git a/docs/advanced-usage/registry-management.md b/docs/advanced-usage/registry-management.md index 51b041493..e8175ca41 100644 --- a/docs/advanced-usage/registry-management.md +++ b/docs/advanced-usage/registry-management.md @@ -216,7 +216,7 @@ dokku registry:set --global push-extra-tags | Property | Scope | Default | Report flags | Description | |---|---|---|---|---| | `image-repo` | app only | `dokku/` | `--registry-image-repo`, `--registry-computed-image-repo` | Repository name used when pushing the app's image (overrides the global template) | -| `image-repo-template` | global only | `dokku/{{ .AppName }}` | `--registry-global-image-repo-template` | Go template used to compute the per-app image repository when `image-repo` is unset | +| `image-repo-template` | global only | none | `--registry-global-image-repo-template`, `--registry-computed-image-repo-template` | Go template used to compute the per-app image repository when `image-repo` is unset | | `push-extra-tags` | app + global | none | `--registry-push-extra-tags` | Comma-separated list of additional tags pushed alongside the deploy tag | | `push-on-release` | app + global | `false` | `--registry-push-on-release`, `--registry-global-push-on-release`, `--registry-computed-push-on-release` | When `true`, pushes the image to the registry on every successful build | | `server` | app + global | none | `--registry-server`, `--registry-global-server`, `--registry-computed-server` | Registry server host (e.g. `ghcr.io`) used when pushing images | diff --git a/docs/appendices/0.38.0-migration-guide.md b/docs/appendices/0.38.0-migration-guide.md index cf0978b50..aa27e9559 100644 --- a/docs/appendices/0.38.0-migration-guide.md +++ b/docs/appendices/0.38.0-migration-guide.md @@ -21,7 +21,7 @@ - The `docker-local` scheduler now sends `SIGTERM` to old containers immediately after a successful deploy, rather than waiting `wait-to-retire` seconds before signaling. This matches Heroku's graceful-shutdown contract and lets applications begin draining in-flight work as soon as proxy traffic switches. The `wait-to-retire` grace period and `stop-timeout-seconds` hard-stop continue to apply as before. See the [zero downtime deploys documentation](/docs/deployment/zero-downtime-deploys.md#wait-to-retire) for more details. - The `docker-local` scheduler no longer queues an image for retirement when another running container of the same app still uses it. This fixes the case where a `ps:rebuild` against an image-based deploy (`git:from-image`) produced an identical-SHA image and the `dokku-retire` cron timer would log `Image ... has running containers, skipping rm` on every run. Stuck entries from prior versions are pruned automatically on the next `ps:retire` run. - All `:report` subcommands now accept the `--global` flag, which scopes the report to globally-configured properties. The flag composes with `--format json`, so a JSON report of global properties can be obtained via, for example, `dokku scheduler:report --global --format json`. Previously, combining `--global` with `--format json` was rejected with an "info flag" error, and `--global` on its own was treated as an unknown flag. -- Every `:report` key of the form `-global-` now returns the raw stored global value (empty when the property has never been set) instead of the resolved value with the built-in default substituted in. A new `-computed-` key has been added wherever a default existed and returns the effective value (per-app value, falling back to the global value, then to the built-in default). This affects `caddy`, `haproxy`, `traefik`, `openresty`, `app-json`, `builder-dockerfile`, `builder-herokuish`, `builder-lambda`, `builder-nixpacks`, `builder-pack`, `builder-railpack`, `checks`, `git`, `logs`, `network`, `proxy`, and `scheduler`. External tooling that read `-global-` and depended on the default value should switch to `-computed-`. The bare `-` keys for caddy/haproxy/traefik/openresty global-only properties (`caddy-image`, `haproxy-log-level`, `traefik-api-enabled`, `openresty-image`, `openresty-letsencrypt-email`, `openresty-letsencrypt-server`, `openresty-allowed-letsencrypt-domains-func-base64`, etc.) have also been replaced by the `global-` and `computed-` pair. +- Every `:report` key of the form `-global-` now returns the raw stored global value (empty when the property has never been set) instead of the resolved value with the built-in default substituted in. A new `-computed-` key has been added wherever a default existed and returns the effective value (per-app value, falling back to the global value, then to the built-in default). This affects `app-json`, `builder-dockerfile`, `builder-herokuish`, `builder-lambda`, `builder-nixpacks`, `builder-pack`, `builder-railpack`, `caddy`, `checks`, `git`, `haproxy`, `logs`, `network`, `nginx`, `openresty``proxy`,`registry`,`scheduler`, `scheduler-k3s` and `traefik`. External tooling that read`-global-` and depended on the default value should switch to `-computed-`. The bare`-`keys for caddy/haproxy/traefik/openresty global-only properties (`caddy-image`,`haproxy-log-level`,`traefik-api-enabled`,`openresty-image`,`openresty-letsencrypt-email`,`openresty-letsencrypt-server`,`openresty-allowed-letsencrypt-domains-func-base64`, etc.) have also been replaced by the`global-` and `computed-` pair. - The `scheduler-k3s` plugin now manages env config and the dokku-generated image pull Secret as their own helm releases with stable names (`config-{app}` and `pull-secret-{app}`) rather than bundling them into the app helm chart with a per-deploy timestamp suffix (`env-{app}.{ts}` / `ims-{app}.{ts}`). This fixes two bugs: a helm rollback of the app chart no longer deletes Secrets that older ReplicaSets still reference, and the Deployment's `imagePullSecrets` list no longer accumulates references to nonexistent Secrets across deploys. The next deploy of an app switches the Deployment's `envFrom` and `imagePullSecrets` references to the stable names and prunes any leaked entries; existing live Deployments do not need to be patched manually. App rename now also uninstalls the old `tls-{app}`, `config-{app}`, and `pull-secret-{app}` releases under the previous app name; the new name's releases are recreated on the next deploy or certs sync. - The storage plugin now treats persistent volumes as named, scheduler-aware first-class resources via `storage:create`, `storage:mount`, `storage:set`, and `storage:destroy`. The legacy `storage:mount :` colon form continues to work on docker-local apps but is deprecated; on k3s apps it is rejected. Existing colon-form mounts are migrated automatically the first time the new storage plugin runs (during the install trigger) - they appear as `legacy-` entries in `storage:list-entries`. The migration is idempotent and tied to a per-app flag file at `$DOKKU_LIB_ROOT/config/storage/.migrated/`; deleting that file forces a re-scan on the next install. The `storage:ensure-directory` command keeps working but now emits a deprecation warning - prefer `storage:create []` (the path defaults to the same `$DOKKU_LIB_ROOT/data/storage/` location). Storage entry names must now be DNS-1123 labels of 45 characters or less so they can be used verbatim as Helm release and Kubernetes resource names; underscores and uppercase characters that the older `ensure-directory` validator accepted are rejected for new names. The migration synthesizer always uses lowercase hex hashes so existing data is never locked out. diff --git a/docs/deployment/schedulers/k3s.md b/docs/deployment/schedulers/k3s.md index 3ffc770d6..0afaed933 100644 --- a/docs/deployment/schedulers/k3s.md +++ b/docs/deployment/schedulers/k3s.md @@ -796,15 +796,15 @@ If unspecified for any task, the default reservation will be `.1` CPU and `128Mi |---|---|---|---|---| | `deploy-timeout` | app + global | `300s` | `--scheduler-k3s-deploy-timeout`, `--scheduler-k3s-global-deploy-timeout`, `--scheduler-k3s-computed-deploy-timeout` | Timeout for a single helm install/upgrade cycle | | `image-pull-secrets` | app + global | none | `--scheduler-k3s-image-pull-secrets`, `--scheduler-k3s-global-image-pull-secrets`, `--scheduler-k3s-computed-image-pull-secrets` | Comma-separated list of Kubernetes secret names used to pull private images | -| `ingress-class` | global only | `nginx` | `--scheduler-k3s-global-ingress-class` | IngressClass name used for app ingresses (e.g. `nginx`, `traefik`) | -| `kube-context` | global only | none | `--scheduler-k3s-global-kube-context` | Kube context name used by helm and kubectl invocations | -| `kubeconfig-path` | global only | `/etc/rancher/k3s/k3s.yaml` | `--scheduler-k3s-global-kubeconfig-path` | Filesystem path to the kubeconfig used to talk to the cluster | -| `kustomize-root-path` | app + global | none | `--scheduler-k3s-kustomize-root-path`, `--scheduler-k3s-global-kustomize-root-path`, `--scheduler-k3s-computed-kustomize-root-path` | Path within the app to a kustomize root applied after the helm install | -| `letsencrypt-email-prod` | global only | none | `--scheduler-k3s-global-letsencrypt-email-prod` | Contact email for the production cert-manager ClusterIssuer | -| `letsencrypt-email-stag` | global only | none | `--scheduler-k3s-global-letsencrypt-email-stag` | Contact email for the staging cert-manager ClusterIssuer | +| `ingress-class` | global only | `nginx` | `--scheduler-k3s-global-ingress-class`, `--scheduler-k3s-computed-ingress-class` | IngressClass name used for app ingresses (e.g. `nginx`, `traefik`) | +| `kube-context` | global only | none | `--scheduler-k3s-global-kube-context`, `--scheduler-k3s-computed-kube-context` | Kube context name used by helm and kubectl invocations | +| `kubeconfig-path` | global only | `/etc/rancher/k3s/k3s.yaml` | `--scheduler-k3s-global-kubeconfig-path`, `--scheduler-k3s-computed-kubeconfig-path` | Filesystem path to the kubeconfig used to talk to the cluster | +| `kustomize-root-path` | app + global | `config/kustomize` | `--scheduler-k3s-kustomize-root-path`, `--scheduler-k3s-global-kustomize-root-path`, `--scheduler-k3s-computed-kustomize-root-path` | Path within the app to a kustomize root applied after the helm install | +| `letsencrypt-email-prod` | global only | none | `--scheduler-k3s-global-letsencrypt-email-prod`, `--scheduler-k3s-computed-letsencrypt-email-prod` | Contact email for the production cert-manager ClusterIssuer | +| `letsencrypt-email-stag` | global only | none | `--scheduler-k3s-global-letsencrypt-email-stag`, `--scheduler-k3s-computed-letsencrypt-email-stag` | Contact email for the staging cert-manager ClusterIssuer | | `letsencrypt-server` | app + global | `prod` | `--scheduler-k3s-letsencrypt-server`, `--scheduler-k3s-global-letsencrypt-server`, `--scheduler-k3s-computed-letsencrypt-server` | ACME directory (`prod` or `staging`) used for app certificates | | `namespace` | app + global | `default` | `--scheduler-k3s-namespace`, `--scheduler-k3s-global-namespace`, `--scheduler-k3s-computed-namespace` | Kubernetes namespace into which the app's resources are installed | -| `network-interface` | global only | none | `--scheduler-k3s-global-network-interface` | Host network interface used by k3s | +| `network-interface` | global only | `eth0` | `--scheduler-k3s-global-network-interface`, `--scheduler-k3s-computed-network-interface` | Host network interface used by k3s | | `rollback-on-failure` | app + global | `false` | `--scheduler-k3s-rollback-on-failure`, `--scheduler-k3s-global-rollback-on-failure`, `--scheduler-k3s-computed-rollback-on-failure` | When `true`, helm rolls back the release if a deploy fails | | `shm-size` | app + global | none | `--scheduler-k3s-shm-size`, `--scheduler-k3s-global-shm-size`, `--scheduler-k3s-computed-shm-size` | `/dev/shm` size override applied to app containers | | `token` | global only | none | (not in report) | Cluster join token used by `scheduler-k3s:cluster-add` | diff --git a/plugins/nginx-vhosts/nginx_vhosts.go b/plugins/nginx-vhosts/nginx_vhosts.go index 6c552fd62..097314212 100644 --- a/plugins/nginx-vhosts/nginx_vhosts.go +++ b/plugins/nginx-vhosts/nginx_vhosts.go @@ -34,12 +34,15 @@ func ComputedAccessLogPath(appName string) string { return appValue } - return GlobalAccessLogPath(appName) + value := GlobalAccessLogPath() + if value == "" { + value = fmt.Sprintf("%s/%s-access.log", getLogRoot(), appName) + } + return value } -func GlobalAccessLogPath(appName string) string { - defaultLogPath := fmt.Sprintf("%s/%s-access.log", getLogRoot(), appName) - return common.PropertyGetDefault("nginx", "--global", "access-log-path", defaultLogPath) +func GlobalAccessLogPath() string { + return common.PropertyGet("nginx", "--global", "access-log-path") } func AppBindAddressIPv4(appName string) string { @@ -69,11 +72,15 @@ func ComputedBindAddressIPv6(appName string) string { return appValue } - return GlobalBindAddressIPv6() + value := GlobalBindAddressIPv6() + if value == "" { + value = "::" + } + return value } func GlobalBindAddressIPv6() string { - return common.PropertyGetDefault("nginx", "--global", "bind-address-ipv6", "::") + return common.PropertyGet("nginx", "--global", "bind-address-ipv6") } func AppClientBodyTimeout(appName string) string { @@ -86,11 +93,15 @@ func ComputedClientBodyTimeout(appName string) string { return appValue } - return GlobalClientBodyTimeout() + value := GlobalClientBodyTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalClientBodyTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "client-body-timeout", "60s") + return common.PropertyGet("nginx", "--global", "client-body-timeout") } func AppClientHeaderTimeout(appName string) string { @@ -103,11 +114,15 @@ func ComputedClientHeaderTimeout(appName string) string { return appValue } - return GlobalClientHeaderTimeout() + value := GlobalClientHeaderTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalClientHeaderTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "client-header-timeout", "60s") + return common.PropertyGet("nginx", "--global", "client-header-timeout") } func AppClientMaxBodySize(appName string) string { @@ -120,11 +135,15 @@ func ComputedClientMaxBodySize(appName string) string { return appValue } - return GlobalClientMaxBodySize() + value := GlobalClientMaxBodySize() + if value == "" { + value = "1m" + } + return value } func GlobalClientMaxBodySize() string { - return common.PropertyGetDefault("nginx", "--global", "client-max-body-size", "1m") + return common.PropertyGet("nginx", "--global", "client-max-body-size") } func AppDisableCustomConfig(appName string) string { @@ -137,11 +156,15 @@ func ComputedDisableCustomConfig(appName string) string { return appValue } - return GlobalDisableCustomConfig() + value := GlobalDisableCustomConfig() + if value == "" { + value = "false" + } + return value } func GlobalDisableCustomConfig() string { - return common.PropertyGetDefault("nginx", "--global", "disable-custom-config", "false") + return common.PropertyGet("nginx", "--global", "disable-custom-config") } func AppErrorLogPath(appName string) string { @@ -154,12 +177,15 @@ func ComputedErrorLogPath(appName string) string { return appValue } - return GlobalErrorLogPath(appName) + value := GlobalErrorLogPath() + if value == "" { + value = fmt.Sprintf("%s/%s-error.log", getLogRoot(), appName) + } + return value } -func GlobalErrorLogPath(appName string) string { - defaultLogPath := fmt.Sprintf("%s/%s-error.log", getLogRoot(), appName) - return common.PropertyGetDefault("nginx", "--global", "error-log-path", defaultLogPath) +func GlobalErrorLogPath() string { + return common.PropertyGet("nginx", "--global", "error-log-path") } func AppHSTSIncludeSubdomains(appName string) string { @@ -172,11 +198,15 @@ func ComputedHSTSIncludeSubdomains(appName string) string { return appValue } - return GlobalHSTSIncludeSubdomains() + value := GlobalHSTSIncludeSubdomains() + if value == "" { + value = "true" + } + return value } func GlobalHSTSIncludeSubdomains() string { - return common.PropertyGetDefault("nginx", "--global", "hsts-include-subdomains", "true") + return common.PropertyGet("nginx", "--global", "hsts-include-subdomains") } func AppHSTSMaxAge(appName string) string { @@ -189,11 +219,15 @@ func ComputedHSTSMaxAge(appName string) string { return appValue } - return GlobalHSTSMaxAge() + value := GlobalHSTSMaxAge() + if value == "" { + value = "15724800" + } + return value } func GlobalHSTSMaxAge() string { - return common.PropertyGetDefault("nginx", "--global", "hsts-max-age", "15724800") + return common.PropertyGet("nginx", "--global", "hsts-max-age") } func AppHSTSPreload(appName string) string { @@ -206,11 +240,15 @@ func ComputedHSTSPreload(appName string) string { return appValue } - return GlobalHSTSPreload() + value := GlobalHSTSPreload() + if value == "" { + value = "false" + } + return value } func GlobalHSTSPreload() string { - return common.PropertyGetDefault("nginx", "--global", "hsts-preload", "false") + return common.PropertyGet("nginx", "--global", "hsts-preload") } func AppHSTS(appName string) string { @@ -223,11 +261,15 @@ func ComputedHSTS(appName string) string { return appValue } - return GlobalHSTS() + value := GlobalHSTS() + if value == "" { + value = "true" + } + return value } func GlobalHSTS() string { - return common.PropertyGetDefault("nginx", "--global", "hsts", "true") + return common.PropertyGet("nginx", "--global", "hsts") } func AppNginxConfSigilPath(appName string) string { @@ -240,11 +282,15 @@ func ComputedNginxConfSigilPath(appName string) string { return appValue } - return GlobalNginxConfSigilPath() + value := GlobalNginxConfSigilPath() + if value == "" { + value = "nginx.conf.sigil" + } + return value } func GlobalNginxConfSigilPath() string { - return common.PropertyGetDefault("nginx", "--global", "nginx-conf-sigil-path", "nginx.conf.sigil") + return common.PropertyGet("nginx", "--global", "nginx-conf-sigil-path") } func AppNginxServiceCommand(appName string) string { @@ -261,7 +307,7 @@ func ComputedNginxServiceCommand(appName string) string { } func GlobalNginxServiceCommand() string { - return common.PropertyGetDefault("nginx", "--global", "nginx-service-command", "") + return common.PropertyGet("nginx", "--global", "nginx-service-command") } func AppKeepaliveTimeout(appName string) string { @@ -274,11 +320,15 @@ func ComputedKeepaliveTimeout(appName string) string { return appValue } - return GlobalKeepaliveTimeout() + value := GlobalKeepaliveTimeout() + if value == "" { + value = "75s" + } + return value } func GlobalKeepaliveTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "keepalive-timeout", "75s") + return common.PropertyGet("nginx", "--global", "keepalive-timeout") } func AppLingeringTimeout(appName string) string { @@ -291,11 +341,15 @@ func ComputedLingeringTimeout(appName string) string { return appValue } - return GlobalLingeringTimeout() + value := GlobalLingeringTimeout() + if value == "" { + value = "5s" + } + return value } func GlobalLingeringTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "lingering-timeout", "5s") + return common.PropertyGet("nginx", "--global", "lingering-timeout") } func AppProxyBufferSize(appName string) string { @@ -308,11 +362,15 @@ func ComputedProxyBufferSize(appName string) string { return appValue } - return GlobalProxyBufferSize() + value := GlobalProxyBufferSize() + if value == "" { + value = fmt.Sprintf("%dk", os.Getpagesize()/1024) + } + return value } func GlobalProxyBufferSize() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-buffer-size", fmt.Sprintf("%dk", os.Getpagesize()/1024)) + return common.PropertyGet("nginx", "--global", "proxy-buffer-size") } func AppProxyBuffering(appName string) string { @@ -325,11 +383,15 @@ func ComputedProxyBuffering(appName string) string { return appValue } - return GlobalProxyBuffering() + value := GlobalProxyBuffering() + if value == "" { + value = "on" + } + return value } func GlobalProxyBuffering() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-buffering", "on") + return common.PropertyGet("nginx", "--global", "proxy-buffering") } func AppProxyBuffers(appName string) string { @@ -342,11 +404,15 @@ func ComputedProxyBuffers(appName string) string { return appValue } - return GlobalProxyBuffers() + value := GlobalProxyBuffers() + if value == "" { + value = fmt.Sprintf("8 %dk", os.Getpagesize()/1024) + } + return value } func GlobalProxyBuffers() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-buffers", fmt.Sprintf("8 %dk", os.Getpagesize()/1024)) + return common.PropertyGet("nginx", "--global", "proxy-buffers") } func AppProxyBusyBuffersSize(appName string) string { @@ -359,11 +425,15 @@ func ComputedProxyBusyBuffersSize(appName string) string { return appValue } - return GlobalProxyBusyBuffersSize() + value := GlobalProxyBusyBuffersSize() + if value == "" { + value = fmt.Sprintf("%dk", (os.Getpagesize()/1024)*2) + } + return value } func GlobalProxyBusyBuffersSize() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-busy-buffers-size", fmt.Sprintf("%dk", (os.Getpagesize()/1024)*2)) + return common.PropertyGet("nginx", "--global", "proxy-busy-buffers-size") } func AppProxyConnectTimeout(appName string) string { @@ -376,11 +446,15 @@ func ComputedProxyConnectTimeout(appName string) string { return appValue } - return GlobalProxyConnectTimeout() + value := GlobalProxyConnectTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalProxyConnectTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-connect-timeout", "60s") + return common.PropertyGet("nginx", "--global", "proxy-connect-timeout") } func AppProxyReadTimeout(appName string) string { @@ -393,11 +467,15 @@ func ComputedProxyReadTimeout(appName string) string { return appValue } - return GlobalProxyReadTimeout() + value := GlobalProxyReadTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalProxyReadTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-read-timeout", "60s") + return common.PropertyGet("nginx", "--global", "proxy-read-timeout") } func AppProxySendTimeout(appName string) string { @@ -410,11 +488,15 @@ func ComputedProxySendTimeout(appName string) string { return appValue } - return GlobalProxySendTimeout() + value := GlobalProxySendTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalProxySendTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-send-timeout", "60s") + return common.PropertyGet("nginx", "--global", "proxy-send-timeout") } func AppSendTimeout(appName string) string { @@ -427,11 +509,15 @@ func ComputedSendTimeout(appName string) string { return appValue } - return GlobalSendTimeout() + value := GlobalSendTimeout() + if value == "" { + value = "60s" + } + return value } func GlobalSendTimeout() string { - return common.PropertyGetDefault("nginx", "--global", "send-timeout", "60s") + return common.PropertyGet("nginx", "--global", "send-timeout") } func AppUnderscoreInHeaders(appName string) string { @@ -444,11 +530,15 @@ func ComputedUnderscoreInHeaders(appName string) string { return appValue } - return GlobalUnderscoreInHeaders() + value := GlobalUnderscoreInHeaders() + if value == "" { + value = "off" + } + return value } func GlobalUnderscoreInHeaders() string { - return common.PropertyGetDefault("nginx", "--global", "underscore-in-headers", "off") + return common.PropertyGet("nginx", "--global", "underscore-in-headers") } func AppXForwardedForValue(appName string) string { @@ -461,11 +551,15 @@ func ComputedXForwardedForValue(appName string) string { return appValue } - return GlobalXForwardedForValue() + value := GlobalXForwardedForValue() + if value == "" { + value = "$remote_addr" + } + return value } func GlobalXForwardedForValue() string { - return common.PropertyGetDefault("nginx", "--global", "x-forwarded-for-value", "$remote_addr") + return common.PropertyGet("nginx", "--global", "x-forwarded-for-value") } func AppXForwardedPortValue(appName string) string { @@ -478,11 +572,15 @@ func ComputedXForwardedPortValue(appName string) string { return appValue } - return GlobalXForwardedPortValue() + value := GlobalXForwardedPortValue() + if value == "" { + value = "$server_port" + } + return value } func GlobalXForwardedPortValue() string { - return common.PropertyGetDefault("nginx", "--global", "x-forwarded-port-value", "$server_port") + return common.PropertyGet("nginx", "--global", "x-forwarded-port-value") } func AppXForwardedProtoValue(appName string) string { @@ -495,11 +593,15 @@ func ComputedXForwardedProtoValue(appName string) string { return appValue } - return GlobalXForwardedProtoValue() + value := GlobalXForwardedProtoValue() + if value == "" { + value = "$scheme" + } + return value } func GlobalXForwardedProtoValue() string { - return common.PropertyGetDefault("nginx", "--global", "x-forwarded-proto-value", "$scheme") + return common.PropertyGet("nginx", "--global", "x-forwarded-proto-value") } func AppXForwardedSSL(appName string) string { @@ -516,7 +618,7 @@ func ComputedXForwardedSSL(appName string) string { } func GlobalXForwardedSSL() string { - return common.PropertyGetDefault("nginx", "--global", "x-forwarded-ssl", "") + return common.PropertyGet("nginx", "--global", "x-forwarded-ssl") } func AppProxyKeepalive(appName string) string { @@ -533,5 +635,5 @@ func ComputedProxyKeepalive(appName string) string { } func GlobalProxyKeepalive() string { - return common.PropertyGetDefault("nginx", "--global", "proxy-keepalive", "") + return common.PropertyGet("nginx", "--global", "proxy-keepalive") } diff --git a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go index 74f9e09a9..84d041a36 100644 --- a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go +++ b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go @@ -178,7 +178,7 @@ func globalValue(appName string, property string) string { case "access-log-format": value = nginx_vhosts.GlobalAccessLogFormat() case "access-log-path": - value = nginx_vhosts.GlobalAccessLogPath(appName) + value = nginx_vhosts.GlobalAccessLogPath() case "bind-address-ipv4": value = nginx_vhosts.GlobalBindAddressIPv4() case "bind-address-ipv6": @@ -192,7 +192,7 @@ func globalValue(appName string, property string) string { case "disable-custom-config": value = nginx_vhosts.GlobalDisableCustomConfig() case "error-log-path": - value = nginx_vhosts.GlobalErrorLogPath(appName) + value = nginx_vhosts.GlobalErrorLogPath() case "hsts-include-subdomains": value = nginx_vhosts.GlobalHSTSIncludeSubdomains() case "hsts-max-age": diff --git a/plugins/registry/report.go b/plugins/registry/report.go index a4ca924e7..1071b78c7 100644 --- a/plugins/registry/report.go +++ b/plugins/registry/report.go @@ -17,23 +17,27 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { var flags map[string]common.ReportFunc if appName == "--global" { flags = map[string]common.ReportFunc{ - "--registry-global-push-on-release": reportGlobalPushOnRelease, - "--registry-global-server": reportGlobalServer, - "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, + "--registry-computed-push-on-release": reportComputedPushOnRelease, + "--registry-global-push-on-release": reportGlobalPushOnRelease, + "--registry-computed-server": reportComputedServer, + "--registry-global-server": reportGlobalServer, + "--registry-computed-image-repo-template": reportComputedImageRepoTemplate, + "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, } } else { flags = map[string]common.ReportFunc{ - "--registry-computed-image-repo": reportComputedImageRepo, - "--registry-image-repo": reportImageRepo, - "--registry-computed-push-on-release": reportComputedPushOnRelease, - "--registry-global-push-on-release": reportGlobalPushOnRelease, - "--registry-push-on-release": reportPushOnRelease, - "--registry-computed-server": reportComputedServer, - "--registry-global-server": reportGlobalServer, - "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, - "--registry-server": reportServer, - "--registry-tag-version": reportTagVersion, - "--registry-push-extra-tags": reportPushExtraTags, + "--registry-computed-image-repo": reportComputedImageRepo, + "--registry-image-repo": reportImageRepo, + "--registry-computed-push-on-release": reportComputedPushOnRelease, + "--registry-global-push-on-release": reportGlobalPushOnRelease, + "--registry-push-on-release": reportPushOnRelease, + "--registry-computed-server": reportComputedServer, + "--registry-global-server": reportGlobalServer, + "--registry-computed-image-repo-template": reportComputedImageRepoTemplate, + "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, + "--registry-server": reportServer, + "--registry-tag-version": reportTagVersion, + "--registry-push-extra-tags": reportPushExtraTags, } } @@ -96,6 +100,10 @@ func reportGlobalImageRepoTemplate(appName string) string { return common.PropertyGet("registry", "--global", "image-repo-template") } +func reportComputedImageRepoTemplate(appName string) string { + return reportGlobalImageRepoTemplate(appName) +} + func reportGlobalServer(appName string) string { return common.PropertyGet("registry", "--global", "server") } diff --git a/plugins/scheduler-k3s/functions.go b/plugins/scheduler-k3s/functions.go index 3bb27b193..fc0e2e7e3 100644 --- a/plugins/scheduler-k3s/functions.go +++ b/plugins/scheduler-k3s/functions.go @@ -307,14 +307,14 @@ func applyClusterIssuers(ctx context.Context) error { "letsencrypt-stag": { Email: letsencryptEmailStag, Enabled: letsencryptEmailStag != "", - IngressClass: getGlobalIngressClass(), + IngressClass: getComputedIngressClass(), Name: "letsencrypt-stag", Server: "https://acme-staging-v02.api.letsencrypt.org/directory", }, "letsencrypt-prod": { Email: letsencryptEmailProd, Enabled: letsencryptEmailProd != "", - IngressClass: getGlobalIngressClass(), + IngressClass: getComputedIngressClass(), Name: "letsencrypt-prod", Server: "https://acme-v02.api.letsencrypt.org/directory", }, @@ -794,11 +794,11 @@ func getAnnotation(appName string, processType string, resourceType string) (map } func getDeployTimeout(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "deploy-timeout", "") + return common.PropertyGet("scheduler-k3s", appName, "deploy-timeout") } func getGlobalDeployTimeout() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "deploy-timeout", "300s") + return common.PropertyGet("scheduler-k3s", "--global", "deploy-timeout") } func getComputedDeployTimeout(appName string) string { @@ -806,16 +806,19 @@ func getComputedDeployTimeout(appName string) string { if deployTimeout == "" { deployTimeout = getGlobalDeployTimeout() } + if deployTimeout == "" { + deployTimeout = "300s" + } return deployTimeout } func getImagePullSecrets(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "image-pull-secrets", "") + return common.PropertyGet("scheduler-k3s", appName, "image-pull-secrets") } func getGlobalImagePullSecrets() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "image-pull-secrets", "") + return common.PropertyGet("scheduler-k3s", "--global", "image-pull-secrets") } func getComputedImagePullSecrets(appName string) string { @@ -885,7 +888,16 @@ func needsImagePullSecretsPrune(live []corev1.LocalObjectReference, keepSet map[ } func getGlobalIngressClass() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "ingress-class", DefaultIngressClass) + return common.PropertyGet("scheduler-k3s", "--global", "ingress-class") +} + +func getComputedIngressClass() string { + ingressClass := getGlobalIngressClass() + if ingressClass == "" { + ingressClass = DefaultIngressClass + } + + return ingressClass } func getIngressAnnotations(appName string, processType string) (map[string]string, error) { @@ -1225,11 +1237,11 @@ func getLabel(appName string, processType string, resourceType string) (map[stri } func getLetsencryptServer(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "letsencrypt-server", "") + return common.PropertyGet("scheduler-k3s", appName, "letsencrypt-server") } func getGlobalLetsencryptServer() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-server", "prod") + return common.PropertyGet("scheduler-k3s", "--global", "letsencrypt-server") } func getComputedLetsencryptServer(appName string) string { @@ -1237,16 +1249,27 @@ func getComputedLetsencryptServer(appName string) string { if letsencryptServer == "" { letsencryptServer = getGlobalLetsencryptServer() } + if letsencryptServer == "" { + letsencryptServer = "prod" + } return letsencryptServer } func getGlobalLetsencryptEmailProd() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-email-prod", "") + return common.PropertyGet("scheduler-k3s", "--global", "letsencrypt-email-prod") +} + +func getComputedLetsencryptEmailProd() string { + return getGlobalLetsencryptEmailProd() } func getGlobalLetsencryptEmailStag() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-email-stag", "") + return common.PropertyGet("scheduler-k3s", "--global", "letsencrypt-email-stag") +} + +func getComputedLetsencryptEmailStag() string { + return getGlobalLetsencryptEmailStag() } func getKustomizeDirectory(appName string) string { @@ -1255,11 +1278,11 @@ func getKustomizeDirectory(appName string) string { } func getKustomizeRootPath(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "kustomize-root-path", "") + return common.PropertyGet("scheduler-k3s", appName, "kustomize-root-path") } func getGlobalKustomizeRootPath() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "kustomize-root-path", "config/kustomize") + return common.PropertyGet("scheduler-k3s", "--global", "kustomize-root-path") } func getComputedKustomizeRootPath(appName string) string { @@ -1267,16 +1290,19 @@ func getComputedKustomizeRootPath(appName string) string { if kustomizeRootPath == "" { kustomizeRootPath = getGlobalKustomizeRootPath() } + if kustomizeRootPath == "" { + kustomizeRootPath = "config/kustomize" + } return kustomizeRootPath } func getNamespace(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "namespace", "") + return common.PropertyGet("scheduler-k3s", appName, "namespace") } func getGlobalNamespace() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "namespace", "default") + return common.PropertyGet("scheduler-k3s", "--global", "namespace") } func getComputedNamespace(appName string) string { @@ -1284,20 +1310,32 @@ func getComputedNamespace(appName string) string { if namespace == "" { namespace = getGlobalNamespace() } + if namespace == "" { + namespace = "default" + } return namespace } func getGlobalNetworkInterface() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "network-interface", "eth0") + return common.PropertyGet("scheduler-k3s", "--global", "network-interface") +} + +func getComputedNetworkInterface() string { + networkInterface := getGlobalNetworkInterface() + if networkInterface == "" { + networkInterface = "eth0" + } + + return networkInterface } func getRollbackOnFailure(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "rollback-on-failure", "") + return common.PropertyGet("scheduler-k3s", appName, "rollback-on-failure") } func getGlobalRollbackOnFailure() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "rollback-on-failure", "false") + return common.PropertyGet("scheduler-k3s", "--global", "rollback-on-failure") } func getComputedRollbackOnFailure(appName string) string { @@ -1305,16 +1343,19 @@ func getComputedRollbackOnFailure(appName string) string { if rollbackOnFailure == "" { rollbackOnFailure = getGlobalRollbackOnFailure() } + if rollbackOnFailure == "" { + rollbackOnFailure = "false" + } return rollbackOnFailure } func getShmSize(appName string) string { - return common.PropertyGetDefault("scheduler-k3s", appName, "shm-size", "") + return common.PropertyGet("scheduler-k3s", appName, "shm-size") } func getGlobalShmSize() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "shm-size", "") + return common.PropertyGet("scheduler-k3s", "--global", "shm-size") } func getComputedShmSize(appName string) string { @@ -1573,7 +1614,7 @@ func getProcessResources(appName string, processType string) (ProcessResourcesMa func getServerIP() (string, error) { serverIP := "" - networkInterface := getGlobalNetworkInterface() + networkInterface := getComputedNetworkInterface() ifaces, err := net.Interfaces() if err != nil { return "", fmt.Errorf("Unable to get network interfaces: %w", err) @@ -1968,7 +2009,7 @@ func isK3sInstalled() error { return fmt.Errorf("k3s binary is not available") } - if !common.FileExists(getKubeconfigPath()) { + if !common.FileExists(getComputedKubeconfigPath()) { return fmt.Errorf("k3s kubeconfig is not available") } @@ -1977,7 +2018,7 @@ func isK3sInstalled() error { // isK3sKubernetes returns true if the current kubernetes cluster is configured to be k3s func isK3sKubernetes() bool { - return getKubeconfigPath() == KubeConfigPath + return getComputedKubeconfigPath() == KubeConfigPath } func isPodReady(ctx context.Context, clientset KubernetesClient, podName, namespace string) wait.ConditionWithContextFunc { diff --git a/plugins/scheduler-k3s/helm.go b/plugins/scheduler-k3s/helm.go index 3f5e49df4..aa7ff9496 100644 --- a/plugins/scheduler-k3s/helm.go +++ b/plugins/scheduler-k3s/helm.go @@ -107,8 +107,8 @@ func NewHelmAgent(namespace string, logger action.DebugLog) (*HelmAgent, error) helmDriver = "secrets" } - kubeconfigPath := getKubeconfigPath() - kubeContext := getKubeContext() + kubeconfigPath := getComputedKubeconfigPath() + kubeContext := getComputedKubeContext() kubeConfig := kube.GetConfig(kubeconfigPath, kubeContext, namespace) if err := actionConfig.Init(kubeConfig, namespace, helmDriver, logger); err != nil { return nil, err diff --git a/plugins/scheduler-k3s/k8s.go b/plugins/scheduler-k3s/k8s.go index 205cab96c..dac8abf78 100644 --- a/plugins/scheduler-k3s/k8s.go +++ b/plugins/scheduler-k3s/k8s.go @@ -40,12 +40,30 @@ import ( "k8s.io/utils/ptr" ) -func getKubeconfigPath() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "kubeconfig-path", KubeConfigPath) +func getGlobalKubeconfigPath() string { + return common.PropertyGet("scheduler-k3s", "--global", "kubeconfig-path") } -func getKubeContext() string { - return common.PropertyGetDefault("scheduler-k3s", "--global", "kube-context", DefaultKubeContext) +func getComputedKubeconfigPath() string { + kubeconfigPath := getGlobalKubeconfigPath() + if kubeconfigPath == "" { + kubeconfigPath = KubeConfigPath + } + + return kubeconfigPath +} + +func getGlobalKubeContext() string { + return common.PropertyGet("scheduler-k3s", "--global", "kube-context") +} + +func getComputedKubeContext() string { + kubeContext := getGlobalKubeContext() + if kubeContext == "" { + kubeContext = DefaultKubeContext + } + + return kubeContext } type NotFoundError struct { @@ -84,8 +102,8 @@ type KubernetesClient struct { // NewKubernetesClient creates a new Kubernetes client func NewKubernetesClient() (KubernetesClient, error) { - kubeconfigPath := getKubeconfigPath() - kubeContext := getKubeContext() + kubeconfigPath := getComputedKubeconfigPath() + kubeContext := getComputedKubeContext() clientConfig := KubernetesClientConfig(kubeconfigPath, kubeContext) restConf, err := clientConfig.ClientConfig() if err != nil { @@ -220,11 +238,11 @@ func (k KubernetesClient) ApplyKubernetesManifest(ctx context.Context, input App input.Manifest, } - if kubeContext := getKubeContext(); kubeContext != "" { + if kubeContext := getComputedKubeContext(); kubeContext != "" { args = append([]string{"--context", kubeContext}, args...) } - if kubeconfigPath := getKubeconfigPath(); kubeconfigPath != "" { + if kubeconfigPath := getComputedKubeconfigPath(); kubeconfigPath != "" { args = append([]string{"--kubeconfig", kubeconfigPath}, args...) } diff --git a/plugins/scheduler-k3s/report.go b/plugins/scheduler-k3s/report.go index 4ba9a5c8d..9456932f7 100644 --- a/plugins/scheduler-k3s/report.go +++ b/plugins/scheduler-k3s/report.go @@ -18,49 +18,68 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { var flags map[string]common.ReportFunc if appName == "--global" { flags = map[string]common.ReportFunc{ - "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, - "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, - "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, - "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, - "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, - "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, - "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, - "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, - "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, - "--scheduler-k3s-global-namespace": reportGlobalNamespace, - "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, - "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, - "--scheduler-k3s-global-shm-size": reportGlobalShmSize, + "--scheduler-k3s-computed-deploy-timeout": reportComputedDeployTimeout, + "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, + "--scheduler-k3s-computed-image-pull-secrets": reportComputedImagePullSecrets, + "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, + "--scheduler-k3s-computed-ingress-class": reportComputedIngressClass, + "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, + "--scheduler-k3s-computed-kubeconfig-path": reportComputedKubeconfigPath, + "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, + "--scheduler-k3s-computed-kube-context": reportComputedKubeContext, + "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, + "--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath, + "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, + "--scheduler-k3s-computed-letsencrypt-server": reportComputedLetsencryptServer, + "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, + "--scheduler-k3s-computed-letsencrypt-email-prod": reportComputedLetsencryptEmailProd, + "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, + "--scheduler-k3s-computed-letsencrypt-email-stag": reportComputedLetsencryptEmailStag, + "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, + "--scheduler-k3s-computed-namespace": reportComputedNamespace, + "--scheduler-k3s-global-namespace": reportGlobalNamespace, + "--scheduler-k3s-computed-network-interface": reportComputedNetworkInterface, + "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, + "--scheduler-k3s-computed-rollback-on-failure": reportComputedRollbackOnFailure, + "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, + "--scheduler-k3s-computed-shm-size": reportComputedShmSize, + "--scheduler-k3s-global-shm-size": reportGlobalShmSize, } } else { flags = map[string]common.ReportFunc{ - "--scheduler-k3s-computed-deploy-timeout": reportComputedDeployTimeout, - "--scheduler-k3s-deploy-timeout": reportDeployTimeout, - "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, - "--scheduler-k3s-computed-image-pull-secrets": reportComputedImagePullSecrets, - "--scheduler-k3s-image-pull-secrets": reportImagePullSecrets, - "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, - "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, - "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, - "--scheduler-k3s-computed-letsencrypt-server": reportComputedLetsencryptServer, - "--scheduler-k3s-letsencrypt-server": reportLetsencryptServer, - "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, - "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, - "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, - "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, - "--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath, - "--scheduler-k3s-kustomize-root-path": reportKustomizeRootPath, - "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, - "--scheduler-k3s-computed-namespace": reportComputedNamespace, - "--scheduler-k3s-namespace": reportNamespace, - "--scheduler-k3s-global-namespace": reportGlobalNamespace, - "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, - "--scheduler-k3s-computed-rollback-on-failure": reportComputedRollbackOnFailure, - "--scheduler-k3s-rollback-on-failure": reportRollbackOnFailure, - "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, - "--scheduler-k3s-computed-shm-size": reportComputedShmSize, - "--scheduler-k3s-global-shm-size": reportGlobalShmSize, - "--scheduler-k3s-shm-size": reportShmSize, + "--scheduler-k3s-computed-deploy-timeout": reportComputedDeployTimeout, + "--scheduler-k3s-deploy-timeout": reportDeployTimeout, + "--scheduler-k3s-global-deploy-timeout": reportGlobalDeployTimeout, + "--scheduler-k3s-computed-image-pull-secrets": reportComputedImagePullSecrets, + "--scheduler-k3s-image-pull-secrets": reportImagePullSecrets, + "--scheduler-k3s-global-image-pull-secrets": reportGlobalImagePullSecrets, + "--scheduler-k3s-computed-ingress-class": reportComputedIngressClass, + "--scheduler-k3s-global-ingress-class": reportGlobalIngressClass, + "--scheduler-k3s-computed-kubeconfig-path": reportComputedKubeconfigPath, + "--scheduler-k3s-global-kubeconfig-path": reportGlobalKubeconfigPath, + "--scheduler-k3s-computed-kube-context": reportComputedKubeContext, + "--scheduler-k3s-global-kube-context": reportGlobalKubeContext, + "--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath, + "--scheduler-k3s-kustomize-root-path": reportKustomizeRootPath, + "--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath, + "--scheduler-k3s-computed-letsencrypt-server": reportComputedLetsencryptServer, + "--scheduler-k3s-letsencrypt-server": reportLetsencryptServer, + "--scheduler-k3s-global-letsencrypt-server": reportGlobalLetsencryptServer, + "--scheduler-k3s-computed-letsencrypt-email-prod": reportComputedLetsencryptEmailProd, + "--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd, + "--scheduler-k3s-computed-letsencrypt-email-stag": reportComputedLetsencryptEmailStag, + "--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag, + "--scheduler-k3s-computed-namespace": reportComputedNamespace, + "--scheduler-k3s-namespace": reportNamespace, + "--scheduler-k3s-global-namespace": reportGlobalNamespace, + "--scheduler-k3s-computed-network-interface": reportComputedNetworkInterface, + "--scheduler-k3s-global-network-interface": reportGlobalNetworkInterface, + "--scheduler-k3s-computed-rollback-on-failure": reportComputedRollbackOnFailure, + "--scheduler-k3s-rollback-on-failure": reportRollbackOnFailure, + "--scheduler-k3s-global-rollback-on-failure": reportGlobalRollbackOnFailure, + "--scheduler-k3s-computed-shm-size": reportComputedShmSize, + "--scheduler-k3s-global-shm-size": reportGlobalShmSize, + "--scheduler-k3s-shm-size": reportShmSize, } } @@ -141,17 +160,30 @@ func reportGlobalImagePullSecrets(appName string) string { return getGlobalImagePullSecrets() } +func reportComputedIngressClass(appName string) string { + return getComputedIngressClass() +} + func reportGlobalIngressClass(appName string) string { return getGlobalIngressClass() } +func reportComputedKubeconfigPath(appName string) string { + return getComputedKubeconfigPath() +} + func reportGlobalKubeconfigPath(appName string) string { - return getKubeconfigPath() + return getGlobalKubeconfigPath() +} + +func reportComputedKubeContext(appName string) string { + return getComputedKubeContext() } func reportGlobalKubeContext(appName string) string { - return getKubeContext() + return getGlobalKubeContext() } + func reportComputedLetsencryptServer(appName string) string { return getComputedLetsencryptServer(appName) } @@ -164,10 +196,18 @@ func reportGlobalLetsencryptServer(appName string) string { return getGlobalLetsencryptServer() } +func reportComputedLetsencryptEmailProd(appName string) string { + return getComputedLetsencryptEmailProd() +} + func reportGlobalLetsencryptEmailProd(appName string) string { return getGlobalLetsencryptEmailProd() } +func reportComputedLetsencryptEmailStag(appName string) string { + return getComputedLetsencryptEmailStag() +} + func reportGlobalLetsencryptEmailStag(appName string) string { return getGlobalLetsencryptEmailStag() } @@ -196,6 +236,10 @@ func reportGlobalNamespace(appName string) string { return getGlobalNamespace() } +func reportComputedNetworkInterface(appName string) string { + return getComputedNetworkInterface() +} + func reportGlobalNetworkInterface(appName string) string { return getGlobalNetworkInterface() } diff --git a/plugins/scheduler-k3s/subcommands.go b/plugins/scheduler-k3s/subcommands.go index 24fd074d6..a33d7377c 100644 --- a/plugins/scheduler-k3s/subcommands.go +++ b/plugins/scheduler-k3s/subcommands.go @@ -908,7 +908,7 @@ func CommandEnsureCharts(forceInstall bool, forceChartNames []string) error { return fmt.Errorf("Unable to create kubernetes client: %w", err) } - ingressClass := getGlobalIngressClass() + ingressClass := getComputedIngressClass() namespacedHelmAgents := map[string]*HelmAgent{} for _, chart := range HelmCharts { @@ -1209,7 +1209,7 @@ func CommandSet(appName string, property string, value string) error { // CommandShowKubeconfig displays the kubeconfig file contents func CommandShowKubeconfig() error { - kubeconfigPath := getKubeconfigPath() + kubeconfigPath := getComputedKubeconfigPath() if !common.FileExists(kubeconfigPath) { return fmt.Errorf("Kubeconfig file does not exist: %s", kubeconfigPath) } diff --git a/plugins/scheduler-k3s/triggers.go b/plugins/scheduler-k3s/triggers.go index 3201afeff..0350d781f 100644 --- a/plugins/scheduler-k3s/triggers.go +++ b/plugins/scheduler-k3s/triggers.go @@ -569,7 +569,7 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e Labels: globalLabels, Namespace: namespace, Network: GlobalNetwork{ - IngressClass: getGlobalIngressClass(), + IngressClass: getComputedIngressClass(), PrimaryPort: primaryPort, PrimaryServicePort: primaryServicePort, }, diff --git a/tests/unit/nginx-vhosts_properties.bats b/tests/unit/nginx-vhosts_properties.bats index accc328d6..70c9636ab 100644 --- a/tests/unit/nginx-vhosts_properties.bats +++ b/tests/unit/nginx-vhosts_properties.bats @@ -58,6 +58,10 @@ assert_nginx_property_set_get() { run /bin/bash -c "dokku nginx:set --global $prop" assert_success + + run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"global-$prop\"'" + assert_success + assert_output "" } @test "(nginx:report) timeout properties raw/global/computed" { @@ -100,4 +104,5 @@ assert_nginx_property_set_get() { assert_nginx_property_set_get "disable-custom-config" "false" "true" assert_nginx_property_set_get "underscore-in-headers" "on" "off" assert_nginx_property_set_get "proxy-keepalive" "8" "16" + assert_nginx_property_set_get "nginx-conf-sigil-path" "custom.sigil" "global.sigil" } diff --git a/tests/unit/registry.bats b/tests/unit/registry.bats index b027bf03c..a31189f2d 100644 --- a/tests/unit/registry.bats +++ b/tests/unit/registry.bats @@ -226,6 +226,77 @@ teardown() { assert_success } +@test "(registry:report --global) computed and global keys" { + run /bin/bash -c "dokku registry:set --global push-on-release" + assert_success + run /bin/bash -c "dokku registry:set --global server" + assert_success + run /bin/bash -c "dokku registry:set --global image-repo-template" + assert_success + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-on-release\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-on-release\"'" + assert_success + assert_output "false" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-server\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-server\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-image-repo-template\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-image-repo-template\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku registry:set --global push-on-release true" + assert_success + run /bin/bash -c "dokku registry:set --global server ghcr.io" + assert_success + run /bin/bash -c "dokku registry:set --global image-repo-template 'dokku/{{ APP }}'" + assert_success + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-on-release\"'" + assert_success + assert_output "true" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-on-release\"'" + assert_success + assert_output "true" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-server\"'" + assert_success + assert_output "ghcr.io" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-server\"'" + assert_success + assert_output "ghcr.io/" + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-image-repo-template\"'" + assert_success + assert_output 'dokku/{{ APP }}' + + run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-image-repo-template\"'" + assert_success + assert_output 'dokku/{{ APP }}' + + run /bin/bash -c "dokku registry:set --global push-on-release" + assert_success + run /bin/bash -c "dokku registry:set --global server" + assert_success + run /bin/bash -c "dokku registry:set --global image-repo-template" + assert_success +} + @test "(registry:report) push-extra-tags raw" { run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-push-extra-tags\"'" assert_success diff --git a/tests/unit/scheduler-k3s-report.bats b/tests/unit/scheduler-k3s-report.bats new file mode 100644 index 000000000..045e0976d --- /dev/null +++ b/tests/unit/scheduler-k3s-report.bats @@ -0,0 +1,124 @@ +#!/usr/bin/env bats + +load test_helper + +setup() { + global_setup +} + +teardown() { + for prop in deploy-timeout image-pull-secrets ingress-class kubeconfig-path kube-context kustomize-root-path namespace network-interface rollback-on-failure shm-size; do + dokku scheduler-k3s:set --global "$prop" >/dev/null 2>/dev/null || true + done + global_teardown +} + +# assert_k3s_global_unset_set verifies that a global property cycles correctly +# through the raw/computed split: when unset, the global key is empty and the +# computed key returns the built-in default; after setting, both pair members +# match the set value. Excludes letsencrypt-* properties whose set path applies +# cluster issuers via helm and requires a live k3s cluster. +assert_k3s_global_unset_set() { + declare prop="$1" expected_default="$2" set_value="$3" + + run /bin/bash -c "dokku scheduler-k3s:set --global $prop" + assert_success + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-$prop\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-$prop\"'" + assert_success + assert_output "$expected_default" + + run /bin/bash -c "dokku scheduler-k3s:set --global $prop '$set_value'" + assert_success + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-$prop\"'" + assert_success + assert_output "$set_value" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-$prop\"'" + assert_success + assert_output "$set_value" + + run /bin/bash -c "dokku scheduler-k3s:set --global $prop" + assert_success +} + +@test "(scheduler-k3s:report --global) defaulted properties raw/computed cycle" { + assert_k3s_global_unset_set "deploy-timeout" "300s" "600s" + assert_k3s_global_unset_set "kustomize-root-path" "config/kustomize" "deploy/kustomize" + assert_k3s_global_unset_set "namespace" "default" "production" + assert_k3s_global_unset_set "rollback-on-failure" "false" "true" + assert_k3s_global_unset_set "ingress-class" "nginx" "traefik" + assert_k3s_global_unset_set "network-interface" "eth0" "eth1" + assert_k3s_global_unset_set "kubeconfig-path" "/etc/rancher/k3s/k3s.yaml" "/tmp/custom-kubeconfig.yaml" +} + +@test "(scheduler-k3s:report --global) empty-default properties expose computed sibling" { + for prop in image-pull-secrets shm-size kube-context; do + run /bin/bash -c "dokku scheduler-k3s:set --global $prop" + assert_success + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-$prop\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-$prop\"'" + assert_success + assert_output "" + done + + run /bin/bash -c "dokku scheduler-k3s:set --global image-pull-secrets my-secret" + assert_success + run /bin/bash -c "dokku scheduler-k3s:set --global shm-size 64Mi" + assert_success + run /bin/bash -c "dokku scheduler-k3s:set --global kube-context my-context" + assert_success + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-image-pull-secrets\"'" + assert_success + assert_output "my-secret" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-image-pull-secrets\"'" + assert_success + assert_output "my-secret" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-shm-size\"'" + assert_success + assert_output "64Mi" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-shm-size\"'" + assert_success + assert_output "64Mi" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-kube-context\"'" + assert_success + assert_output "my-context" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-kube-context\"'" + assert_success + assert_output "my-context" +} + +@test "(scheduler-k3s:report --global) letsencrypt properties unset state" { + for prop in letsencrypt-server letsencrypt-email-prod letsencrypt-email-stag; do + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-global-$prop\"'" + assert_success + assert_output "" + done + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-letsencrypt-server\"'" + assert_success + assert_output "prod" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-letsencrypt-email-prod\"'" + assert_success + assert_output "" + + run /bin/bash -c "dokku scheduler-k3s:report --global --format json | jq -r '.\"scheduler-k3s-computed-letsencrypt-email-stag\"'" + assert_success + assert_output "" +}