diff --git a/docs/deployment/schedulers/k3s.md b/docs/deployment/schedulers/k3s.md index d3ff4f6a0..62b694dbc 100644 --- a/docs/deployment/schedulers/k3s.md +++ b/docs/deployment/schedulers/k3s.md @@ -5,10 +5,13 @@ ``` scheduler-k3s:annotations:set () [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear an annotation for a given app/process-type/resource-type combination +scheduler-k3s:autoscaling-auth:set [<--metadata key=value>...], Set or clear a scheduler-k3s autoscaling keda trigger authentication resource for an app +scheduler-k3s:autoscaling-auth:report [--format stdout|json] [--include-metadata] # Displays a scheduler-k3s autoscaling auth report for an app scheduler-k3s:cluster-add [ssh://user@host:port] # Adds a server node to a Dokku-managed cluster scheduler-k3s:cluster-list # Lists all nodes in a Dokku-managed cluster scheduler-k3s:cluster-remove [node-id] # Removes client node to a Dokku-managed cluster scheduler-k3s:initialize # Initializes a cluster +scheduler-k3s:labels:set () [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear a label for a given app/process-type/resource-type combination scheduler-k3s:report [] [] # Displays a scheduler-k3s report for one or more apps scheduler-k3s:set [|--global] () # Set or clear a scheduler-k3s property for an app or the scheduler scheduler-k3s:show-kubeconfig # Displays the kubeconfig for remote usage @@ -231,7 +234,9 @@ The default value may be set by passing an empty value for the option. dokku scheduler-k3s:set --global image-pull-secrets ``` -### Enabling letsencrypt integration +### SSL Certificates + +#### Enabling letsencrypt integration By default, letsencrypt is disabled and https port mappings are ignored. To enable, set the `letsencrypt-email-prod` or `letsencrypt-email-stag` property with the `--global` flag: @@ -245,7 +250,7 @@ dokku scheduler-k3s:set --global letsencrypt-email-stag automated@dokku.sh After enabling and rebuilding, all apps with an `http:80` port mapping will have a corresponding `https:443` added and ssl will be automatically enabled. All http requests will then be redirected to https. -### Customizing the letsencrypt server +#### Customizing the letsencrypt server The letsencrypt integration is set to the production letsencrypt server by default. This can be changed on an app-level by setting the `letsencrypt-server` property with the `scheduler-k3s:set` command @@ -350,6 +355,118 @@ dokku scheduler-k3s:annotations:set node-js-app label.key --resource-type deploy dokku scheduler-k3s:labels:set node-js-app label.key --resource-type deployment --process-type web ``` +### Autoscaling + +#### Workload Autoscaling + +> [!IMPORTANT] +> New as of 0.33.8 +> Users with older installations will need to manually install Keda. + +Autoscaling in k3s is managed by [Keda](https://keda.sh/), which integrates with a variety of external metric providers to allow for autoscaling application workloads. + +To enable autoscaling, use the `app.json` `formations.$PROCESS_TYPE.autoscaling` key to manage rules. In addition to the existing configuration used for process management, each process type in the `formations.$PROCESS_TYPE.autoscaling` key can have the following keys: + +- `min_quantity`: The minimum number of instances the application can run. If not specified, the `quantity` specified for the app is used. +- `max_quantity`: The maximum number of instances the application can run. If not specified, the higher value of `quantity` and the `min_quantity` is used. +- `polling_interval_seconds`: (default: 30) The interval to wait for polling each of the configured triggers +- `cooldown_seconds`: (default: 300) The number of seconds to wait in between each scaling event +- `triggers`: A list of autoscaling triggers. + +Autoscaling triggers are passed as is to Keda, and should match the configuration keda uses for a given [scaler](https://keda.sh/docs/2.13/scalers/). Below is an example for [datadog](https://keda.sh/docs/2.13/scalers/datadog/#example-2---driving-scale-directly): + +```json +{ + "formations": { + "web": { + "autoscaling": { + "min_quantity": 1, + "max_quantity": 10, + "triggers": [ + { + "name": "name-for-trigger", + "type": "datadog", + "metadata": { + "query": "per_second(sum:http.requests{service:myservice1}).rollup(max, 300))/180,per_second(sum:http.backlog{service:myservice1}).rollup(max, 300)/30", + "queryValue": "1", + "queryAggregator": "max" + } + } + ] + } + } + } +} +``` + +Each value in the `metadata` stanza can use the following interpolated strings: + +- `DOKKU_DEPLOYMENT_NAME`: The name of the deployment being scaled +- `DOKKU_PROCESS_TYPE`: The name of the process being scaled +- `DOKKU_APP_NAME`: The name of the app being scaled + +#### Workload Autoscaling Authentication + +Most Keda triggers require some form of authentication to query for data. In the Kubernetes API, they are represented by `TriggerAuthentication` and `ClusterTriggerAuthentication` resources. Dokku can manage these via the `scheduler-k3s:autoscaling-auth` commands, and includes generated resources with each helm release generated by a deploy. + +If no app-specific authentication is provided for a given trigger type, Dokku will fallback to any globally defined `ClusterTriggerAuthentication` resources. Autoscaling triggers within an app all share the same `TriggerAuthentication` resources, while `ClusterTriggerAuthentication` resources can be shared across all apps deployed by Dokku within a given cluster. + +##### Creating Authentication Resources + +Users can specify custom authentication resources directly via the Kubernetes api _or_ use the `scheduler-k3s:autoscaling-auth:set` command to create the resources in the Kubernetes cluster. + +```shell +dokku scheduler-k3s:autoscaling-auth:set $APP $TRIGGER --metadata apiKey=some-api-key --metadata appKey=some-app-key +``` + +For example, the following will configure the authentication for all datadog triggers on the specified app: + +```shell +dokku scheduler-k3s:autoscaling-auth:set node-js-app datadog --metadata apiKey=1234567890 --metadata appKey=asdfghjkl --metadata datadogSite=us5.datadoghq.com +``` + +After execution, Dokku will include the following resources for each specified trigger with the helm release generated on subsequent app deploys: + +- `Secret`: an Opaque `Secret` resource storing the authentication credentials +- `TriggerAuthentication`: A `TriggerAuthentication` resource that references the secret for use by triggers + +If the `--global` flag is specified instead of an app name, a custom helm chart is created on the fly with the above resources. + +##### Removing Authentication Resources + +To remove a configured authenticatin resource, run the `scheduler-k3s:autoscaling-auth:set` command with no metadata specified. Subsequent deploys will not include these resources. + +```shell +dokku scheduler-k3s:autoscaling-auth:set $APP $TRIGGER_TYPE +``` + +##### Displaying an Authentication Resource report + +To see a list of authentication resources managed by Dokku, run the `scheduler-k3s:autoscaling-auth:report` command. + +```shell +dokku scheduler-k3s:autoscaling-auth:report node-js-app +``` + +``` +====> $APP autoscaling-auth report + datadog: configured +``` + +By default, the report will not display configured metadata - making it safe to include in Dokku report output. To include metadata and their values, add the `--include-metadata` flag: + +```shell +dokku scheduler-k3s:autoscaling-auth:report node-js-app --include-metadata +``` + +``` +====> node-js-app autoscaling-auth report + Datadog: configured + Datadog apiKey: 1234567890 + Datadog appKey: asdfghjkl + Datadog datadogSite: us5.datadoghq.com +``` + ### Using kubectl remotely > [!WARNING] diff --git a/plugins/app-json/appjson.go b/plugins/app-json/appjson.go index cba952105..90fbfc3fd 100644 --- a/plugins/app-json/appjson.go +++ b/plugins/app-json/appjson.go @@ -3,10 +3,12 @@ package appjson import ( "encoding/json" "fmt" + "math" "os" "strings" "github.com/dokku/dokku/plugins/common" + "k8s.io/utils/ptr" ) var ( @@ -59,6 +61,9 @@ type CronCommand struct { // Formation is a struct that represents the scale for a process from an app.json file type Formation struct { + // Autoscaling is whether or not to enable autoscaling + Autoscaling *FormationAutoscaling `json:"autoscaling"` + // Quantity is the number of processes to run Quantity *int `json:"quantity"` @@ -66,6 +71,36 @@ type Formation struct { MaxParallel *int `json:"max_parallel"` } +// FormationAutoscaling is a struct that represents the autoscaling configuration for a process from an app.json file +type FormationAutoscaling struct { + // CoolDownSeconds is the number of seconds to wait before scaling again + CooldownPeriodSeconds *int `json:"cooldown_period_seconds,omitempty"` + + // MaxQuantity is the maximum number of processes to run + MaxQuantity *int `json:"max_quantity,omitempty"` + + // MinQuantity is the minimum number of processes to run + MinQuantity *int `json:"min_quantity,omitempty"` + + // PollingIntervalSeconds is the number of seconds to wait between autoscaling checks + PollingIntervalSeconds *int `json:"polling_interval_seconds,omitempty"` + + // Triggers is a list of triggers to use for autoscaling + Triggers []FormationAutoscalingTrigger `json:"triggers,omitempty"` +} + +// FormationAutoscalingTrigger is a struct that represents a single autoscaling trigger from an app.json file +type FormationAutoscalingTrigger struct { + // Name is the name of the trigger + Name string `json:"name,omitempty"` + + // Type is the type of the trigger + Type string `json:"type,omitempty"` + + // Metadata is a map of metadata to use for the trigger + Metadata map[string]string `json:"metadata,omitempty"` +} + // Healthcheck is a struct that represents a single healthcheck from an app.json file type Healthcheck struct { // Attempts is the number of attempts to make before considering a healthcheck failed @@ -181,3 +216,45 @@ func GetAppJSON(appName string) (AppJSON, error) { return appJSON, nil } + +func GetAutoscalingConfig(appName string, processType string, replicas int) (FormationAutoscaling, bool, error) { + appJSON, err := GetAppJSON(appName) + if err != nil { + return FormationAutoscaling{}, false, err + } + + common.LogWarn(fmt.Sprintf("appJSON: %v", appJSON)) + + formation, ok := appJSON.Formation[processType] + if !ok { + return FormationAutoscaling{}, false, nil + } + + if formation.Autoscaling == nil { + return FormationAutoscaling{}, false, nil + } + + autoscaling := *formation.Autoscaling + if autoscaling.CooldownPeriodSeconds == nil { + autoscaling.CooldownPeriodSeconds = ptr.To(300) + } + + if autoscaling.MinQuantity == nil { + autoscaling.MinQuantity = ptr.To(replicas) + } + + if autoscaling.MaxQuantity == nil { + defaultValue := math.Max(float64(replicas), float64(*autoscaling.MinQuantity)) + autoscaling.MaxQuantity = ptr.To(int(defaultValue)) + } + + if autoscaling.PollingIntervalSeconds == nil { + autoscaling.PollingIntervalSeconds = ptr.To(30) + } + + if len(autoscaling.Triggers) == 0 { + return FormationAutoscaling{}, false, nil + } + + return autoscaling, true, nil +} diff --git a/plugins/app-json/go.mod b/plugins/app-json/go.mod index 3b37ad66b..8ffa9aa50 100644 --- a/plugins/app-json/go.mod +++ b/plugins/app-json/go.mod @@ -7,6 +7,7 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/spf13/pflag v1.0.5 golang.org/x/sync v0.6.0 + k8s.io/utils v0.0.0-20240102154912-e7106e64919e ) require ( diff --git a/plugins/app-json/go.sum b/plugins/app-json/go.sum index ecf8b6528..6131c1424 100644 --- a/plugins/app-json/go.sum +++ b/plugins/app-json/go.sum @@ -4,8 +4,9 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+Bu github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -95,3 +96,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= diff --git a/plugins/common/properties.go b/plugins/common/properties.go index 3b131b4f3..f0f1c23d2 100644 --- a/plugins/common/properties.go +++ b/plugins/common/properties.go @@ -138,6 +138,40 @@ func PropertyGetAll(pluginName string, appName string) (map[string]string, error return properties, nil } +// PropertyGetAllByPrefix returns a map of all properties for a given app with a specified prefix +func PropertyGetAllByPrefix(pluginName string, appName string, prefix string) (map[string]string, error) { + properties := make(map[string]string) + pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName) + + fi, err := os.Stat(pluginAppConfigRoot) + if err != nil { + return properties, nil + } + + if !fi.IsDir() { + return properties, errors.New("Specified property path is not a directory") + } + + files, err := os.ReadDir(pluginAppConfigRoot) + if err != nil { + return properties, err + } + + for _, file := range files { + if file.IsDir() { + continue + } + property := file.Name() + if !strings.HasPrefix(property, prefix) { + continue + } + + properties[property] = PropertyGet(pluginName, appName, property) + } + + return properties, nil +} + // PropertyGetDefault returns the value for a given property with a specified default value func PropertyGetDefault(pluginName, appName, property, defaultValue string) (val string) { if !PropertyExists(pluginName, appName, property) { diff --git a/plugins/cron/go.mod b/plugins/cron/go.mod index b37f672ad..7fab44cd3 100644 --- a/plugins/cron/go.mod +++ b/plugins/cron/go.mod @@ -30,6 +30,7 @@ require ( golang.org/x/crypto v0.21.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.18.0 // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect ) replace github.com/dokku/dokku/plugins/app-json => ../app-json diff --git a/plugins/cron/go.sum b/plugins/cron/go.sum index d84c69cbd..3dad92380 100644 --- a/plugins/cron/go.sum +++ b/plugins/cron/go.sum @@ -4,8 +4,9 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+Bu github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -107,5 +108,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= diff --git a/plugins/scheduler-docker-local/go.mod b/plugins/scheduler-docker-local/go.mod index 1e950c939..db86c77b1 100644 --- a/plugins/scheduler-docker-local/go.mod +++ b/plugins/scheduler-docker-local/go.mod @@ -29,6 +29,7 @@ require ( github.com/ryanuber/columnize v2.1.2+incompatible // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/sys v0.18.0 // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect mvdan.cc/sh/v3 v3.8.0 // indirect ) diff --git a/plugins/scheduler-docker-local/go.sum b/plugins/scheduler-docker-local/go.sum index 18f4d85be..c231b0109 100644 --- a/plugins/scheduler-docker-local/go.sum +++ b/plugins/scheduler-docker-local/go.sum @@ -4,8 +4,9 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+Bu github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -105,5 +106,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= diff --git a/plugins/scheduler-k3s/Makefile b/plugins/scheduler-k3s/Makefile index c150d6aa1..0efc49c33 100644 --- a/plugins/scheduler-k3s/Makefile +++ b/plugins/scheduler-k3s/Makefile @@ -1,4 +1,4 @@ -SUBCOMMANDS = subcommands/annotations:set subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall +SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove 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-deploy triggers/scheduler-enter triggers/scheduler-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 3b18c0540..df3decc37 100644 --- a/plugins/scheduler-k3s/functions.go +++ b/plugins/scheduler-k3s/functions.go @@ -1,7 +1,9 @@ package scheduler_k3s import ( + "bytes" "context" + "encoding/base64" "errors" "fmt" "net" @@ -10,6 +12,7 @@ import ( "sort" "strconv" "strings" + "text/template" "time" appjson "github.com/dokku/dokku/plugins/app-json" @@ -27,6 +30,7 @@ import ( "k8s.io/client-go/tools/remotecommand" "k8s.io/kubectl/pkg/util/term" "k8s.io/kubernetes/pkg/client/conditions" + "k8s.io/utils/ptr" "mvdan.cc/sh/v3/shell" ) @@ -118,6 +122,118 @@ type WaitForPodToExistInput struct { LabelSelector string } +// applyKedaClusterTriggerAuthentications applies keda cluster trigger authentications chart to the cluster +func applyKedaClusterTriggerAuthentications(ctx context.Context, triggerType string, metadata map[string]string) error { + chartDir, err := os.MkdirTemp("", "keda-cluster-trigger-authentications-chart-") + if err != nil { + return fmt.Errorf("Error creating keda-cluster-trigger-authentications chart directory: %w", err) + } + defer os.RemoveAll(chartDir) + + // create the chart.yaml + chart := &Chart{ + ApiVersion: "v2", + AppVersion: "1.0.0", + Icon: "https://dokku.com/assets/dokku-logo.svg", + Name: fmt.Sprintf("keda-cluster-trigger-authentications-%s", triggerType), + Version: "0.0.1", + } + + err = writeYaml(WriteYamlInput{ + Object: chart, + Path: filepath.Join(chartDir, "Chart.yaml"), + }) + if err != nil { + return fmt.Errorf("Error writing keda-cluster-trigger-authentications chart: %w", err) + } + + // create the values.yaml + values := ClusterKedaValues{ + Secrets: map[string]string{}, + Type: triggerType, + } + + for key, value := range metadata { + values.Secrets[key] = base64.StdEncoding.EncodeToString([]byte(value)) + } + + if err := os.MkdirAll(filepath.Join(chartDir, "templates"), os.FileMode(0755)); err != nil { + return fmt.Errorf("Error creating keda-cluster-trigger-authentications chart templates directory: %w", err) + } + + err = writeYaml(WriteYamlInput{ + Object: values, + Path: filepath.Join(chartDir, "values.yaml"), + }) + if err != nil { + return fmt.Errorf("Error writing chart: %w", err) + } + + templateFiles := []string{"keda-cluster-trigger-authentication", "keda-cluster-secret"} + for _, template := range templateFiles { + b, err := templates.ReadFile(fmt.Sprintf("templates/chart/%s.yaml", template)) + if err != nil { + return fmt.Errorf("Error reading %s template: %w", template, err) + } + + filename := filepath.Join(chartDir, "templates", fmt.Sprintf("%s.yaml", template)) + err = os.WriteFile(filename, b, os.FileMode(0644)) + if err != nil { + return fmt.Errorf("Error writing %s template: %w", template, err) + } + + if os.Getenv("DOKKU_TRACE") == "1" { + common.CatFile(filename) + } + } + + b, err := templates.ReadFile("templates/chart/_helpers.tpl") + if err != nil { + return fmt.Errorf("Error reading _helpers template: %w", err) + } + + helpersFile := filepath.Join(chartDir, "templates", "_helpers.tpl") + err = os.WriteFile(helpersFile, b, os.FileMode(0644)) + if err != nil { + return fmt.Errorf("Error writing _helpers template: %w", err) + } + + if os.Getenv("DOKKU_TRACE") == "1" { + common.CatFile(helpersFile) + } + + // install the chart + helmAgent, err := NewHelmAgent("keda", DeployLogPrinter) + if err != nil { + return fmt.Errorf("Error creating helm agent: %w", err) + } + + chartPath, err := filepath.Abs(chartDir) + if err != nil { + return fmt.Errorf("Error getting chart path: %w", err) + } + + timeoutDuration, err := time.ParseDuration("300s") + if err != nil { + return fmt.Errorf("Error parsing deploy timeout duration: %w", err) + } + + err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{ + ChartPath: chartPath, + Namespace: "keda", + ReleaseName: fmt.Sprintf("keda-cluster-trigger-authentications-%s", triggerType), + RollbackOnFailure: true, + Timeout: timeoutDuration, + }) + if err != nil { + return fmt.Errorf("Error installing keda-cluster-trigger-authentications-%s chart: %w", triggerType, err) + } + + common.LogInfo1Quiet(fmt.Sprintf("Applied keda-cluster-trigger-authentications-%s chart", triggerType)) + + return nil +} + func applyClusterIssuers(ctx context.Context) error { chartDir, err := os.MkdirTemp("", "cluster-issuer-chart-") if err != nil { @@ -395,6 +511,24 @@ func getAnnotations(appName string, processType string) (ProcessAnnotations, err } annotations.JobAnnotations = jobAnnotations + kedaScalingObjectAnnotations, err := getAnnotation(appName, processType, "keda_scaled_object") + if err != nil { + return annotations, err + } + annotations.KedaScalingObjectAnnotations = kedaScalingObjectAnnotations + + kedaSecretAnnotations, err := getAnnotation(appName, processType, "keda_secret") + if err != nil { + return annotations, err + } + annotations.KedaSecretAnnotations = kedaSecretAnnotations + + kedaTriggerAuthenticationAnnotations, err := getAnnotation(appName, processType, "keda_trigger_authentication") + if err != nil { + return annotations, err + } + annotations.KedaTriggerAuthenticationAnnotations = kedaTriggerAuthenticationAnnotations + podAnnotations, err := getAnnotation(appName, processType, "pod") if err != nil { return annotations, err @@ -434,6 +568,147 @@ func getAnnotations(appName string, processType string) (ProcessAnnotations, err return annotations, nil } +// GetAutoscalingInput contains all the information needed to get autoscaling config +type GetAutoscalingInput struct { + // AppName is the name of the app + AppName string + + // ProcessType is the process type + ProcessType string + + // Replicas is the number of replicas + Replicas int + + // KedaValues is the keda values + KedaValues GlobalKedaValues +} + +// getAutoscaling retrieves autoscaling config for a given app and process type +func getAutoscaling(input GetAutoscalingInput) (ProcessAutoscaling, error) { + config, ok, err := appjson.GetAutoscalingConfig(input.AppName, input.ProcessType, input.Replicas) + if err != nil { + common.LogWarn(fmt.Sprintf("Error getting autoscaling config for %s: %v", input.AppName, err)) + return ProcessAutoscaling{}, err + } + + if !ok { + common.LogWarn(fmt.Sprintf("No autoscaling config found for %s", input.AppName)) + return ProcessAutoscaling{}, nil + } + + replacements := map[string]string{ + "APP_NAME": input.AppName, + "PROCESS_TYPE": input.ProcessType, + "DEPLOYMENT_NAME": fmt.Sprintf("%s-%s", input.AppName, input.ProcessType), + } + + triggers := []ProcessAutoscalingTrigger{} + for _, trigger := range config.Triggers { + metadata := map[string]string{} + for key, value := range trigger.Metadata { + tmpl, err := template.New("").Delims("[[", "]]").Parse(value) + if err != nil { + return ProcessAutoscaling{}, fmt.Errorf("Error parsing autoscaling trigger metadata: %w", err) + } + + var output bytes.Buffer + if err := tmpl.Execute(&output, replacements); err != nil { + return ProcessAutoscaling{}, fmt.Errorf("Error executing autoscaling trigger metadata template: %w", err) + } + metadata[key] = output.String() + } + + trigger := ProcessAutoscalingTrigger{ + Name: trigger.Name, + Type: trigger.Type, + Metadata: metadata, + } + + if auth, ok := input.KedaValues.Authentications[trigger.Type]; ok { + trigger.AuthenticationRef = &ProcessAutoscalingTriggerAuthenticationRef{ + Name: auth.Name, + Kind: string(auth.Kind), + } + } else if auth, ok := input.KedaValues.GlobalAuthentications[trigger.Type]; ok { + trigger.AuthenticationRef = &ProcessAutoscalingTriggerAuthenticationRef{ + Name: auth.Name, + Kind: string(auth.Kind), + } + } + + triggers = append(triggers, trigger) + } + + autoscaling := ProcessAutoscaling{ + CooldownPeriodSeconds: ptr.Deref(config.CooldownPeriodSeconds, 300), + Enabled: len(triggers) > 0, + MaxReplicas: ptr.Deref(config.MaxQuantity, 0), + MinReplicas: ptr.Deref(config.MinQuantity, 0), + PollingIntervalSeconds: ptr.Deref(config.PollingIntervalSeconds, 30), + Triggers: triggers, + Type: "keda", + } + + return autoscaling, nil +} + +// getKedaValues retrieves keda values for a given app and process type +func getKedaValues(ctx context.Context, clientset KubernetesClient, appName string) (GlobalKedaValues, error) { + properties, err := common.PropertyGetAllByPrefix("scheduler-k3s", appName, TriggerAuthPropertyPrefix) + if err != nil { + return GlobalKedaValues{}, fmt.Errorf("Error getting trigger-auth properties: %w", err) + } + + auths := map[string]KedaAuthentication{} + for key, value := range properties { + parts := strings.SplitN(strings.TrimPrefix(key, TriggerAuthPropertyPrefix), ".", 2) + if len(parts) != 2 { + return GlobalKedaValues{}, fmt.Errorf("Invalid trigger-auth property format: %s", key) + } + + authType := parts[0] + secretKey := parts[1] + if len(secretKey) == 0 { + return GlobalKedaValues{}, fmt.Errorf("Invalid trigger-auth property format: %s", key) + } + + if _, ok := auths[authType]; !ok { + auths[authType] = KedaAuthentication{ + Name: fmt.Sprintf("%s-%s", appName, authType), + Type: authType, + Kind: KedaAuthenticationKind_TriggerAuthentication, + Secrets: make(map[string]string), + } + } + + auths[authType].Secrets[secretKey] = base64.StdEncoding.EncodeToString([]byte(value)) + } + + items, err := clientset.ListClusterTriggerAuthentications(ctx, ListClusterTriggerAuthenticationsInput{}) + if err != nil { + return GlobalKedaValues{}, fmt.Errorf("Error listing cluster trigger authentications: %w", err) + } + + globalAuths := map[string]KedaAuthentication{} + for _, item := range items { + if !strings.HasPrefix(item.Name, "global-auth-") { + continue + } + + authType := strings.TrimPrefix(item.Name, "global-auth-") + globalAuths[authType] = KedaAuthentication{ + Name: item.Name, + Kind: KedaAuthenticationKind_ClusterTriggerAuthentication, + Type: authType, + } + } + + return GlobalKedaValues{ + Authentications: auths, + GlobalAuthentications: globalAuths, + }, nil +} + // getGlobalAnnotations retrieves global annotations for a given app func getGlobalAnnotations(appName string) (ProcessAnnotations, error) { return getAnnotations(appName, GlobalProcessType) diff --git a/plugins/scheduler-k3s/go.mod b/plugins/scheduler-k3s/go.mod index 31c182908..3d7e4d9bf 100644 --- a/plugins/scheduler-k3s/go.mod +++ b/plugins/scheduler-k3s/go.mod @@ -10,10 +10,11 @@ require ( github.com/dokku/dokku/plugins/cron v0.0.0-00010101000000-000000000000 github.com/dokku/dokku/plugins/nginx-vhosts v0.0.0-00010101000000-000000000000 github.com/fatih/color v1.16.0 - github.com/go-openapi/jsonpointer v0.19.6 + github.com/go-openapi/jsonpointer v0.20.2 github.com/go-resty/resty/v2 v2.11.0 github.com/gofrs/flock v0.8.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 + github.com/kedacore/keda/v2 v2.13.0 github.com/ryanuber/columnize v2.1.2+incompatible github.com/spf13/pflag v1.0.5 github.com/traefik/traefik/v2 v2.10.7 @@ -40,7 +41,7 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -58,41 +59,45 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.11.2 // indirect + github.com/evanphx/json-patch v5.8.1+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.8.1 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/expr-lang/expr v1.15.8 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-acme/lego/v4 v4.14.0 // indirect - github.com/go-errors/errors v1.4.2 // 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/v3 v3.0.1 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.22.7 // 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.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.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.3.1 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.13 // 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/joho/godotenv v1.2.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.1 // indirect + github.com/klauspost/compress v1.17.4 // 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 @@ -101,8 +106,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect github.com/melbahja/goph v1.4.0 // indirect github.com/miekg/dns v1.1.55 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -125,40 +129,44 @@ require ( 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.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rubenv/sql-migrate v1.5.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/traefik/paerser v0.2.0 // 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/contrib/instrumentation/net/http/otelhttp v0.46.0 // indirect - go.opentelemetry.io/otel v1.20.0 // indirect - go.opentelemetry.io/otel/metric v1.20.0 // indirect - go.opentelemetry.io/otel/trace v1.20.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect + go.starlark.net v0.0.0-20231121155337-90ade8b19d09 // indirect golang.org/x/crypto v0.21.0 // indirect + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.17.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/grpc v1.60.1 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/evanphx/json-patch.v5 v5.8.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apiextensions-apiserver v0.29.0 // indirect @@ -166,14 +174,16 @@ require ( k8s.io/cli-runtime v0.29.0 // indirect k8s.io/component-base v0.29.0 // indirect k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 // indirect + knative.dev/pkg v0.0.0-20240116073220-b488e7be5902 // indirect oras.land/oras-go v1.2.4 // indirect + sigs.k8s.io/controller-runtime v0.16.3 // indirect sigs.k8s.io/gateway-api v0.8.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // 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.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace github.com/dokku/dokku/plugins/app-json => ../app-json @@ -185,3 +195,5 @@ replace github.com/dokku/dokku/plugins/config => ../config replace github.com/dokku/dokku/plugins/cron => ../cron replace github.com/dokku/dokku/plugins/nginx-vhosts => ../nginx-vhosts + +replace github.com/joho/godotenv => github.com/joho/godotenv v1.2.0 diff --git a/plugins/scheduler-k3s/go.sum b/plugins/scheduler-k3s/go.sum index 763f9129f..6486f8292 100644 --- a/plugins/scheduler-k3s/go.sum +++ b/plugins/scheduler-k3s/go.sum @@ -1,9 +1,7 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 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= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= @@ -31,8 +29,8 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhs 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-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +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= @@ -47,17 +45,12 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXe github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cert-manager/cert-manager v1.13.3 h1:3R4G0RI7K0OkTZhWlVOC5SGZMYa2NwqmQJoyKydrz/M= github.com/cert-manager/cert-manager v1.13.3/go.mod h1:BM2+Pt/NmSv1Zr25/MHv6BgIEF9IUxA1xAjp80qkxgc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= @@ -71,7 +64,6 @@ github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= @@ -100,14 +92,16 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 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.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= +github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.8.1+incompatible h1:2toJaoe7/rNa1zpeQx0UnVEjqk6z2ecyA20V/zg8vTU= +github.com/evanphx/json-patch v5.8.1+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.8.1 h1:iPEdwg0XayoS+E7Mth9JxwUtOgyVxnDTXHtKhZPlZxA= +github.com/evanphx/json-patch/v5 v5.8.1/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.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI= +github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -116,10 +110,12 @@ github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6 github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= 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.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-acme/lego/v4 v4.14.0 h1:/skZoRHgVh0d2RK7l1g3Ch8HqeqP9LB8ZEjLdGEpcDE= github.com/go-acme/lego/v4 v4.14.0/go.mod h1:zjmvNCDLGz7GrC1OqdVpVmZFKSRabEDtWbdzmcpBsGo= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +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/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= @@ -128,20 +124,24 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 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.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +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.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= +github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -158,20 +158,13 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j 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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 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.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= @@ -180,12 +173,8 @@ 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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -193,20 +182,20 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN 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-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= -github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 h1:dHLYa5D8/Ta0aLR2XcPsrkpAgGeFs6thhMcQK0oQ0n8= +github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= 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/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.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/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= 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= @@ -222,8 +211,8 @@ github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.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.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +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= @@ -241,19 +230,18 @@ github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwS 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/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.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g= -github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= @@ -278,14 +266,12 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 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.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +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/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= 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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -324,8 +310,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m 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/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -355,22 +341,24 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz 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.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= 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.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= 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.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= 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.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= -github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +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/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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -390,16 +378,14 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx 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.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.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 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/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.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -407,9 +393,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV 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.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/traefik/paerser v0.2.0 h1:zqCLGSXoNlcBd+mzqSCLjon/I6phqIjeJL2xFB2ysgQ= @@ -436,16 +419,22 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1 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/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0/go.mod h1:HyABWq60Uy1kjJSa2BVOxUVao8Cdick5AWSKPutqy6U= -go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= -go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= -go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= -go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= -go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= -go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= -go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +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.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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -458,23 +447,16 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= 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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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= @@ -488,10 +470,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -501,7 +481,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -526,7 +505,6 @@ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.0.0-20220526004731-065cf7ba2467/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= @@ -534,23 +512,20 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 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 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 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= @@ -562,36 +537,24 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +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/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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/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= @@ -601,15 +564,12 @@ 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.0/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= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= @@ -626,27 +586,31 @@ k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 h1:avRdiaB03v88Mfvum2S3BBwkNuTlmuar4LlfO9Hajko= +k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022/go.mod h1:sIV51WBTkZrlGOJMCDZDA1IaPBUDTulPpD4y7oe038k= k8s.io/kubectl v0.29.0 h1:Oqi48gXjikDhrBF67AYuZRTcJV4lg2l42GmvsP7FmYI= k8s.io/kubectl v0.29.0/go.mod h1:0jMjGWIcMIQzmUaMgAzhSELv5WtHo2a8pq67DtviAJs= k8s.io/kubernetes v1.29.1 h1:fxJFVb8uqbYZDYHpwIsAndBQs360cQGb0xa1gYFh3fo= k8s.io/kubernetes v1.29.1/go.mod h1:xZPKU0yO0CBbLTnbd+XGyRmmtmaVuJykDb8gNCkeeUE= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/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.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= +sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= sigs.k8s.io/gateway-api v0.8.0 h1:isQQ3Jx2qFP7vaA3ls0846F0Amp9Eq14P08xbSwVbQg= sigs.k8s.io/gateway-api v0.8.0/go.mod h1:okOnjPNBFbIS/Rw9kAhuIUaIkLhTKEu+ARIuXk2dgaM= 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.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +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.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/plugins/scheduler-k3s/k8s.go b/plugins/scheduler-k3s/k8s.go index 556d8d4ab..f7f13245e 100644 --- a/plugins/scheduler-k3s/k8s.go +++ b/plugins/scheduler-k3s/k8s.go @@ -7,6 +7,7 @@ import ( "github.com/dokku/dokku/plugins/common" "github.com/go-openapi/jsonpointer" + kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" appsv1 "k8s.io/api/apps/v1" autoscalingv1 "k8s.io/api/autoscaling/v1" batchv1 "k8s.io/api/batch/v1" @@ -15,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -35,6 +37,9 @@ type KubernetesClient struct { // Client is the Kubernetes client Client kubernetes.Clientset + // DynamicClient is the Kubernetes dynamic client + DynamicClient dynamic.Interface + // KubeConfigPath is the path to the Kubernetes config KubeConfigPath string @@ -72,8 +77,14 @@ func NewKubernetesClient() (KubernetesClient, error) { return KubernetesClient{}, err } + dynamicClient, err := dynamic.NewForConfig(restConf) + if err != nil { + return KubernetesClient{}, err + } + return KubernetesClient{ Client: *client, + DynamicClient: dynamicClient, KubeConfigPath: kubeconfigPath, RestConfig: *restConf, RestClient: restClient, @@ -337,6 +348,44 @@ func (k KubernetesClient) LabelNode(ctx context.Context, input LabelNodeInput) e return nil } +// ListClusterTriggerAuthenticationsInput contains all the information needed to list Kubernetes trigger authentications +type ListClusterTriggerAuthenticationsInput struct { + // Namespace is the Kubernetes namespace + Namespace string + + // LabelSelector is the Kubernetes label selector + LabelSelector string +} + +// ListClusterTriggerAuthentications lists Kubernetes trigger authentications +func (k KubernetesClient) ListClusterTriggerAuthentications(ctx context.Context, input ListClusterTriggerAuthenticationsInput) ([]kedav1alpha1.ClusterTriggerAuthentication, error) { + listOptions := metav1.ListOptions{LabelSelector: input.LabelSelector} + + gvr := schema.GroupVersionResource{ + Group: "keda.sh", + Version: "v1alpha1", + Resource: "clustertriggerauthentications", + } + + response, err := k.DynamicClient.Resource(gvr).Namespace(input.Namespace).List(ctx, listOptions) + if err != nil { + return []kedav1alpha1.ClusterTriggerAuthentication{}, err + } + + triggerAuthentications := []kedav1alpha1.ClusterTriggerAuthentication{} + for _, triggerAuthentication := range response.Items { + var ta kedav1alpha1.ClusterTriggerAuthentication + err := runtime.DefaultUnstructuredConverter.FromUnstructured(triggerAuthentication.Object, &ta) + if err != nil { + return []kedav1alpha1.ClusterTriggerAuthentication{}, err + } + + triggerAuthentications = append(triggerAuthentications, ta) + } + + return triggerAuthentications, nil +} + // ListCronJobsInput contains all the information needed to list Kubernetes cron jobs type ListCronJobsInput struct { // LabelSelector is the Kubernetes label selector @@ -451,6 +500,44 @@ func (k KubernetesClient) ListPods(ctx context.Context, input ListPodsInput) ([] return podList.Items, err } +// ListTriggerAuthenticationsInput contains all the information needed to list Kubernetes trigger authentications +type ListTriggerAuthenticationsInput struct { + // Namespace is the Kubernetes namespace + Namespace string + + // LabelSelector is the Kubernetes label selector + LabelSelector string +} + +// ListTriggerAuthentications lists Kubernetes trigger authentications +func (k KubernetesClient) ListTriggerAuthentications(ctx context.Context, input ListTriggerAuthenticationsInput) ([]kedav1alpha1.TriggerAuthentication, error) { + listOptions := metav1.ListOptions{LabelSelector: input.LabelSelector} + + gvr := schema.GroupVersionResource{ + Group: "keda.sh", + Version: "v1alpha1", + Resource: "triggerauthentications", + } + + response, err := k.DynamicClient.Resource(gvr).Namespace(input.Namespace).List(ctx, listOptions) + if err != nil { + return []kedav1alpha1.TriggerAuthentication{}, err + } + + triggerAuthentications := []kedav1alpha1.TriggerAuthentication{} + for _, triggerAuthentication := range response.Items { + var ta kedav1alpha1.TriggerAuthentication + err := runtime.DefaultUnstructuredConverter.FromUnstructured(triggerAuthentication.Object, &ta) + if err != nil { + return []kedav1alpha1.TriggerAuthentication{}, err + } + + triggerAuthentications = append(triggerAuthentications, ta) + } + + return triggerAuthentications, nil +} + // ScaleDeploymentInput contains all the information needed to scale a Kubernetes deployment type ScaleDeploymentInput struct { // Name is the Kubernetes deployment name diff --git a/plugins/scheduler-k3s/report.go b/plugins/scheduler-k3s/report.go index 2e25445df..fd388c067 100644 --- a/plugins/scheduler-k3s/report.go +++ b/plugins/scheduler-k3s/report.go @@ -1,6 +1,9 @@ package scheduler_k3s import ( + "fmt" + "strings" + "github.com/dokku/dokku/plugins/common" ) @@ -45,6 +48,37 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { return common.ReportSingleApp("scheduler-k3s", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) } +// ReportAutoscalingAuthSingleApp is an internal function that displays the scheduler-k3s autoscaling-auth report for one app +func ReportAutoscalingAuthSingleApp(appName string, format string, includeMetadata bool) error { + properties, err := common.PropertyGetAllByPrefix("scheduler-k3s", appName, TriggerAuthPropertyPrefix) + if err != nil { + return fmt.Errorf("Unable to get property list: %w", err) + } + + infoFlags := map[string]string{} + for key, value := range properties { + metadataKey := strings.TrimPrefix(key, TriggerAuthPropertyPrefix) + authType := strings.SplitN(metadataKey, ".", 2)[0] + if authType == "" { + continue + } + + infoFlags[authType] = "configured" + if includeMetadata { + infoFlags[strings.ReplaceAll(metadataKey, ".", "-")] = value + } + } + + flagKeys := []string{} + for flagKey := range infoFlags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + return common.ReportSingleApp("scheduler-k3s", appName, "", infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + func reportComputedDeployTimeout(appName string) string { return getComputedDeployTimeout(appName) } diff --git a/plugins/scheduler-k3s/scheduler_k3s.go b/plugins/scheduler-k3s/scheduler_k3s.go index 39ce66f11..70dec17f5 100644 --- a/plugins/scheduler-k3s/scheduler_k3s.go +++ b/plugins/scheduler-k3s/scheduler_k3s.go @@ -5,6 +5,7 @@ import ( "sync" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" traefikv1alpha1 "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefikio/v1alpha1" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -45,6 +46,7 @@ const DefaultIngressClass = "traefik" const GlobalProcessType = "--global" const KubeConfigPath = "/etc/rancher/k3s/k3s.yaml" const DefaultKubeContext = "" +const TriggerAuthPropertyPrefix = "trigger-auth." var ( runtimeScheme = runtime.NewScheme() @@ -160,5 +162,6 @@ func init() { _ = certmanagerv1.AddToScheme(runtimeScheme) _ = corev1.AddToScheme(runtimeScheme) _ = traefikv1alpha1.AddToScheme(runtimeScheme) + _ = kedav1alpha1.AddToScheme(runtimeScheme) }) } diff --git a/plugins/scheduler-k3s/src/commands/commands.go b/plugins/scheduler-k3s/src/commands/commands.go index 6eb64640a..702c3ba96 100644 --- a/plugins/scheduler-k3s/src/commands/commands.go +++ b/plugins/scheduler-k3s/src/commands/commands.go @@ -17,11 +17,13 @@ Manage scheduler-k3s settings for an app Additional commands:` helpContent = ` + scheduler-k3s:autoscaling-auth:set [<--metadata key=value>...], Set or clear a scheduler-k3s autoscaling keda trigger authentication resource for an app scheduler-k3s:annotations:set () [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear an annotation for a given app/process-type/resource-type combination scheduler-k3s:cluster-add [--insecure-allow-unknown-hosts] [--server-ip SERVER_IP] [--taint-scheduling] , Adds a server node to a Dokku-managed cluster scheduler-k3s:cluster-list [--format json|stdout], Lists all nodes in a Dokku-managed cluster scheduler-k3s:cluster-remove [node-id], Removes client node to a Dokku-managed cluster scheduler-k3s:initialize [--server-ip SERVER_IP] [--taint-scheduling], Initializes a cluster + scheduler-k3s:labels:set () [--process-type PROCESS_TYPE] <--resource-type RESOURCE_TYPE>, Set or clear a label for a given app/process-type/resource-type combination scheduler-k3s:report [] [], Displays a scheduler-k3s report for one or more apps scheduler-k3s:set (), Set or clear a scheduler-k3s property for an app scheduler-k3s:show-kubeconfig, Displays the kubeconfig for remote usage diff --git a/plugins/scheduler-k3s/src/subcommands/subcommands.go b/plugins/scheduler-k3s/src/subcommands/subcommands.go index 4685d0834..883dc4a56 100644 --- a/plugins/scheduler-k3s/src/subcommands/subcommands.go +++ b/plugins/scheduler-k3s/src/subcommands/subcommands.go @@ -34,6 +34,26 @@ func main() { } err = scheduler_k3s.CommandAnnotationsSet(appName, *processType, *resourceType, property, value) + case "autoscaling-auth:set": + args := flag.NewFlagSet("scheduler-k3s:autoscaling-auth:set", flag.ExitOnError) + global := args.Bool("global", false, "--global: set a global property") + metadata := args.StringToString("metadata", map[string]string{}, "--metadata: a key=value map of parameter metadata") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + trigger := args.Arg(1) + if *global { + appName = "--global" + trigger = args.Arg(0) + } + err = scheduler_k3s.CommandAutoscalingAuthSet(appName, trigger, *metadata, *global) + case "autoscaling-auth:report": + args := flag.NewFlagSet("scheduler-k3s:autoscaling-auth:report", flag.ExitOnError) + global := args.Bool("global", false, "--global: show a global report") + includeMetadata := args.Bool("include-metadata", false, "--include-metadata: include metadata in the report") + format := args.String("format", "stdout", "format: [ stdout | json ]") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + err = scheduler_k3s.CommandAutoscalingAuthReport(appName, *format, *global, *includeMetadata) case "cluster-add": args := flag.NewFlagSet("scheduler-k3s:cluster-add", flag.ExitOnError) allowUknownHosts := args.Bool("insecure-allow-unknown-hosts", false, "insecure-allow-unknown-hosts: allow unknown hosts") diff --git a/plugins/scheduler-k3s/subcommands.go b/plugins/scheduler-k3s/subcommands.go index 681e426ae..abe02da91 100644 --- a/plugins/scheduler-k3s/subcommands.go +++ b/plugins/scheduler-k3s/subcommands.go @@ -58,6 +58,78 @@ func CommandAnnotationsSet(appName string, processType string, resourceType stri return nil } +// CommandAutoscalingAuthSet set or clear a scheduler-k3s autoscaling keda trigger authentication object for an app +func CommandAutoscalingAuthSet(appName string, trigger string, metadata map[string]string, global bool) error { + if global { + appName = "--global" + } + + if len(metadata) == 0 { + properties, err := common.PropertyGetAllByPrefix("scheduler-k3s", appName, fmt.Sprintf("%s%s.", TriggerAuthPropertyPrefix, trigger)) + if err != nil { + return fmt.Errorf("Unable to get property list: %w", err) + } + + for key := range properties { + if err := common.PropertyDelete("scheduler-k3s", appName, key); err != nil { + return fmt.Errorf("Unable to delete property: %w", err) + } + } + + if appName == "--global" { + helmAgent, err := NewHelmAgent("keda", DeployLogPrinter) + if err != nil { + return fmt.Errorf("Unable to create helm agent: %w", err) + } + + releaseName := fmt.Sprintf("keda-cluster-trigger-authentications-%s", trigger) + if err := helmAgent.UninstallChart(releaseName); err != nil { + return fmt.Errorf("Unable to uninstall chart: %w", err) + } + } + + return nil + } + + for key, value := range metadata { + if err := common.PropertyWrite("scheduler-k3s", appName, fmt.Sprintf("%s%s.%s", TriggerAuthPropertyPrefix, trigger, key), value); err != nil { + return fmt.Errorf("Unable to set property: %w", err) + } + } + + if appName == "--global" { + err := applyKedaClusterTriggerAuthentications(context.Background(), trigger, metadata) + if err != nil { + return fmt.Errorf("Unable to install chart: %w", err) + } + } + + return nil +} + +// CommandAutoscalingAuthReport displays a scheduler-k3s autoscaling keda trigger authentication report for one or more apps +func CommandAutoscalingAuthReport(appName string, format string, global bool, includeMetadata bool) error { + if len(appName) == 0 && !global { + return fmt.Errorf("Missing required app name or --global flag") + } + + if len(appName) > 0 && global { + return fmt.Errorf("Cannot specify both app name and --global flag") + } + + if !global { + if err := common.VerifyAppName(appName); err != nil { + return err + } + } + + if len(appName) > 0 { + return ReportAutoscalingAuthSingleApp(appName, format, includeMetadata) + } + + return ReportAutoscalingAuthSingleApp("--global", format, includeMetadata) +} + // CommandInitialize initializes a k3s cluster on the local server func CommandInitialize(ingressClass string, serverIP string, taintScheduling bool) error { if ingressClass != "nginx" && ingressClass != "traefik" { diff --git a/plugins/scheduler-k3s/template.go b/plugins/scheduler-k3s/template.go index 1af9c8445..d5fb94ba3 100644 --- a/plugins/scheduler-k3s/template.go +++ b/plugins/scheduler-k3s/template.go @@ -27,6 +27,14 @@ type ClusterIssuerValues struct { ClusterIssuers map[string]ClusterIssuer `yaml:"cluster_issuers"` } +type ClusterKedaValues struct { + Global struct { + Annotations ProcessAnnotations `yaml:"annotations,omitempty"` + } `yaml:"global"` + Secrets map[string]string `yaml:"secrets"` + Type string `yaml:"type"` +} + type AppValues struct { Global GlobalValues `yaml:"global"` Processes map[string]ProcessValues `yaml:"processes"` @@ -38,6 +46,7 @@ type GlobalValues struct { DeploymentID string `yaml:"deploment_id"` Image GlobalImage `yaml:"image"` Labels ProcessLabels `yaml:"labels,omitempty"` + Keda GlobalKedaValues `yaml:"keda"` Namespace string `yaml:"namespace"` Network GlobalNetwork `yaml:"network"` Secrets map[string]string `yaml:"secrets,omitempty"` @@ -56,9 +65,41 @@ type GlobalNetwork struct { PrimaryPort int32 `yaml:"primary_port"` } +// GlobalKedaValues contains the global keda configuration +type GlobalKedaValues struct { + // Authentications is a map of authentication objects to use for keda + Authentications map[string]KedaAuthentication `yaml:"authentications"` + + // GlobalAuthentications is a map of global authentication objects to use for keda + GlobalAuthentications map[string]KedaAuthentication `yaml:"global_authentications"` +} + +// KedaAuthentication contains the authentication configuration for keda +type KedaAuthentication struct { + // Name is the name of the authentication object + Name string `yaml:"name"` + + // Kind is the kind of authentication object + Kind KedaAuthenticationKind `yaml:"kind,omitempty"` + + // Type is the type of authentication to use + Type string `yaml:"type"` + + // Secrets is a map of secrets to use for authentication + Secrets map[string]string `yaml:"secrets,omitempty"` +} + +type KedaAuthenticationKind string + +const ( + KedaAuthenticationKind_ClusterTriggerAuthentication KedaAuthenticationKind = "ClusterTriggerAuthentication" + KedaAuthenticationKind_TriggerAuthentication KedaAuthenticationKind = "TriggerAuthentication" +) + type ProcessValues struct { Annotations ProcessAnnotations `yaml:"annotations,omitempty"` Args []string `yaml:"args,omitempty"` + Autoscaling ProcessAutoscaling `yaml:"autoscaling,omitempty"` Cron ProcessCron `yaml:"cron,omitempty"` Healthchecks ProcessHealthchecks `yaml:"healthchecks,omitempty"` Labels ProcessLabels `yaml:"labels,omitempty"` @@ -69,17 +110,68 @@ type ProcessValues struct { } type ProcessAnnotations struct { - CertificateAnnotations map[string]string `yaml:"certificate,omitempty"` - CronJobAnnotations map[string]string `yaml:"cronjob,omitempty"` - DeploymentAnnotations map[string]string `yaml:"deployment,omitempty"` - IngressAnnotations map[string]string `yaml:"ingress,omitempty"` - JobAnnotations map[string]string `yaml:"job,omitempty"` - PodAnnotations map[string]string `yaml:"pod,omitempty"` - SecretAnnotations map[string]string `yaml:"secret,omitempty"` - ServiceAccountAnnotations map[string]string `yaml:"serviceaccount,omitempty"` - ServiceAnnotations map[string]string `yaml:"service,omitempty"` - TraefikIngressRouteAnnotations map[string]string `yaml:"traefik_ingressroute,omitempty"` - TraefikMiddlewareAnnotations map[string]string `yaml:"traefik_middleware,omitempty"` + CertificateAnnotations map[string]string `yaml:"certificate,omitempty"` + CronJobAnnotations map[string]string `yaml:"cronjob,omitempty"` + DeploymentAnnotations map[string]string `yaml:"deployment,omitempty"` + IngressAnnotations map[string]string `yaml:"ingress,omitempty"` + JobAnnotations map[string]string `yaml:"job,omitempty"` + KedaScalingObjectAnnotations map[string]string `yaml:"keda_scaled_object,omitempty"` + KedaSecretAnnotations map[string]string `yaml:"keda_secret,omitempty"` + KedaTriggerAuthenticationAnnotations map[string]string `yaml:"keda_trigger_authentication,omitempty"` + PodAnnotations map[string]string `yaml:"pod,omitempty"` + SecretAnnotations map[string]string `yaml:"secret,omitempty"` + ServiceAccountAnnotations map[string]string `yaml:"serviceaccount,omitempty"` + ServiceAnnotations map[string]string `yaml:"service,omitempty"` + TraefikIngressRouteAnnotations map[string]string `yaml:"traefik_ingressroute,omitempty"` + TraefikMiddlewareAnnotations map[string]string `yaml:"traefik_middleware,omitempty"` +} + +// ProcessAutoscaling contains the autoscaling configuration for a process +type ProcessAutoscaling struct { + // CooldownPeriodSeconds is the number of seconds after a scaling event before another can be triggered + CooldownPeriodSeconds int `yaml:"cooldown_period_seconds,omitempty"` + + // Enabled is a flag to enable autoscaling + Enabled bool `yaml:"enabled"` + + // MaxReplicas is the maximum number of replicas to scale to + MaxReplicas int `yaml:"max_replicas,omitempty"` + + // MinReplicas is the minimum number of replicas to scale to + MinReplicas int `yaml:"min_replicas,omitempty"` + + // PollingIntervalSeconds is the number of seconds between polling for new metrics + PollingIntervalSeconds int `yaml:"polling_interval_seconds,omitempty"` + + // Triggers is a list of triggers to use for autoscaling + Triggers []ProcessAutoscalingTrigger `yaml:"triggers,omitempty"` + + // Type is the type of autoscaling to use + Type string `yaml:"type"` +} + +// ProcessAutoscalingTrigger is a trigger to use for autoscaling +type ProcessAutoscalingTrigger struct { + // Name is the name of the trigger + Name string `yaml:"name"` + + // Type is the type of trigger to use + Type string `yaml:"type"` + + // Metadata is a map of key-value pairs that can be used to store arbitrary trigger data + Metadata map[string]string `yaml:"metadata,omitempty"` + + // AuthenticationRef is a reference to an authentication object + AuthenticationRef *ProcessAutoscalingTriggerAuthenticationRef `yaml:"authenticationRef,omitempty"` +} + +// ProcessAutoscalingTriggerAuthenticationRef is a reference to an authentication object +type ProcessAutoscalingTriggerAuthenticationRef struct { + // Name is the name of the authentication object + Name string `yaml:"name"` + + // Kind is the kind of authentication object + Kind string `yaml:"kind,omitempty"` } type ProcessHealthchecks struct { diff --git a/plugins/scheduler-k3s/templates/chart/keda-cluster-secret.yaml b/plugins/scheduler-k3s/templates/chart/keda-cluster-secret.yaml new file mode 100644 index 000000000..b60c4424d --- /dev/null +++ b/plugins/scheduler-k3s/templates/chart/keda-cluster-secret.yaml @@ -0,0 +1,21 @@ +{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + dokku.com/managed: "true" + {{ include "print.annotations" (dict "config" $.Values.global "key" "keda_secret") | indent 4 }} + labels: + app.kubernetes.io/instance: {{ $.Values.type }} + app.kubernetes.io/name: {{ $.Values.type }} + app.kubernetes.io/part-of: cluster + {{ include "print.labels" (dict "config" $.Values.global "key" "keda_secret") | indent 4 }} + name: ckta-{{ $.Values.type }} + namespace: keda +data: +{{- with $.Values.secrets }} +data: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-cluster-trigger-authentication.yaml b/plugins/scheduler-k3s/templates/chart/keda-cluster-trigger-authentication.yaml new file mode 100644 index 000000000..581698fa9 --- /dev/null +++ b/plugins/scheduler-k3s/templates/chart/keda-cluster-trigger-authentication.yaml @@ -0,0 +1,22 @@ +{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} +--- +apiVersion: keda.sh/v1alpha1 +kind: ClusterTriggerAuthentication +metadata: + annotations: + dokku.com/managed: "true" + {{ include "print.annotations" (dict "config" $.Values.global "key" "keda_trigger_authentication") | indent 4 }} + labels: + app.kubernetes.io/instance: {{ $.Values.type }} + app.kubernetes.io/name: {{ $.Values.type }} + app.kubernetes.io/part-of: cluster + {{ include "print.labels" (dict "config" $.Values.global "key" "keda_trigger_authentication") | indent 4 }} + name: {{ $.Values.type }} +spec: + secretTargetRef: + {{- range $k, $v := $.Values.secrets }} + - key: {{ $k }} + name: ckta-{{ $.Values.type }} + parameter: {{ $k }} + {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml b/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml new file mode 100644 index 000000000..13e766797 --- /dev/null +++ b/plugins/scheduler-k3s/templates/chart/keda-scaled-object.yaml @@ -0,0 +1,39 @@ +{{- $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" -}} +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + annotations: + app.kubernetes.io/version: {{ $.Values.global.deploment_id | quote }} + dokku.com/managed: "true" + {{ include "print.annotations" (dict "config" $.Values.global "key" "keda_scaled_object") | indent 4 }} + {{ include "print.annotations" (dict "config" $config "key" "keda_scaled_object") | indent 4 }} + labels: + app.kubernetes.io/instance: {{ $.Values.global.app_name }}-{{ $processName }} + app.kubernetes.io/name: {{ $processName }} + app.kubernetes.io/part-of: {{ $.Values.global.app_name }} + {{ include "print.labels" (dict "config" $.Values.global "key" "keda_scaled_object") | indent 4 }} + {{ include "print.labels" (dict "config" $config "key" "keda_scaled_object") | indent 4 }} + name: {{ $.Values.global.app_name}}-{{ $processName }} + namespace: {{ $.Values.global.namespace }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ $.Values.global.app_name }}-{{ $processName }} + envSourceContainerName: {{ $.Values.global.app_name }}-{{ $processName }} + cooldownPeriod: {{ $config.autoscaling.cooldown_period_seconds }} + pollingInterval: {{ $config.autoscaling.polling_interval_seconds }} + minReplicaCount: {{ $config.autoscaling.min_replicas }} + maxReplicaCount: {{ $config.autoscaling.max_replicas }} + fallback: + failureThreshold: 3 + replicas: {{ $config.replicas }} + triggers: + {{- with $config.autoscaling.triggers }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-secret.yaml b/plugins/scheduler-k3s/templates/chart/keda-secret.yaml new file mode 100644 index 000000000..d57815ffa --- /dev/null +++ b/plugins/scheduler-k3s/templates/chart/keda-secret.yaml @@ -0,0 +1,23 @@ +{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} +{{- $config := index .Values.global.keda.authentications "AUTH_NAME" }} +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + app.kubernetes.io/version: {{ $.Values.global.deploment_id | quote }} + dokku.com/managed: "true" + {{ include "print.annotations" (dict "config" $.Values.global "key" "keda_secret") | indent 4 }} + labels: + app.kubernetes.io/instance: {{ $.Values.global.app_name }}-{{ $config.type }} + app.kubernetes.io/name: {{ $config.type }} + app.kubernetes.io/part-of: {{ $.Values.global.app_name }} + {{ include "print.labels" (dict "config" $.Values.global "key" "keda_secret") | indent 4 }} + name: kta-{{ $.Values.global.app_name }}-{{ $config.type }} + namespace: {{ $.Values.global.namespace }} +data: +{{- with $config.secrets }} +data: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml b/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml new file mode 100644 index 000000000..2748a675c --- /dev/null +++ b/plugins/scheduler-k3s/templates/chart/keda-trigger-authentication.yaml @@ -0,0 +1,28 @@ +{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}} +{{- $config := index .Values.global.keda.authentications "AUTH_NAME" }} +--- +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + annotations: + app.kubernetes.io/version: {{ $.Values.global.deploment_id | quote }} + dokku.com/managed: "true" + {{- if and $.Values.global.annotations $.Values.global.annotations.keda_trigger_authentication }} + {{- range $k, $v := $.Values.global.annotations.keda_trigger_authentication }} + {{ $k }}: {{ $v | quote }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/instance: {{ $.Values.global.app_name }}-{{ $config.type }} + app.kubernetes.io/name: {{ $config.type }} + app.kubernetes.io/part-of: {{ $.Values.global.app_name }} + name: {{ $.Values.global.app_name }}-{{ $config.type }} + namespace: {{ $.Values.global.namespace }} +spec: + secretTargetRef: + {{- range $k, $v := $config.secrets }} + - key: {{ $k }} + name: kta-{{ $.Values.global.app_name }}-{{ $config.type }} + parameter: {{ $k }} + {{- end }} +{{- end }} diff --git a/plugins/scheduler-k3s/triggers.go b/plugins/scheduler-k3s/triggers.go index 24be9066e..a3195c3ce 100644 --- a/plugins/scheduler-k3s/triggers.go +++ b/plugins/scheduler-k3s/triggers.go @@ -266,11 +266,26 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e return fmt.Errorf("Error getting global labels: %w", err) } + clientset, err := NewKubernetesClient() + if err != nil { + return fmt.Errorf("Error creating kubernetes client: %w", err) + } + + if err := clientset.Ping(); err != nil { + return fmt.Errorf("kubernetes api not available: %w", err) + } + + kedaValues, err := getKedaValues(ctx, clientset, appName) + if err != nil { + return fmt.Errorf("Error getting keda values: %w", err) + } + values := &AppValues{ Global: GlobalValues{ Annotations: globalAnnotations, AppName: appName, DeploymentID: fmt.Sprint(deploymentId), + Keda: kedaValues, Image: GlobalImage{ ImagePullSecrets: imagePullSecrets, PullSecretBase64: pullSecretBase64, @@ -289,6 +304,27 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e Processes: map[string]ProcessValues{}, } + for authName := range kedaValues.Authentications { + templateFiles := []string{"keda-secret", "keda-trigger-authentication"} + for _, templateName := range templateFiles { + b, err := templates.ReadFile(fmt.Sprintf("templates/chart/%s.yaml", templateName)) + if err != nil { + 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)) + if err != nil { + return fmt.Errorf("Error writing %s template: %w", templateName, err) + } + + if os.Getenv("DOKKU_TRACE") == "1" { + common.CatFile(filename) + } + } + } + for processType, processCount := range processes { // todo: implement deployment annotations // todo: implement pod annotations @@ -327,8 +363,19 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e return fmt.Errorf("Error getting process labels: %w", err) } + autoscaling, err := getAutoscaling(GetAutoscalingInput{ + AppName: appName, + ProcessType: processType, + Replicas: int(processCount), + KedaValues: kedaValues, + }) + if err != nil { + return fmt.Errorf("Error getting autoscaling: %w", err) + } + processValues := ProcessValues{ Annotations: annotations, + Autoscaling: autoscaling, Args: args, Healthchecks: processHealthchecks, Labels: labels, @@ -336,6 +383,7 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e Replicas: int32(processCount), Resources: processResources, } + if processType == "web" { processValues.Web = ProcessWeb{ Domains: domains, @@ -392,7 +440,7 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e values.Processes[processType] = processValues - templateFiles := []string{"deployment"} + templateFiles := []string{"deployment", "keda-scaled-object"} if processType == "web" { templateFiles = append(templateFiles, "service", "certificate", "ingress", "ingress-route", "https-redirect-middleware") } @@ -413,16 +461,6 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e common.CatFile(filename) } } - - } - - clientset, err := NewKubernetesClient() - if err != nil { - return fmt.Errorf("Error creating kubernetes client: %w", err) - } - - if err := clientset.Ping(); err != nil { - return fmt.Errorf("kubernetes api not available: %w", err) } cronJobs, err := clientset.ListCronJobs(ctx, ListCronJobsInput{ diff --git a/tests/unit/scheduler-k3s.bats b/tests/unit/scheduler-k3s.bats index 530d29bda..c2a4ffc41 100644 --- a/tests/unit/scheduler-k3s.bats +++ b/tests/unit/scheduler-k3s.bats @@ -86,7 +86,7 @@ uninstall_k3s() { INGRESS_CLASS=nginx TAINT_SCHEDULING=true install_k3s } -@test "(scheduler-k3s) deploy traefik [resource]" { +@test "(scheduler-k3s) deploy traefik [resource] [autoscaling]" { if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN" fi @@ -103,6 +103,11 @@ uninstall_k3s() { echo "status: $status" assert_success + run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP memory --metadata some-key=1234567890 --metadata some-value=asdfghjkl" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git" echo "output: $output" echo "status: $status" @@ -115,6 +120,43 @@ uninstall_k3s() { assert_http_localhost_response "http" "$TEST_APP.dokku.me" "80" "" "python/http.server" + # include autoscaling tests + run /bin/bash -c "kubectl get scaledobjects.keda.sh $TEST_APP-web -o=jsonpath='{.spec.triggers[0].authenticationRef.name}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "$TEST_APP-memory" + + run /bin/bash -c "kubectl get triggerauthentications.keda.sh $TEST_APP-memory -o=jsonpath='{.spec.secretTargetRef[0].key}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "some-key" + + run /bin/bash -c "kubectl get triggerauthentications.keda.sh $TEST_APP-memory -o=jsonpath='{.spec.secretTargetRef[0].name}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "kta-$TEST_APP-memory" + + run /bin/bash -c "kubectl get triggerauthentications.keda.sh $TEST_APP-memory -o=jsonpath='{.spec.secretTargetRef[0].parameter}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "some-key" + + run /bin/bash -c "kubectl get secret kta-$TEST_APP-memory -o=jsonpath='{.data.some-key}' | base64 --decode" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "1234567890" + + run /bin/bash -c "kubectl get secret kta-$TEST_APP-memory -o=jsonpath='{.data.some-value}' | base64 --decode" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "asdfghjkl" + # include resource tests run /bin/bash -c "kubectl get pods -o=jsonpath='{.items[*]..resources.requests.cpu}'" echo "output: $output"