diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7b1d82267..f0a2a7825 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -31,9 +31,10 @@ ], "overrideCommand": false, "postCreateCommand": "setup-dev-env", + "postStartCommand": "printenv > .vscode/devcontainer.env", "runArgs": [ "--init" ], "workspaceFolder": "/root/go/src/github.com/dokku/dokku", "workspaceMount": "type=bind,source=${localWorkspaceFolder},target=/root/go/src/github.com/dokku/dokku,consistency=cached" -} +} \ No newline at end of file diff --git a/README.md b/README.md index 6ed589ba9..083312489 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Support us with a monthly donation and help us continue our activities. [[Become A fresh VM running any of the following operating systems: -- Ubuntu 20.04 / 22.04 / 24.04 (amd64/arm64) - Any currently supported release +- Ubuntu 22.04 / 24.04 (amd64/arm64) - Any currently supported release - Debian 11+ (amd64/arm64) An SSH keypair that can be used for application deployment. If this exists before installation, it will be automatically imported into dokku. diff --git a/bootstrap.sh b/bootstrap.sh index 21b65d3c1..8386c182f 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -3,7 +3,7 @@ set -eo pipefail [[ $TRACE ]] && set -x # A script to bootstrap dokku. -# It expects to be run on Ubuntu 20.04/22.04/24.04 via 'sudo` +# It expects to be run on Ubuntu 22.04/24.04 via 'sudo` # If installing a tag higher than 0.3.13, it may install dokku via a package (so long as the package is higher than 0.3.13) # It checks out the dokku source code from GitHub into ~/dokku and then runs 'make install' from dokku source. @@ -12,7 +12,7 @@ set -eo pipefail # That's good because it prevents our output overlapping with wget's. # It also means that we can't run a partially downloaded script. -SUPPORTED_VERSIONS="Debian [11, 12], Ubuntu [20.04, 22.04, 24.04]" +SUPPORTED_VERSIONS="Debian [11, 12], Ubuntu [22.04, 24.04]" log-fail() { declare desc="log fail formatter" @@ -160,7 +160,7 @@ install-dokku-from-deb-package() { local NO_INSTALL_RECOMMENDS=${DOKKU_NO_INSTALL_RECOMMENDS:=""} local OS_ID - if ! in-array "$DOKKU_DISTRO_VERSION" "20.04" "22.04" "24.04" "10" "11" "12"; then + if ! in-array "$DOKKU_DISTRO_VERSION" "22.04" "24.04" "10" "11" "12"; then log-fail "Unsupported Linux distribution. Only the following versions are supported: $SUPPORTED_VERSIONS" fi @@ -188,7 +188,7 @@ install-dokku-from-deb-package() { fi if [[ "$DOKKU_DISTRO" == "ubuntu" ]]; then - OS_IDS=("focal" "jammy" "noble") + OS_IDS=("jammy" "noble") if ! in-array "$OS_ID" "${OS_IDS[@]}"; then OS_ID="noble" fi diff --git a/common.mk b/common.mk index d6a00a5a6..450e9688d 100644 --- a/common.mk +++ b/common.mk @@ -1,7 +1,7 @@ GO_ARGS ?= GO_PLUGIN_MAKE_TARGET ?= build GO_REPO_ROOT := /go/src/github.com/dokku/dokku -BUILD_IMAGE := golang:1.23.0 +BUILD_IMAGE := golang:1.24.5 GO_BUILD_CACHE ?= /tmp/dokku-go-build-cache GO_MOD_CACHE ?= /tmp/dokku-go-mod-mod GO_ROOT_MOUNT ?= $$PWD/../..:$(GO_REPO_ROOT) diff --git a/contrib/dependencies.json b/contrib/dependencies.json index 2038615f8..8d6359ed8 100644 --- a/contrib/dependencies.json +++ b/contrib/dependencies.json @@ -2,10 +2,10 @@ "dependencies": [ { "name": "docker-container-healthchecker", - "version": "0.11.5", + "version": "0.14.0", "urls": { - "amd64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.11.5/docker-container-healthchecker-linux-amd64", - "arm64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.11.5/docker-container-healthchecker-linux-arm64" + "amd64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.14.0/docker-container-healthchecker-linux-amd64", + "arm64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.14.0/docker-container-healthchecker-linux-arm64" } }, { @@ -86,11 +86,11 @@ }, { "name": "herokuish", - "version": "0.10.3", + "version": "0.11.0", "urls": { - "amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.10.3/herokuish_0.10.3_linux_x86_64.tgz", - "arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.10.3/herokuish_0.10.3_linux_x86_64.tgz" + "amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.0/herokuish_0.11.0_linux_x86_64.tgz", + "arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.11.0/herokuish_0.11.0_linux_x86_64.tgz" } } ] -} +} \ No newline at end of file diff --git a/contrib/release-dokku b/contrib/release-dokku index f71c39ee0..9b114fbcb 100755 --- a/contrib/release-dokku +++ b/contrib/release-dokku @@ -144,7 +144,7 @@ fn-publish-package() { fi done elif [[ "$DIST" == "ubuntu" ]]; then - OS_IDS=("focal" "jammy" "noble") + OS_IDS=("jammy" "noble") for OS_ID in "${OS_IDS[@]}"; do log-info "(release-dokku) pushing ${RELEASE_TYPE} to packagecloud.com/${REPOSITORY}/${DIST}" package_cloud push "${REPOSITORY}/${DIST}/${OS_ID}" "$PACKAGE_NAME" diff --git a/docs/appendices/0.36.0-migration-guide.md b/docs/appendices/0.36.0-migration-guide.md new file mode 100644 index 000000000..2caeca288 --- /dev/null +++ b/docs/appendices/0.36.0-migration-guide.md @@ -0,0 +1,12 @@ +# 0.36.0 Migration Guide + +## Changes + +- Process stop timeouts are now configured via the `ps` property `stop-timeout-seconds`. Existing `DOKKU_DOCKER_STOP_TIMEOUT` environment variables will be automatically migrated to the new value. +- Processes now default to a `30` second stop timeout. +- The `domains:clear` command no longer runs domain setup after clearing the domains. Use `domains:reset` or run `domains:setup` manually to have the same effect. +- The deprecated `DOKKU_DISABLE_ANSI_PREFIX_REMOVAL` setting has been removed. Dokku deploys no longer use shell escape codes to modify output, and thus deploy output may now contain `remote:` as a prefix in each lines output. + +## Deprecations + +Ubuntu 20.04 is now a deprecated installation target. The operating system will be considered EOL by Canonical in April 2025. Users are encouraged to upgrade to Ubuntu 24.04 or consider switching their instllation method to the [Docker-based installation method](/docs/getting-started/install/docker.md) to avoid any disruption in usage. diff --git a/docs/configuration/domains.md b/docs/configuration/domains.md index 71ac8a98f..120157f45 100644 --- a/docs/configuration/domains.md +++ b/docs/configuration/domains.md @@ -13,6 +13,7 @@ domains:enable # Enable VHOST support domains:remove [ ...] # Remove domains from app domains:remove-global [ ...] # Remove global domain names domains:report [|--global] [] # Displays a domains report for one or more apps +domains:reset # Reset app domains to global-configured domains domains:set [ ...] # Set domains for app domains:set-global [ ...] # Set global domain names ``` @@ -75,6 +76,9 @@ dokku domains:remove node-js-app dokku.me # set all custom domains for app dokku domains:set node-js-app dokku.me dokku.org + +# delete all app domains and configure available global domains on it +dokku domains:reset node-js-app ``` ## Displaying domains reports for an app diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index 3734d44c6..69da15c2d 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -110,9 +110,7 @@ The following config variables have special meanings and can be set in a variety | `DOKKU_CHECKS_ATTEMPTS` | `5` | `dokku config:set` | Number of retries for to run for a specific check before marking it as a failure | `DOKKU_DEFAULT_CHECKS_WAIT` | `10` | `dokku config:set` | If no user-defined checks are specified - or if the process being checked is not a `web` process - this is the period of time Dokku will wait before checking that a container is still running. | | `DOKKU_DISABLE_PROXY` | none | `dokku proxy:disable`
`dokku proxy:enable` | Disables the proxy in front of your application, resulting in publicly routing the docker container. | -| `DOKKU_DISABLE_ANSI_PREFIX_REMOVAL` | none | `dokku config:set`
`/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | Disables removal of the ANSI prefix during deploys. Can be used in cases where the client deployer does not understand ansi escape codes. | | `DOKKU_DISABLE_APP_AUTOCREATION` | none | `dokku config:set` | Disables automatic creation of a non-existent app on deploy. | -| `DOKKU_DOCKER_STOP_TIMEOUT` | `10` | `dokku config:set` | Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands _also_ respect this value. If not specified, the docker defaults for the [docker stop command](https://docs.docker.com/engine/reference/commandline/stop/) will be used.| | `DOKKU_DOCKERFILE_CACHE_BUILD` | none | `dokku config:set` | | | `DOKKU_DOCKERFILE_START_CMD` | none | `dokku config:set` | | | `DOKKU_PARALLEL_ARGUMENTS`. | none | `dokku config:set` | Allows passing custom arguments to parallel for `ps:*all` commands | diff --git a/docs/deployment/schedulers/k3s.md b/docs/deployment/schedulers/k3s.md index 372ce4d70..5056deb2e 100644 --- a/docs/deployment/schedulers/k3s.md +++ b/docs/deployment/schedulers/k3s.md @@ -141,6 +141,7 @@ The k3s plugin provides a number of settings that can be used to managed deploym | Name | Description | Global Default | |-----------------------|---------------------------------------------------|--------------------| | `deploy-timeout` | Controls when app deploys will timeout in seconds | `300s` | +| `kustomize-root-path` | Controls the folder context from the deployed repository used for Kustomize | `config/kustomize` | | `image-pull-secrets` | Name of a kubernetes secret used to auth against a registry | Contents of `~/.docker/config.json` from Dokku server | | `namespace` | Controls the namespace used for resource creation | `default` | | `rollback-on-failure` | Whether to rollback failed deploys | `false` | @@ -365,7 +366,6 @@ dokku scheduler-k3s:ensure-charts Once the chart is configured, an `http` trigger can be specified like so: - ```json { "formation": { @@ -461,6 +461,30 @@ dokku scheduler-k3s:autoscaling-auth:report node-js-app --include-metadata Datadog datadogSite: us5.datadoghq.com ``` +### Integrating Kustomize + +Dokku supports integration with [Kustomize](https://kustomize.io/) to further customize the generated helm charts for app deployments. For example, a `config/kustomize/kustomization.yaml` file with the following contents will override the scale for each process deployed to `3`: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- rendered.yaml +patches: +- patch: |- + - op: replace + path: /spec/replicas + value: 3 + target: + group: apps + version: v1 + kind: Deployment +``` + +When using Kustomize with Dokku, all Kustomize-files _must_ be placed in the `config/kustomize` folder, with a `kustomization.yaml` file being the entrypoint to Kustomize. Dokku will render the helm chart to a `rendered.yaml` file, and then execute Kustomize with the `config/kustomize` folder as the context. + +See the [Kustomize](https://kustomize.io/) website for more details on how to use Kustomize. + ### Using kubectl remotely > [!WARNING] @@ -515,7 +539,6 @@ dokku scheduler-k3s:set --global chart.cert-manager.version 1.13.3 > [!NOTE] > Properties follow dot-notation, and are expanded according to Helm's internal logic. See the [Helm documentation](https://helm.sh/docs/helm/helm_install/#helm-install) for `helm install` for further details. - To unset a chart property, omit the value from the `scheduler-k3s:set` call: ```shell diff --git a/docs/deployment/schedulers/scheduler-management.md b/docs/deployment/schedulers/scheduler-management.md index 0189092bf..4fac3ce0f 100644 --- a/docs/deployment/schedulers/scheduler-management.md +++ b/docs/deployment/schedulers/scheduler-management.md @@ -98,7 +98,7 @@ At this time, the following dokku commands are used to implement a complete sche - `apps:clone`: handles app cloning - triggers: post-app-clone-setup - `cron`: generates cron tasks for the app - - triggers: cron-write + - triggers: scheduler-cron-write - `deploy`: deploys app proceses and checks the status of a deploy - triggers: scheduler-app-status, scheduler-deploy, scheduler-is-deployed, scheduler-logs-failed - `enter`: enters a running container @@ -112,7 +112,9 @@ At this time, the following dokku commands are used to implement a complete sche - `run:logs`: fetches running container logs - triggers: scheduler-run-logs - `ps:stop`: stops app processes - - triggers: scheduler-stop + - triggers: scheduler-stop, scheduler-cron-write +- `ps:start`: starts app processes + - triggers: scheduler-deploy, scheduler-cron-write - `ps:inspect`: outputs inspect output for processes in an app - triggers: scheduler-inspect diff --git a/docs/deployment/zero-downtime-deploys.md b/docs/deployment/zero-downtime-deploys.md index b811b2d1e..e769b2193 100644 --- a/docs/deployment/zero-downtime-deploys.md +++ b/docs/deployment/zero-downtime-deploys.md @@ -36,12 +36,15 @@ dokku checks:set node-js-app wait-to-retire 30 Defaults to `60`. +## Setting stop grace period + +You can set the `stop-timeout-seconds` property on the `ps` plugin to change this value (default: `30`). See the [process management documentation](/docs/processes/process-management.md#changing-process-management-settings) for more information. + ## Configuring check settings using the `config` plugin There are certain settings that can be configured via environment variables: - `DOKKU_DEFAULT_CHECKS_WAIT`: (default: `10`) If no user-defined checks are specified - or if the process being checked is not a `web` process - this is the period of time Dokku will wait before checking that a container is still running. -- `DOKKU_DOCKER_STOP_TIMEOUT`: (default: `10`) Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands *also* respect this value. If not specified, the Docker defaults for the [`docker stop` command](https://docs.docker.com/engine/reference/commandline/stop/) will be used. The following settings may also be specified in the `app.json` file, though are available as environment variables in order to ease application reuse. diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index a8551d54e..43bbab731 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -119,6 +119,21 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x # TODO ``` +### `app-json-is-valid` + +- Description: Checks to see if the provided app.json file is valid +- Invoked by: Appjson extraction during deployment +- Arguments: `$APP $APP_JSON_PATH` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x + +# TODO +``` + ### `app-maybe-create` - Description: Creates an app (gated by whether this is globally enabled or not) @@ -583,22 +598,6 @@ DOKKU_SCHEDULER="$1" # TODO ``` -### `cron-write` - -- Description: Force triggers writing out cron entries -- Invoked by: -- Arguments: -- Example: - -```shell -#!/usr/bin/env bash - -set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" - -# TODO -``` - ### `dependencies` - Description: Used to install system-level dependencies. @@ -1700,7 +1699,7 @@ curl "http://httpstat.us/200" ### `post-domains-update` - Description: Allows you to run commands once the domain for an app has been updated. It also sends in the command that has been used. This can be "add", "clear" or "remove". The third argument will be the optional list of domains -- Invoked by: `dokku domains:add`, `dokku domains:clear`, `dokku domains:remove`, `dokku domains:set` +- Invoked by: `dokku domains:add`, `dokku domains:clear`, `dokku domains:remove`, `dokku domains:reset`, `dokku domains:set` - Arguments: `$APP` `action name` `domains` - Example: @@ -2445,6 +2444,26 @@ DOKKU_SCHEDULER="$1"; APP="$2"; # TODO ``` +### `scheduler-cron-write` + +> [!WARNING] +> The scheduler plugin trigger apis are under development and may change +> between minor releases until the 1.0 release. + +- Description: Force triggers writing out cron entries. Arguments are optional. +- Invoked by: `ps:start`, `ps:stop`, `cron:set` +- Arguments: `$DOKKU_SCHEDULER $APP` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +# TODO +``` + ### `scheduler-deploy` > [!WARNING] diff --git a/docs/development/testing.md b/docs/development/testing.md index 669449a24..1daaca2be 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -13,7 +13,7 @@ All pull requests have tests run against them on [GitHub Actions](https://github If you wish to skip tests for a particular commit, e.g. documentation changes, you may add the `[ci skip]` designator to your commit message. Commits that _should_ be tested but have the above designator will not be merged. -While we do provide official packages for a variety of platforms, as our test suite currently runs on Ubuntu Noble 24.04, we only provide official installation support for that platform and the supported LTS releases of Ubuntu (currently 20.04, 22.04, and 24.04). +While we do provide official packages for a variety of platforms, as our test suite currently runs on Ubuntu Noble 24.04, we only provide official installation support for that platform and the supported LTS releases of Ubuntu (currently 22.04, and 24.04). ## Local Test Execution diff --git a/docs/getting-started/installation/index.md b/docs/getting-started/installation/index.md index 1787a75c8..62e9f0613 100644 --- a/docs/getting-started/installation/index.md +++ b/docs/getting-started/installation/index.md @@ -9,7 +9,7 @@ Dokku is an extensible, open source Platform as a Service that runs on a single To start using Dokku, you'll need a system that meets the following minimum requirements: - A fresh installation of any of the following operating systems: - - [Ubuntu 20.04/22.04/24.04](https://www.ubuntu.com/download) + - [Ubuntu 22.04/24.04](https://www.ubuntu.com/download) - [Debian 11+ x64](https://www.debian.org/distrib/) - A server with one of the following architectures - AMD64 (alternatively known as `x86_64`), commonly used for Intel cloud servers diff --git a/docs/networking/proxies/caddy.md b/docs/networking/proxies/caddy.md index fe2f6b9c7..b56ab994d 100644 --- a/docs/networking/proxies/caddy.md +++ b/docs/networking/proxies/caddy.md @@ -117,6 +117,16 @@ dokku caddy:set --global log-level DEBUG After modifying, the Caddy container will need to be restarted. +### Changing the label key for the app + +The default label key for the app is `caddy`. This can be changed by setting the `label-key` property: + +```shell +dokku caddy:set node-js-app label-key caddy_0 +``` + +This will update the app's label key to `caddy_0`. The label key is used to identify the app in the Caddy configuration. If you change the label key, you will need to restart or rebuild the app to apply the updates. + ### SSL Configuration The caddy plugin only supports automatic ssl certificates from it's letsencrypt integration. Managed certificates provided by the `certs` plugin are ignored. diff --git a/docs/networking/proxies/nginx.md b/docs/networking/proxies/nginx.md index ed1d64d47..bd6b5d92a 100644 --- a/docs/networking/proxies/nginx.md +++ b/docs/networking/proxies/nginx.md @@ -332,6 +332,7 @@ Changing these value globally or on a per-app basis will require rebuilding the | keepalive-timeout | `75s` | string | Timeout (with units) during which a keep-alive client connection will stay open on the server side | | lingering-timeout | `5s` | string | Timeout (with units) is the maximum waiting time for more client data to arrive | | nginx-conf-sigil-path | `nginx.conf.sigil` | string | Path in the repository to the `nginx.conf.sigil` file | +| nginx-service-command | | string | Full path to an executable script or binary to invoke instead of the system's init process when interacting with nginx | | proxy-buffer-size | `8k` (# is os pagesize) | string | Size of the buffer used for reading the first part of proxied server response | | proxy-buffering | `on` | string | Enables or disables buffering of responses from the proxied server | | proxy-buffers | `8 8k` | string | Number and size of the buffers used for reading the proxied server response, for a single connection | diff --git a/docs/networking/proxy-management.md b/docs/networking/proxy-management.md index 6b1ec7f55..173b2e868 100644 --- a/docs/networking/proxy-management.md +++ b/docs/networking/proxy-management.md @@ -158,6 +158,8 @@ At this time, the following dokku commands are used to interact with a complete - triggers: `pre-enable-vhost` - `domains:remove`: Removes a domain from an app. - triggers: `post-domains-update` +- `domains:reset`: Reset app domains to global-configured domains. + - triggers: `post-domains-update` - `domains:set`: Sets all domains for a given app. - triggers: `post-domains-update` - `proxy:build-config`: Builds - or rebuilds - external proxy configuration. diff --git a/docs/processes/process-management.md b/docs/processes/process-management.md index abc64ebac..86b80982e 100644 --- a/docs/processes/process-management.md +++ b/docs/processes/process-management.md @@ -107,6 +107,38 @@ proctype: qty web: 1 ``` +### Changing process management settings + +The `ps` plugin provides a number of settings that can be used to managed deployments on a per-app basis. The following table outlines ones not covered elsewhere: + +| Name | Description | Global Default | +|-----------------------|---------------------------------------------------|--------------------| +| `stop-timeout` | Configurable grace period given to the `docker stop` command. If a container has not stopped by this time, a `kill -9` signal or equivalent is sent in order to force-terminate the container. Both the `ps:stop` and `apps:destroy` commands *also* respect this value. If not specified, the Docker defaults for the [`docker stop` command](https://docs.docker.com/engine/reference/commandline/stop/) will be used. | `30` | + +All settings can be set via the `ps:set` command. Using `stop-timeout` as an example: + +```shell +dokku ps:set node-js-app stop-timeout 60 +``` + +The default value may be set by passing an empty value for the option in question: + +```shell +dokku ps:set node-js-app stop-timeout +``` + +Properties can also be set globally. If not set for an app, the global value will apply. + +```shell +dokku ps:set --global stop-timeout 60 +``` + +The global default value may be set by passing an empty value for the option. + +```shell +dokku ps:set --global stop-timeout +``` + ### Defining Processes #### Procfile diff --git a/docs/processes/scheduled-cron-tasks.md b/docs/processes/scheduled-cron-tasks.md index 145c890c6..ac1ed4809 100644 --- a/docs/processes/scheduled-cron-tasks.md +++ b/docs/processes/scheduled-cron-tasks.md @@ -53,39 +53,39 @@ When running scheduled cron tasks, there are a few items to be aware of: - Scheduled cron tasks are supported on a per-scheduler basis, and are currently only implemented by the `docker-local` scheduler. - Tasks for _all_ apps managed by the `docker-local` scheduler are written to a single crontab file owned by the `dokku` user. The `dokku` user's crontab should be considered reserved for this purpose. -#### Specifying a MAILFROM value -> [!IMPORTANT] -> New as of 0.35.14 +### Changing cron management settings -Users can specify a value for `MAILFROM` via the global `mailfrom` cron property by using the `cron:set` command. +The `cron` plugin provides a number of settings that can be used to managed deployments on a per-app basis. The following table outlines ones not covered elsewhere: + +| Name | Description | Level | Global Default | +|-----------------------|----------------------------------------------------------------|-------------|----------------| +| `mailfrom` | Sets the `MAILFROM` variable in a cron file for cron reporting | Global-only | empty string | +| `maintenance` | Whether to have cron running for the app or not. | App-only | `false` | +| `mailto` | Sets the `MAILTO` variable in a cron file for cron reporting | Global-only | empty string | + +All settings can be set via the `cron:set` command. Using `maintenance` as an example: ```shell -dokku cron:set --global mailfrom example@example.com +dokku cron:set node-js-app maintenance true ``` -All output for individual cron runs will be sent from the specified email. - -Cron emails can be reset to use the system email by running the `cron:set` command for the global `mailfrom` property with no value. +The default value may be set by passing an empty value for the option in question: ```shell -dokku cron:set --global mailfrom +dokku cron:set node-js-app maintenance ``` -#### Specifying a MAILTO value - -By default, cron tasks complete and do not perform any reporting. Users can specify a value for `MAILTO` via the global `mailto` cron property by using the `cron:set` command. +If a property can be set globally - such as `mailto`, use the `--global` flag. If not set for an app, the global value will apply if it exists. ```shell -dokku cron:set --global mailto example@example.com +dokku cron:set --global maintenance true ``` -All output for individual cron runs will be sent to the specified email. - -Cron emails can be disabled by running the `cron:set` command for the global `mailto` property with no value. +The global default value may be set by passing an empty value for the option. ```shell -dokku cron:set --global mailto +dokku cron:set --global maintenance ``` #### Listing Cron tasks diff --git a/go.work b/go.work index 72ea6651e..a7a0ee40c 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.23.0 +go 1.24.0 use ( ./plugins/app-json diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index 5ea123f1c..75f0ccced 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -200,21 +200,9 @@ func GetAppJSON(appName string) (AppJSON, error) { return AppJSON{}, nil } - b, err := os.ReadFile(getProcessSpecificAppJSONPath(appName)) - if err != nil { - return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err) - } + appJSONPath := getProcessSpecificAppJSONPath(appName) - if strings.TrimSpace(string(b)) == "" { - return AppJSON{}, nil - } - - var appJSON AppJSON - if err = json.Unmarshal(b, &appJSON); err != nil { - return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err) - } - - return appJSON, nil + return ReadAppJSON(appJSONPath) } func GetAutoscalingConfig(appName string, processType string, replicas int) (FormationAutoscaling, bool, error) { @@ -256,3 +244,22 @@ func GetAutoscalingConfig(appName string, processType string, replicas int) (For return autoscaling, true, nil } + +// ReadAppJSON reads an app.json file from a given path +func ReadAppJSON(path string) (AppJSON, error) { + b, err := os.ReadFile(path) + if err != nil { + return AppJSON{}, fmt.Errorf("Cannot read app.json file: %v", err) + } + + if strings.TrimSpace(string(b)) == "" { + return AppJSON{}, nil + } + + var appJSON AppJSON + if err = json.Unmarshal(b, &appJSON); err != nil { + return AppJSON{}, fmt.Errorf("Cannot parse app.json: %v", err) + } + + return appJSON, nil +} diff --git a/plugins/app-json/go.mod b/plugins/app-json/go.mod index 9116a51ca..b70b63489 100644 --- a/plugins/app-json/go.mod +++ b/plugins/app-json/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/app-json -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/app-json/triggers.go b/plugins/app-json/triggers.go index 35d88240c..06b5126e0 100644 --- a/plugins/app-json/triggers.go +++ b/plugins/app-json/triggers.go @@ -1,10 +1,9 @@ package appjson import ( + "errors" "fmt" "os" - "path" - "path/filepath" "strings" "github.com/dokku/dokku/plugins/common" @@ -58,90 +57,70 @@ func TriggerAppJSONGetContent(appName string) error { return nil } -// TriggerCorePostDeploy sets a property to -// allow the app to be restored on boot +// TriggerCorePostDeploy moves the extracted app.json to the app data directory +// allowing the app to be restored on boot func TriggerCorePostDeploy(appName string) error { - existingAppJSON := getAppJSONPath(appName) - processSpecificAppJSON := fmt.Sprintf("%s.%s", existingAppJSON, os.Getenv("DOKKU_PID")) - if common.FileExists(processSpecificAppJSON) { - if err := os.Rename(processSpecificAppJSON, existingAppJSON); err != nil { - return err - } - } else if common.FileExists(fmt.Sprintf("%s.missing", processSpecificAppJSON)) { - if err := os.Remove(fmt.Sprintf("%s.missing", processSpecificAppJSON)); err != nil { - return err - } - - if common.FileExists(existingAppJSON) { - if err := os.Remove(existingAppJSON); err != nil { - return err - } - } - } - - return nil + return common.CorePostDeploy(common.CorePostDeployInput{ + AppName: appName, + Destination: common.GetAppDataDirectory("app-json", appName), + PluginName: "app-json", + ExtractedPaths: []common.CorePostDeployPath{ + {Path: "app.json", IsDirectory: false}, + }, + }) } // TriggerCorePostExtract ensures that the main app.json is the one specified by app-json-path func TriggerCorePostExtract(appName string, sourceWorkDir string) error { + destination := common.GetAppDataDirectory("app-json", appName) appJSONPath := strings.Trim(reportComputedAppjsonpath(appName), "/") if appJSONPath == "" { appJSONPath = "app.json" } - existingAppJSON := getAppJSONPath(appName) - files, err := filepath.Glob(fmt.Sprintf("%s.*", existingAppJSON)) - if err != nil { - return err - } - for _, f := range files { - if err := os.Remove(f); err != nil { + validator := func(appName string, path string) error { + if !common.FileExists(path) { + return nil + } + + result, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "app-json-is-valid", + Args: []string{appName, path}, + StreamStdout: true, + StreamStderr: true, + }) + + if err != nil { + if result.StderrContents() != "" { + return errors.New(result.StderrContents()) + } + return err } + return nil } - processSpecificAppJSON := fmt.Sprintf("%s.%s", existingAppJSON, os.Getenv("DOKKU_PID")) results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ - Trigger: "git-get-property", - Args: []string{appName, "source-image"}, - }) - appSourceImage := results.StdoutContents() - - results, _ = common.CallPlugnTrigger(common.PlugnTriggerInput{ Trigger: "builder-get-property", Args: []string{appName, "build-dir"}, }) buildDir := results.StdoutContents() - - repoDefaultAppJSONPath := path.Join(sourceWorkDir, "app.json") - if appSourceImage == "" { - repoAppJSONPath := path.Join(sourceWorkDir, buildDir, appJSONPath) - if !common.FileExists(repoAppJSONPath) { - if appJSONPath != "app.json" && common.FileExists(repoDefaultAppJSONPath) { - if err := os.Remove(repoDefaultAppJSONPath); err != nil { - return err - } - } - return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificAppJSON)) - } - - if err := common.Copy(repoAppJSONPath, processSpecificAppJSON); err != nil { - return fmt.Errorf("Unable to extract app.json: %v", err.Error()) - } - - if appJSONPath != "app.json" { - if err := common.Copy(repoAppJSONPath, repoDefaultAppJSONPath); err != nil { - return fmt.Errorf("Unable to move app.json into place: %v", err.Error()) - } - } - } else { - if err := common.CopyFromImage(appName, appSourceImage, path.Join(buildDir, appJSONPath), processSpecificAppJSON); err != nil { - return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificAppJSON)) - } - } - - // TODO: add validation to app.json file by ensuring it can be deserialized - return nil + return common.CorePostExtract(common.CorePostExtractInput{ + AppName: appName, + BuildDir: buildDir, + Destination: destination, + PluginName: "app-json", + SourceWorkDir: sourceWorkDir, + ToExtract: []common.CorePostExtractToExtract{ + { + Path: appJSONPath, + IsDirectory: false, + Name: "app.json", + Destination: "app.json", + Validator: validator, + }, + }, + }) } // TriggerInstall initializes app-json directory structures diff --git a/plugins/apps/go.mod b/plugins/apps/go.mod index ebaad4008..935537634 100644 --- a/plugins/apps/go.mod +++ b/plugins/apps/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/apps -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/builder/go.mod b/plugins/builder/go.mod index ff3840fa0..d46541ca6 100644 --- a/plugins/builder/go.mod +++ b/plugins/builder/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/builder -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/buildpacks/go.mod b/plugins/buildpacks/go.mod index 44e15bddb..57ac12969 100644 --- a/plugins/buildpacks/go.mod +++ b/plugins/buildpacks/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/buildpacks -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/caddy-vhosts/docker-args-process-deploy b/plugins/caddy-vhosts/docker-args-process-deploy index 65a9c9796..9dd1f61f1 100755 --- a/plugins/caddy-vhosts/docker-args-process-deploy +++ b/plugins/caddy-vhosts/docker-args-process-deploy @@ -8,7 +8,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() { declare desc="nginx-vhosts core-post-deploy plugin trigger" declare trigger="docker-args-process-deploy" declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3" PROC_TYPE="$4" CONTAINER_INDEX="$5" - local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes scheme tls_internal + local app_domains caddy_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes scheme tls_internal label_key local proxy_container_http_port proxy_container_http_port_candidate proxy_host_http_port_candidate local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate local STDIN=$(cat) @@ -88,13 +88,14 @@ trigger-caddy-vhosts-docker-args-process-deploy() { if [[ -n "$is_app_listening" ]] && [[ -n "$caddy_domains" ]]; then has_443_mapping=false tls_internal="$(fn-caddy-tls-internal)" + label_key="$(fn-caddy-label-key "$APP")" if [[ -n "$proxy_container_https_port" ]] || [[ -n "$proxy_container_https_port_candidate" ]]; then has_443_mapping=true fi ssl_warning_mapping="https:443" if [[ "$tls_internal" == "true" ]]; then - output="--label caddy.tls=internal" + output="--label ${label_key}.tls=internal" if [[ "$has_443_mapping" == "false" ]]; then ssl_warning_mapping="http:80" proxy_host_https_port_candidate="$proxy_host_http_port_candidate" @@ -105,7 +106,7 @@ trigger-caddy-vhosts-docker-args-process-deploy() { scheme="http" if [[ -n "$letsencrypt_email" ]] && [[ "$has_443_mapping" == "true" ]]; then - output="--label 'caddy=${caddy_domains}'" + output="--label '${label_key}=${caddy_domains}'" scheme="https" if [[ -z "$proxy_container_https_port" ]]; then warning_scheme="$(awk -F ':' '{ print $1 }' <<<"$ssl_warning_mapping")" @@ -114,17 +115,17 @@ trigger-caddy-vhosts-docker-args-process-deploy() { proxy_container_https_port="$proxy_container_https_port_candidate" fi - output="$output --label \"caddy.reverse_proxy={{ upstreams $proxy_container_https_port }}\"" + output="$output --label \"${label_key}.reverse_proxy={{ upstreams $proxy_container_https_port }}\"" elif [[ -n "$proxy_container_http_port" ]] || [[ -n "$proxy_container_http_port_candidate" ]]; then caddy_domains="${caddy_domains//, /:80, }" - output="--label 'caddy=${caddy_domains}:80'" + output="--label '${label_key}=${caddy_domains}:80'" if [[ -z "$proxy_container_http_port" ]]; then dokku_log_warn "Warning: http:80 port mapping not found" dokku_log_warn "Utilizing first http port mapping, http:$proxy_host_http_port_candidate:$proxy_container_http_port_candidate" proxy_container_http_port="$proxy_container_http_port_candidate" fi - output="$output --label \"caddy.reverse_proxy={{ upstreams $proxy_container_http_port }}\"" + output="$output --label \"${label_key}.reverse_proxy={{ upstreams $proxy_container_http_port }}\"" fi fi diff --git a/plugins/caddy-vhosts/internal-functions b/plugins/caddy-vhosts/internal-functions index 86727e364..88758f732 100755 --- a/plugins/caddy-vhosts/internal-functions +++ b/plugins/caddy-vhosts/internal-functions @@ -71,3 +71,8 @@ fn-caddy-tls-internal() { declare APP="$1" fn-plugin-property-get-default "caddy" "$APP" "tls-internal" "false" } + +fn-caddy-label-key() { + declare APP="$1" + fn-plugin-property-get-default "caddy" "$APP" "label-key" "caddy" +} diff --git a/plugins/caddy-vhosts/subcommands/set b/plugins/caddy-vhosts/subcommands/set index 99954cf3e..39dc3daa2 100755 --- a/plugins/caddy-vhosts/subcommands/set +++ b/plugins/caddy-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-caddy-set() { declare cmd="caddy:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval" "tls-internal") + local VALID_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval" "label-key" "tls-internal") local GLOBAL_KEYS=("image" "letsencrypt-email" "letsencrypt-server" "log-level" "polling-interval") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval tls-internal" + dokku_log_fail "Invalid key specified, valid keys include: image letsencrypt-email letsencrypt-server log-level polling-interval label-key tls-internal" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/plugins/common/common.go b/plugins/common/common.go index 80aed6746..a8ae3e662 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -14,6 +14,7 @@ import ( "strings" "unicode" + "github.com/otiai10/copy" "github.com/ryanuber/columnize" "golang.org/x/sync/errgroup" ) @@ -74,6 +75,298 @@ func CommandUsage(helpHeader string, helpContent string) { fmt.Println(columnize.Format(content, config)) } +// CorePostDeployPath is a file or directory that was extracted +type CorePostDeployPath struct { + // IsDirectory is whether the source is a directory + IsDirectory bool + + // Path is the name of the file or directory + Path string +} + +// CorePostDeployInput is the input for the CorePostDeploy function +type CorePostDeployInput struct { + // AppName is the name of the app + AppName string + + // Destination is the destination directory + Destination string + + // PluginName is the name of the plugin that is deploying the file or directory + PluginName string + + // ExtractedPaths is the list of paths that were extracted + ExtractedPaths []CorePostDeployPath +} + +// CorePostDeploy moves extracted paths to the destination directory +// and removes any existing files or directories that were not extracted +// +// CorePostDeploy(CorePostDeployInput{ +// AppName: "my-app", +// Destination: "/var/lib/dokku/data/my-app", +// ExtractedPaths: []CorePostDeployPath{ +// {Name: "app.json", IsDirectory: false}, +// {Name: "kustomization", IsDirectory: true}, +// }, +// }) +func CorePostDeploy(input CorePostDeployInput) error { + if input.PluginName == "" { + return fmt.Errorf("Missing required PluginName in CorePostDeploy") + } + + if input.AppName == "" { + return fmt.Errorf("Missing required AppName in CorePostDeploy for plugin %v", input.PluginName) + } + + if input.Destination == "" { + return fmt.Errorf("Missing required Destination in CorePostDeploy for plugin %v", input.PluginName) + } + + for i, extractedPath := range input.ExtractedPaths { + if extractedPath.Path == "" { + return fmt.Errorf("Missing required Name in CorePostDeploy for index %v for plugin %v", i, input.PluginName) + } + + existingPath := filepath.Join(input.Destination, extractedPath.Path) + processSpecificPath := fmt.Sprintf("%s.%s", existingPath, os.Getenv("DOKKU_PID")) + + if extractedPath.IsDirectory { + if DirectoryExists(processSpecificPath) { + if err := os.RemoveAll(existingPath); err != nil { + return err + } + + if err := os.Rename(processSpecificPath, existingPath); err != nil { + return err + } + } else if DirectoryExists(fmt.Sprintf("%s.missing", processSpecificPath)) { + if err := os.RemoveAll(fmt.Sprintf("%s.missing", processSpecificPath)); err != nil { + return err + } + + if DirectoryExists(existingPath) { + if err := os.RemoveAll(existingPath); err != nil { + return err + } + } + } + } else { + if FileExists(processSpecificPath) { + if err := os.Rename(processSpecificPath, existingPath); err != nil { + return err + } + } else if FileExists(fmt.Sprintf("%s.missing", processSpecificPath)) { + if err := os.Remove(fmt.Sprintf("%s.missing", processSpecificPath)); err != nil { + return err + } + + if FileExists(existingPath) { + if err := os.Remove(existingPath); err != nil { + return err + } + } + } + } + } + + return nil +} + +// CorePostExtractValidator is a function that validates the file or directory +type CorePostExtractValidator func(appName string, path string) error + +// CorePostExtractToExtract is a file or directory to extract +type CorePostExtractToExtract struct { + // Destination is an optional alias destination path + // If not provided, the Path will be used as the destination + Destination string + + // IsDirectory is whether the source is a directory + IsDirectory bool + + // Name is the common name of the file or directory to extract + Name string + + // Path is the path to the file or directory to extract + Path string + + // Validator is a function that validates the file or directory + Validator CorePostExtractValidator +} + +// CorePostExtractInput is the input for the CorePostExtract function +type CorePostExtractInput struct { + // AppName is the name of the app + AppName string + + // BuildDir is the optional build directory to extract from + BuildDir string + + // DestinationDir is the destination directory + Destination string + + // PluginName is the name of the plugin that is extracting the file or directory + PluginName string + + // SourceWorkDir is the source work directory + SourceWorkDir string + + // ToExtract is a list of files or directories to extract + ToExtract []CorePostExtractToExtract +} + +// CorePostExtract extracts files or directories from a source work directory to a destination directory +// +// CorePostExtract(CorePostExtractInput{ +// AppName: "my-app", +// SourceWorkDir: "/tmp/my-app-source", +// Destination: "/var/lib/dokku/data/my-app", +// ToExtract: []CorePostExtractToExtract{ +// {Path: "app2.json", IsDirectory: false, Name: "app.json"}, +// {Path: "config/kustomize", IsDirectory: true, Destination: "kustomization"}, +// }, +// }) +func CorePostExtract(input CorePostExtractInput) error { + if input.PluginName == "" { + return fmt.Errorf("Missing required PluginName in CorePostExtract") + } + + if input.AppName == "" { + return fmt.Errorf("Missing required AppName in CorePostExtract for plugin %v", input.PluginName) + } + + if input.Destination == "" { + return fmt.Errorf("Missing required Destination in CorePostExtract for plugin %v", input.PluginName) + } + + if input.SourceWorkDir == "" { + return fmt.Errorf("Missing required SourceWorkDir in CorePostExtract for plugin %v", input.PluginName) + } + + results, _ := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "git-get-property", + Args: []string{input.AppName, "source-image"}, + }) + sourceImage := results.StdoutContents() + + for i, toExtract := range input.ToExtract { + if toExtract.Name == "" { + return fmt.Errorf("Name is required for index %v in CorePostExtract for plugin %v", i, input.PluginName) + } + + if toExtract.Path == "" { + return fmt.Errorf("Path is required for index %v in CorePostExtract for plugin %v", i, input.PluginName) + } + + if toExtract.Destination == "" { + toExtract.Destination = toExtract.Path + } + + sourcePath := filepath.Join(input.SourceWorkDir, toExtract.Path) + repoDefaultSourcePath := filepath.Join(input.SourceWorkDir, toExtract.Name) + imageSourcePath := toExtract.Path + if input.BuildDir != "" { + sourcePath = filepath.Join(input.SourceWorkDir, input.BuildDir, toExtract.Path) + repoDefaultSourcePath = filepath.Join(input.SourceWorkDir, input.BuildDir, toExtract.Name) + imageSourcePath = filepath.Join(input.BuildDir, toExtract.Path) + } + + destination := filepath.Join(input.Destination, toExtract.Destination) + processSpecificDestination := fmt.Sprintf("%s.%s", destination, os.Getenv("DOKKU_PID")) + missingDestination := fmt.Sprintf("%s.missing", processSpecificDestination) + files, err := filepath.Glob(fmt.Sprintf("%s.*", destination)) + if err != nil { + return err + } + for _, f := range files { + if err := os.Remove(f); err != nil { + return err + } + } + + // ignore if the path is empty + if toExtract.Path == "" { + if err := TouchFile(missingDestination); err != nil { + return err + } + continue + } + + if sourceImage == "" { + // ignore if the file does not exist + if toExtract.IsDirectory { + if !DirectoryExists(sourcePath) { + if sourcePath != repoDefaultSourcePath && DirectoryExists(repoDefaultSourcePath) { + if err := os.RemoveAll(repoDefaultSourcePath); err != nil { + return fmt.Errorf("Unable to remove existing %v: %s", toExtract.Name, err.Error()) + } + } + + if err := TouchFile(missingDestination); err != nil { + return err + } + continue + } + + if err := Copy(sourcePath, processSpecificDestination); err != nil { + return fmt.Errorf("Unable to extract %v from %v: %s", toExtract.Name, toExtract.Path, err.Error()) + } + + if sourcePath != repoDefaultSourcePath { + if err := Copy(sourcePath, repoDefaultSourcePath); err != nil { + return fmt.Errorf("Unable to move %v into place: %s", toExtract.Name, err.Error()) + } + } + } else { + if !FileExists(sourcePath) { + // delete the existing file if the user tried to override it with a non-existent file + if sourcePath != repoDefaultSourcePath && FileExists(repoDefaultSourcePath) { + if err := os.Remove(repoDefaultSourcePath); err != nil { + return err + } + } + if err := TouchFile(missingDestination); err != nil { + return err + } + continue + } + + if err := Copy(sourcePath, processSpecificDestination); err != nil { + return fmt.Errorf("Unable to extract %v from %v: %v", toExtract.Name, toExtract.Path, err.Error()) + } + + if sourcePath != repoDefaultSourcePath { + // ensure the file in the repo is the same as the one the user specified + if err := copy.Copy(sourcePath, repoDefaultSourcePath); err != nil { + return fmt.Errorf("Unable to move %v into place: %v", toExtract.Name, err.Error()) + } + } + } + } else { + if toExtract.IsDirectory { + + if err := CopyDirFromImage(input.AppName, sourceImage, imageSourcePath, processSpecificDestination); err != nil { + return TouchFile(missingDestination) + } + } else { + if err := CopyFromImage(input.AppName, sourceImage, imageSourcePath, processSpecificDestination); err != nil { + return TouchFile(missingDestination) + } + } + } + + // validate the file + if toExtract.Validator != nil { + if err := toExtract.Validator(input.AppName, processSpecificDestination); err != nil { + return err + } + } + } + + return nil +} + // EnvWrap wraps a func with a setenv call and resets the value at the end func EnvWrap(fn func() error, environ map[string]string) error { oldEnviron := map[string]string{} @@ -578,7 +871,7 @@ func SuppressOutput(f errfunc) error { os.Stdout = rescueStdout if err != nil { - fmt.Printf(string(out[:])) + fmt.Print(string(out[:])) } return err diff --git a/plugins/common/docker.go b/plugins/common/docker.go index bf3cef0cd..11a0c1a39 100644 --- a/plugins/common/docker.go +++ b/plugins/common/docker.go @@ -151,6 +151,98 @@ func ContainerWaitTilReady(containerID string, timeout time.Duration) error { return nil } +// CopyDirFromImage copies a directory from named image to destination +func CopyDirFromImage(appName string, image string, source string, destination string) error { + if !VerifyImage(image) { + return fmt.Errorf("Invalid docker image for copying content") + } + + if !IsAbsPath(source) { + workDir := GetWorkingDir(appName, image) + if workDir != "" { + source = fmt.Sprintf("%s/%s", workDir, source) + } + } + + tmpDir, err := os.MkdirTemp("", fmt.Sprintf("dokku-%s-%s", MustGetEnv("DOKKU_PID"), "CopyFromImage")) + if err != nil { + return fmt.Errorf("Error creating temporary directory: %v", err) + } + + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + LogWarn(fmt.Sprintf("Error removing temporary directory %s: %v\n", tmpDir, err)) + } + }() + + globalRunArgs := MustGetEnv("DOKKU_GLOBAL_RUN_ARGS") + createLabelArgs := []string{"--label", fmt.Sprintf("com.dokku.app-name=%s", appName), globalRunArgs} + containerID, err := DockerContainerCreate(image, createLabelArgs) + if err != nil { + return fmt.Errorf("Unable to create temporary container: %v", err) + } + defer ContainerRemove(containerID) + + // docker cp exits with status 1 when run as non-root user when it tries to chown the file + // after successfully copying the file. Thus, we suppress stderr. + // ref: https://github.com/dotcloud/docker/issues/3986 + result, err := CallExecCommand(ExecCommandInput{ + Command: DockerBin(), + Args: []string{"container", "cp", "--quiet", fmt.Sprintf("%s:%s", containerID, source), tmpDir}, + }) + if err != nil { + return fmt.Errorf("Unable to copy file %s from image: %w", source, err) + } + if result.ExitCode != 0 { + return fmt.Errorf("Unable to copy file %s from image: %v", source, result.StderrContents()) + } + + if !DirectoryExists(tmpDir) { + return fmt.Errorf("Unable to copy file %s from image: %v", source, result.StderrContents()) + } + + files, err := os.ReadDir(tmpDir) + if err != nil { + return fmt.Errorf("Unable to read temporary directory: %v", err) + } + + for _, file := range files { + if file.IsDir() { + continue + } + + sourceFile := fmt.Sprintf("%s/%s", tmpDir, file.Name()) + destinationFile := fmt.Sprintf("%s/%s", destination, file.Name()) + // workaround when owner is root. seems to only happen when running inside docker + CallExecCommand(ExecCommandInput{ + Command: "dos2unix", + Args: []string{"-l", "-n", sourceFile, destinationFile}, + }) // nolint: errcheck + + // add trailing newline for certain places where file parsing depends on it + result, err = CallExecCommand(ExecCommandInput{ + Command: "tail", + Args: []string{"-c1", destination}, + }) + if err != nil || result.ExitCode != 0 { + return fmt.Errorf("Unable to append trailing newline to copied file: %v", result.Stderr) + } + + if result.Stdout != "" { + f, err := os.OpenFile(destination, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + if _, err := f.WriteString("\n"); err != nil { + return fmt.Errorf("Unable to append trailing newline to copied file: %v", err) + } + } + } + + return nil +} + // CopyFromImage copies a file from named image to destination func CopyFromImage(appName string, image string, source string, destination string) error { if !VerifyImage(image) { diff --git a/plugins/common/functions b/plugins/common/functions index 73beec9c1..f98068aac 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -488,7 +488,6 @@ parse_args() { copy_from_image() { declare desc="copy file from named image to destination" declare IMAGE="$1" SRC_FILE="$2" DST_FILE="$3" - local WORK_DIR="" if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" copy-from-image "$APP" "$IMAGE" "$SRC_FILE" "$DST_FILE"; then return 1 @@ -498,56 +497,8 @@ copy_from_image() { copy_dir_from_image() { declare desc="copy a directory from named image to destination" declare IMAGE="$1" SRC_DIR="$2" DST_DIR="$3" - local WORK_DIR="" - local DOCKER_CREATE_LABEL_ARGS="--label=com.dokku.app-name=$APP" - - if verify_image "$IMAGE"; then - if ! is_abs_path "$SRC_DIR"; then - if is_image_cnb_based "$IMAGE"; then - WORKDIR="/workspace" - elif is_image_herokuish_based "$IMAGE" "$APP"; then - WORKDIR="/app" - else - WORKDIR="$("$DOCKER_BIN" image inspect --format '{{.Config.WorkingDir}}' "$IMAGE")" - fi - - if [[ -n "$WORKDIR" ]]; then - SRC_DIR="${WORKDIR}/${SRC_DIR}" - fi - fi - - TMP_DIR_COMMAND_OUTPUT=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") - trap "rm -rf '$TMP_DIR_COMMAND_OUTPUT' &>/dev/null || true" RETURN - - local CID=$("$DOCKER_BIN" container create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE") - "$DOCKER_BIN" container cp "$CID:$SRC_DIR" "$TMP_DIR_COMMAND_OUTPUT" 2>/dev/null || true - "$DOCKER_BIN" container rm --force "$CID" &>/dev/null - plugn trigger scheduler-register-retired "$APP" "$CID" - - # docker cp exits with status 1 when run as non-root user when it tries to chown the file - # after successfully copying the file. Thus, we suppress stderr. - # ref: https://github.com/dotcloud/docker/issues/3986 - if [[ ! -d "$TMP_DIR_COMMAND_OUTPUT" ]]; then - return 1 - fi - - pushd "$TMP_DIR_COMMAND_OUTPUT" >/dev/null - for filename in *; do - if [[ ! -f "$TMP_DIR_COMMAND_OUTPUT/$filename" ]]; then - continue - fi - - # workaround for CHECKS file when owner is root. seems to only happen when running inside docker - dos2unix -l <"$TMP_DIR_COMMAND_OUTPUT/$filename" >"$DST_DIR/$filename" - - # add trailing newline for certain places where file parsing depends on it - if [[ "$(tail -c1 "$DST_DIR/$filename")" != "" ]]; then - echo "" >>"$DST_DIR/$filename" - fi - done - popd &>/dev/null || pushd "/tmp" >/dev/null - else + if ! "$PLUGIN_CORE_AVAILABLE_PATH/common/common" copy-dir-from-image "$APP" "$IMAGE" "$SRC_DIR" "$DST_DIR"; then return 1 fi } diff --git a/plugins/common/go.mod b/plugins/common/go.mod index fc2372707..f0177deb3 100644 --- a/plugins/common/go.mod +++ b/plugins/common/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/common -go 1.23.0 +go 1.24.0 toolchain go1.24.1 diff --git a/plugins/common/io.go b/plugins/common/io.go index a6d614116..08426c15f 100644 --- a/plugins/common/io.go +++ b/plugins/common/io.go @@ -195,23 +195,33 @@ func SetPermissions(input SetPermissionInput) error { return os.Chown(input.Filename, uid, gid) } +// TouchDir creates an empty directory at the specified path +func TouchDir(filename string) error { + mode := os.FileMode(0700) + return os.MkdirAll(filename, mode) +} + // TouchFile creates an empty file at the specified path func TouchFile(filename string) error { mode := os.FileMode(0600) file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) if err != nil { - return err + return fmt.Errorf("Error opening file %v for creation: %v", filename, err) } defer file.Close() if err := file.Chmod(mode); err != nil { - return err + return fmt.Errorf("Error setting chown for new file %v: %v", filename, err) } - return SetPermissions(SetPermissionInput{ + if err := SetPermissions(SetPermissionInput{ Filename: filename, Mode: mode, - }) + }); err != nil { + return fmt.Errorf("Error setting permissions for new file %v: %v", filename, err) + } + + return nil } // WriteSliceToFileInput writes a slice of strings to a file diff --git a/plugins/common/src/common/common.go b/plugins/common/src/common/common.go index 7d59e39d4..5c95746aa 100644 --- a/plugins/common/src/common/common.go +++ b/plugins/common/src/common/common.go @@ -34,6 +34,12 @@ func main() { ProjectName: projectName, ComposeFile: composeFile, }) + case "copy-dir-from-image": + appName := flag.Arg(1) + image := flag.Arg(2) + source := flag.Arg(3) + destination := flag.Arg(4) + err = common.CopyDirFromImage(appName, image, source, destination) case "copy-from-image": appName := flag.Arg(1) image := flag.Arg(2) diff --git a/plugins/config/Makefile b/plugins/config/Makefile index 86ffcb36b..0cf396bd8 100644 --- a/plugins/config/Makefile +++ b/plugins/config/Makefile @@ -1,6 +1,6 @@ GOARCH ?= amd64 SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset -TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/post-app-clone-setup triggers/post-app-rename-setup +TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/config-unset triggers/post-app-clone-setup triggers/post-app-rename-setup BUILD = commands config_sub subcommands triggers PLUGIN_NAME = config diff --git a/plugins/config/go.mod b/plugins/config/go.mod index f810332fc..c4566f2e5 100644 --- a/plugins/config/go.mod +++ b/plugins/config/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/config -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/config/src/triggers/triggers.go b/plugins/config/src/triggers/triggers.go index 1f8f58732..96e95d455 100644 --- a/plugins/config/src/triggers/triggers.go +++ b/plugins/config/src/triggers/triggers.go @@ -24,7 +24,7 @@ func main() { global := flag.Arg(1) merged := flag.Arg(2) format := flag.Arg(3) - config.TriggerConfigExport(appName, global, merged, format) + err = config.TriggerConfigExport(appName, global, merged, format) case "config-get": appName := flag.Arg(0) key := flag.Arg(1) @@ -36,6 +36,16 @@ func main() { case "config-get-global": key := flag.Arg(0) err = config.TriggerConfigGetGlobal(key) + case "config-unset": + appName := flag.Arg(0) + key := flag.Arg(1) + restart := flag.Arg(2) + if *global { + appName = "--global" + key = flag.Arg(0) + restart = flag.Arg(1) + } + err = config.TriggerConfigUnset(appName, key, common.ToBool(restart)) case "post-app-clone-setup": oldAppName := flag.Arg(0) newAppName := flag.Arg(1) diff --git a/plugins/config/triggers.go b/plugins/config/triggers.go index af96d114c..b0c3a57f3 100644 --- a/plugins/config/triggers.go +++ b/plugins/config/triggers.go @@ -45,6 +45,12 @@ func TriggerConfigGetGlobal(key string) error { return nil } +// TriggerConfigUnset unsets an app config value by key +func TriggerConfigUnset(appName string, key string, restart bool) error { + UnsetMany(appName, []string{key}, restart) + return nil +} + // TriggerPostAppCloneSetup creates new buildpacks files func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { oldEnv, err := LoadAppEnv(oldAppName) diff --git a/plugins/cron/.gitignore b/plugins/cron/.gitignore index 949e5b1cd..ee795a9c9 100644 --- a/plugins/cron/.gitignore +++ b/plugins/cron/.gitignore @@ -2,7 +2,9 @@ /subcommands/* /triggers/* /triggers +/app-json-is-valid /cron-* /install /post-* /report +/scheduler-stop diff --git a/plugins/cron/Makefile b/plugins/cron/Makefile index e0e1dbe33..98eeb5fd2 100644 --- a/plugins/cron/Makefile +++ b/plugins/cron/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/list subcommands/report subcommands/run subcommands/set -TRIGGERS = triggers/cron-get-property +TRIGGERS = triggers/app-json-is-valid triggers/cron-get-property triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/scheduler-stop BUILD = commands subcommands triggers PLUGIN_NAME = cron diff --git a/plugins/cron/cron.go b/plugins/cron/cron.go index 056eadb4c..8013debe1 100644 --- a/plugins/cron/cron.go +++ b/plugins/cron/cron.go @@ -4,6 +4,7 @@ import ( "fmt" appjson "github.com/dokku/dokku/plugins/app-json" + "github.com/dokku/dokku/plugins/common" "github.com/multiformats/go-base36" cronparser "github.com/robfig/cron/v3" @@ -12,14 +13,16 @@ import ( var ( // DefaultProperties is a map of all valid cron properties with corresponding default property values DefaultProperties = map[string]string{ - "mailfrom": "", - "mailto": "", + "mailfrom": "", + "mailto": "", + "maintenance": "false", } // GlobalProperties is a map of all valid global cron properties GlobalProperties = map[string]bool{ - "mailfrom": true, - "mailto": true, + "mailfrom": true, + "mailto": true, + "maintenance": true, } ) @@ -42,6 +45,9 @@ type TemplateCommand struct { // LogFile is the log file to write to LogFile string `json:"-"` + + // Maintenance is whether the cron command is in maintenance mode + Maintenance bool `json:"maintenance"` } // CronCommand returns the command to run for a given cron command @@ -56,30 +62,63 @@ func (t TemplateCommand) CronCommand() string { return fmt.Sprintf("dokku run --cron-id %s %s %s", t.ID, t.App, t.Command) } +// FetchCronEntriesInput is the input for the FetchCronEntries function +type FetchCronEntriesInput struct { + AppName string + AppJSON *appjson.AppJSON + WarnToFailure bool +} + // FetchCronEntries returns a list of cron commands for a given app -func FetchCronEntries(appName string) ([]TemplateCommand, error) { +func FetchCronEntries(input FetchCronEntriesInput) ([]TemplateCommand, error) { + appName := input.AppName commands := []TemplateCommand{} - appJSON, err := appjson.GetAppJSON(appName) - if err != nil { - return commands, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error()) + isMaintenance := reportComputedMaintenance(appName) == "true" + + if input.AppJSON == nil { + appJSON, err := appjson.GetAppJSON(appName) + if err != nil { + return commands, fmt.Errorf("Unable to fetch app.json for app %s: %s", appName, err.Error()) + } + + input.AppJSON = &appJSON } - if appJSON.Cron == nil { + if input.AppJSON.Cron == nil { return commands, nil } - for _, c := range appJSON.Cron { + for i, c := range input.AppJSON.Cron { + if c.Command == "" { + if input.WarnToFailure { + return commands, fmt.Errorf("Missing cron command for app %s (index %d)", appName, i) + } + + common.LogWarn(fmt.Sprintf("Missing cron command for app %s (index %d)", appName, i)) + continue + } + + if c.Schedule == "" { + if input.WarnToFailure { + return commands, fmt.Errorf("Missing cron schedule for app %s (index %d)", appName, i) + } + + common.LogWarn(fmt.Sprintf("Missing cron schedule for app %s (index %d)", appName, i)) + continue + } + parser := cronparser.NewParser(cronparser.Minute | cronparser.Hour | cronparser.Dom | cronparser.Month | cronparser.Dow | cronparser.Descriptor) _, err := parser.Parse(c.Schedule) if err != nil { - return commands, fmt.Errorf("Invalid cron schedule %s: %s", c.Schedule, err.Error()) + return commands, fmt.Errorf("Invalid cron schedule for app %s (schedule %s): %s", appName, c.Schedule, err.Error()) } commands = append(commands, TemplateCommand{ - App: appName, - Command: c.Command, - Schedule: c.Schedule, - ID: GenerateCommandID(appName, c), + App: appName, + Command: c.Command, + Schedule: c.Schedule, + ID: GenerateCommandID(appName, c), + Maintenance: isMaintenance, }) } diff --git a/plugins/cron/go.mod b/plugins/cron/go.mod index 09ec4c2e4..d4170a313 100644 --- a/plugins/cron/go.mod +++ b/plugins/cron/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/cron -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/app-json v0.0.0-00010101000000-000000000000 diff --git a/plugins/cron/report.go b/plugins/cron/report.go index c5fe8dc5d..3514b8f53 100644 --- a/plugins/cron/report.go +++ b/plugins/cron/report.go @@ -13,9 +13,12 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--cron-mailfrom": reportMailfrom, - "--cron-mailto": reportMailto, - "--cron-task-count": reportTasks, + "--cron-mailfrom": reportMailfrom, + "--cron-mailto": reportMailto, + "--cron-task-count": reportTasks, + "--cron-global-maintenance": reportGlobalMaintenance, + "--cron-computed-maintenance": reportComputedMaintenance, + "--cron-maintenance": reportMaintenance, } flagKeys := []string{} @@ -38,6 +41,23 @@ func reportMailto(_ string) string { } func reportTasks(appName string) string { - c, _ := FetchCronEntries(appName) + c, _ := FetchCronEntries(FetchCronEntriesInput{AppName: appName}) return strconv.Itoa(len(c)) } + +func reportGlobalMaintenance(_ string) string { + return common.PropertyGet("cron", "--global", "maintenance") +} + +func reportComputedMaintenance(appName string) string { + maintenance := common.PropertyGet("cron", appName, "maintenance") + if maintenance == "true" { + return "true" + } + + return common.PropertyGetDefault("cron", "--global", "maintenance", DefaultProperties["maintenance"]) +} + +func reportMaintenance(appName string) string { + return common.PropertyGet("cron", appName, "maintenance") +} diff --git a/plugins/cron/src/triggers/triggers.go b/plugins/cron/src/triggers/triggers.go index 083cbb25b..1a65cec73 100644 --- a/plugins/cron/src/triggers/triggers.go +++ b/plugins/cron/src/triggers/triggers.go @@ -19,6 +19,10 @@ func main() { var err error switch trigger { + case "app-json-is-valid": + appName := flag.Arg(0) + appJSONPath := flag.Arg(1) + err = cron.TriggerAppJSONIsValid(appName, appJSONPath) case "cron-get-property": appName := flag.Arg(0) property := flag.Arg(1) @@ -43,6 +47,11 @@ func main() { case "report": appName := flag.Arg(0) err = cron.ReportSingleApp(appName, "", "") + case "scheduler-stop": + scheduler := flag.Arg(0) + appName := flag.Arg(1) + removeContainers := flag.Arg(2) + err = cron.TriggerSchedulerStop(scheduler, appName, removeContainers) default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } diff --git a/plugins/cron/subcommands.go b/plugins/cron/subcommands.go index 593f6212a..2d5717b4b 100644 --- a/plugins/cron/subcommands.go +++ b/plugins/cron/subcommands.go @@ -26,15 +26,15 @@ func CommandList(appName string, format string) error { return fmt.Errorf("Invalid format specified, supported formats: json, stdout") } - entries, err := FetchCronEntries(appName) + entries, err := FetchCronEntries(FetchCronEntriesInput{AppName: appName}) if err != nil { return err } if format == "stdout" { - output := []string{"ID | Schedule | Command"} + output := []string{"ID | Schedule | Maintenance | Command"} for _, entry := range entries { - output = append(output, fmt.Sprintf("%s | %s | %s", entry.ID, entry.Schedule, entry.Command)) + output = append(output, fmt.Sprintf("%s | %s | %t | %s", entry.ID, entry.Schedule, entry.Maintenance, entry.Command)) } result := columnize.SimpleFormat(output) @@ -79,7 +79,7 @@ func CommandRun(appName string, cronID string, detached bool) error { return err } - entries, err := FetchCronEntries(appName) + entries, err := FetchCronEntries(FetchCronEntriesInput{AppName: appName}) if err != nil { return err } @@ -130,8 +130,10 @@ func CommandSet(appName string, property string, value string) error { } common.CommandPropertySet("cron", appName, property, value, DefaultProperties, GlobalProperties) + scheduler := common.GetAppScheduler(appName) _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ - Trigger: "cron-write", + Trigger: "scheduler-cron-write", + Args: []string{scheduler, appName}, StreamStdio: true, }) return err diff --git a/plugins/cron/triggers.go b/plugins/cron/triggers.go index 42f99044a..499405913 100644 --- a/plugins/cron/triggers.go +++ b/plugins/cron/triggers.go @@ -4,20 +4,46 @@ import ( "errors" "fmt" + appjson "github.com/dokku/dokku/plugins/app-json" "github.com/dokku/dokku/plugins/common" ) // TriggerCronGetProperty writes the cron key to stdout for a given app container func TriggerCronGetProperty(appName string, key string) error { validProperties := map[string]bool{ - "mailfrom": true, - "mailto": true, + "mailfrom": true, + "mailto": true, + "maintenance": true, } if !validProperties[key] { return errors.New("Invalid cron property specified") } - fmt.Println(common.PropertyGet("cron", appName, key)) + value := common.PropertyGetDefault("cron", appName, key, DefaultProperties[key]) + fmt.Println(value) + return nil +} + +// TriggerAppJSONIsValid validates the cron entries for a given app +func TriggerAppJSONIsValid(appName string, appJSONPath string) error { + if !common.FileExists(appJSONPath) { + return nil + } + + appJSON, err := appjson.ReadAppJSON(appJSONPath) + if err != nil { + return err + } + + _, err = FetchCronEntries(FetchCronEntriesInput{ + AppName: appName, + AppJSON: &appJSON, + WarnToFailure: true, + }) + if err != nil { + return err + } + return nil } @@ -55,5 +81,28 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { // TriggerPostDelete destroys the cron property for a given app container func TriggerPostDelete(appName string) error { - return common.PropertyDestroy("cron", appName) + scheduler := common.GetAppScheduler(appName) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-cron-write", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + if err != nil { + return err + } + + if err := common.PropertyDestroy("cron", appName); err != nil { + return err + } + + return nil +} + +// TriggerSchedulerStop stops the scheduler for a given app container +func TriggerSchedulerStop(scheduler string, appName string, removeContainers string) error { + if scheduler != "docker-local" { + return nil + } + + return nil } diff --git a/plugins/docker-options/go.mod b/plugins/docker-options/go.mod index 74045ac5e..5ec40541e 100644 --- a/plugins/docker-options/go.mod +++ b/plugins/docker-options/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/docker-options -go 1.23.0 +go 1.24.0 require github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/domains/functions b/plugins/domains/functions index 0798f48f3..cf705a243 100755 --- a/plugins/domains/functions +++ b/plugins/domains/functions @@ -24,7 +24,6 @@ fn-domains-clear-app() { local APP_VHOST_PATH="$DOKKU_ROOT/$APP/VHOST" rm -f "$APP_VHOST_PATH" - domains_setup "$APP" plugn trigger post-domains-update "$APP" "clear" dokku_log_info1 "Cleared domains in $APP" } diff --git a/plugins/domains/help-functions b/plugins/domains/help-functions index 0f66a8734..028c11204 100755 --- a/plugins/domains/help-functions +++ b/plugins/domains/help-functions @@ -36,6 +36,7 @@ fn-help-content() { domains:remove [ ...], Remove domains from app domains:remove-global [ ...], Remove global domain names domains:report [|--global] [], Displays a domains report for one or more apps + domains:reset , Reset app domains to global-configured domains domains:set [ ...], Set domains for app domains:set-global [ ...], Set global domain names help_content diff --git a/plugins/domains/subcommands/clear-global b/plugins/domains/subcommands/clear-global index ff7ae757b..400450255 100755 --- a/plugins/domains/subcommands/clear-global +++ b/plugins/domains/subcommands/clear-global @@ -5,7 +5,7 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/domains/functions" cmd-domains-clear-global() { - declare desc="clear global domain names via command line" + declare desc="clear global domain names" declare cmd="domains:clear-global" [[ "$1" == "$cmd" ]] && shift 1 diff --git a/plugins/domains/subcommands/reset b/plugins/domains/subcommands/reset new file mode 100755 index 000000000..a01f95957 --- /dev/null +++ b/plugins/domains/subcommands/reset @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/domains/functions" + +cmd-domains-reset() { + declare desc="reset app domains to global-configured domains" + declare cmd="domains:reset" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" + + verify_app_name "$APP" + fn-domains-clear "$APP" + domains_setup "$APP" + plugn trigger post-domains-update "$APP" "reset" + dokku_log_info1_quiet "Reset domains for $APP" +} + +cmd-domains-reset "$@" diff --git a/plugins/domains/subcommands/setup b/plugins/domains/subcommands/setup index 6458bf6c4..4d0bb19b3 100755 --- a/plugins/domains/subcommands/setup +++ b/plugins/domains/subcommands/setup @@ -12,6 +12,8 @@ cmd-domains-setup() { verify_app_name "$APP" domains_setup "$APP" + plugn trigger post-domains-update "$APP" "reset" + dokku_log_info1_quiet "Setup domains for $APP" } cmd-domains-setup "$@" diff --git a/plugins/git/functions b/plugins/git/functions index 6e80a3f27..9de24288d 100755 --- a/plugins/git/functions +++ b/plugins/git/functions @@ -25,16 +25,7 @@ git_build_app_repo() { fn-git-setup-build-dir "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV" pushd "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" >/dev/null - local DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL DOKKU_DISABLE_ANSI_PREFIX_REMOVAL - DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get "$APP" DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true) - DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL=$(config_get --global DOKKU_DISABLE_ANSI_PREFIX_REMOVAL || true) - DOKKU_DISABLE_ANSI_PREFIX_REMOVAL=${DOKKU_APP_DISABLE_ANSI_PREFIX_REMOVAL:="$DOKKU_GLOBAL_DISABLE_ANSI_PREFIX_REMOVAL"} - - if [[ "$DOKKU_DISABLE_ANSI_PREFIX_REMOVAL" == "true" ]]; then - git_trigger_build "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV" - else - git_trigger_build "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV" | sed -u "s/^/"$'\e[1G'"/" - fi + git_trigger_build "$APP" "$GIT_BUILD_APP_REPO_TMP_WORK_DIR" "$REV" return $? } diff --git a/plugins/git/git-from-archive b/plugins/git/git-from-archive index fe1f71e0b..f44bf291b 100755 --- a/plugins/git/git-from-archive +++ b/plugins/git/git-from-archive @@ -42,12 +42,12 @@ trigger-git-git-from-archive() { dokku_log_verbose "Stripping top-level archive folder components" local subpath="$(find "$TMP_WORK_DIR_3" -mindepth 1 -maxdepth 1 -type d)" pushd "$subpath" >/dev/null - find . -maxdepth 1 -exec mv {} "$TMP_WORK_DIR" \; + find . -mindepth 1 -maxdepth 1 -exec mv {} "$TMP_WORK_DIR" \; popd &>/dev/null || pushd "/tmp" >/dev/null else dokku_log_verbose "Moving unarchived files and folders into place" pushd "$TMP_WORK_DIR_3" >/dev/null - find . -maxdepth 1 -exec mv {} "$TMP_WORK_DIR" \; + find . -mindepth 1 -maxdepth 1 -exec mv {} "$TMP_WORK_DIR" \; popd &>/dev/null || pushd "/tmp" >/dev/null fi diff --git a/plugins/logs/go.mod b/plugins/logs/go.mod index c3379087c..5304a8fca 100644 --- a/plugins/logs/go.mod +++ b/plugins/logs/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/logs -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/network/go.mod b/plugins/network/go.mod index 89f9dd2f1..9a9df9d64 100644 --- a/plugins/network/go.mod +++ b/plugins/network/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/network -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/nginx-vhosts/go.mod b/plugins/nginx-vhosts/go.mod index 3897cb106..6fffca170 100644 --- a/plugins/nginx-vhosts/go.mod +++ b/plugins/nginx-vhosts/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/nginx-vhosts -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/nginx-vhosts/internal-functions b/plugins/nginx-vhosts/internal-functions index 90a77fb42..1950e199e 100755 --- a/plugins/nginx-vhosts/internal-functions +++ b/plugins/nginx-vhosts/internal-functions @@ -327,6 +327,21 @@ fn-nginx-global-nginx-conf-sigil-path() { fn-get-property --global "nginx-conf-sigil-path" } +fn-nginx-nginx-service-command() { + declare APP="$1" + fn-get-property --app "$APP" "nginx-service-command" +} + +fn-nginx-computed-nginx-service-command() { + declare APP="$1" + fn-get-property --computed --app "$APP" "nginx-service-command" +} + +fn-nginx-global-nginx-service-command() { + declare APP="$1" + fn-get-property --global "nginx-service-command" +} + fn-nginx-proxy-buffer-size() { declare desc="get the configured proxy buffer size" declare APP="$1" @@ -729,9 +744,14 @@ fn-nginx-vhosts-nginx-is-running() { fn-nginx-vhosts-nginx-init-cmd() { declare desc="start nginx for given distros" declare CMD="$1" - local NGINX_INIT_NAME - NGINX_INIT_NAME=nginx + local NGINX_SERVICE_COMMAND="$(fn-nginx-computed-nginx-service-command "$APP")" + if [[ -n "$NGINX_SERVICE_COMMAND" ]]; then + "$NGINX_SERVICE_COMMAND" $CMD + return + fi + + local NGINX_INIT_NAME=nginx if fn-nginx-vhosts-uses-openresty; then NGINX_INIT_NAME=openresty fi diff --git a/plugins/nginx-vhosts/nginx_vhosts.go b/plugins/nginx-vhosts/nginx_vhosts.go index 4d7d17ac6..8c25ac1a7 100644 --- a/plugins/nginx-vhosts/nginx_vhosts.go +++ b/plugins/nginx-vhosts/nginx_vhosts.go @@ -234,6 +234,36 @@ func AppNginxConfSigilPath(appName string) string { return common.PropertyGet("nginx", appName, "nginx-conf-sigil-path") } +func ComputedNginxConfSigilPath(appName string) string { + appValue := AppNginxConfSigilPath(appName) + if appValue != "" { + return appValue + } + + return GlobalNginxConfSigilPath() +} + +func GlobalNginxConfSigilPath() string { + return common.PropertyGetDefault("nginx", "--global", "nginx-conf-sigil-path", "nginx.conf.sigil") +} + +func AppNginxServiceCommand(appName string) string { + return common.PropertyGet("nginx", appName, "nginx-service-command") +} + +func ComputedNginxServiceCommand(appName string) string { + appValue := AppNginxServiceCommand(appName) + if appValue != "" { + return appValue + } + + return GlobalNginxServiceCommand() +} + +func GlobalNginxServiceCommand() string { + return common.PropertyGetDefault("nginx", "--global", "nginx-service-command", "") +} + func AppKeepaliveTimeout(appName string) string { return common.PropertyGet("nginx", appName, "keepalive-timeout") } @@ -268,19 +298,6 @@ func GlobalLingeringTimeout() string { return common.PropertyGetDefault("nginx", "--global", "lingering-timeout", "5s") } -func ComputedNginxConfSigilPath(appName string) string { - appValue := AppNginxConfSigilPath(appName) - if appValue != "" { - return appValue - } - - return GlobalNginxConfSigilPath() -} - -func GlobalNginxConfSigilPath() string { - return common.PropertyGetDefault("nginx", "--global", "nginx-conf-sigil-path", "nginx.conf.sigil") -} - func AppProxyBufferSize(appName string) string { return common.PropertyGet("nginx", appName, "proxy-buffer-size") } diff --git a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go index 6270d97c2..47c3bbd49 100644 --- a/plugins/nginx-vhosts/src/nginx-property/nginx-property.go +++ b/plugins/nginx-vhosts/src/nginx-property/nginx-property.go @@ -67,6 +67,8 @@ func appValue(appName string, property string) string { value = nginx_vhosts.AppLingeringTimeout(appName) case "nginx-conf-sigil-path": value = nginx_vhosts.AppNginxConfSigilPath(appName) + case "nginx-service-command": + value = nginx_vhosts.AppNginxServiceCommand(appName) case "proxy-buffer-size": value = nginx_vhosts.AppProxyBufferSize(appName) case "proxy-buffering": @@ -133,6 +135,8 @@ func computedValue(appName string, property string) string { value = nginx_vhosts.ComputedLingeringTimeout(appName) case "nginx-conf-sigil-path": value = nginx_vhosts.ComputedNginxConfSigilPath(appName) + case "nginx-service-command": + value = nginx_vhosts.ComputedNginxServiceCommand(appName) case "proxy-buffer-size": value = nginx_vhosts.ComputedProxyBufferSize(appName) case "proxy-buffering": @@ -199,6 +203,8 @@ func globalValue(appName string, property string) string { value = nginx_vhosts.ComputedLingeringTimeout(appName) case "nginx-conf-sigil-path": value = nginx_vhosts.GlobalNginxConfSigilPath() + case "nginx-service-command": + value = nginx_vhosts.GlobalNginxServiceCommand() case "proxy-buffer-size": value = nginx_vhosts.GlobalProxyBufferSize() case "proxy-buffering": diff --git a/plugins/nginx-vhosts/subcommands/set b/plugins/nginx-vhosts/subcommands/set index 49e2e541b..12cfaaab5 100755 --- a/plugins/nginx-vhosts/subcommands/set +++ b/plugins/nginx-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-nginx-set() { declare cmd="nginx:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-body-timeout" "client-header-timeout" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "keepalive-timeout" "lingering-timeout" "nginx-conf-sigil-path" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "proxy-connect-timeout" "proxy-read-timeout" "proxy-send-timeout" "send-timeout" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") - local GLOBAL_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-body-timeout" "client-header-timeout" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts-include-subdomains" "hsts-max-age" "hsts-preload" "hsts" "keepalive-timeout" "lingering-timeout" "nginx-conf-sigil-path" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "proxy-connect-timeout" "proxy-read-timeout" "proxy-send-timeout" "send-timeout" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") + local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-body-timeout" "client-header-timeout" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "keepalive-timeout" "lingering-timeout" "nginx-conf-sigil-path" "nginx-service-command" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "proxy-connect-timeout" "proxy-read-timeout" "proxy-send-timeout" "send-timeout" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") + local GLOBAL_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "client-body-timeout" "client-header-timeout" "client-max-body-size" "disable-custom-config" "error-log-path" "hsts-include-subdomains" "hsts-max-age" "hsts-preload" "hsts" "keepalive-timeout" "lingering-timeout" "nginx-conf-sigil-path" "nginx-service-command" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "proxy-connect-timeout" "proxy-read-timeout" "proxy-send-timeout" "send-timeout" "underscore-in-headers" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value" "x-forwarded-ssl") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, keepalive-timeout, lingering-timeout, nginx-conf-sigil-path, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" + dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, client-body-timeout, client-header-timeout, client-max-body-size, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, keepalive-timeout, lingering-timeout, nginx-conf-sigil-path, nginx-service-command, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout, send-timeout, underscore-in-headers, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value, x-forwarded-ssl" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/plugins/ports/go.mod b/plugins/ports/go.mod index e9de9ed08..1e04b6fae 100644 --- a/plugins/ports/go.mod +++ b/plugins/ports/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/ports -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/ports/triggers.go b/plugins/ports/triggers.go index 4391170f1..bb4e7a83d 100644 --- a/plugins/ports/triggers.go +++ b/plugins/ports/triggers.go @@ -25,8 +25,16 @@ func TriggerInstall() error { continue } - common.LogInfo1(fmt.Sprintf("Migrating DOKKU_PROXY_PORT_MAP to ports map property for %s", appName)) - portMapString := config.GetWithDefault(appName, "DOKKU_PROXY_PORT_MAP", "") + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_PROXY_PORT_MAP"}, + }) + portMapString := results.StdoutContents() + if portMapString == "" { + continue + } + + common.LogVerboseQuiet(fmt.Sprintf("Setting %s ports property 'map' to %v", appName, portMapString)) portMaps, _ := parsePortMapString(portMapString) propertyValue := []string{} @@ -38,7 +46,11 @@ func TriggerInstall() error { return err } - if err := config.UnsetMany(appName, []string{"DOKKU_PROXY_PORT_MAP"}, false); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-unset", + Args: []string{appName, "DOKKU_PROXY_PORT_MAP"}, + }) + if err != nil { return err } } diff --git a/plugins/proxy/go.mod b/plugins/proxy/go.mod index d577e388b..89bf527ee 100644 --- a/plugins/proxy/go.mod +++ b/plugins/proxy/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/proxy -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/ps/Makefile b/plugins/ps/Makefile index 8e8457fc4..3f8016f33 100644 --- a/plugins/ps/Makefile +++ b/plugins/ps/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/inspect subcommands/rebuild subcommands/report subcommands/restart subcommands/restore subcommands/retire subcommands/scale subcommands/set subcommands/start subcommands/stop -TRIGGERS = triggers/app-restart triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone triggers/post-app-clone-setup triggers/post-app-rename triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/post-release-builder triggers/post-stop triggers/procfile-get-command triggers/procfile-exists triggers/ps-can-scale triggers/ps-current-scale triggers/ps-set-scale triggers/report +TRIGGERS = triggers/app-restart triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone triggers/post-app-clone-setup triggers/post-app-rename triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/post-release-builder triggers/post-stop triggers/procfile-get-command triggers/procfile-exists triggers/ps-can-scale triggers/ps-current-scale triggers/ps-get-property triggers/ps-set-scale triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = ps diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index 3bb7f1235..b6af4f6dc 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -247,33 +247,77 @@ func scaleReport(appName string) error { return nil } -func scaleSet(appName string, skipDeploy bool, clearExisting bool, processTuples []string) error { - formations, err := parseProcessTuples(processTuples) +// scaleSetInput is the input for the scaleSet function +type scaleSetInput struct { + // appName is the name of the app to scale + appName string + + // skipDeploy is a flag to skip the deploy phase + skipDeploy bool + + // clearExisting is a flag to clear the existing scale + clearExisting bool + + // processTuples is a list of process tuples to scale + processTuples []string + + // deployOnlyChanged is a flag to deploy only the changed formations + deployOnlyChanged bool +} + +func scaleSet(input scaleSetInput) error { + existingFormations, err := getFormations(input.appName) if err != nil { return err } - if err := updateScale(appName, clearExisting, formations); err != nil { - return err - } - - if skipDeploy { - return nil - } - - if !common.IsDeployed(appName) { - return nil - } - - imageTag, err := common.GetRunningImageTag(appName, "") + formations, err := parseProcessTuples(input.processTuples) if err != nil { return err } - for _, formation := range formations { + if err := updateScale(input.appName, input.clearExisting, formations); err != nil { + return err + } + + if input.skipDeploy { + return nil + } + + if !common.IsDeployed(input.appName) { + return nil + } + + imageTag, err := common.GetRunningImageTag(input.appName, "") + if err != nil { + return err + } + + changedFormations := FormationSlice{} + if input.deployOnlyChanged { + for _, formation := range formations { + isChanged := true + for _, existingFormation := range existingFormations { + if existingFormation.ProcessType == formation.ProcessType { + if existingFormation.Quantity == formation.Quantity { + isChanged = false + break + } + } + } + + if isChanged { + changedFormations = append(changedFormations, formation) + } + } + } else { + changedFormations = formations + } + + for _, formation := range changedFormations { _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ Trigger: "deploy", - Args: []string{appName, imageTag, formation.ProcessType}, + Args: []string{input.appName, imageTag, formation.ProcessType}, StreamStdio: true, }) if err != nil { diff --git a/plugins/ps/go.mod b/plugins/ps/go.mod index 70d245401..7cb1b6598 100644 --- a/plugins/ps/go.mod +++ b/plugins/ps/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/ps -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/ps/ps.go b/plugins/ps/ps.go index 7e1e2f4d9..307306f24 100644 --- a/plugins/ps/ps.go +++ b/plugins/ps/ps.go @@ -13,13 +13,15 @@ const RunInSerial = 0 var ( // DefaultProperties is a map of all valid ps properties with corresponding default property values DefaultProperties = map[string]string{ - "restart-policy": "on-failure:10", - "procfile-path": "", + "restart-policy": "on-failure:10", + "procfile-path": "", + "stop-timeout-seconds": "30", } // GlobalProperties is a map of all valid global ps properties GlobalProperties = map[string]bool{ - "procfile-path": true, + "procfile-path": true, + "stop-timeout-seconds": true, } ) diff --git a/plugins/ps/report.go b/plugins/ps/report.go index 5e0ddfe40..74c4c17a9 100644 --- a/plugins/ps/report.go +++ b/plugins/ps/report.go @@ -15,15 +15,18 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { } flags := map[string]common.ReportFunc{ - "--deployed": reportDeployed, - "--processes": reportProcesses, - "--ps-can-scale": reportCanScale, - "--ps-restart-policy": reportRestartPolicy, - "--ps-computed-procfile-path": reportComputedProcfilePath, - "--ps-global-procfile-path": reportGlobalProcfilePath, - "--ps-procfile-path": reportProcfilePath, - "--restore": reportRestore, - "--running": reportRunningState, + "--deployed": reportDeployed, + "--processes": reportProcesses, + "--ps-can-scale": reportCanScale, + "--ps-restart-policy": reportRestartPolicy, + "--ps-computed-procfile-path": reportComputedProcfilePath, + "--ps-global-procfile-path": reportGlobalProcfilePath, + "--ps-procfile-path": reportProcfilePath, + "--restore": reportRestore, + "--running": reportRunningState, + "--global-stop-timeout-seconds": reportGlobalStopTimeoutSeconds, + "--computed-stop-timeout-seconds": reportComputedStopTimeoutSeconds, + "--stop-timeout-seconds": reportStopTimeoutSeconds, } extraFlags := addStatusFlags(appName, infoFlag) @@ -146,3 +149,20 @@ func reportRestore(appName string) string { func reportRunningState(appName string) string { return getRunningState(appName) } + +func reportComputedStopTimeoutSeconds(appName string) string { + value := reportStopTimeoutSeconds(appName) + if value == "" { + value = reportGlobalStopTimeoutSeconds(appName) + } + + return value +} + +func reportGlobalStopTimeoutSeconds(appName string) string { + return common.PropertyGetDefault("ps", "--global", "stop-timeout-seconds", "30") +} + +func reportStopTimeoutSeconds(appName string) string { + return common.PropertyGetDefault("ps", appName, "stop-timeout-seconds", "30") +} diff --git a/plugins/ps/src/triggers/triggers.go b/plugins/ps/src/triggers/triggers.go index 4d2821dad..3ec4beaec 100644 --- a/plugins/ps/src/triggers/triggers.go +++ b/plugins/ps/src/triggers/triggers.go @@ -75,8 +75,11 @@ func main() { case "ps-current-scale": appName := flag.Arg(0) err = ps.TriggerPsCurrentScale(appName) - case "ps-set-scale": + case "ps-get-property": appName := flag.Arg(0) + property := flag.Arg(1) + err = ps.TriggerPsGetProperty(appName, property) + case "ps-set-scale": appName, args := common.ShiftString(flag.Args()) skipDeploy, args := common.ShiftString(args) clearExisting, processTuples := common.ShiftString(args) diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index 6c5882e5e..783a26161 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -160,7 +160,13 @@ func CommandScale(appName string, skipDeploy bool, processTuples []string) error } common.LogInfo1(fmt.Sprintf("Scaling %s processes: %s", appName, strings.Join(processTuples, " "))) - return scaleSet(appName, skipDeploy, false, processTuples) + return scaleSet(scaleSetInput{ + appName: appName, + skipDeploy: skipDeploy, + clearExisting: false, + processTuples: processTuples, + deployOnlyChanged: true, + }) } // CommandSet sets or clears a ps property for an app diff --git a/plugins/ps/triggers.go b/plugins/ps/triggers.go index 674369db5..ad69a9f61 100644 --- a/plugins/ps/triggers.go +++ b/plugins/ps/triggers.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "os" - "path" "path/filepath" "strconv" "strings" @@ -22,22 +21,16 @@ func TriggerAppRestart(appName string) error { // TriggerCorePostDeploy sets a property to // allow the app to be restored on boot func TriggerCorePostDeploy(appName string) error { - existingProcfile := getProcfilePath(appName) - processSpecificProcfile := fmt.Sprintf("%s.%s", existingProcfile, os.Getenv("DOKKU_PID")) - if common.FileExists(processSpecificProcfile) { - if err := os.Rename(processSpecificProcfile, existingProcfile); err != nil { - return err - } - } else if common.FileExists(fmt.Sprintf("%s.missing", processSpecificProcfile)) { - if err := os.Remove(fmt.Sprintf("%s.missing", processSpecificProcfile)); err != nil { - return err - } - - if common.FileExists(existingProcfile) { - if err := os.Remove(existingProcfile); err != nil { - return err - } - } + err := common.CorePostDeploy(common.CorePostDeployInput{ + AppName: appName, + Destination: common.GetAppDataDirectory("ps", appName), + PluginName: "ps", + ExtractedPaths: []common.CorePostDeployPath{ + {Path: "Procfile", IsDirectory: false}, + }, + }) + if err != nil { + return err } if err := common.PropertyDelete("ps", appName, "scale.old"); err != nil { @@ -55,67 +48,45 @@ func TriggerCorePostDeploy(appName string) error { // TriggerCorePostExtract ensures that the main Procfile is the one specified by procfile-path func TriggerCorePostExtract(appName string, sourceWorkDir string) error { + destination := common.GetAppDataDirectory("ps", appName) procfilePath := strings.Trim(reportComputedProcfilePath(appName), "/") if procfilePath == "" { procfilePath = "Procfile" } - existingProcfile := getProcfilePath(appName) - files, err := filepath.Glob(fmt.Sprintf("%s.*", existingProcfile)) - if err != nil { - return err - } - for _, f := range files { - if err := os.Remove(f); err != nil { + validator := func(appName string, path string) error { + if !common.FileExists(path) { + return nil + } + + result, err := common.CallExecCommand(common.ExecCommandInput{ + Command: "procfile-util", + Args: []string{"check", "-P", path}, + }) + if err != nil { return err } + if result.ExitCode != 0 { + return fmt.Errorf("Invalid Procfile: %s", result.StderrContents()) + } + return nil } - processSpecificProcfile := fmt.Sprintf("%s.%s", existingProcfile, os.Getenv("DOKKU_PID")) - results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ - Trigger: "git-get-property", - Args: []string{appName, "source-image"}, + return common.CorePostExtract(common.CorePostExtractInput{ + AppName: appName, + Destination: destination, + PluginName: "ps", + SourceWorkDir: sourceWorkDir, + ToExtract: []common.CorePostExtractToExtract{ + { + Path: procfilePath, + IsDirectory: false, + Name: "Procfile", + Destination: "Procfile", + Validator: validator, + }, + }, }) - appSourceImage := results.StdoutContents() - - repoDefaultProcfilePath := path.Join(sourceWorkDir, "Procfile") - if appSourceImage == "" { - repoProcfilePath := path.Join(sourceWorkDir, procfilePath) - if !common.FileExists(repoProcfilePath) { - if procfilePath != "Procfile" && common.FileExists(repoDefaultProcfilePath) { - if err := os.Remove(repoDefaultProcfilePath); err != nil { - return err - } - } - return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificProcfile)) - } - - if err := common.Copy(repoProcfilePath, processSpecificProcfile); err != nil { - return fmt.Errorf("Unable to extract Procfile: %v", err.Error()) - } - - if procfilePath != "Procfile" { - if err := common.Copy(repoProcfilePath, repoDefaultProcfilePath); err != nil { - return fmt.Errorf("Unable to move Procfile into place: %v", err.Error()) - } - } - } else { - if err := common.CopyFromImage(appName, appSourceImage, procfilePath, processSpecificProcfile); err != nil { - return common.TouchFile(fmt.Sprintf("%s.missing", processSpecificProcfile)) - } - } - - result, err := common.CallExecCommand(common.ExecCommandInput{ - Command: "procfile-util", - Args: []string{"check", "-P", processSpecificProcfile}, - }) - if err != nil { - return fmt.Errorf(result.StderrContents()) - } - if result.ExitCode != 0 { - return fmt.Errorf("Invalid Procfile: %s", result.StderrContents()) - } - return nil } // TriggerInstall initializes app restart policies @@ -164,8 +135,29 @@ func TriggerInstall() error { if common.FileExists(dokkuScaleExtracted) { os.Remove(dokkuScaleExtracted) } - } + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_DOCKER_STOP_TIMEOUT"}, + }) + stopTimeout := results.StdoutContents() + if stopTimeout == "" { + continue + } + + common.LogVerboseQuiet(fmt.Sprintf("Setting %s ps property 'stop-timeout-seconds' to %v", appName, stopTimeout)) + if err := common.PropertyWrite("ps", appName, "stop-timeout-seconds", stopTimeout); err != nil { + return err + } + + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-unset", + Args: []string{appName, "DOKKU_DOCKER_STOP_TIMEOUT"}, + }) + if err != nil { + return err + } + } return nil } @@ -318,5 +310,25 @@ func TriggerPsCurrentScale(appName string) error { // TriggerPsSetScale configures the scale parameters for a given app func TriggerPsSetScale(appName string, skipDeploy bool, clearExisting bool, processTuples []string) error { - return scaleSet(appName, skipDeploy, clearExisting, processTuples) + return scaleSet(scaleSetInput{ + appName: appName, + skipDeploy: skipDeploy, + clearExisting: clearExisting, + processTuples: processTuples, + deployOnlyChanged: false, + }) +} + +func TriggerPsGetProperty(appName string, property string) error { + computedValueMap := map[string]common.ReportFunc{ + "stop-timeout-seconds": reportComputedStopTimeoutSeconds, + } + + fn, ok := computedValueMap[property] + if !ok { + return fmt.Errorf("Invalid network property specified: %v", property) + } + + fmt.Println(fn(appName)) + return nil } diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 7c2882c62..eb85e060b 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -2,7 +2,6 @@ package registry import ( "bytes" - "errors" "fmt" "strconv" "strings" @@ -96,14 +95,12 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e fullImage := fmt.Sprintf("%s%s:%d", registryServer, imageRepo, tag) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s:%d in registry format", imageRepo, tag)) - if !dockerTag(imageID, fullImage) { - // TODO: better error - return errors.New("Unable to tag image") + if err := dockerTag(imageID, fullImage); err != nil { + return fmt.Errorf("unable to tag image %s as %s: %w", imageID, fullImage, err) } - if !dockerTag(imageID, fmt.Sprintf("%s:%d", imageRepo, tag)) { - // TODO: better error - return errors.New("Unable to tag image") + if err := dockerTag(imageID, fmt.Sprintf("%s:%d", imageRepo, tag)); err != nil { + return fmt.Errorf("unable to tag image %s as %s:%d: %w", imageID, imageRepo, tag, err) } extraTags := getRegistryPushExtraTagsForApp(appName) @@ -112,26 +109,25 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e for _, extraTag := range extraTagsArray { extraTagImage := fmt.Sprintf("%s%s:%s", registryServer, imageRepo, extraTag) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as %s in registry format", imageRepo, extraTag)) - if !dockerTag(imageID, extraTagImage) { - return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) + if err := dockerTag(imageID, extraTagImage); err != nil { + return fmt.Errorf("unable to tag image %s as %s: %w", imageID, extraTagImage, err) } defer func() { common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) if err := common.RemoveImages([]string{extraTagImage}); err != nil { - common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag, err.Error())) + common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s: %s", extraTag, err.Error())) } }() common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", extraTagImage)) - if !dockerPush(extraTagImage) { - return errors.New(fmt.Sprintf("Unable to push image with %s tag", extraTag)) + if err := dockerPush(extraTagImage); err != nil { + return fmt.Errorf("unable to push image with %s tag: %w", extraTag, err) } } } common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", fullImage)) - if !dockerPush(fullImage) { - // TODO: better error - return errors.New("Unable to push image") + if err := dockerPush(fullImage); err != nil { + return fmt.Errorf("unable to push image %s: %w", fullImage, err) } // Only clean up when the scheduler is not docker-local @@ -148,22 +144,34 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e return nil } -func dockerTag(imageID string, imageTag string) bool { +func dockerTag(imageID string, imageTag string) error { result, err := common.CallExecCommand(common.ExecCommandInput{ Command: common.DockerBin(), Args: []string{"image", "tag", imageID, imageTag}, StreamStdio: true, }) - return err == nil && result.ExitCode == 0 + if err != nil { + return fmt.Errorf("docker tag command failed: %w", err) + } + if result.ExitCode != 0 { + return fmt.Errorf("docker tag command exited with code %d: %s", result.ExitCode, result.Stderr) + } + return nil } -func dockerPush(imageTag string) bool { +func dockerPush(imageTag string) error { result, err := common.CallExecCommand(common.ExecCommandInput{ Command: common.DockerBin(), Args: []string{"image", "push", imageTag}, StreamStdio: true, }) - return err == nil && result.ExitCode == 0 + if err != nil { + return fmt.Errorf("docker push command failed: %w", err) + } + if result.ExitCode != 0 { + return fmt.Errorf("docker push command exited with code %d: %s", result.ExitCode, result.Stderr) + } + return nil } func imageCleanup(appName string, imageRepo string, imageTag string, tag int) { diff --git a/plugins/registry/go.mod b/plugins/registry/go.mod index 0aace5cc7..244b07925 100644 --- a/plugins/registry/go.mod +++ b/plugins/registry/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/registry -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/registry/triggers.go b/plugins/registry/triggers.go index 44ec3d729..30cc97564 100644 --- a/plugins/registry/triggers.go +++ b/plugins/registry/triggers.go @@ -1,7 +1,6 @@ package registry import ( - "errors" "fmt" "strings" @@ -108,9 +107,8 @@ func TriggerPostReleaseBuilder(appName string, image string) error { newImage := strings.Replace(image, imageRepo+":", computedImageRepo+":", 1) if computedImageRepo != imageRepo { - if !dockerTag(imageID, newImage) { - // TODO: better error - return errors.New("Unable to tag image") + if err := dockerTag(imageID, newImage); err != nil { + return fmt.Errorf("unable to tag image %s as %s: %w", imageID, newImage, err) } } diff --git a/plugins/repo/go.mod b/plugins/repo/go.mod index d82f384bb..1f07d43f3 100644 --- a/plugins/repo/go.mod +++ b/plugins/repo/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/repo -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/resource/go.mod b/plugins/resource/go.mod index e7ea4f721..8453760a2 100644 --- a/plugins/resource/go.mod +++ b/plugins/resource/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/resource -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/scheduler-docker-local/.gitignore b/plugins/scheduler-docker-local/.gitignore index 637119bb8..cdf10f66f 100644 --- a/plugins/scheduler-docker-local/.gitignore +++ b/plugins/scheduler-docker-local/.gitignore @@ -1,3 +1,4 @@ /triggers/* /triggers /cron-* +/scheduler-cron-write diff --git a/plugins/scheduler-docker-local/Makefile b/plugins/scheduler-docker-local/Makefile index 09f04eabb..bd7c75ae1 100644 --- a/plugins/scheduler-docker-local/Makefile +++ b/plugins/scheduler-docker-local/Makefile @@ -1,4 +1,4 @@ -TRIGGERS = triggers/cron-write +TRIGGERS = triggers/scheduler-cron-write BUILD = triggers PLUGIN_NAME = scheduler-docker-local diff --git a/plugins/scheduler-docker-local/functions.go b/plugins/scheduler-docker-local/functions.go index bcf852426..e11d7c035 100644 --- a/plugins/scheduler-docker-local/functions.go +++ b/plugins/scheduler-docker-local/functions.go @@ -52,10 +52,11 @@ func generateCronEntries() ([]cron.TemplateCommand, error) { return nil } - c, err := cron.FetchCronEntries(appName) + c, err := cron.FetchCronEntries(cron.FetchCronEntriesInput{AppName: appName}) if err != nil { results <- []cron.TemplateCommand{} - return err + common.LogWarn(err.Error()) + return nil } results <- c @@ -83,9 +84,10 @@ func generateCronEntries() ([]cron.TemplateCommand, error) { id := base36.EncodeToStringLc([]byte(strings.Join(parts, ";;;"))) command := cron.TemplateCommand{ - ID: id, - Schedule: parts[0], - AltCommand: parts[1], + ID: id, + Schedule: parts[0], + AltCommand: parts[1], + Maintenance: false, } if len(parts) == 3 { command.LogFile = parts[2] @@ -106,7 +108,7 @@ func generateCronEntries() ([]cron.TemplateCommand, error) { for result := range results { c := result - if len(c) > 0 { + if len(c) > 0 && !c[0].Maintenance { commands = append(commands, c...) } } @@ -114,7 +116,12 @@ func generateCronEntries() ([]cron.TemplateCommand, error) { return commands, nil } -func writeCronEntries() error { +func writeCronEntries(scheduler string) error { + // allow empty scheduler, which means all apps (used by letsencrypt) + if scheduler != "docker-local" && scheduler != "" { + return nil + } + commands, err := generateCronEntries() if err != nil { return err diff --git a/plugins/scheduler-docker-local/go.mod b/plugins/scheduler-docker-local/go.mod index 612775e50..6af90f0eb 100644 --- a/plugins/scheduler-docker-local/go.mod +++ b/plugins/scheduler-docker-local/go.mod @@ -1,6 +1,6 @@ module github.com/dokku/dokku/plugins/scheduler-docker-local -go 1.23.0 +go 1.24.0 require ( github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index ebce46b95..d0cfdb061 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -114,7 +114,7 @@ fn-scheduler-docker-local-retire-container() { return fi - DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)" + DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)" [[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" if [[ "$STATE" == "restarting" ]]; then diff --git a/plugins/scheduler-docker-local/post-delete b/plugins/scheduler-docker-local/post-delete index 472643544..109b07748 100755 --- a/plugins/scheduler-docker-local/post-delete +++ b/plugins/scheduler-docker-local/post-delete @@ -14,8 +14,6 @@ trigger-scheduler-docker-local-post-delete() { # remove all application containers "$DOCKER_BIN" container ls --filter "label=com.dokku.app-name=${APP}" -q | xargs -n1 -I {} "$DOCKER_BIN" container rm --force {} &>/dev/null || true - - plugn trigger cron-write } trigger-scheduler-docker-local-post-delete "$@" diff --git a/plugins/scheduler-docker-local/post-deploy b/plugins/scheduler-docker-local/post-deploy index 3c19037f1..0b56c6d24 100755 --- a/plugins/scheduler-docker-local/post-deploy +++ b/plugins/scheduler-docker-local/post-deploy @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -eo pipefail +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" [[ $DOKKU_TRACE ]] && set -x trigger-scheduler-docker-local-post-deploy() { @@ -7,7 +8,8 @@ trigger-scheduler-docker-local-post-deploy() { declare trigger="post-deploy" declare APP="$1" - plugn trigger cron-write + local DOKKU_SCHEDULER="$(get_app_scheduler "$APP")" + plugn trigger scheduler-cron-write "$DOKKU_SCHEDULER" "$APP" } trigger-scheduler-docker-local-post-deploy "$@" diff --git a/plugins/scheduler-docker-local/scheduler-deploy b/plugins/scheduler-docker-local/scheduler-deploy index 3192c0e63..e7e9f4adf 100755 --- a/plugins/scheduler-docker-local/scheduler-deploy +++ b/plugins/scheduler-docker-local/scheduler-deploy @@ -32,7 +32,7 @@ trigger-scheduler-docker-local-scheduler-deploy() { local oldids=$(get_app_container_ids "$APP" "$PROCESS_TYPE") DOKKU_NETWORK_BIND_ALL="$(plugn trigger network-get-property "$APP" bind-all-interfaces)" - DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)" + DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds)" [[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" DOKKU_START_CMD="$(config_get "$APP" DOKKU_START_CMD || true)" diff --git a/plugins/scheduler-docker-local/scheduler-run-stop b/plugins/scheduler-docker-local/scheduler-run-stop index d46f9ad72..d72015f38 100755 --- a/plugins/scheduler-docker-local/scheduler-run-stop +++ b/plugins/scheduler-docker-local/scheduler-run-stop @@ -51,7 +51,7 @@ trigger-scheduler-docker-local-scheduler-run-stop() { verify_app_name "$APP" - DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)" + DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)" if [[ -n "$CONTAINER_NAME" ]]; then fn-scheduler-docker-local-stop-container "$CONTAINER_NAME" "$DOKKU_DOCKER_STOP_TIMEOUT" return $? diff --git a/plugins/scheduler-docker-local/scheduler-stop b/plugins/scheduler-docker-local/scheduler-stop index 88dd43091..12fcb5400 100755 --- a/plugins/scheduler-docker-local/scheduler-stop +++ b/plugins/scheduler-docker-local/scheduler-stop @@ -4,6 +4,12 @@ set -eo pipefail source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +fn-stop-container() { + declare APP="$1" CID="$2" + "$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true + "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CID" &>/dev/null || true +} + trigger-scheduler-docker-local-scheduler-stop() { declare desc="scheduler-docker-local scheduler-stop plugin trigger" declare trigger="scheduler-stop" @@ -14,19 +20,27 @@ trigger-scheduler-docker-local-scheduler-stop() { fi local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null) - local DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)" + local DOKKU_DOCKER_STOP_TIMEOUT="$(plugn trigger ps-get-property "$APP" stop-timeout-seconds || true)" [[ -n "$DOKKU_DOCKER_STOP_TIMEOUT" ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" if [[ -n "$DOKKU_APP_RUNNING_CONTAINER_IDS" ]]; then - # Disable the container restart policy - "$DOCKER_BIN" container update --restart=no $DOKKU_APP_RUNNING_CONTAINER_IDS &>/dev/null || true + for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do + fn-stop-container "$APP" "$CID" + done + fi - "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG $DOKKU_APP_RUNNING_CONTAINER_IDS >/dev/null || true + # Stop all other containers related to the app + # fetch all containers with the com.dokku.app-name label + local DOKKU_APP_CIDS="$(docker container ls -q -f label=com.dokku.app-name="$APP")" + if [[ -n "$DOKKU_APP_CIDS" ]]; then + for CID in $DOKKU_APP_CIDS; do + fn-stop-container "$APP" "$CID" + done fi if [[ "$REMOVE_CONTAINERS" == "true" ]]; then - local DOKKU_APP_CIDS=$(get_app_container_ids "$APP") + local DOKKU_APP_CIDS="$(docker ps -q -f label=com.dokku.app-name="$APP")" if [[ -n "$DOKKU_APP_CIDS" ]]; then for CID in $DOKKU_APP_CIDS; do @@ -36,6 +50,8 @@ trigger-scheduler-docker-local-scheduler-stop() { "$DOCKER_BIN" container rm --force $DOKKU_APP_CIDS &>/dev/null || true fi fi + + plugn trigger scheduler-cron-write "$DOKKU_SCHEDULER" "$APP" } trigger-scheduler-docker-local-scheduler-stop "$@" diff --git a/plugins/scheduler-docker-local/src/triggers/triggers.go b/plugins/scheduler-docker-local/src/triggers/triggers.go index 86b030d9d..7ee657f92 100644 --- a/plugins/scheduler-docker-local/src/triggers/triggers.go +++ b/plugins/scheduler-docker-local/src/triggers/triggers.go @@ -18,8 +18,9 @@ func main() { var err error switch trigger { - case "cron-write": - err = schedulerdockerlocal.TriggerCronWrite() + case "scheduler-cron-write": + scheduler := flag.Arg(0) + err = schedulerdockerlocal.TriggerSchedulerCronWrite(scheduler) default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } diff --git a/plugins/scheduler-docker-local/triggers.go b/plugins/scheduler-docker-local/triggers.go index 018ff411e..4f9fded0d 100644 --- a/plugins/scheduler-docker-local/triggers.go +++ b/plugins/scheduler-docker-local/triggers.go @@ -1,6 +1,6 @@ package schedulerdockerlocal -// TriggerCronWrite force updates the cron file for all apps -func TriggerCronWrite() error { - return writeCronEntries() +// TriggerSchedulerCronWrite force updates the cron file for all apps +func TriggerSchedulerCronWrite(scheduler string) error { + return writeCronEntries(scheduler) } diff --git a/plugins/scheduler-k3s/Makefile b/plugins/scheduler-k3s/Makefile index 449103c2c..870e3ba05 100644 --- a/plugins/scheduler-k3s/Makefile +++ b/plugins/scheduler-k3s/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall -TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop +TRIGGERS = triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop BUILD = commands subcommands triggers PLUGIN_NAME = scheduler-k3s diff --git a/plugins/scheduler-k3s/functions.go b/plugins/scheduler-k3s/functions.go index 942d5c4f2..16b9a1ab6 100644 --- a/plugins/scheduler-k3s/functions.go +++ b/plugins/scheduler-k3s/functions.go @@ -576,7 +576,7 @@ func getAutoscaling(input GetAutoscalingInput) (ProcessAutoscaling, error) { } if !ok { - common.LogWarn(fmt.Sprintf("No autoscaling config found for %s", input.AppName)) + common.LogWarn(fmt.Sprintf("No autoscaling config found for %s:%s", input.AppName, input.ProcessType)) return ProcessAutoscaling{}, nil } @@ -1190,6 +1190,28 @@ func getGlobalLetsencryptEmailStag() string { return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-email-stag", "") } +func getKustomizeDirectory(appName string) string { + directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "scheduler-k3s", appName) + return filepath.Join(directory, "kustomization") +} + +func getKustomizeRootPath(appName string) string { + return common.PropertyGetDefault("scheduler-k3s", appName, "kustomize-root-path", "") +} + +func getGlobalKustomizeRootPath() string { + return common.PropertyGetDefault("scheduler-k3s", "--global", "kustomize-root-path", "config/kustomize") +} + +func getComputedKustomizeRootPath(appName string) string { + kustomizeRootPath := getKustomizeRootPath(appName) + if kustomizeRootPath == "" { + kustomizeRootPath = getGlobalKustomizeRootPath() + } + + return kustomizeRootPath +} + func getNamespace(appName string) string { return common.PropertyGetDefault("scheduler-k3s", appName, "namespace", "") } @@ -1477,6 +1499,34 @@ func getStartCommand(input StartCommandInput) (StartCommandOutput, error) { }, nil } +func getProcessSpecificKustomizeRootPath(appName string) string { + if !hasKustomizeDirectory(appName) { + return "" + } + + directory := getKustomizeDirectory(appName) + processSpecificDirectory := fmt.Sprintf("%s.%s", directory, os.Getenv("DOKKU_PID")) + if common.DirectoryExists(processSpecificDirectory) { + return processSpecificDirectory + } + + return directory +} + +func hasKustomizeDirectory(appName string) bool { + directory := getKustomizeDirectory(appName) + + if common.DirectoryExists(fmt.Sprintf("%s.%s.missing", directory, os.Getenv("DOKKU_PID"))) { + return false + } + + if common.DirectoryExists(fmt.Sprintf("%s.%s", directory, os.Getenv("DOKKU_PID"))) { + return true + } + + return common.DirectoryExists(directory) +} + func installHelmCharts(ctx context.Context, clientset KubernetesClient, shouldInstall func(HelmChart) bool) error { for _, repo := range HelmRepositories { helmAgent, err := NewHelmAgent("default", DeployLogPrinter) diff --git a/plugins/scheduler-k3s/go.mod b/plugins/scheduler-k3s/go.mod index 152503419..bf48e9f6f 100644 --- a/plugins/scheduler-k3s/go.mod +++ b/plugins/scheduler-k3s/go.mod @@ -1,124 +1,115 @@ module github.com/dokku/dokku/plugins/scheduler-k3s -go 1.23.0 +go 1.24.0 require ( - github.com/cert-manager/cert-manager v1.15.4 - github.com/dokku/dokku/plugins/app-json v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/cron v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/logs v0.0.0-00010101000000-000000000000 - github.com/dokku/dokku/plugins/nginx-vhosts v0.0.0-00010101000000-000000000000 + github.com/cert-manager/cert-manager v1.18.2 + github.com/dokku/dokku/plugins/app-json v0.0.0-20250618161309-8d0c35f1333c + github.com/dokku/dokku/plugins/common v0.0.0-20250618161309-8d0c35f1333c + github.com/dokku/dokku/plugins/config v0.0.0-20250618161309-8d0c35f1333c + github.com/dokku/dokku/plugins/cron v0.0.0-20250618161309-8d0c35f1333c + github.com/dokku/dokku/plugins/logs v0.0.0-20250618161309-8d0c35f1333c + github.com/dokku/dokku/plugins/nginx-vhosts v0.0.0-20250618161309-8d0c35f1333c github.com/fatih/color v1.18.0 - github.com/go-openapi/jsonpointer v0.21.0 + github.com/fluxcd/pkg/kustomize v1.18.0 + github.com/go-openapi/jsonpointer v0.21.1 github.com/go-resty/resty/v2 v2.16.5 github.com/gofrs/flock v0.12.1 - github.com/gosimple/slug v1.14.0 + github.com/gosimple/slug v1.15.0 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/kedacore/keda/v2 v2.13.0 + github.com/kedacore/keda/v2 v2.17.1-0.20250708210620-a239d2459a35 github.com/ryanuber/columnize v2.1.2+incompatible github.com/spf13/pflag v1.0.6 - github.com/traefik/traefik/v2 v2.11.25 + github.com/traefik/traefik/v2 v2.11.26 golang.org/x/sync v0.15.0 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.14.2 - k8s.io/api v0.30.1 - k8s.io/apimachinery v0.30.1 - k8s.io/client-go v0.30.1 - k8s.io/kubectl v0.29.0 - k8s.io/kubernetes v1.29.14 - k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 - mvdan.cc/sh/v3 v3.11.0 + helm.sh/helm/v3 v3.18.4 + k8s.io/api v0.33.2 + k8s.io/apimachinery v0.33.2 + k8s.io/client-go v0.33.2 + k8s.io/kubectl v0.33.2 + k8s.io/kubernetes v1.33.2 + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + mvdan.cc/sh/v3 v3.12.0 + sigs.k8s.io/kustomize/api v0.20.0 ) require ( - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + dario.cat/mergo v1.0.2 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/alexellis/go-execute/v2 v2.2.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/carapace-sh/carapace-shlex v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/chai2010/gettext-go v1.0.3 // indirect github.com/containerd/containerd v1.7.27 // indirect - github.com/containerd/errdefs v0.3.0 // indirect + github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/distribution/reference v0.6.0 // indirect - github.com/docker/cli v27.1.1+incompatible // indirect - github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v27.1.1+incompatible // indirect - github.com/docker/docker-credential-helpers v0.7.0 // indirect - github.com/docker/go-connections v0.5.0 // indirect - github.com/docker/go-metrics v0.0.1 // indirect - github.com/dokku/dokku/plugins/docker-options v0.0.0-00010101000000-000000000000 // indirect - github.com/emicklei/go-restful/v3 v3.12.0 // indirect - github.com/evanphx/json-patch v5.9.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/expr-lang/expr v1.17.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/go-acme/lego/v4 v4.23.1 // indirect + github.com/docker/docker-credential-helpers v0.9.3 // indirect + github.com/dokku/dokku/plugins/docker-options v0.0.0-20250618161309-8d0c35f1333c // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/evanphx/json-patch v5.9.11+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/expr-lang/expr v1.17.5 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/go-acme/lego/v4 v4.24.0 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/btree v1.0.1 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/gorilla/websocket v1.5.3 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/gosuri/uitable v0.0.4 // indirect - github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.5.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.11-0.20241004063537-dbd6c381492a // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/melbahja/goph v1.4.0 // indirect - github.com/miekg/dns v1.1.64 // indirect + github.com/miekg/dns v1.1.66 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/locker v1.0.1 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.5.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -126,68 +117,63 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/otiai10/copy v1.14.1 // indirect github.com/otiai10/mint v1.6.3 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkg/sftp v1.13.5 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.54.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/rivo/uniseg v0.4.4 // indirect + github.com/pkg/sftp v1.13.9 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/procfs v0.17.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rubenv/sql-migrate v1.5.2 // indirect + github.com/rubenv/sql-migrate v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.7.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/cast v1.9.2 // indirect + github.com/spf13/cobra v1.9.1 // indirect github.com/traefik/paerser v0.2.2 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect - go.opentelemetry.io/otel v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.34.0 // indirect - go.starlark.net v0.0.0-20231121155337-90ade8b19d09 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.39.0 // indirect - golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect golang.org/x/mod v0.25.0 // indirect - golang.org/x/net v0.40.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/net v0.41.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.26.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.33.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect - google.golang.org/grpc v1.71.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect - gopkg.in/evanphx/json-patch.v5 v5.8.1 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.34.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/grpc v1.73.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.30.1 // indirect - k8s.io/apiserver v0.30.1 // indirect - k8s.io/cli-runtime v0.29.0 // indirect - k8s.io/component-base v0.30.1 // indirect - k8s.io/klog/v2 v2.120.1 // indirect - k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f // indirect - knative.dev/pkg v0.0.0-20240116073220-b488e7be5902 // indirect - oras.land/oras-go v1.2.5 // indirect - sigs.k8s.io/controller-runtime v0.18.2 // indirect - sigs.k8s.io/gateway-api v1.1.0 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.16.0 // indirect - sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/apiextensions-apiserver v0.33.2 // indirect + k8s.io/apiserver v0.33.2 // indirect + k8s.io/cli-runtime v0.33.2 // indirect + k8s.io/component-base v0.33.2 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 // indirect + knative.dev/pkg v0.0.0-20250708013613-d3550d4350f9 // indirect + oras.land/oras-go/v2 v2.6.0 // indirect + sigs.k8s.io/controller-runtime v0.21.0 // indirect + sigs.k8s.io/gateway-api v1.3.0 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect + sigs.k8s.io/yaml v1.5.0 // indirect ) replace github.com/dokku/dokku/plugins/app-json => ../app-json @@ -205,3 +191,5 @@ replace github.com/dokku/dokku/plugins/logs => ../logs replace github.com/dokku/dokku/plugins/nginx-vhosts => ../nginx-vhosts replace github.com/joho/godotenv => github.com/joho/godotenv v1.2.0 + +replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 diff --git a/plugins/scheduler-k3s/go.sum b/plugins/scheduler-k3s/go.sum index beb819ffd..08511dbb7 100644 --- a/plugins/scheduler-k3s/go.sum +++ b/plugins/scheduler-k3s/go.sum @@ -1,308 +1,248 @@ -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ= -github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/carapace-sh/carapace-shlex v1.0.1 h1:ww0JCgWpOVuqWG7k3724pJ18Lq8gh5pHQs9j3ojUs1c= +github.com/carapace-sh/carapace-shlex v1.0.1/go.mod h1:lJ4ZsdxytE0wHJ8Ta9S7Qq0XpjgjU0mdfCqiI2FHx7M= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cert-manager/cert-manager v1.15.4 h1:FtH6BOTmkNBNRjoYSW2b80MYpUq4Zw1zbEB6flYzkiM= -github.com/cert-manager/cert-manager v1.15.4/go.mod h1:stBge/DTvrhfQMB/93+Y62s+gQgZBsfL1o0C/4AL/mI= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cert-manager/cert-manager v1.18.2 h1:H2P75ycGcTMauV3gvpkDqLdS3RSXonWF2S49QGA1PZE= +github.com/cert-manager/cert-manager v1.18.2/go.mod h1:icDJx4kG9BCNpGjBvrmsFd99d+lXUvWdkkcrSSQdIiw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= -github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= +github.com/chai2010/gettext-go v1.0.3 h1:9liNh8t+u26xl5ddmWLmsOsdNLwkdRTg5AG+JnTiM80= +github.com/chai2010/gettext-go v1.0.3/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII= github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0= -github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= -github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= -github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= -github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= -github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM= +github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE= -github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= -github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= -github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= -github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= +github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= -github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= -github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/expr-lang/expr v1.17.0 h1:+vpszOyzKLQXC9VF+wA8cVA0tlA984/Wabc/1hF9Whg= -github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= +github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= +github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= -github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= +github.com/fluxcd/pkg/kustomize v1.18.0 h1:wWK+qYwmBmba3N3VAqZ9ijnfVGGaIjcaHWo033URZTw= +github.com/fluxcd/pkg/kustomize v1.18.0/go.mod h1:Ij9722MdWIE6B1EPg2ZJUf6npycgfRfN4Lohi7D/Kic= +github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= +github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4= -github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-acme/lego/v4 v4.24.0 h1:pe0q49JKxfSGEP3lkgkMVQrZM1KbD+e0dpJ2McYsiVw= +github.com/go-acme/lego/v4 v4.24.0/go.mod h1:hkstZY6D0jylIrZbuNmEQrWQxTIfaJH7prwaWvKDOjw= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= -github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= -github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= -github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= -github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= -github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= -github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ= -github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= -github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= +github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= -github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= +github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= 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/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0 h1:ct2XA1aDw8A07Dr8gtrrZgIgLKcZNAl2o9nn0WRMK4Y= github.com/joncalhoun/qson v0.0.0-20200422171543-84433dcd3da0/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwSWoI= -github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kedacore/keda/v2 v2.13.0 h1:vUjLnEUQGrPBavyEFbPK7KxG10w+HfOnWk3eg8NPnnY= -github.com/kedacore/keda/v2 v2.13.0/go.mod h1:AZTRgxWpK5/6pq+DqJ15y3Bl/C8sl9C7tUVF4phzGDQ= +github.com/kedacore/keda/v2 v2.17.1-0.20250708210620-a239d2459a35 h1:dVamAZ0mkRedF4AMZDFoaV1lakRfdfrzN9tvk+zgAlk= +github.com/kedacore/keda/v2 v2.17.1-0.20250708210620-a239d2459a35/go.mod h1:WGhOV69k9YW3iTSj592glrCOqdO9Zy8hmYcyStZ5+tk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.11-0.20241004063537-dbd6c381492a h1:cwHOqPB4H4iQq8177kf2SxpjNbcjJ2m3lNwKIe28Hqg= -github.com/klauspost/compress v1.17.11-0.20241004063537-dbd6c381492a/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= -github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= -github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= -github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs= github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68= -github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ= -github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= -github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= @@ -311,18 +251,17 @@ github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9 github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= @@ -333,77 +272,73 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go= github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg= +github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw= +github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho= +github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc= +github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= -github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= +github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o= +github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= +github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ= github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24= -github.com/traefik/traefik/v2 v2.11.25 h1:gkWvq7zhnLqJJlivFfnITWiDwTmph2EQt1XI8pWCnKI= -github.com/traefik/traefik/v2 v2.11.25/go.mod h1:OFifHrTIFq/UUHvtXtSrNSAxqA6Cgmh+Gcq7eiGC4iA= +github.com/traefik/traefik/v2 v2.11.26 h1:i+kjoyL8lwe4E7lLtin/+IhFz0zXkKwAsmDFaMOBmQA= +github.com/traefik/traefik/v2 v2.11.26/go.mod h1:VuRYNzcBHrI8fan5VJGlhgSI1NCmL8Ma4HDjT6rsTKo= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -416,77 +351,114 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= -go.starlark.net v0.0.0-20231121155337-90ade8b19d09 h1:hzy3LFnSN8kuQK8h9tHl4ndF6UruMj47OqwqsS+/Ai4= -go.starlark.net v0.0.0-20231121155337-90ade8b19d09/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w= +go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4= +go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0 h1:9PgnL3QNlj10uGxExowIDIZu66aVBwWhXmbOp1pa6RA= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0/go.mod h1:0ineDcLELf6JmKfuo0wvvhAVMuxWFYvkTin2iV4ydPQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= +go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILrLVgHxjA/AMjqHKes+uzo= +go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= +go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk= +go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs= +go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU= -golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -496,109 +468,124 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v5 v5.8.1 h1:BVxXj2YS+4i9fttNkVvDKi4Pg1pVMpVE8tdEwaKeQY0= -gopkg.in/evanphx/json-patch.v5 v5.8.1/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= -helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= -k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY= -k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM= -k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= -k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4= -k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U= -k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8= -k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo= -k8s.io/cli-runtime v0.29.0 h1:q2kC3cex4rOBLfPOnMSzV2BIrrQlx97gxHJs21KxKS4= -k8s.io/cli-runtime v0.29.0/go.mod h1:VKudXp3X7wR45L+nER85YUzOQIru28HQpXr0mTdeCrk= -k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q= -k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc= -k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ= -k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= -k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= -k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI= -k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs= -k8s.io/kubernetes v1.29.14 h1:mbk5M/WaJr/AX7p3p2/7eJjrtI+I3AKu7IEjI8+Ny/U= -k8s.io/kubernetes v1.29.14/go.mod h1:L6/pfKQZ6Tv2O8gyT4OxhGZp+nNsjV54xtNodRoup9k= -k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= -k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/pkg v0.0.0-20240116073220-b488e7be5902 h1:H6+JJN23fhwYWCHY1339sY6uhIyoUwDy1a8dN233fdk= -knative.dev/pkg v0.0.0-20240116073220-b488e7be5902/go.mod h1:NYk8mMYoLkO7CQWnNkti4YGGnvLxN6MIDbUvtgeo0C0= -mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw= -mvdan.cc/sh/v3 v3.11.0/go.mod h1:LRM+1NjoYCzuq/WZ6y44x14YNAI0NK7FLPeQSaFagGg= -oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= -oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= -sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q= -sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= -sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM= -sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.16.0 h1:/zAR4FOQDCkgSDmVzV2uiFbuy9bhu3jEzthrHCuvm1g= -sigs.k8s.io/kustomize/api v0.16.0/go.mod h1:MnFZ7IP2YqVyVwMWoRxPtgl/5hpA+eCCrQR/866cm5c= -sigs.k8s.io/kustomize/kyaml v0.16.0 h1:6J33uKSoATlKZH16unr2XOhDI+otoe2sR3M8PDzW3K0= -sigs.k8s.io/kustomize/kyaml v0.16.0/go.mod h1:xOK/7i+vmE14N2FdFyugIshB8eF6ALpy7jI87Q2nRh4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +helm.sh/helm/v3 v3.18.4 h1:pNhnHM3nAmDrxz6/UC+hfjDY4yeDATQCka2/87hkZXQ= +helm.sh/helm/v3 v3.18.4/go.mod h1:WVnwKARAw01iEdjpEkP7Ii1tT1pTPYfM1HsakFKM3LI= +k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= +k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= +k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= +k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= +k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4= +k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M= +k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y= +k8s.io/cli-runtime v0.33.2/go.mod h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88= +k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= +k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= +k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0= +k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911 h1:gAXU86Fmbr/ktY17lkHwSjw5aoThQvhnstGGIYKlKYc= +k8s.io/kube-openapi v0.0.0-20250701173324-9bd5c66d9911/go.mod h1:GLOk5B+hDbRROvt0X2+hqX64v/zO3vXN7J78OUmBSKw= +k8s.io/kubectl v0.33.2 h1:7XKZ6DYCklu5MZQzJe+CkCjoGZwD1wWl7t/FxzhMz7Y= +k8s.io/kubectl v0.33.2/go.mod h1:8rC67FB8tVTYraovAGNi/idWIK90z2CHFNMmGJZJ3KI= +k8s.io/kubernetes v1.33.2 h1:Vk3hsCaazyMQ6CXhu029AEPlBoYsEnD8oEIC0bP2pWQ= +k8s.io/kubernetes v1.33.2/go.mod h1:nrt8sldmckKz2fCZhgRX3SKfS2e+CzXATPv6ITNkU00= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +knative.dev/pkg v0.0.0-20250708013613-d3550d4350f9 h1:yCiThjArNgVjRbyBGvRvYr/B6G3djvr5pXrh8MXfnsk= +knative.dev/pkg v0.0.0-20250708013613-d3550d4350f9/go.mod h1:I2vWm0knRQH2WBfpIAkRzOPk0XoXxfu8YJT63ddYWd4= +mvdan.cc/sh/v3 v3.12.0 h1:ejKUR7ONP5bb+UGHGEG/k9V5+pRVIyD+LsZz7o8KHrI= +mvdan.cc/sh/v3 v3.12.0/go.mod h1:Se6Cj17eYSn+sNooLZiEUnNNmNxg0imoYlTu4CyaGyg= +oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= +oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M= +sigs.k8s.io/gateway-api v1.3.0/go.mod h1:d8NV8nJbaRbEKem+5IuxkL8gJGOZ+FJ+NvOIltV8gDk= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/kustomize/api v0.20.0 h1:xPLqcobHI0bThyRUteO+nCV8G4d1Rlo5HafO57VRcas= +sigs.k8s.io/kustomize/api v0.20.0/go.mod h1:F6CfaV27oevRCMJgehLqyX81dlUnRX/Fc13Uo7+OSo4= +sigs.k8s.io/kustomize/kyaml v0.20.0 h1:tT8KMKi4R3hCJ1+9HDdek2VoXpkerP92ZfF6fDgGw14= +sigs.k8s.io/kustomize/kyaml v0.20.0/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= +sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/plugins/scheduler-k3s/helm.go b/plugins/scheduler-k3s/helm.go index 8f007cdf1..e9dd9f97e 100644 --- a/plugins/scheduler-k3s/helm.go +++ b/plugins/scheduler-k3s/helm.go @@ -14,6 +14,7 @@ import ( "unicode" "github.com/dokku/dokku/plugins/common" + "github.com/fluxcd/pkg/kustomize/filesys" "github.com/gofrs/flock" "gopkg.in/yaml.v3" "helm.sh/helm/v3/pkg/action" @@ -21,9 +22,13 @@ import ( "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/kube" + "helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v3/pkg/storage/driver" + "sigs.k8s.io/kustomize/api/konfig" + "sigs.k8s.io/kustomize/api/krusty" + "sigs.k8s.io/kustomize/api/types" ) var DevNullPrinter = func(format string, v ...interface{}) {} @@ -46,16 +51,37 @@ var DeployLogPrinter = func(format string, v ...interface{}) { } } +// ChartInput is the input for the InstallOrUpgradeChart function type ChartInput struct { - ChartPath string - Namespace string - ReleaseName string - RepoURL string + // ChartPath is the path to the chart to install or upgrade + ChartPath string + + // KustomizeRootPath is the path to the kustomize root path to use + KustomizeRootPath string + + // Namespace is the namespace to install or upgrade the chart in + Namespace string + + // ReleaseName is the name of the release to install or upgrade + ReleaseName string + + // RepoURL is the URL of the chart repository to install or upgrade the chart from + RepoURL string + + // RollbackOnFailure is whether to rollback on failure RollbackOnFailure bool - Timeout time.Duration - Wait bool - Version string - Values map[string]interface{} + + // Timeout is the timeout for the install or upgrade + Timeout time.Duration + + // Wait is whether to wait for the install or upgrade to complete + Wait bool + + // Version is the version of the chart to install or upgrade + Version string + + // Values is the values to pass to the chart + Values map[string]interface{} } type Release struct { @@ -237,11 +263,22 @@ func (h *HelmAgent) InstallChart(ctx context.Context, input ChartInput) error { input.Values = map[string]interface{}{} } + kustomizeRenderer := KustomizeRenderer{ + KustomizeRootPath: input.KustomizeRootPath, + } + client := action.NewInstall(h.Configuration) client.Atomic = false client.ChartPathOptions = action.ChartPathOptions{} client.CreateNamespace = true client.DryRun = false + if os.Getenv("DOKKU_TRACE") == "1" { + client.PostRenderer = &DebugRenderer{ + Renderer: &kustomizeRenderer, + } + } else { + client.PostRenderer = &kustomizeRenderer + } client.Namespace = namespace client.ReleaseName = input.ReleaseName client.Timeout = input.Timeout @@ -333,16 +370,6 @@ func (h *HelmAgent) ListRevisions(input ListRevisionsInput) ([]Release, error) { return releases, nil } -type DebugRenderer struct { -} - -func (p *DebugRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { - for _, line := range strings.Split(renderedManifests.String(), "\n") { - common.LogWarn(line) - } - return renderedManifests, nil -} - func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error { namespace := input.Namespace if namespace == "" { @@ -359,14 +386,21 @@ func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error { input.Values = map[string]interface{}{} } + kustomizeRenderer := KustomizeRenderer{ + KustomizeRootPath: input.KustomizeRootPath, + } + client := action.NewUpgrade(h.Configuration) client.Atomic = input.RollbackOnFailure client.ChartPathOptions = action.ChartPathOptions{} client.CleanupOnFail = true client.MaxHistory = 10 if os.Getenv("DOKKU_TRACE") == "1" { - client.DryRun = true - client.PostRenderer = &DebugRenderer{} + client.PostRenderer = &DebugRenderer{ + Renderer: &kustomizeRenderer, + } + } else { + client.PostRenderer = &kustomizeRenderer } client.Namespace = namespace client.Timeout = input.Timeout @@ -413,3 +447,71 @@ func (h *HelmAgent) UninstallChart(releaseName string) error { return nil } + +type DebugRenderer struct { + Renderer postrender.PostRenderer +} + +func (p *DebugRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { + renderedManifests, err := p.Renderer.Run(renderedManifests) + if err != nil { + return nil, err + } + + for _, line := range strings.Split(renderedManifests.String(), "\n") { + common.LogWarn(line) + } + return renderedManifests, nil +} + +type KustomizeRenderer struct { + KustomizeRootPath string +} + +func (p *KustomizeRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { + if p.KustomizeRootPath == "" { + return renderedManifests, nil + } + + if !common.DirectoryExists(p.KustomizeRootPath) { + return renderedManifests, nil + } + + fs, err := filesys.MakeFsOnDiskSecureBuild(p.KustomizeRootPath) + if err != nil { + return nil, fmt.Errorf("Error creating filesystem: %w", err) + } + + var kfile string + for _, f := range konfig.RecognizedKustomizationFileNames() { + if kf := filepath.Join(p.KustomizeRootPath, f); fs.Exists(kf) { + kfile = kf + break + } + } + if kfile == "" { + return nil, fmt.Errorf("%s not found", konfig.DefaultKustomizationFileName()) + } + + if err := fs.WriteFile(filepath.Join(p.KustomizeRootPath, "rendered.yaml"), renderedManifests.Bytes()); err != nil { + return nil, fmt.Errorf("Error writing rendered.yaml: %w", err) + } + + buildOptions := &krusty.Options{ + LoadRestrictions: types.LoadRestrictionsNone, + PluginConfig: types.DisabledPluginConfig(), + } + + k := krusty.MakeKustomizer(buildOptions) + m, err := k.Run(fs, p.KustomizeRootPath) + if err != nil { + return nil, err + } + + resources, err := m.AsYaml() + if err != nil { + return nil, err + } + + return bytes.NewBuffer(resources), nil +} diff --git a/plugins/scheduler-k3s/k8s.go b/plugins/scheduler-k3s/k8s.go index 2cb7a8095..491e9174a 100644 --- a/plugins/scheduler-k3s/k8s.go +++ b/plugins/scheduler-k3s/k8s.go @@ -416,6 +416,35 @@ func (k KubernetesClient) ExecCommand(ctx context.Context, input ExecCommandInpu }) } +// GetPodLogsInput contains all the information needed to get the logs for a Kubernetes pod +type GetLogsInput struct { + // Name is the Kubernetes pod name + Name string + + // Namespace is the Kubernetes namespace + Namespace string +} + +// GetLogs gets the logs for a Kubernetes pod +func (k KubernetesClient) GetLogs(ctx context.Context, input GetLogsInput) ([]byte, error) { + logOptions := corev1.PodLogOptions{} + + request := k.Client.CoreV1().Pods(input.Namespace).GetLogs(input.Name, &logOptions) + + readCloser, err := request.Stream(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get logs: %w", err) + } + defer readCloser.Close() + + bytes, err := io.ReadAll(readCloser) + if err != nil { + return nil, fmt.Errorf("failed to read logs: %w", err) + } + + return bytes, nil +} + // GetNodeInput contains all the information needed to get a Kubernetes node type GetNodeInput struct { // Name is the Kubernetes node name @@ -940,3 +969,32 @@ func streamLogsFromRequest(ctx context.Context, request rest.ResponseWrapper, ou } } } + +// SuspendCronJobsInput contains all the information needed to suspend a Kubernetes cron job +type SuspendCronJobsInput struct { + // LabelSelector is the Kubernetes label selector + LabelSelector string + + // Namespace is the Kubernetes namespace + Namespace string +} + +// SuspendCronJobs suspends a Kubernetes cron job +func (k KubernetesClient) SuspendCronJobs(ctx context.Context, input SuspendCronJobsInput) error { + cronJobs, err := k.Client.BatchV1().CronJobs(input.Namespace).List(ctx, metav1.ListOptions{ + LabelSelector: input.LabelSelector, + }) + if err != nil { + return err + } + + for _, cronJob := range cronJobs.Items { + cronJob.Spec.Suspend = ptr.To(true) + _, err := k.Client.BatchV1().CronJobs(input.Namespace).Update(ctx, &cronJob, metav1.UpdateOptions{}) + if err != nil { + return err + } + } + + return nil +} diff --git a/plugins/scheduler-k3s/report.go b/plugins/scheduler-k3s/report.go index d480969b6..d1bb6d2de 100644 --- a/plugins/scheduler-k3s/report.go +++ b/plugins/scheduler-k3s/report.go @@ -28,6 +28,9 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { "--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, @@ -148,6 +151,18 @@ func reportGlobalLetsencryptEmailStag(appName string) string { return getGlobalLetsencryptEmailStag() } +func reportComputedKustomizeRootPath(appName string) string { + return getComputedKustomizeRootPath(appName) +} + +func reportKustomizeRootPath(appName string) string { + return getKustomizeRootPath(appName) +} + +func reportGlobalKustomizeRootPath(appName string) string { + return getGlobalKustomizeRootPath() +} + func reportComputedNamespace(appName string) string { return getComputedNamespace(appName) } diff --git a/plugins/scheduler-k3s/scheduler_k3s.go b/plugins/scheduler-k3s/scheduler_k3s.go index 9a37a78bd..fbf29a7bc 100644 --- a/plugins/scheduler-k3s/scheduler_k3s.go +++ b/plugins/scheduler-k3s/scheduler_k3s.go @@ -20,6 +20,7 @@ var ( DefaultProperties = map[string]string{ "deploy-timeout": "", "letsencrypt-server": "", + "kustomize-root-path": "", "image-pull-secrets": "", "namespace": "", "rollback-on-failure": "", @@ -33,6 +34,7 @@ var ( "ingress-class": true, "kube-context": true, "kubeconfig-path": true, + "kustomize-root-path": true, "letsencrypt-server": true, "letsencrypt-email-prod": true, "letsencrypt-email-stag": true, diff --git a/plugins/scheduler-k3s/src/triggers/triggers.go b/plugins/scheduler-k3s/src/triggers/triggers.go index 4092da096..692c62e1f 100644 --- a/plugins/scheduler-k3s/src/triggers/triggers.go +++ b/plugins/scheduler-k3s/src/triggers/triggers.go @@ -22,6 +22,13 @@ func main() { var err error switch trigger { + case "core-post-deploy": + appName := flag.Arg(0) + err = scheduler_k3s.TriggerCorePostDeploy(appName) + case "core-post-extract": + appName := flag.Arg(0) + sourceWorkDir := flag.Arg(1) + err = scheduler_k3s.TriggerCorePostExtract(appName, sourceWorkDir) case "install": err = scheduler_k3s.TriggerInstall() case "post-app-clone-setup": @@ -32,6 +39,9 @@ func main() { oldAppName := flag.Arg(0) newAppName := flag.Arg(1) err = scheduler_k3s.TriggerPostAppRenameSetup(oldAppName, newAppName) + case "post-create": + appName := flag.Arg(0) + err = scheduler_k3s.TriggerPostCreate(appName) case "post-delete": appName := flag.Arg(0) err = scheduler_k3s.TriggerPostDelete(appName) diff --git a/plugins/scheduler-k3s/templates/chart/certificate.yaml b/plugins/scheduler-k3s/templates/chart/certificate.yaml index 029230020..077470ce8 100644 --- a/plugins/scheduler-k3s/templates/chart/certificate.yaml +++ b/plugins/scheduler-k3s/templates/chart/certificate.yaml @@ -1,5 +1,9 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + {{- if and $config.web.tls.enabled $config.web.domains }} --- apiVersion: cert-manager.io/v1 @@ -34,3 +38,4 @@ spec: - {{ $domain.name }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/cron-job.yaml b/plugins/scheduler-k3s/templates/chart/cron-job.yaml index 412e57916..cad22ce7c 100644 --- a/plugins/scheduler-k3s/templates/chart/cron-job.yaml +++ b/plugins/scheduler-k3s/templates/chart/cron-job.yaml @@ -1,5 +1,8 @@ -{{- $processName := "CRON_ID" }} -{{- $config := index .Values.processes "CRON_ID" }} +{{- range $processName, $config := .Values.processes }} +# Only process cron jobs +{{- if not (and (hasKey $config "cron") (hasKey $config.cron "id")) }} +{{- continue }} +{{- end }} --- apiVersion: batch/v1 kind: CronJob @@ -113,3 +116,4 @@ spec: successfulJobsHistoryLimit: 10 suspend: false timeZone: Etc/UTC +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/deployment.yaml b/plugins/scheduler-k3s/templates/chart/deployment.yaml index 3bb1d6e64..a741804d1 100644 --- a/plugins/scheduler-k3s/templates/chart/deployment.yaml +++ b/plugins/scheduler-k3s/templates/chart/deployment.yaml @@ -1,7 +1,11 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + {{- $mappings := dict }} -{{- if eq $processName "web" }} +{{- if hasKey $config "web" }} {{- range $pdx, $port_map := $config.web.port_maps }} {{- $mappings := set $mappings $port_map.name "true" }} {{- end }} @@ -57,7 +61,7 @@ spec: {{- range $config.args }} - {{ . }} {{- end }} - {{- if eq $processName "web" }} + {{- if hasKey $config "web" }} env: - name: PORT value: "{{ $.Values.global.network.primary_port }}" @@ -69,7 +73,7 @@ spec: image: {{ $.Values.global.image.name }} imagePullPolicy: Always name: {{ $.Values.global.app_name }}-{{ $processName }} - {{- if eq $processName "web" }} + {{- if hasKey $config "web" }} ports: {{- range $pdx, $port_map := $config.web.port_maps }} {{- if and (eq $port_map.scheme "https") (hasKey $mappings (printf "http-80-%.0f" $port_map.container_port)) }} @@ -143,3 +147,4 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/https-redirect-middleware.yaml b/plugins/scheduler-k3s/templates/chart/https-redirect-middleware.yaml index 20a3d4429..4a38d1291 100644 --- a/plugins/scheduler-k3s/templates/chart/https-redirect-middleware.yaml +++ b/plugins/scheduler-k3s/templates/chart/https-redirect-middleware.yaml @@ -1,5 +1,9 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + {{- if and $config.web.domains (eq $.Values.global.network.ingress_class "traefik") }} --- apiVersion: traefik.io/v1alpha1 @@ -22,3 +26,4 @@ spec: scheme: https permanent: true {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/ingress-route.yaml b/plugins/scheduler-k3s/templates/chart/ingress-route.yaml index 306e4a7a3..fb137204e 100644 --- a/plugins/scheduler-k3s/templates/chart/ingress-route.yaml +++ b/plugins/scheduler-k3s/templates/chart/ingress-route.yaml @@ -1,5 +1,9 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + {{- if and $config.web.domains (eq $.Values.global.network.ingress_class "traefik") }} {{- $mappings := dict }} {{- range $pdx, $port_map := $config.web.port_maps }} @@ -53,3 +57,4 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/ingress.yaml b/plugins/scheduler-k3s/templates/chart/ingress.yaml index 5530525f3..1b5cd1081 100644 --- a/plugins/scheduler-k3s/templates/chart/ingress.yaml +++ b/plugins/scheduler-k3s/templates/chart/ingress.yaml @@ -1,8 +1,12 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + {{- $routeToKeda := false }} -{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }} -{{- if and (.Capabilities.APIVersions.Has "http.keda.sh/v1alpha1") (and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http")) }} +{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }} +{{- if and ($.Capabilities.APIVersions.Has "http.keda.sh/v1alpha1") (and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http")) }} {{- $routeToKeda = true }} {{- end }} {{- end }} @@ -59,3 +63,4 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-http-scaled-object.yaml b/plugins/scheduler-k3s/templates/chart/keda-http-scaled-object.yaml index bd761642f..5907ead1e 100644 --- a/plugins/scheduler-k3s/templates/chart/keda-http-scaled-object.yaml +++ b/plugins/scheduler-k3s/templates/chart/keda-http-scaled-object.yaml @@ -1,7 +1,12 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} -{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }} -{{- if and (.Capabilities.APIVersions.Has "http.keda.sh/v1alpha1") (and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http")) }} +{{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + +{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }} +{{- if and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http") }} {{- $mappings := dict }} {{- range $pdx, $port_map := $config.web.port_maps }} {{- $mappings := set $mappings $port_map.name "true" }} @@ -51,3 +56,5 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-interceptor-proxy-service.yaml b/plugins/scheduler-k3s/templates/chart/keda-interceptor-proxy-service.yaml index c12d6411e..ade8549a2 100644 --- a/plugins/scheduler-k3s/templates/chart/keda-interceptor-proxy-service.yaml +++ b/plugins/scheduler-k3s/templates/chart/keda-interceptor-proxy-service.yaml @@ -1,7 +1,11 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} -{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }} {{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + +{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }} --- kind: Service apiVersion: v1 @@ -24,3 +28,4 @@ spec: externalName: keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml b/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml index 24e6ed5e1..3f37603ac 100644 --- a/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml +++ b/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml @@ -1,7 +1,11 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} -{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }} {{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + +{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }} --- apiVersion: keda.sh/v1alpha1 kind: ScaledObject @@ -42,3 +46,4 @@ spec: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-secret.yaml b/plugins/scheduler-k3s/templates/chart/keda-secret.yaml index 3e40bcc62..e8a3b7aa1 100644 --- a/plugins/scheduler-k3s/templates/chart/keda-secret.yaml +++ b/plugins/scheduler-k3s/templates/chart/keda-secret.yaml @@ -1,5 +1,5 @@ {{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} -{{- $config := index .Values.global.keda.authentications "AUTH_NAME" }} +{{- range $authName, $config := .Values.global.keda.authentications }} --- apiVersion: v1 kind: Secret @@ -21,3 +21,4 @@ data: {{- toYaml . | nindent 2 }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml b/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml index c39b94b0a..bf77542be 100644 --- a/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml +++ b/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml @@ -1,5 +1,5 @@ {{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} -{{- $config := index .Values.global.keda.authentications "AUTH_NAME" }} +{{- range $authName, $config := .Values.global.keda.authentications }} --- apiVersion: keda.sh/v1alpha1 kind: TriggerAuthentication @@ -26,3 +26,4 @@ spec: parameter: {{ $k }} {{- end }} {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/service.yaml b/plugins/scheduler-k3s/templates/chart/service.yaml index bf5d3d34b..8980597da 100644 --- a/plugins/scheduler-k3s/templates/chart/service.yaml +++ b/plugins/scheduler-k3s/templates/chart/service.yaml @@ -1,5 +1,9 @@ -{{- $processName := "PROCESS_NAME" }} -{{- $config := index .Values.processes "PROCESS_NAME" }} +{{- range $processName, $config := .Values.processes }} +{{- if not (hasKey $config "web") }} +# Skip {{ $processName }} as it doesn't have a web section +{{- continue }} +{{- end }} + --- apiVersion: v1 kind: Service @@ -28,3 +32,4 @@ spec: app.kubernetes.io/instance: {{ $.Values.global.app_name }}-{{ $processName }} app.kubernetes.io/name: {{ $processName }} app.kubernetes.io/part-of: {{ $.Values.global.app_name }} +{{- end }} diff --git a/plugins/scheduler-k3s/triggers.go b/plugins/scheduler-k3s/triggers.go index cb4c27e49..7c0a9f8c4 100644 --- a/plugins/scheduler-k3s/triggers.go +++ b/plugins/scheduler-k3s/triggers.go @@ -32,11 +32,50 @@ import ( "k8s.io/kubernetes/pkg/client/conditions" ) +// TriggerCorePostDeploy moves a configured kustomize root path to be in the app root dir +func TriggerCorePostDeploy(appName string) error { + return common.CorePostDeploy(common.CorePostDeployInput{ + AppName: appName, + Destination: common.GetAppDataDirectory("scheduler-k3s", appName), + PluginName: "scheduler-k3s", + ExtractedPaths: []common.CorePostDeployPath{ + {Path: "kustomization", IsDirectory: true}, + }, + }) + + return nil +} + +// TriggerCorePostExtract moves a configured kustomize root path to be in the app root dir +func TriggerCorePostExtract(appName string, sourceWorkDir string) error { + destination := common.GetAppDataDirectory("scheduler-k3s", appName) + kustomizeRootPath := getComputedKustomizeRootPath(appName) + return common.CorePostExtract(common.CorePostExtractInput{ + AppName: appName, + Destination: destination, + PluginName: "scheduler-k3s", + SourceWorkDir: sourceWorkDir, + ToExtract: []common.CorePostExtractToExtract{ + { + Path: kustomizeRootPath, + IsDirectory: true, + Name: "config/kustomize", + Destination: "kustomization", + }, + }, + }) +} + // TriggerInstall runs the install step for the scheduler-k3s plugin func TriggerInstall() error { if err := common.PropertySetup("scheduler-k3s"); err != nil { return fmt.Errorf("Unable to install the scheduler-k3s plugin: %s", err.Error()) } + + if err := common.SetupAppData("scheduler-k3s"); err != nil { + return err + } + return nil } @@ -63,6 +102,11 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { return nil } +// TriggerPostCreate creates the scheduler-k3s data directory +func TriggerPostCreate(appName string) error { + return common.CreateAppDataDirectory("scheduler-k3s", appName) +} + // TriggerPostDelete destroys the scheduler-k3s data for a given app container func TriggerPostDelete(appName string) error { dataErr := common.RemoveAppDataDirectory("scheduler-k3s", appName) @@ -266,10 +310,17 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e workingDir := common.GetWorkingDir(appName, image) - cronEntries, err := cron.FetchCronEntries(appName) + allCronEntries, err := cron.FetchCronEntries(cron.FetchCronEntriesInput{AppName: appName}) if err != nil { return fmt.Errorf("Error fetching cron entries: %w", err) } + // remove maintenance cron entries + cronEntries := []cron.TemplateCommand{} + for _, cronEntry := range allCronEntries { + if !cronEntry.Maintenance { + cronEntries = append(cronEntries, cronEntry) + } + } domains := []string{} if _, ok := processes["web"]; ok { @@ -361,7 +412,7 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e Processes: map[string]ProcessValues{}, } - for authName := range kedaValues.Authentications { + if len(kedaValues.Authentications) > 0 { templateFiles := []string{"keda-secret", "keda-trigger-authentication"} for _, templateName := range templateFiles { b, err := templates.ReadFile(fmt.Sprintf("templates/chart/%s.yaml", templateName)) @@ -369,9 +420,8 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e return fmt.Errorf("Error reading %s template: %w", templateName, err) } - filename := filepath.Join(chartDir, "templates", fmt.Sprintf("%s-%s.yaml", templateName, authName)) - contents := strings.ReplaceAll(string(b), "AUTH_NAME", authName) - err = os.WriteFile(filename, []byte(contents), os.FileMode(0644)) + filename := filepath.Join(chartDir, "templates", fmt.Sprintf("%s.yaml", templateName)) + err = os.WriteFile(filename, b, os.FileMode(0644)) if err != nil { return fmt.Errorf("Error writing %s template: %w", templateName, err) } @@ -528,9 +578,8 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e return fmt.Errorf("Error reading %s template: %w", templateName, err) } - filename := filepath.Join(chartDir, "templates", fmt.Sprintf("%s-%s.yaml", templateName, processType)) - contents := strings.ReplaceAll(string(b), "PROCESS_NAME", processType) - err = os.WriteFile(filename, []byte(contents), os.FileMode(0644)) + filename := filepath.Join(chartDir, "templates", fmt.Sprintf("%s.yaml", templateName)) + err = os.WriteFile(filename, b, os.FileMode(0644)) if err != nil { return fmt.Errorf("Error writing %s template: %w", templateName, err) } @@ -606,15 +655,16 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e Volumes: processVolumes, } values.Processes[cronEntry.ID] = processValues + } + if len(cronEntries) > 0 { b, err := templates.ReadFile("templates/chart/cron-job.yaml") if err != nil { return fmt.Errorf("Error reading cron job template: %w", err) } - cronFile := filepath.Join(chartDir, "templates", fmt.Sprintf("cron-job-%s.yaml", cronEntry.ID)) - contents := strings.ReplaceAll(string(b), "CRON_ID", cronEntry.ID) - err = os.WriteFile(cronFile, []byte(contents), os.FileMode(0644)) + cronFile := filepath.Join(chartDir, "templates", "cron-job.yaml") + err = os.WriteFile(cronFile, b, os.FileMode(0644)) if err != nil { return fmt.Errorf("Error writing cron job template: %w", err) } @@ -698,9 +748,15 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e } } + kustomizeRootPath := "" + if hasKustomizeDirectory(appName) { + kustomizeRootPath = getProcessSpecificKustomizeRootPath(appName) + } + common.LogInfo2(fmt.Sprintf("Installing %s", appName)) err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{ ChartPath: chartPath, + KustomizeRootPath: kustomizeRootPath, Namespace: namespace, ReleaseName: appName, RollbackOnFailure: allowRollbacks, @@ -1492,5 +1548,14 @@ func TriggerSchedulerStop(scheduler string, appName string) error { } } + // get all cronjobs for the app + err = clientset.SuspendCronJobs(ctx, SuspendCronJobsInput{ + Namespace: namespace, + LabelSelector: fmt.Sprintf("app.kubernetes.io/part-of=%s", appName), + }) + if err != nil { + return fmt.Errorf("Error suspending cron jobs: %w", err) + } + return nil } diff --git a/plugins/scheduler/go.mod b/plugins/scheduler/go.mod index 938db56c5..3312ef412 100644 --- a/plugins/scheduler/go.mod +++ b/plugins/scheduler/go.mod @@ -1,10 +1,9 @@ module github.com/dokku/dokku/plugins/scheduler -go 1.23.0 +go 1.24.0 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.6 ) @@ -13,7 +12,6 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/joho/godotenv v1.2.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/plugins/scheduler/go.sum b/plugins/scheduler/go.sum index 12803b5db..b61585913 100644 --- a/plugins/scheduler/go.sum +++ b/plugins/scheduler/go.sum @@ -10,8 +10,6 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -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/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= diff --git a/plugins/scheduler/triggers.go b/plugins/scheduler/triggers.go index 3d350e2db..a83ce8013 100644 --- a/plugins/scheduler/triggers.go +++ b/plugins/scheduler/triggers.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/config" ) // TriggerSchedulerDetect outputs a manually selected scheduler for the app @@ -36,30 +35,46 @@ func TriggerInstall() error { return nil } - globalScheduler := config.GetWithDefault("--global", "DOKKU_SCHEDULER", "") + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_SCHEDULER"}, + }) + globalScheduler := results.StdoutContents() if globalScheduler != "" { common.LogVerboseQuiet(fmt.Sprintf("Setting scheduler property 'selected' to %v", globalScheduler)) if err := common.PropertyWrite("scheduler", "--global", "selected", globalScheduler); err != nil { return err } - if err := config.UnsetMany("--global", []string{"DOKKU_SCHEDULER"}, false); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-unset", + Args: []string{"--global", "DOKKU_SCHEDULER"}, + }) + if err != nil { common.LogWarn(err.Error()) } } for _, appName := range apps { - scheduler := config.GetWithDefault(appName, "DOKKU_SCHEDULER", "") + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_SCHEDULER"}, + }) + scheduler := results.StdoutContents() if scheduler == "" { continue } - common.LogVerboseQuiet(fmt.Sprintf("Setting scheduler property 'selected' to %v", scheduler)) + common.LogVerboseQuiet(fmt.Sprintf("Setting %s scheduler property 'selected' to %v", appName, scheduler)) if err := common.PropertyWrite("scheduler", appName, "selected", scheduler); err != nil { return err } - if err := config.UnsetMany(appName, []string{"DOKKU_SCHEDULER"}, false); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-unset", + Args: []string{appName, "DOKKU_SCHEDULER"}, + }) + if err != nil { common.LogWarn(err.Error()) } } diff --git a/tests/apps/nodejs-express-noappjson/package.json b/tests/apps/nodejs-express-noappjson/package.json index 444351953..d6ab60955 100644 --- a/tests/apps/nodejs-express-noappjson/package.json +++ b/tests/apps/nodejs-express-noappjson/package.json @@ -2,9 +2,9 @@ "name": "node-example", "version": "0.0.1", "dependencies": { - "express": "4.21.x" + "express": "5.1.x" }, "engines": { - "node": "4.2.x" + "node": "18.x.x" } } diff --git a/tests/apps/nodejs-express/package.json b/tests/apps/nodejs-express/package.json index 444351953..d6ab60955 100644 --- a/tests/apps/nodejs-express/package.json +++ b/tests/apps/nodejs-express/package.json @@ -2,9 +2,9 @@ "name": "node-example", "version": "0.0.1", "dependencies": { - "express": "4.21.x" + "express": "5.1.x" }, "engines": { - "node": "4.2.x" + "node": "18.x.x" } } diff --git a/tests/apps/python/project2.toml b/tests/apps/python/project2.toml index 67df953e6..ff4dc30cf 100644 --- a/tests/apps/python/project2.toml +++ b/tests/apps/python/project2.toml @@ -10,7 +10,7 @@ uri = "./cnb/1" uri = "./cnb/1" [[build.buildpacks]] -uri = "gcr.io/paketo-buildpacks/python" +uri = "docker.io/paketobuildpacks/python" [[order.group]] -uri = "gcr.io/paketo-buildpacks/procfile" +uri = "docker.io/paketobuildpacks/procfile" diff --git a/tests/unit/caddy.bats b/tests/unit/caddy.bats index d48d41196..0155cda71 100644 --- a/tests/unit/caddy.bats +++ b/tests/unit/caddy.bats @@ -50,6 +50,34 @@ teardown() { assert_output_contains "python/http.server" } +@test "(caddy) custom label key" { + run /bin/bash -c "dokku builder-herokuish:set $TEST_APP allowed true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku proxy:set $TEST_APP caddy" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku caddy:set $TEST_APP label-key caddy_0" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"caddy_0\" }}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "$TEST_APP.${DOKKU_DOMAIN}:80" +} + @test "(caddy) multiple domains" { run /bin/bash -c "dokku proxy:set $TEST_APP caddy" echo "output: $output" diff --git a/tests/unit/cron.bats b/tests/unit/cron.bats index 097104af9..e22145aa7 100644 --- a/tests/unit/cron.bats +++ b/tests/unit/cron.bats @@ -121,7 +121,7 @@ teardown() { echo "echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries - run /bin/bash -c "dokku plugin:trigger cron-write" + run /bin/bash -c "dokku plugin:trigger scheduler-cron-write" echo "output: $output" echo "status: $status" assert_success @@ -136,7 +136,7 @@ teardown() { echo "echo '@daily;/bin/true;/var/log/dokku/log.log'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries - run /bin/bash -c "dokku plugin:trigger cron-write" + run /bin/bash -c "dokku plugin:trigger scheduler-cron-write" echo "output: $output" echo "status: $status" assert_success @@ -151,7 +151,7 @@ teardown() { echo "[[ \$1 == 'docker-local' ]] && echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries - run /bin/bash -c "dokku plugin:trigger cron-write" + run /bin/bash -c "dokku plugin:trigger scheduler-cron-write" echo "output: $output" echo "status: $status" assert_success @@ -166,7 +166,7 @@ teardown() { echo "[[ \$1 == 'kubernetes' ]] && echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries - run /bin/bash -c "dokku plugin:trigger cron-write" + run /bin/bash -c "dokku plugin:trigger scheduler-cron-write" echo "output: $output" echo "status: $status" assert_success diff --git a/tests/unit/domains.bats b/tests/unit/domains.bats index 24f0571d5..362131020 100644 --- a/tests/unit/domains.bats +++ b/tests/unit/domains.bats @@ -188,7 +188,7 @@ teardown() { assert_output_contains a--domain.with--hyphens } -@test "(domains) domains:clear" { +@test "(domains) domains:reset" { run /bin/bash -c "dokku domains:add $TEST_APP test.app.${DOKKU_DOMAIN}" echo "output: $output" echo "status: $status" @@ -199,7 +199,7 @@ teardown() { echo "status: $status" assert_success - run /bin/bash -c "dokku domains:clear $TEST_APP" + run /bin/bash -c "dokku domains:reset $TEST_APP" echo "output: $output" echo "status: $status" assert_success @@ -347,8 +347,8 @@ teardown() { echo "status: $status" assert_success - # run domains:clear in order to invoke default vhost creation - run /bin/bash -c "dokku --quiet domains:clear test.dokku.test" + # run domains:reset in order to invoke default vhost creation + run /bin/bash -c "dokku --quiet domains:reset test.dokku.test" echo "output: $output" echo "status: $status" assert_success diff --git a/tests/unit/ps-dockerfile-2.bats b/tests/unit/ps-dockerfile-2.bats index dd4cf314d..7a26fe212 100644 --- a/tests/unit/ps-dockerfile-2.bats +++ b/tests/unit/ps-dockerfile-2.bats @@ -171,3 +171,18 @@ teardown() { assert_success done } + +@test "(ps:scale) dockerfile unchanged process" { + run deploy_app dockerfile + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:scale $TEST_APP worker=2" + echo "output: $output" + echo "status: $status" + assert_output_contains "Scaling $TEST_APP processes: worker=2" + assert_output_contains "Deploying worker" + assert_output_contains "Deploying web" 0 + assert_success +} diff --git a/tests/unit/scheduler-k3s-3.bats b/tests/unit/scheduler-k3s-3.bats new file mode 100644 index 000000000..c6dba70c6 --- /dev/null +++ b/tests/unit/scheduler-k3s-3.bats @@ -0,0 +1,65 @@ +#!/usr/bin/env bats + +load test_helper + +TEST_APP="rdmtestapp" + +setup() { + uninstall_k3s || true + global_setup + dokku nginx:stop + export KUBECONFIG="/etc/rancher/k3s/k3s.yaml" +} + +teardown_() { + global_teardown + dokku nginx:start + uninstall_k3s || true +} + +@test "(scheduler-k3s) kustomize" { + if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then + skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN" + fi + + INGRESS_CLASS=nginx install_k3s + + run /bin/bash -c "dokku apps:create $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP inject_kustomization_yaml + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "kubectl get deployment $TEST_APP-web -o json | jq -r '.spec.replicas'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "3" +} + +inject_kustomization_yaml() { + local APP="$1" + local APP_REPO_DIR="$2" + [[ -z "$APP" ]] && local APP="$TEST_APP" + mkdir -p "$APP_REPO_DIR/config/kustomize" + touch "$APP_REPO_DIR/config/kustomize/kustomization.yaml" + cat <"$APP_REPO_DIR/config/kustomize/kustomization.yaml" +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- rendered.yaml +patches: +- patch: |- + - op: replace + path: /spec/replicas + value: 3 + target: + group: apps + version: v1 + kind: Deployment +EOF +}