From e0ba57d996f5fe656ef6719949069e4ecb4adca8 Mon Sep 17 00:00:00 2001 From: Pedro Tanaka Date: Thu, 19 Jan 2023 13:56:48 +0100 Subject: [PATCH] Backport fixes to release 2.8 (#4135) * fix: CVE-2022-3172 (#3693) Signed-off-by: Pedro Tanaka * fix: Respect optional parameter inside envs for ScaledJobs (#3694) Signed-off-by: Jorge Turrado Signed-off-by: Pedro Tanaka * fix(prometheus scaler): Detect Inf before casting float to int (#3762) * fix(prometheus scaler): Detect Inf before casting float to int Signed-off-by: Jorge Turrado * Improve the log message Signed-off-by: Jorge Turrado Signed-off-by: Jorge Turrado Signed-off-by: Pedro Tanaka * fix(nats-jetstream): correctly count messages that should be redelivered (waiting for ack) towards keda value (#3809) * fix: keda now include the messages that should be retried in the count of pending messages used for scaling Signed-off-by: Antoine Laffargue * chore: update changelog Signed-off-by: Antoine Laffargue Signed-off-by: Antoine Laffargue Signed-off-by: Pedro Tanaka * NewRelic scaler crashes on logging (#3946) Signed-off-by: Laszlo Kishalmi Signed-off-by: Laszlo Kishalmi Signed-off-by: Pedro Tanaka Signed-off-by: Pedro Tanaka * Fix stackdriver client returning 0 for metric types of double (#3788) * Update stackdriver client to handle metrics of value type double Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> * move change log note to below general Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> * parse activation value as float64 Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> * change target value to float64 for GCP pub/sub and stackdriver Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> Signed-off-by: Pedro Tanaka * Fixing conflicts after cherry-pick Signed-off-by: Pedro Tanaka * fix: Close is called twice on PushScaler's deletion (#3599) Signed-off-by: ytz <1020560484@qq.com> Signed-off-by: taenyang <1020560484@qq.com> Signed-off-by: Pedro Tanaka * fix/datadog-scaler-null-last-point (#3954) Signed-off-by: Tony Lee Signed-off-by: Tony Lee Signed-off-by: Zbynek Roubalik Co-authored-by: Tony Lee Co-authored-by: Zbynek Roubalik Signed-off-by: Pedro Tanaka * fix(mongodb): escape username and password (#3989) Fixes https://github.com/kedacore/keda/issues/3992 Signed-off-by: Pedro Tanaka * Hacking generated files to version CI expects Signed-off-by: Pedro Tanaka * Updating aws-sdk and golang packages to fix CVEs Signed-off-by: Pedro Tanaka * Updating golang/text package to fix CVE Signed-off-by: Pedro Tanaka * Using same version of aws sdk as in main Signed-off-by: Pedro Tanaka Signed-off-by: Pedro Tanaka Signed-off-by: Jorge Turrado Signed-off-by: Antoine Laffargue Signed-off-by: Pedro Tanaka Signed-off-by: Laszlo Kishalmi Signed-off-by: Eric Takemoto <24865872+octothorped@users.noreply.github.com> Signed-off-by: ytz <1020560484@qq.com> Signed-off-by: taenyang <1020560484@qq.com> Signed-off-by: Tony Lee Signed-off-by: Tony Lee Signed-off-by: Zbynek Roubalik Co-authored-by: Jorge Turrado Ferrero Co-authored-by: Antoine LAFFARGUE Co-authored-by: Laszlo Kishalmi Co-authored-by: Eric Takemoto Co-authored-by: taenyang <1020560484@qq.com> Co-authored-by: Tony Lee Co-authored-by: Tony Lee Co-authored-by: Zbynek Roubalik --- .golangci.yml | 11 +- BUILD.md | 10 +- CHANGELOG.md | 11 +- go.mod | 35 +++-- go.sum | 101 +++++-------- pkg/mock/mock_scale/mock_interfaces.go | 2 +- pkg/scalers/datadog_scaler.go | 145 +++++++++++++++---- pkg/scalers/datadog_scaler_test.go | 40 ++++- pkg/scalers/gcp_pubsub_scaler.go | 18 +-- pkg/scalers/gcp_pubsub_scaler_test.go | 2 + pkg/scalers/gcp_stackdriver_scaler.go | 16 +- pkg/scalers/gcp_stackdriver_scaler_test.go | 2 + pkg/scalers/mongo_scaler.go | 25 ++-- pkg/scalers/mongo_scaler_test.go | 41 +++++- pkg/scalers/nats_jetstream_scaler.go | 2 +- pkg/scalers/newrelic_scaler.go | 3 +- pkg/scalers/prometheus_scaler.go | 10 ++ pkg/scalers/prometheus_scaler_test.go | 32 ++++ pkg/scalers/stackdriver_client.go | 22 ++- pkg/scaling/resolver/scale_resolvers.go | 6 + pkg/scaling/resolver/scale_resolvers_test.go | 72 +++++++++ pkg/scaling/scale_handler.go | 1 - 22 files changed, 455 insertions(+), 152 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 732b505c192..a0df949c2ab 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -17,7 +17,7 @@ linters: - goprintffuncname - govet - nolintlint - - rowserrcheck + #- rowserrcheck - gofmt - revive - goimports @@ -27,8 +27,6 @@ linters: - ineffassign - staticcheck - exportloopref - - structcheck - - deadcode - depguard - dogsled - errcheck @@ -40,7 +38,6 @@ linters: - gosimple - stylecheck - unused - - varcheck - unparam - unconvert - whitespace @@ -91,7 +88,11 @@ issues: - path: stan_scaler.go linters: - dupl - + # Exclude for datadog_scaler, reason: + # Introduce new parameters to fix DataDog API response issue #3906 (PR #3954) + - path: datadog_scaler.go + linters: + - gocyclo linters-settings: funlen: lines: 80 diff --git a/BUILD.md b/BUILD.md index 5c7d28ca3ff..26a96382646 100644 --- a/BUILD.md +++ b/BUILD.md @@ -138,7 +138,10 @@ Follow these instructions if you want to debug the KEDA operator using VS Code. "request": "launch", "mode": "debug", "program": "${workspaceFolder}/main.go", - "env": {"WATCH_NAMESPACE": ""} + "env": { + "WATCH_NAMESPACE": "", + "KEDA_CLUSTER_OBJECT_NAMESPACE": "keda" + } } ] } @@ -171,7 +174,10 @@ Follow these instructions if you want to debug the KEDA metrics server using VS "request": "launch", "mode": "auto", "program": "${workspaceFolder}/adapter/main.go", - "env": {"WATCH_NAMESPACE": ""}, + "env": { + "WATCH_NAMESPACE": "", + "KEDA_CLUSTER_OBJECT_NAMESPACE": "keda" + }, "args": [ "--authentication-kubeconfig=PATH_TO_YOUR_KUBECONFIG", "--authentication-skip-lookup", diff --git a/CHANGELOG.md b/CHANGELOG.md index 85cb0c4050b..49cf3156d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,16 @@ To learn more about our roadmap, we recommend reading [this document](ROADMAP.md ### Fixes -- TODO ([#XXX](https://github.com/kedacore/keda/issue/XXX)) +- **General:** Provide patch for CVE-2022-3172 vulnerability ([#3690](https://github.com/kedacore/keda/issues/3690)) +- **General:** Respect optional parameter inside envs for ScaledJobs ([#3568](https://github.com/kedacore/keda/issues/3568)) +- **General:** Close is called twice on PushScaler's deletion ([#3881](https://github.com/kedacore/keda/issues/3881)) +- **Azure Blob Scaler** Store forgotten logger ([#3811](https://github.com/kedacore/keda/issues/3811)) +- **Datadog Scaler** The last data point of some specific query is always null ([#3906](https://github.com/kedacore/keda/issues/3906)) +- **GCP Stackdriver Scalar:** Update Stackdriver client to handle detecting double and int64 value types ([#3777](https://github.com/kedacore/keda/issues/3777)) +- **MongoDB Scaler:** Username/password can contain `:/?#[]@` ([#3992](https://github.com/kedacore/keda/issues/3992)) +- **New Relic Scaler** Store forgotten logger ([#3945](https://github.com/kedacore/keda/issues/3945)) +- **Prometheus Scaler:** Treat Inf the same as Null result ([#3644](https://github.com/kedacore/keda/issues/3644)) +- **NATS Jetstream:** Correctly count messages that should be redelivered (waiting for ack) towards keda value ([#3787](https://github.com/kedacore/keda/issues/3787)) ### Deprecations diff --git a/go.mod b/go.mod index f7b699b93b6..0d97c111a70 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/DataDog/datadog-api-client-go v1.16.0 github.com/Huawei/gophercloud v1.0.21 github.com/Shopify/sarama v1.36.0 - github.com/aws/aws-sdk-go v1.44.88 + github.com/aws/aws-sdk-go v1.44.150 github.com/denisenkom/go-mssqldb v0.12.2 github.com/dysnix/predictkube-libs v0.0.4-0.20220717101015-44c816c4fb9c github.com/dysnix/predictkube-proto v0.0.0-20220713123213-7135dce1e9c9 @@ -61,15 +61,15 @@ require ( google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf google.golang.org/grpc v1.49.0 google.golang.org/protobuf v1.28.1 - k8s.io/api v0.24.3 - k8s.io/apimachinery v0.24.3 - k8s.io/apiserver v0.24.3 - k8s.io/client-go v0.24.3 - k8s.io/code-generator v0.24.3 + k8s.io/api v0.24.5 + k8s.io/apimachinery v0.24.5 + k8s.io/apiserver v0.24.4 + k8s.io/client-go v0.24.5 + k8s.io/code-generator v0.24.4 k8s.io/klog/v2 v2.70.2-0.20220707122935-0990e81f1a8f k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 k8s.io/metrics v0.24.3 - knative.dev/pkg v0.0.0-20220826162920-93b66e6a8700 + knative.dev/pkg v0.0.0-20220909150730-20aabd56be23 sigs.k8s.io/controller-runtime v0.12.3 sigs.k8s.io/custom-metrics-apiserver v1.24.0 ) @@ -92,10 +92,13 @@ replace ( golang.org/x/crypto => golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // https://www.whitesourcesoftware.com/vulnerability-database/CVE-2021-42836 - golang.org/x/text => golang.org/x/text v0.3.7 + golang.org/x/text => golang.org/x/text v0.3.8 // Needed for CVE-2022-28948 https://www.cve.org/CVERecord?id=CVE-2022-28948 gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 + + // Needed for CVE-2022-3172 https://bugzilla.redhat.com/show_bug.cgi?id=2127804 + k8s.io/apimachinery => k8s.io/apimachinery v0.24.5 ) require ( @@ -258,15 +261,15 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.5.0 // indirect golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/term v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.1.10 // indirect + golang.org/x/tools v0.1.12 // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -276,8 +279,8 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.24.2 // indirect - k8s.io/component-base v0.24.3 // indirect + k8s.io/apiextensions-apiserver v0.24.4 // indirect + k8s.io/component-base v0.24.5 // indirect k8s.io/gengo v0.0.0-20220613173612-397b4ae3bce7 // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect nhooyr.io/websocket v1.8.7 // indirect diff --git a/go.sum b/go.sum index 028319c434a..79e61bf2f7b 100644 --- a/go.sum +++ b/go.sum @@ -101,7 +101,6 @@ github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd/go.mo github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= github.com/Azure/go-amqp v0.16.4 h1:/1oIXrq5zwXLHaoYDliJyiFjJSpJZMWGgtMX9e0/Z30= github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -192,8 +191,10 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI 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-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.88 h1:9jhiZsTx9koQQsM29RTgwI0g4mfyphCdc3bkUcKrdwA= -github.com/aws/aws-sdk-go v1.44.88/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.150 h1:X9HBhXu0ZPi+tOHUaZkjx43int7g0Ejk+IVbW25+wYg= +github.com/aws/aws-sdk-go v1.44.150/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.181 h1:w4OzE8bwIVo62gUTAp/uEFO2HSsUtf1pjXpSs36cluY= +github.com/aws/aws-sdk-go v1.44.181/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -205,9 +206,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= @@ -500,7 +498,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= @@ -568,7 +565,6 @@ github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/Oth github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k= @@ -761,7 +757,6 @@ github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -821,7 +816,6 @@ github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/I github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -884,7 +878,6 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -913,7 +906,6 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= @@ -982,19 +974,14 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= @@ -1076,8 +1063,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -1186,9 +1173,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -1246,7 +1233,6 @@ golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1254,9 +1240,12 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= -golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced h1:3dYNDff0VT5xj+mbj2XucFst9WKk6PdGOrb9n+SbIvw= golang.org/x/net v0.0.0-20220809184613-07c6da5e1ced/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1268,7 +1257,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -1342,7 +1330,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1368,7 +1355,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1392,15 +1378,18 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1411,7 +1400,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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= @@ -1472,11 +1460,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1509,7 +1496,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -1702,7 +1688,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1734,36 +1719,35 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/api v0.23.9/go.mod h1:r4g0GrGdLgwSYB90qgO4tBrbKtALBhUfut+oFt4ikCc= k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/api v0.24.3 h1:tt55QEmKd6L2k5DP6G/ZzdMQKvG5ro4H4teClqm0sTY= k8s.io/api v0.24.3/go.mod h1:elGR/XSZrS7z7cSZPzVWaycpJuGIw57j9b95/1PdJNI= -k8s.io/apiextensions-apiserver v0.23.9/go.mod h1:uu79PjF1T6YbfFqL5kVTmEdxb40Z0eHM7MfHDHz9dho= -k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= +k8s.io/api v0.24.4/go.mod h1:42pVfA0NRxrtJhZQOvRSyZcJihzAdU59WBtTjYcB0/M= +k8s.io/api v0.24.5 h1:dujOrusqYFyeDIfDn4jVrLUGW4OUahkLBcaKjDLENrc= +k8s.io/api v0.24.5/go.mod h1:0qqWiH+FEHlS5MMv1NOodAcGzeOFgtsBOT7S8luxr7E= k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.23.9/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg= -k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apiserver v0.23.9/go.mod h1:vIXpgCnHep34bP/y+wGhYdn1NgxAvWtntxfEjst0e74= +k8s.io/apiextensions-apiserver v0.24.4 h1:w53Pm4zu8fCt9WfiRgS2YI6LE6I4NJ5aUi78GElD3K8= +k8s.io/apiextensions-apiserver v0.24.4/go.mod h1:iDK+Xb4jsPNnRGj5jU/WqqjLvt8363M7cKixKe1C9+U= +k8s.io/apimachinery v0.24.5 h1:6pbRsdruZAjwcbffR2lTN6U+KsF30m2GLTbgAlPU9fg= +k8s.io/apimachinery v0.24.5/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= -k8s.io/apiserver v0.24.3 h1:J8CKjUaZopT0hSgxjzUyp3T1GK78iixxOuFpEC0MI3k= k8s.io/apiserver v0.24.3/go.mod h1:aXfwtIn4U27B7lYs5f2BKgz6DRbgWy+HJeYReN1jLJ8= +k8s.io/apiserver v0.24.4 h1:ei+OunC83pVEiagBeZhTnRZvkclHgpzs/rrm7aSBDYs= +k8s.io/apiserver v0.24.4/go.mod h1:mAuC3pZVc0IDXLx7lUHoisBOtBa1SobfLW/CI3klXQE= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= -k8s.io/client-go v0.23.9/go.mod h1:sNo0X0MZqo4Uu0qDY5Fl5Y60cJFinBDWWUBOAM5JUCM= k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/client-go v0.24.3 h1:Nl1840+6p4JqkFWEW2LnMKU667BUxw03REfLAVhuKQY= k8s.io/client-go v0.24.3/go.mod h1:AAovolf5Z9bY1wIg2FZ8LPQlEdKHjLI7ZD4rw920BJw= -k8s.io/code-generator v0.23.9/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/client-go v0.24.4/go.mod h1:+AxlPWw/H6f+EJhRSjIeALaJT4tbeB/8g9BNvXGPd0Y= +k8s.io/client-go v0.24.5 h1:N9XKQYF7hT5P1VApMwZhUf0mKGKTYV7O46NLUaagQnk= +k8s.io/client-go v0.24.5/go.mod h1:Aw2SOOn3y3iiCGTMicMpgsVGAzg7/Y+CV3UtqQS/uFI= k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= -k8s.io/code-generator v0.24.3 h1:itd1V1ZAYKM+WT+qQDlFKhU1D/Ff5HcEFL/icfClnZA= k8s.io/code-generator v0.24.3/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= -k8s.io/component-base v0.23.9/go.mod h1:WUNtIRIMd9WBS2r5LCSNZoh6f/Uh+8O+aGuZUG5t428= +k8s.io/code-generator v0.24.4 h1:HLnoAabkTFKy1Ex4cMvffz6KkWFJ7oFN2yX37Icbbyg= +k8s.io/code-generator v0.24.4/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= -k8s.io/component-base v0.24.3 h1:u99WjuHYCRJjS1xeLOx72DdRaghuDnuMgueiGMFy1ec= k8s.io/component-base v0.24.3/go.mod h1:bqom2IWN9Lj+vwAkPNOv2TflsP1PeVDIwIN0lRthxYY= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/component-base v0.24.4/go.mod h1:sWxkgcMfbYHadw0OJ0N+vIscd14/nqSIM2veCdg843o= +k8s.io/component-base v0.24.5 h1:PoGX+D5FQiGYuZNktuL2iRkLoX4g2gEq8fQp/j5ru2g= +k8s.io/component-base v0.24.5/go.mod h1:ys3MybmrUao2SRdx2HcI3RELSnogOa3Rh4S8WQfqnoU= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20220613173612-397b4ae3bce7 h1:RGb68G3yotdQggcyenx9y0+lnVJCXXcLa6geXOMlf5o= @@ -1771,26 +1755,22 @@ k8s.io/gengo v0.0.0-20220613173612-397b4ae3bce7/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAE k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.70.2-0.20220707122935-0990e81f1a8f h1:dltw7bAn8bCrQ2CmzzhgoieUZEbWqrvIGVdHGioP5nY= k8s.io/klog/v2 v2.70.2-0.20220707122935-0990e81f1a8f/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/metrics v0.24.3 h1:pXzh+PG8L8ANg0PD3Ce8+yG5oj8BLvzBgsz8yCVEXyg= k8s.io/metrics v0.24.3/go.mod h1:p1M0lhMySWfhISkSd3HEj8xIgrVnJTK3PPhFq2rA3To= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= knative.dev/hack v0.0.0-20220823140917-8d1e4ccf9dc3/go.mod h1:t/azP8I/Cygaw+87O7rkAPrNRjCelmtfSzWzu/9TM7I= -knative.dev/pkg v0.0.0-20220826162920-93b66e6a8700 h1:6xjS69vf5Pbwu+dWckqPALmm5pc3p0/XScPpRBhugRc= -knative.dev/pkg v0.0.0-20220826162920-93b66e6a8700/go.mod h1:WIQZyPTLzT+z0V3/gB91aWugIi3E1mkU9rjCrLfjOwY= +knative.dev/pkg v0.0.0-20220909150730-20aabd56be23 h1:ZjPa1ok6jltFnMye3TXiz3tErLwLrM9BhwRu+qsqbIA= +knative.dev/pkg v0.0.0-20220909150730-20aabd56be23/go.mod h1:uqKBKF69qddn8MgRJjLUoOUlszZqly8U2sXUYAJS36w= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= @@ -1803,7 +1783,6 @@ sigs.k8s.io/controller-runtime v0.12.3 h1:FCM8xeY/FI8hoAfh/V4XbbYMY20gElh9yh+A98 sigs.k8s.io/controller-runtime v0.12.3/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0= sigs.k8s.io/custom-metrics-apiserver v1.24.0 h1:zCFOM10HKpqbvalU63t7L7AcFIRsRusXJmsMTtpwiuI= sigs.k8s.io/custom-metrics-apiserver v1.24.0/go.mod h1:0aVCsZRrWfUnVS6Ejf6JAXXt9TF31BU/z/3TjT8+BXo= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/pkg/mock/mock_scale/mock_interfaces.go b/pkg/mock/mock_scale/mock_interfaces.go index 45c07456ca6..473dd2f765d 100644 --- a/pkg/mock/mock_scale/mock_interfaces.go +++ b/pkg/mock/mock_scale/mock_interfaces.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: /go/pkg/mod/k8s.io/client-go@v0.23.8/scale/interfaces.go +// Source: /go/pkg/mod/k8s.io/client-go@v0.24.5/scale/interfaces.go // Package mock_scale is a generated GoMock package. package mock_scale diff --git a/pkg/scalers/datadog_scaler.go b/pkg/scalers/datadog_scaler.go index f3c2ab131a6..ada7fc359c5 100644 --- a/pkg/scalers/datadog_scaler.go +++ b/pkg/scalers/datadog_scaler.go @@ -24,19 +24,25 @@ type datadogScaler struct { } type datadogMetadata struct { - apiKey string - appKey string - datadogSite string - query string - queryValue float64 - activationQueryValue float64 - vType v2beta2.MetricTargetType - metricName string - age int - useFiller bool - fillValue float64 + apiKey string + appKey string + datadogSite string + query string + queryValue float64 + queryAggegrator string + activationQueryValue float64 + vType v2beta2.MetricTargetType + metricName string + age int + timeWindowOffset int + lastAvailablePointOffset int + useFiller bool + fillValue float64 } +const maxString = "max" +const avgString = "average" + var filter *regexp.Regexp func init() { @@ -83,6 +89,9 @@ func parseDatadogMetadata(config *ScalerConfig, logger logr.Logger) (*datadogMet } meta.age = age + if age < 0 { + return nil, fmt.Errorf("age should not be smaller than 0 seconds") + } if age < 60 { logger.Info("selecting a window smaller than 60 seconds can cause Datadog not finding a metric value for the query") } @@ -90,6 +99,33 @@ func parseDatadogMetadata(config *ScalerConfig, logger logr.Logger) (*datadogMet meta.age = 90 // Default window 90 seconds } + if val, ok := config.TriggerMetadata["timeWindowOffset"]; ok { + timeWindowOffset, err := strconv.Atoi(val) + if err != nil { + return nil, fmt.Errorf("timeWindowOffset parsing error %s", err.Error()) + } + if timeWindowOffset < 0 { + return nil, fmt.Errorf("timeWindowOffset should not be smaller than 0 seconds") + } + meta.timeWindowOffset = timeWindowOffset + } else { + meta.timeWindowOffset = 0 // Default delay 0 seconds + } + + if val, ok := config.TriggerMetadata["lastAvailablePointOffset"]; ok { + lastAvailablePointOffset, err := strconv.Atoi(val) + if err != nil { + return nil, fmt.Errorf("lastAvailablePointOffset parsing error %s", err.Error()) + } + + if lastAvailablePointOffset < 0 { + return nil, fmt.Errorf("lastAvailablePointOffset should not be smaller than 0") + } + meta.lastAvailablePointOffset = lastAvailablePointOffset + } else { + meta.lastAvailablePointOffset = 0 // Default use the last point + } + if val, ok := config.TriggerMetadata["query"]; ok { _, err := parseDatadogQuery(val) @@ -111,6 +147,18 @@ func parseDatadogMetadata(config *ScalerConfig, logger logr.Logger) (*datadogMet return nil, fmt.Errorf("no queryValue given") } + if val, ok := config.TriggerMetadata["queryAggregator"]; ok && val != "" { + queryAggregator := strings.ToLower(val) + switch queryAggregator { + case avgString, maxString: + meta.queryAggegrator = queryAggregator + default: + return nil, fmt.Errorf("queryAggregator value %s has to be one of '%s, %s'", queryAggregator, avgString, maxString) + } + } else { + meta.queryAggegrator = "" + } + meta.activationQueryValue = 0 if val, ok := config.TriggerMetadata["activationQueryValue"]; ok { activationQueryValue, err := strconv.ParseFloat(val, 64) @@ -136,7 +184,7 @@ func parseDatadogMetadata(config *ScalerConfig, logger logr.Logger) (*datadogMet } val = strings.ToLower(val) switch val { - case "average": + case avgString: meta.vType = v2beta2.AverageValueMetricType case "global": meta.vType = v2beta2.ValueMetricType @@ -247,7 +295,9 @@ func (s *datadogScaler) getQueryResult(ctx context.Context) (float64, error) { "site": s.metadata.datadogSite, }) - resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, time.Now().Unix()-int64(s.metadata.age), time.Now().Unix(), s.metadata.query) //nolint:bodyclose + timeWindowTo := time.Now().Unix() - int64(s.metadata.timeWindowOffset) + timeWindowFrom := timeWindowTo - int64(s.metadata.age) + resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, timeWindowFrom, timeWindowTo, s.metadata.query) //nolint:bodyclose if err != nil { return -1, fmt.Errorf("error when retrieving Datadog metrics: %s", err) } @@ -272,10 +322,6 @@ func (s *datadogScaler) getQueryResult(ctx context.Context) (float64, error) { series := resp.GetSeries() - if len(series) > 1 { - return 0, fmt.Errorf("query returned more than 1 series; modify the query to return only 1 series") - } - if len(series) == 0 { if !s.metadata.useFiller { return 0, fmt.Errorf("no Datadog metrics returned for the given time window") @@ -283,18 +329,45 @@ func (s *datadogScaler) getQueryResult(ctx context.Context) (float64, error) { return s.metadata.fillValue, nil } - points := series[0].GetPointlist() + // Require queryAggregator be set explicitly for multi-query + if len(series) > 1 && s.metadata.queryAggegrator == "" { + return 0, fmt.Errorf("query returned more than 1 series; modify the query to return only 1 series or add a queryAggregator") + } - index := len(points) - 1 - if len(points) == 0 || len(points[index]) < 2 || points[index][1] == nil { - if !s.metadata.useFiller { - return 0, fmt.Errorf("no Datadog metrics returned for the given time window") + // Collect all latest point values from any/all series + results := make([]float64, len(series)) + for i := 0; i < len(series); i++ { + points := series[i].GetPointlist() + index := len(points) - 1 + // Find out the last point != nil + for j := index; j >= 0; j-- { + if len(points[j]) >= 2 && points[j][1] != nil { + index = j + break + } } - return s.metadata.fillValue, nil + if index < s.metadata.lastAvailablePointOffset { + return 0, fmt.Errorf("index is smaller than the lastAvailablePointOffset") + } + index -= s.metadata.lastAvailablePointOffset + + if len(points) == 0 || len(points[index]) < 2 || points[index][1] == nil { + if !s.metadata.useFiller { + return 0, fmt.Errorf("no Datadog metrics returned for the given time window") + } + return s.metadata.fillValue, nil + } + // Return the last point from the series + results[i] = *points[index][1] } - // Return the last point from the series - return *points[index][1], nil + switch s.metadata.queryAggegrator { + case avgString: + return AvgFloatFromSlice(results), nil + default: + // Aggregate Results - default Max value: + return MaxFloatFromSlice(results), nil + } } // GetMetricSpecForScaling returns the MetricSpec for the Horizontal Pod Autoscaler @@ -312,7 +385,7 @@ func (s *datadogScaler) GetMetricSpecForScaling(context.Context) []v2beta2.Metri } // GetMetrics returns value for a supported metric and an error if there is a problem getting the metric -func (s *datadogScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *datadogScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { s.logger.Error(err, "error getting metrics from Datadog") @@ -323,3 +396,23 @@ func (s *datadogScaler) GetMetrics(ctx context.Context, metricName string, metri return append([]external_metrics.ExternalMetricValue{}, metric), nil } + +// Find the largest value in a slice of floats +func MaxFloatFromSlice(results []float64) float64 { + max := results[0] + for _, result := range results { + if result > max { + max = result + } + } + return max +} + +// Find the average value in a slice of floats +func AvgFloatFromSlice(results []float64) float64 { + total := 0.0 + for _, result := range results { + total += result + } + return total / float64(len(results)) +} diff --git a/pkg/scalers/datadog_scaler_test.go b/pkg/scalers/datadog_scaler_test.go index c372c653482..28954e9976a 100644 --- a/pkg/scalers/datadog_scaler_test.go +++ b/pkg/scalers/datadog_scaler_test.go @@ -27,6 +27,31 @@ type datadogAuthMetadataTestData struct { isError bool } +func assertEqual(t *testing.T, a interface{}, b interface{}) { + if a == b { + return + } + t.Errorf("%v != %v", a, b) +} + +func TestMaxFloatFromSlice(t *testing.T) { + input := []float64{1.0, 2.0, 3.0, 4.0} + expectedOutput := float64(4.0) + + output := MaxFloatFromSlice(input) + + assertEqual(t, output, expectedOutput) +} + +func TestAvgFloatFromSlice(t *testing.T) { + input := []float64{1.0, 2.0, 3.0, 4.0} + expectedOutput := float64(2.5) + + output := AvgFloatFromSlice(input) + + assertEqual(t, output, expectedOutput) +} + var testParseQueries = []datadogQueries{ {"", false, true}, // All properly formed @@ -36,9 +61,14 @@ var testParseQueries = []datadogQueries{ {"top(per_second(abs(sum:http.requests{service:myapp,dc:us-west-2}.rollup(max, 2))), 5, 'mean', 'desc')", true, false}, {"system.cpu.user{*}.rollup(sum, 30)", true, false}, {"min:system.cpu.user{*}", true, false}, + // Multi-query + {"avg:system.cpu.user{*}.rollup(sum, 30),sum:system.cpu.user{*}.rollup(30)", true, false}, // Missing filter {"min:system.cpu.user", false, true}, + + // Find out last point with value + {"sum:trace.express.request.hits{*}.as_rate()/avg:kubernetes.cpu.requests{*}.rollup(10)", true, false}, } func TestDatadogScalerParseQueries(t *testing.T) { @@ -62,9 +92,15 @@ var testDatadogMetadata = []datadogAuthMetadataTestData{ {"", map[string]string{}, map[string]string{}, true}, // all properly formed - {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "metricUnavailableValue": "1.5", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, + {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "metricUnavailableValue": "1.5", "type": "average", "age": "60", "timeWindowOffset": "30", "lastAvailablePointOffset": "1"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, + // Multi-query all properly formed + {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count(),sum:trace.redis.command.hits{env:none,service:redis}.as_count()/2", "queryValue": "7", "queryAggregator": "average", "metricUnavailableValue": "1.5", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, // default age {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "type": "average"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, + // default timeWindowOffset + {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "metricUnavailableValue": "1.5", "type": "average", "age": "60", "lastAvailablePointOffset": "1"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, + // default lastAvailablePointOffset + {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "metricUnavailableValue": "1.5", "type": "average", "age": "60", "timeWindowOffset": "30"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, // default type {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "7", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, false}, // wrong type @@ -77,6 +113,8 @@ var testDatadogMetadata = []datadogAuthMetadataTestData{ {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, true}, // wrong query value type {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "notanint", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, true}, + // wrong queryAggregator value + {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "notanint", "queryAggegrator": "1.0", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, true}, // wrong activation query value type {"", map[string]string{"query": "sum:trace.redis.command.hits{env:none,service:redis}.as_count()", "queryValue": "1", "activationQueryValue": "notanint", "type": "average", "age": "60"}, map[string]string{"apiKey": "apiKey", "appKey": "appKey", "datadogSite": "datadogSite"}, true}, // malformed query diff --git a/pkg/scalers/gcp_pubsub_scaler.go b/pkg/scalers/gcp_pubsub_scaler.go index 48393792a68..bee406a0eb4 100644 --- a/pkg/scalers/gcp_pubsub_scaler.go +++ b/pkg/scalers/gcp_pubsub_scaler.go @@ -38,8 +38,8 @@ type pubsubScaler struct { type pubsubMetadata struct { mode string - value int64 - activationValue int64 + value float64 + activationValue float64 subscriptionName string gcpAuthorization *gcpAuthorizationMetadata @@ -80,7 +80,7 @@ func parsePubSubMetadata(config *ScalerConfig, logger logr.Logger) (*pubsubMetad } logger.Info("subscriptionSize field is deprecated. Use mode and value fields instead") meta.mode = pubsubModeSubscriptionSize - subSizeValue, err := strconv.ParseInt(subSize, 10, 64) + subSizeValue, err := strconv.ParseFloat(subSize, 64) if err != nil { return nil, fmt.Errorf("value parsing error %s", err.Error()) } @@ -100,7 +100,7 @@ func parsePubSubMetadata(config *ScalerConfig, logger logr.Logger) (*pubsubMetad } if valuePresent { - triggerValue, err := strconv.ParseInt(value, 10, 64) + triggerValue, err := strconv.ParseFloat(value, 64) if err != nil { return nil, fmt.Errorf("value parsing error %s", err.Error()) } @@ -120,7 +120,7 @@ func parsePubSubMetadata(config *ScalerConfig, logger logr.Logger) (*pubsubMetad meta.activationValue = 0 if val, ok := config.TriggerMetadata["activationValue"]; ok { - activationValue, err := strconv.ParseInt(val, 10, 64) + activationValue, err := strconv.ParseFloat(val, 64) if err != nil { return nil, fmt.Errorf("activationValue parsing error %s", err.Error()) } @@ -176,7 +176,7 @@ func (s *pubsubScaler) GetMetricSpecForScaling(context.Context) []v2beta2.Metric Metric: v2beta2.MetricIdentifier{ Name: GenerateMetricNameWithIndex(s.metadata.scalerIndex, kedautil.NormalizeString(fmt.Sprintf("gcp-ps-%s", s.metadata.subscriptionName))), }, - Target: GetMetricTarget(s.metricType, s.metadata.value), + Target: GetMetricTargetMili(s.metricType, s.metadata.value), } // Create the metric spec for the HPA @@ -190,7 +190,7 @@ func (s *pubsubScaler) GetMetricSpecForScaling(context.Context) []v2beta2.Metric // GetMetrics connects to Stack Driver and finds the size of the pub sub subscription func (s *pubsubScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { - var value int64 + var value float64 var err error switch s.metadata.mode { @@ -208,7 +208,7 @@ func (s *pubsubScaler) GetMetrics(ctx context.Context, metricName string, metric } } - metric := GenerateMetricInMili(metricName, float64(value)) + metric := GenerateMetricInMili(metricName, value) return append([]external_metrics.ExternalMetricValue{}, metric), nil } @@ -230,7 +230,7 @@ func (s *pubsubScaler) setStackdriverClient(ctx context.Context) error { } // getMetrics gets metric type value from stackdriver api -func (s *pubsubScaler) getMetrics(ctx context.Context, metricType string) (int64, error) { +func (s *pubsubScaler) getMetrics(ctx context.Context, metricType string) (float64, error) { if s.client == nil { err := s.setStackdriverClient(ctx) if err != nil { diff --git a/pkg/scalers/gcp_pubsub_scaler_test.go b/pkg/scalers/gcp_pubsub_scaler_test.go index 6b6503afd5d..4b2b898e861 100644 --- a/pkg/scalers/gcp_pubsub_scaler_test.go +++ b/pkg/scalers/gcp_pubsub_scaler_test.go @@ -56,6 +56,8 @@ var testPubSubMetadata = []parsePubSubMetadataTestData{ {nil, map[string]string{"subscriptionName": "projects/myproject/subscriptions/mysubscription", "subscriptionSize": "7", "credentialsFromEnv": "SAMPLE_CREDS"}, false}, // with full (bad) link to subscription {nil, map[string]string{"subscriptionName": "projects/myproject/mysubscription", "subscriptionSize": "7", "credentialsFromEnv": "SAMPLE_CREDS"}, false}, + // properly formed float value and activationTargetValue + {nil, map[string]string{"subscriptionName": "mysubscription", "value": "7.1", "credentialsFromEnv": "SAMPLE_CREDS", "activationValue": "2.1"}, false}, } var gcpPubSubMetricIdentifiers = []gcpPubSubMetricIdentifier{ diff --git a/pkg/scalers/gcp_stackdriver_scaler.go b/pkg/scalers/gcp_stackdriver_scaler.go index 0be57fc9295..446744bd8b3 100644 --- a/pkg/scalers/gcp_stackdriver_scaler.go +++ b/pkg/scalers/gcp_stackdriver_scaler.go @@ -28,8 +28,8 @@ type stackdriverScaler struct { type stackdriverMetadata struct { projectID string filter string - targetValue int64 - activationTargetValue int64 + targetValue float64 + activationTargetValue float64 metricName string gcpAuthorization *gcpAuthorizationMetadata @@ -92,7 +92,7 @@ func parseStackdriverMetadata(config *ScalerConfig, logger logr.Logger) (*stackd meta.metricName = GenerateMetricNameWithIndex(config.ScalerIndex, name) if val, ok := config.TriggerMetadata["targetValue"]; ok { - targetValue, err := strconv.ParseInt(val, 10, 64) + targetValue, err := strconv.ParseFloat(val, 64) if err != nil { logger.Error(err, "Error parsing targetValue") return nil, fmt.Errorf("error parsing targetValue: %s", err.Error()) @@ -103,7 +103,7 @@ func parseStackdriverMetadata(config *ScalerConfig, logger logr.Logger) (*stackd meta.activationTargetValue = 0 if val, ok := config.TriggerMetadata["activationTargetValue"]; ok { - activationTargetValue, err := strconv.ParseInt(val, 10, 64) + activationTargetValue, err := strconv.ParseFloat(val, 64) if err != nil { return nil, fmt.Errorf("activationTargetValue parsing error %s", err.Error()) } @@ -189,7 +189,7 @@ func (s *stackdriverScaler) GetMetricSpecForScaling(context.Context) []v2beta2.M Metric: v2beta2.MetricIdentifier{ Name: s.metadata.metricName, }, - Target: GetMetricTarget(s.metricType, s.metadata.targetValue), + Target: GetMetricTargetMili(s.metricType, s.metadata.targetValue), } // Create the metric spec for the HPA @@ -209,17 +209,17 @@ func (s *stackdriverScaler) GetMetrics(ctx context.Context, metricName string, m return []external_metrics.ExternalMetricValue{}, err } - metric := GenerateMetricInMili(metricName, float64(value)) + metric := GenerateMetricInMili(metricName, value) return append([]external_metrics.ExternalMetricValue{}, metric), nil } // getMetrics gets metric type value from stackdriver api -func (s *stackdriverScaler) getMetrics(ctx context.Context) (int64, error) { +func (s *stackdriverScaler) getMetrics(ctx context.Context) (float64, error) { val, err := s.client.GetMetrics(ctx, s.metadata.filter, s.metadata.projectID, s.metadata.aggregation) if err == nil { s.logger.V(1).Info( - fmt.Sprintf("Getting metrics for project %s, filter %s and aggregation %v. Result: %d", + fmt.Sprintf("Getting metrics for project %s, filter %s and aggregation %v. Result: %f", s.metadata.projectID, s.metadata.filter, s.metadata.aggregation, diff --git a/pkg/scalers/gcp_stackdriver_scaler_test.go b/pkg/scalers/gcp_stackdriver_scaler_test.go index c48241bfa7f..43ddc1d21a0 100644 --- a/pkg/scalers/gcp_stackdriver_scaler_test.go +++ b/pkg/scalers/gcp_stackdriver_scaler_test.go @@ -53,6 +53,8 @@ var testStackdriverMetadata = []parseStackdriverMetadataTestData{ {nil, map[string]string{"projectId": "myProject", "filter": sdFilter, "credentialsFromEnv": "SAMPLE_CREDS", "alignmentPeriodSeconds": "30"}, true}, // With bad alignment period {nil, map[string]string{"projectId": "myProject", "filter": sdFilter, "credentialsFromEnv": "SAMPLE_CREDS", "alignmentPeriodSeconds": "a"}, true}, + // properly formed float targetValue and activationTargetValue + {nil, map[string]string{"projectId": "myProject", "filter": sdFilter, "credentialsFromEnv": "SAMPLE_CREDS", "targetValue": "1.1", "activationTargetValue": "2.1"}, false}, } var gcpStackdriverMetricIdentifiers = []gcpStackdriverMetricIdentifier{ diff --git a/pkg/scalers/mongo_scaler.go b/pkg/scalers/mongo_scaler.go index bba3ca9ebbd..82034a20a45 100644 --- a/pkg/scalers/mongo_scaler.go +++ b/pkg/scalers/mongo_scaler.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "net" + "net/url" "strconv" "time" @@ -130,7 +132,7 @@ func parseMongoDBMetadata(config *ScalerConfig) (*mongoDBMetadata, string, error if val, ok := config.TriggerMetadata["queryValue"]; ok { queryValue, err := strconv.ParseInt(val, 10, 64) if err != nil { - return nil, "", fmt.Errorf("failed to convert %v to int, because of %v", queryValue, err.Error()) + return nil, "", fmt.Errorf("failed to convert %v to int, because of %v", val, err.Error()) } meta.queryValue = queryValue } else { @@ -141,15 +143,16 @@ func parseMongoDBMetadata(config *ScalerConfig) (*mongoDBMetadata, string, error if val, ok := config.TriggerMetadata["activationQueryValue"]; ok { activationQueryValue, err := strconv.ParseInt(val, 10, 64) if err != nil { - return nil, "", fmt.Errorf("failed to convert %v to int, because of %v", activationQueryValue, err.Error()) + return nil, "", fmt.Errorf("failed to convert %v to int, because of %v", val, err.Error()) } meta.activationQueryValue = activationQueryValue } - meta.dbName, err = GetFromAuthOrMeta(config, "dbName") + dbName, err := GetFromAuthOrMeta(config, "dbName") if err != nil { return nil, "", err } + meta.dbName = dbName // Resolve connectionString switch { @@ -159,20 +162,23 @@ func parseMongoDBMetadata(config *ScalerConfig) (*mongoDBMetadata, string, error meta.connectionString = config.ResolvedEnv[config.TriggerMetadata["connectionStringFromEnv"]] default: meta.connectionString = "" - meta.host, err = GetFromAuthOrMeta(config, "host") + host, err := GetFromAuthOrMeta(config, "host") if err != nil { return nil, "", err } + meta.host = host - meta.port, err = GetFromAuthOrMeta(config, "port") + port, err := GetFromAuthOrMeta(config, "port") if err != nil { return nil, "", err } + meta.port = port - meta.username, err = GetFromAuthOrMeta(config, "username") + username, err := GetFromAuthOrMeta(config, "username") if err != nil { return nil, "", err } + meta.username = username if config.AuthParams["password"] != "" { meta.password = config.AuthParams["password"] @@ -188,9 +194,8 @@ func parseMongoDBMetadata(config *ScalerConfig) (*mongoDBMetadata, string, error connStr = meta.connectionString } else { // Build connection str - addr := fmt.Sprintf("%s:%s", meta.host, meta.port) - auth := fmt.Sprintf("%s:%s", meta.username, meta.password) - connStr = "mongodb://" + auth + "@" + addr + "/" + meta.dbName + addr := net.JoinHostPort(meta.host, meta.port) + connStr = fmt.Sprintf("mongodb://%s:%s@%s/%s", url.QueryEscape(meta.username), url.QueryEscape(meta.password), addr, meta.dbName) } if val, ok := config.TriggerMetadata["metricName"]; ok { @@ -245,7 +250,7 @@ func (s *mongoDBScaler) getQueryResult(ctx context.Context) (int64, error) { } // GetMetrics query from mongoDB,and return to external metrics -func (s *mongoDBScaler) GetMetrics(ctx context.Context, metricName string, metricSelector labels.Selector) ([]external_metrics.ExternalMetricValue, error) { +func (s *mongoDBScaler) GetMetrics(ctx context.Context, metricName string, _ labels.Selector) ([]external_metrics.ExternalMetricValue, error) { num, err := s.getQueryResult(ctx) if err != nil { return []external_metrics.ExternalMetricValue{}, fmt.Errorf("failed to inspect momgoDB, because of %v", err) diff --git a/pkg/scalers/mongo_scaler_test.go b/pkg/scalers/mongo_scaler_test.go index 303ccf9a3a6..1550ede6fbb 100644 --- a/pkg/scalers/mongo_scaler_test.go +++ b/pkg/scalers/mongo_scaler_test.go @@ -5,12 +5,13 @@ import ( "testing" "github.com/go-logr/logr" + "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/mongo" ) var testMongoDBResolvedEnv = map[string]string{ - "MongoDB_CONN_STR": "test_conn_str", - "MongoDB_PASSWORD": "test", + "MongoDB_CONN_STR": "mongodb://mongodb0.example.com:27017", + "MongoDB_PASSWORD": "test@password", } type parseMongoDBMetadataTestData struct { @@ -20,6 +21,11 @@ type parseMongoDBMetadataTestData struct { raisesError bool } +type mongoDBConnectionStringTestData struct { + metadataTestData *parseMongoDBMetadataTestData + connectionString string +} + type mongoDBMetricIdentifier struct { metadataTestData *parseMongoDBMetadataTestData scalerIndex int @@ -36,22 +42,29 @@ var testMONGODBMetadata = []parseMongoDBMetadataTestData{ }, // connectionStringFromEnv { - metadata: map[string]string{"query": `{"name":"John"}`, "collection": "demo", "queryValue": "12", "connectionStringFromEnv": "Mongo_CONN_STR", "dbName": "test"}, + metadata: map[string]string{"query": `{"name":"John"}`, "collection": "demo", "queryValue": "12", "connectionStringFromEnv": "MongoDB_CONN_STR", "dbName": "test"}, authParams: map[string]string{}, resolvedEnv: testMongoDBResolvedEnv, raisesError: false, }, // with metric name { - metadata: map[string]string{"query": `{"name":"John"}`, "metricName": "hpa", "collection": "demo", "queryValue": "12", "connectionStringFromEnv": "Mongo_CONN_STR", "dbName": "test"}, + metadata: map[string]string{"query": `{"name":"John"}`, "metricName": "hpa", "collection": "demo", "queryValue": "12", "connectionStringFromEnv": "MongoDB_CONN_STR", "dbName": "test"}, authParams: map[string]string{}, resolvedEnv: testMongoDBResolvedEnv, raisesError: false, }, + // from passwordFromEnv + { + metadata: map[string]string{"query": `{"name":"John"}`, "metricName": "hpa", "collection": "demo", "queryValue": "12", "passwordFromEnv": "MongoDB_PASSWORD"}, + authParams: map[string]string{"dbName": "test", "host": "localshot", "port": "1234", "username": "sample"}, + resolvedEnv: testMongoDBResolvedEnv, + raisesError: false, + }, // from trigger auth { metadata: map[string]string{"query": `{"name":"John"}`, "metricName": "hpa", "collection": "demo", "queryValue": "12"}, - authParams: map[string]string{"dbName": "test", "host": "localshot", "port": "1234", "username": "sample", "password": "secure"}, + authParams: map[string]string{"dbName": "test", "host": "localshot", "port": "1234", "username": "sample", "password": "sec@ure"}, resolvedEnv: testMongoDBResolvedEnv, raisesError: false, }, @@ -64,6 +77,12 @@ var testMONGODBMetadata = []parseMongoDBMetadataTestData{ }, } +var mongoDBConnectionStringTestDatas = []mongoDBConnectionStringTestData{ + {metadataTestData: &testMONGODBMetadata[2], connectionString: "mongodb://mongodb0.example.com:27017"}, + {metadataTestData: &testMONGODBMetadata[3], connectionString: "mongodb://sample:test%40password@localshot:1234/test"}, + {metadataTestData: &testMONGODBMetadata[4], connectionString: "mongodb://sample:sec%40ure@localshot:1234/test"}, +} + var mongoDBMetricIdentifiers = []mongoDBMetricIdentifier{ {metadataTestData: &testMONGODBMetadata[2], scalerIndex: 0, name: "s0-mongodb-hpa"}, {metadataTestData: &testMONGODBMetadata[2], scalerIndex: 1, name: "s1-mongodb-hpa"}, @@ -71,7 +90,7 @@ var mongoDBMetricIdentifiers = []mongoDBMetricIdentifier{ func TestParseMongoDBMetadata(t *testing.T) { for _, testData := range testMONGODBMetadata { - _, _, err := parseMongoDBMetadata(&ScalerConfig{TriggerMetadata: testData.metadata, AuthParams: testData.authParams}) + _, _, err := parseMongoDBMetadata(&ScalerConfig{ResolvedEnv: testData.resolvedEnv, TriggerMetadata: testData.metadata, AuthParams: testData.authParams}) if err != nil && !testData.raisesError { t.Error("Expected success but got error:", err) } @@ -81,6 +100,16 @@ func TestParseMongoDBMetadata(t *testing.T) { } } +func TestParseMongoDBConnectionString(t *testing.T) { + for _, testData := range mongoDBConnectionStringTestDatas { + _, connStr, err := parseMongoDBMetadata(&ScalerConfig{ResolvedEnv: testData.metadataTestData.resolvedEnv, TriggerMetadata: testData.metadataTestData.metadata, AuthParams: testData.metadataTestData.authParams}) + if err != nil { + t.Error("Expected success but got error:", err) + } + assert.Equal(t, testData.connectionString, connStr) + } +} + func TestMongoDBGetMetricSpecForScaling(t *testing.T) { for _, testData := range mongoDBMetricIdentifiers { meta, _, err := parseMongoDBMetadata(&ScalerConfig{ResolvedEnv: testData.metadataTestData.resolvedEnv, AuthParams: testData.metadataTestData.authParams, TriggerMetadata: testData.metadataTestData.metadata, ScalerIndex: testData.scalerIndex}) diff --git a/pkg/scalers/nats_jetstream_scaler.go b/pkg/scalers/nats_jetstream_scaler.go index d60c0f1df2d..d2922a35706 100644 --- a/pkg/scalers/nats_jetstream_scaler.go +++ b/pkg/scalers/nats_jetstream_scaler.go @@ -195,7 +195,7 @@ func (s *natsJetStreamScaler) getMaxMsgLag() int64 { for _, consumer := range s.stream.Consumers { if consumer.Name == consumerName { - return int64(consumer.NumPending) + return int64(consumer.NumPending + consumer.NumAckPending) } } return s.stream.State.LastSequence diff --git a/pkg/scalers/newrelic_scaler.go b/pkg/scalers/newrelic_scaler.go index 96fd495f52c..48cc2ca7718 100644 --- a/pkg/scalers/newrelic_scaler.go +++ b/pkg/scalers/newrelic_scaler.go @@ -72,7 +72,8 @@ func NewNewRelicScaler(config *ScalerConfig) (Scaler, error) { return &newrelicScaler{ metricType: metricType, metadata: meta, - nrClient: nrClient}, nil + nrClient: nrClient, + logger: logger}, nil } func parseNewRelicMetadata(config *ScalerConfig, logger logr.Logger) (*newrelicMetadata, error) { diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 4400428d64f..1197783ae38 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "io" + "math" "net/http" url_pkg "net/url" "strconv" @@ -285,6 +286,15 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error } } + if math.IsInf(v, 0) { + if s.metadata.ignoreNullValues { + return 0, nil + } + err := fmt.Errorf("promtheus query returns %f", v) + s.logger.Error(err, "Error converting prometheus value") + return -1, err + } + return v, nil } diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index aa35c343974..f67ad5d87c4 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -216,6 +216,38 @@ var testPromQueryResult = []prometheusQromQueryResultTestData{ isError: true, ignoreNullValues: true, }, + { + name: "+Inf", + bodyStr: `{"data":{"result":[{"value": ["1", "+Inf"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: 0, + isError: false, + ignoreNullValues: true, + }, + { + name: "+Inf but shouldn't ignore ", + bodyStr: `{"data":{"result":[{"value": ["1", "+Inf"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: -1, + isError: true, + ignoreNullValues: false, + }, + { + name: "-Inf", + bodyStr: `{"data":{"result":[{"value": ["1", "-Inf"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: 0, + isError: false, + ignoreNullValues: true, + }, + { + name: "-Inf but shouldn't ignore ", + bodyStr: `{"data":{"result":[{"value": ["1", "-Inf"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: -1, + isError: true, + ignoreNullValues: false, + }, } func TestPrometheusScalerExecutePromQuery(t *testing.T) { diff --git a/pkg/scalers/stackdriver_client.go b/pkg/scalers/stackdriver_client.go index 38a45715ab8..e96d741c37b 100644 --- a/pkg/scalers/stackdriver_client.go +++ b/pkg/scalers/stackdriver_client.go @@ -166,7 +166,7 @@ func (s StackDriverClient) GetMetrics( ctx context.Context, filter string, projectID string, - aggregation *monitoringpb.Aggregation) (int64, error) { + aggregation *monitoringpb.Aggregation) (float64, error) { // Set the start time to 1 minute ago startTime := time.Now().UTC().Add(time.Minute * -2) @@ -197,7 +197,7 @@ func (s StackDriverClient) GetMetrics( // Get an iterator with the list of time series it := s.metricsClient.ListTimeSeries(ctx, req) - var value int64 = -1 + var value float64 = -1 // Get the value from the first metric returned resp, err := it.Next() @@ -212,12 +212,28 @@ func (s StackDriverClient) GetMetrics( if len(resp.GetPoints()) > 0 { point := resp.GetPoints()[0] - value = point.GetValue().GetInt64Value() + value, err = extractValueFromPoint(point) + + if err != nil { + return value, err + } } return value, nil } +// extractValueFromPoint attempts to extract a float64 by asserting the point's value type +func extractValueFromPoint(point *monitoringpb.Point) (float64, error) { + typedValue := point.GetValue() + switch typedValue.Value.(type) { + case *monitoringpb.TypedValue_DoubleValue: + return typedValue.GetDoubleValue(), nil + case *monitoringpb.TypedValue_Int64Value: + return float64(typedValue.GetInt64Value()), nil + } + return -1, fmt.Errorf("could not extract value from metric of type %T", typedValue) +} + // GoogleApplicationCredentials is a struct representing the format of a service account // credentials file type GoogleApplicationCredentials struct { diff --git a/pkg/scaling/resolver/scale_resolvers.go b/pkg/scaling/resolver/scale_resolvers.go index d420b944a79..1b47227cad1 100644 --- a/pkg/scaling/resolver/scale_resolvers.go +++ b/pkg/scaling/resolver/scale_resolvers.go @@ -332,6 +332,9 @@ func resolveEnv(ctx context.Context, client client.Client, logger logr.Logger, c // env is a secret selector value, err = resolveSecretValue(ctx, client, envVar.ValueFrom.SecretKeyRef, envVar.ValueFrom.SecretKeyRef.Key, namespace) if err != nil { + if envVar.ValueFrom.SecretKeyRef.Optional != nil && *envVar.ValueFrom.SecretKeyRef.Optional { + continue + } return nil, fmt.Errorf("error resolving secret name %s for env %s in namespace %s", envVar.ValueFrom.SecretKeyRef, envVar.Name, @@ -341,6 +344,9 @@ func resolveEnv(ctx context.Context, client client.Client, logger logr.Logger, c // env is a configMap selector value, err = resolveConfigValue(ctx, client, envVar.ValueFrom.ConfigMapKeyRef, envVar.ValueFrom.ConfigMapKeyRef.Key, namespace) if err != nil { + if envVar.ValueFrom.ConfigMapKeyRef.Optional != nil && *envVar.ValueFrom.ConfigMapKeyRef.Optional { + continue + } return nil, fmt.Errorf("error resolving config %s for env %s in namespace %s", envVar.ValueFrom.ConfigMapKeyRef, envVar.Name, diff --git a/pkg/scaling/resolver/scale_resolvers_test.go b/pkg/scaling/resolver/scale_resolvers_test.go index e4a109b6bdb..6f5f9d53a77 100644 --- a/pkg/scaling/resolver/scale_resolvers_test.go +++ b/pkg/scaling/resolver/scale_resolvers_test.go @@ -143,6 +143,78 @@ var testMetadatas = []testMetadata{ }}, }, }, + { + isError: false, + comment: "configmap does not exist, but it is marked as an optional, there should not be an error", + container: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "test", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "do-not-exist-and-optional-explicitly", + }, + Key: "test", + Optional: &trueValue, + }, + }, + }}, + }, + }, + { + isError: false, + comment: "secret does not exist, but it is marked as an optional, there should not be an error", + container: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "test", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "do-not-exist-and-optional-explicitly", + }, + Key: "test", + Optional: &trueValue, + }, + }, + }}, + }, + }, + { + isError: true, + comment: "configmap does not exist, and it is not marked as an optional, there should be an error", + container: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "test", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "do-not-exist-and-not-optional", + }, + Key: "test", + Optional: &falseValue, + }, + }, + }}, + }, + }, + { + isError: true, + comment: "secret does not exist, and it is not marked as an optional, there should be an error", + container: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "test", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "do-not-exist-and-not-optional", + }, + Key: "test", + Optional: &falseValue, + }, + }, + }}, + }, + }, } func TestResolveNonExistingConfigMapsOrSecretsEnv(t *testing.T) { diff --git a/pkg/scaling/scale_handler.go b/pkg/scaling/scale_handler.go index 035cc05bebf..a506f6df193 100644 --- a/pkg/scaling/scale_handler.go +++ b/pkg/scaling/scale_handler.go @@ -237,7 +237,6 @@ func (h *scaleHandler) startPushScalers(ctx context.Context, withTriggers *kedav go func(s scalers.PushScaler) { activeCh := make(chan bool) go s.Run(ctx, activeCh) - defer s.Close(ctx) for { select { case <-ctx.Done():