From f49a7249d630e491d43beef34a229fb863d4d2a1 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 14:36:57 +0530 Subject: [PATCH 01/18] =?UTF-8?q?feat(prometheus-scaler):=20=E2=9C=A8=20su?= =?UTF-8?q?pport=20custom=20headers=20for=20querying=20prometheus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler.go | 13 +++++++++++++ pkg/util/parse_string.go | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index b96e61e7a81..8cc8365796f 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -28,6 +28,7 @@ const ( promNamespace = "namespace" promCortexScopeOrgID = "cortexOrgID" promCortexHeaderKey = "X-Scope-OrgID" + promHeaders = "headers" ignoreNullValues = "ignoreNullValues" unsafeSsl = "unsafeSsl" ) @@ -53,6 +54,7 @@ type prometheusMetadata struct { namespace string scalerIndex int cortexOrgID string + headers map[string]string // sometimes should consider there is an error we can accept // default value is true/t, to ignore the null value return from prometheus // change to false/f if can not accept prometheus return null values @@ -160,6 +162,13 @@ func parsePrometheusMetadata(config *ScalerConfig) (meta *prometheusMetadata, er meta.cortexOrgID = val } + if val, ok := config.TriggerMetadata[promHeaders]; ok && val != "" { + meta.headers, err = kedautil.ParseStringList(val) + if err != nil { + return nil, fmt.Errorf("error parsing %s: %w", promHeaders, err) + } + } + meta.ignoreNullValues = defaultIgnoreNullValues if val, ok := config.TriggerMetadata[ignoreNullValues]; ok && val != "" { ignoreNullValues, err := strconv.ParseBool(val) @@ -235,6 +244,10 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error req.Header.Add(promCortexHeaderKey, s.metadata.cortexOrgID) } + for headerName, headerValue := range s.metadata.headers { + req.Header.Add(headerName, headerValue) + } + r, err := s.httpClient.Do(req) if err != nil { return -1, err diff --git a/pkg/util/parse_string.go b/pkg/util/parse_string.go index 878360474e7..e93563e9be0 100644 --- a/pkg/util/parse_string.go +++ b/pkg/util/parse_string.go @@ -63,3 +63,22 @@ func ParseInt32List(pattern string) ([]int32, error) { } return parsed, nil } + +func ParseStringList(pattern string) (map[string]string, error) { + parsed := make(map[string]string) + pattern = strings.TrimSpace(pattern) + if pattern == "" { + return parsed, nil + } + pairs := strings.Split(pattern, ",") + for _, pair := range pairs { + keyvalue := strings.Split(pair, "=") + if len(keyvalue) != 2 { + return nil, fmt.Errorf("error in key-value syntax, got '%s'", pair) + } + keyvalue[0] = strings.TrimSpace(keyvalue[0]) + keyvalue[1] = strings.TrimSpace(keyvalue[1]) + parsed[keyvalue[0]] = keyvalue[1] + } + return parsed, nil +} From 1c1c6fe4ffabb9a57ce4c10e8a0842da9715df40 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 14:38:39 +0530 Subject: [PATCH 02/18] =?UTF-8?q?test:=20=E2=9C=85=20add=20tests=20for=20P?= =?UTF-8?q?arseStringList=20used=20by=20Prometheus=20scaler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/util/parse_string_test.go | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pkg/util/parse_string_test.go b/pkg/util/parse_string_test.go index 647d92c5a09..b64d1542f76 100644 --- a/pkg/util/parse_string_test.go +++ b/pkg/util/parse_string_test.go @@ -85,3 +85,45 @@ func TestParseint32List(t *testing.T) { }) } } + +func TestParseStringList(t *testing.T) { + testData := []struct { + name string + pattern string + exp map[string]string + isError bool + }{ + {"success, no key-value", "", map[string]string{}, false}, + {"success, one key, no value", "key1=", map[string]string{"key1": ""}, false}, + {"success, one key, no value, with spaces", "key1 = ", map[string]string{"key1": ""}, false}, + {"success, one pair", "key1=value1", map[string]string{"key1": "value1"}, false}, + {"success, one pair with spaces", "key1 = value1", map[string]string{"key1": "value1"}, false}, + {"success, one pair with spaces and no value", "key1 = ", map[string]string{"key1": ""}, false}, + {"success, two keys, no value", "key1=,key2=", map[string]string{"key1": "", "key2": ""}, false}, + {"success, two keys, no value, with spaces", "key1 = , key2 = ", map[string]string{"key1": "", "key2": ""}, false}, + {"success, two pairs", "key1=value1,key2=value2", map[string]string{"key1": "value1", "key2": "value2"}, false}, + {"success, two pairs with spaces", "key1 = value1, key2 = value2", map[string]string{"key1": "value1", "key2": "value2"}, false}, + {"failure, one key", "key1", nil, true}, + {"failure, one key ending with two successive equals to", "key1==", nil, true}, + {"failure, one valid pair and invalid one key", "key1=value1,key2", nil, true}, + {"failure, two valid pairs and invalid two keys", "key1=value1,key2=value2,key3,key4", nil, true}, + } + + for _, tt := range testData { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseStringList(tt.pattern) + + if err != nil && !tt.isError { + t.Errorf("Expected no error but got %s\n", err) + } + + if err == nil && tt.isError { + t.Errorf("Expected error but got %s\n", err) + } + + if !reflect.DeepEqual(tt.exp, got) { + t.Errorf("Expected %v but got %v\n", tt.exp, got) + } + }) + } +} From b3cd54ccdbc7e00613d95302529d31d8d9363f38 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 17:10:22 +0530 Subject: [PATCH 03/18] =?UTF-8?q?feat(prometheus-scaler):=20=F0=9F=9A=9A?= =?UTF-8?q?=20use=20customHeaders=20metadata=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 8cc8365796f..962e7d361ff 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -28,7 +28,7 @@ const ( promNamespace = "namespace" promCortexScopeOrgID = "cortexOrgID" promCortexHeaderKey = "X-Scope-OrgID" - promHeaders = "headers" + promCustomHeaders = "customHeaders" ignoreNullValues = "ignoreNullValues" unsafeSsl = "unsafeSsl" ) @@ -54,7 +54,7 @@ type prometheusMetadata struct { namespace string scalerIndex int cortexOrgID string - headers map[string]string + customHeaders map[string]string // sometimes should consider there is an error we can accept // default value is true/t, to ignore the null value return from prometheus // change to false/f if can not accept prometheus return null values @@ -162,10 +162,10 @@ func parsePrometheusMetadata(config *ScalerConfig) (meta *prometheusMetadata, er meta.cortexOrgID = val } - if val, ok := config.TriggerMetadata[promHeaders]; ok && val != "" { - meta.headers, err = kedautil.ParseStringList(val) + if val, ok := config.TriggerMetadata[promCustomHeaders]; ok && val != "" { + meta.customHeaders, err = kedautil.ParseStringList(val) if err != nil { - return nil, fmt.Errorf("error parsing %s: %w", promHeaders, err) + return nil, fmt.Errorf("error parsing %s: %w", promCustomHeaders, err) } } @@ -244,7 +244,7 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error req.Header.Add(promCortexHeaderKey, s.metadata.cortexOrgID) } - for headerName, headerValue := range s.metadata.headers { + for headerName, headerValue := range s.metadata.customHeaders { req.Header.Add(headerName, headerValue) } From 8616cc129193a3840f0f5602d634b455c5893e09 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 17:12:56 +0530 Subject: [PATCH 04/18] =?UTF-8?q?test(prometheus-scaler):=20=E2=9C=85=20ad?= =?UTF-8?q?d=20tests=20for=20custom=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler_test.go | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index 674622cac7a..ec6c5eec99d 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -332,3 +332,43 @@ func TestPrometheusScalerCortexHeader(t *testing.T) { assert.NoError(t, err) } + +func TestPrometheusScalerCustomHeaders(t *testing.T) { + testData := prometheusQromQueryResultTestData{ + name: "no values", + bodyStr: `{"data":{"result":[]}}`, + responseStatus: http.StatusOK, + expectedValue: 0, + isError: false, + ignoreNullValues: true, + } + customHeadersValue := map[string]string{ + "X-Client-Id": "cid", + "X-Tenant-Id": "tid", + "X-Auth-Token": "authtoken", + } + server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + for headerName, headerValue := range customHeadersValue { + reqHeader := request.Header.Get(headerName) + assert.Equal(t, reqHeader, headerValue) + } + + writer.WriteHeader(testData.responseStatus) + if _, err := writer.Write([]byte(testData.bodyStr)); err != nil { + t.Fatal(err) + } + })) + + scaler := prometheusScaler{ + metadata: &prometheusMetadata{ + serverAddress: server.URL, + customHeaders: customHeadersValue, + ignoreNullValues: testData.ignoreNullValues, + }, + httpClient: http.DefaultClient, + } + + _, err := scaler.ExecutePromQuery(context.TODO()) + + assert.NoError(t, err) +} From e051f3f2670c187d7b9ea5d736f87940123586c3 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 17:24:54 +0530 Subject: [PATCH 05/18] =?UTF-8?q?docs:=20=F0=9F=93=9D=20add=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49060cac224..f72b5d92416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Here is an overview of all new **experimental** features: - **RabbitMQ Scaler**: Add TLS support ([#967](https://github.com/kedacore/keda/issues/967)) - **Redis Scalers**: Add support to Redis 7 ([#4052](https://github.com/kedacore/keda/issues/4052)) - **Selenium Grid Scaler**: Add 'platformName' to selenium-grid scaler metadata structure ([#4038](https://github.com/kedacore/keda/issues/4038)) +- **Prometheus Scaler**: Add custom headers support ([#4037](https://github.com/kedacore/keda/issues/4208)) ### Fixes From 1b630101210703c11d6e086522104f1a863267a2 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 17:32:40 +0530 Subject: [PATCH 06/18] =?UTF-8?q?fix(prometheus-scaler):=20=F0=9F=90=9B=20?= =?UTF-8?q?only=20set=20customHeaders=20when=20no=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 962e7d361ff..1cceec4cd60 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -163,10 +163,12 @@ func parsePrometheusMetadata(config *ScalerConfig) (meta *prometheusMetadata, er } if val, ok := config.TriggerMetadata[promCustomHeaders]; ok && val != "" { - meta.customHeaders, err = kedautil.ParseStringList(val) + customHeaders, err := kedautil.ParseStringList(val) if err != nil { return nil, fmt.Errorf("error parsing %s: %w", promCustomHeaders, err) } + + meta.customHeaders = customHeaders } meta.ignoreNullValues = defaultIgnoreNullValues From 45aedf08e52a342d626f797e3976cf4c01f6da38 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 17:49:37 +0530 Subject: [PATCH 07/18] =?UTF-8?q?docs:=20=F0=9F=93=9D=20update=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f72b5d92416..dfbfce03209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,7 @@ Here is an overview of all new **experimental** features: - **RabbitMQ Scaler**: Add TLS support ([#967](https://github.com/kedacore/keda/issues/967)) - **Redis Scalers**: Add support to Redis 7 ([#4052](https://github.com/kedacore/keda/issues/4052)) - **Selenium Grid Scaler**: Add 'platformName' to selenium-grid scaler metadata structure ([#4038](https://github.com/kedacore/keda/issues/4038)) -- **Prometheus Scaler**: Add custom headers support ([#4037](https://github.com/kedacore/keda/issues/4208)) +- **Prometheus Scaler**: Add custom headers support ([#4208](https://github.com/kedacore/keda/issues/4208)) ### Fixes From e7741dec9bc9bbd34cbe5b1d6c32010270c77b6d Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 19:06:13 +0530 Subject: [PATCH 08/18] =?UTF-8?q?feat(prometheus-scaler):=20=F0=9F=9A=9A?= =?UTF-8?q?=20add=20custom=20auth=20header=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/authentication/authentication_helpers.go | 11 +++++++++++ pkg/scalers/authentication/authentication_types.go | 7 +++++++ pkg/scalers/prometheus_scaler.go | 2 ++ 3 files changed, 20 insertions(+) diff --git a/pkg/scalers/authentication/authentication_helpers.go b/pkg/scalers/authentication/authentication_helpers.go index 6ecf5c315a5..e8623984c01 100644 --- a/pkg/scalers/authentication/authentication_helpers.go +++ b/pkg/scalers/authentication/authentication_helpers.go @@ -69,6 +69,17 @@ func GetAuthConfigs(triggerMetadata, authParams map[string]string) (out *AuthMet out.Key = authParams["key"] out.EnableTLS = true + case CustomAuthType: + if len(authParams["customAuthHeader"]) == 0 { + return nil, errors.New("no custom auth header given") + } + out.CustomAuthHeader = authParams["customAuthHeader"] + + if len(authParams["customAuthValue"]) == 0 { + return nil, errors.New("no custom auth value given") + } + out.CustomAuthValue = authParams["customAuthValue"] + out.EnableCustomAuth = true default: return nil, fmt.Errorf("incorrect value for authMode is given: %s", t) } diff --git a/pkg/scalers/authentication/authentication_types.go b/pkg/scalers/authentication/authentication_types.go index 13f49167e13..557e69c5132 100644 --- a/pkg/scalers/authentication/authentication_types.go +++ b/pkg/scalers/authentication/authentication_types.go @@ -14,6 +14,8 @@ const ( TLSAuthType Type = "tls" // BearerAuthType is a auth type using a bearer token BearerAuthType Type = "bearer" + // CustomAuthType is a auth type using a custom header + CustomAuthType Type = "customAuth" ) // TransportType is type of http transport @@ -39,6 +41,11 @@ type AuthMeta struct { Cert string Key string CA string + + // custom auth header + EnableCustomAuth bool + CustomAuthHeader string + CustomAuthValue string } type HTTPTransport struct { diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 1cceec4cd60..889886b7488 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -240,6 +240,8 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error req.Header.Add("Authorization", authentication.GetBearerToken(s.metadata.prometheusAuth)) } else if s.metadata.prometheusAuth != nil && s.metadata.prometheusAuth.EnableBasicAuth { req.SetBasicAuth(s.metadata.prometheusAuth.Username, s.metadata.prometheusAuth.Password) + } else if s.metadata.prometheusAuth != nil && s.metadata.prometheusAuth.EnableCustomAuth { + req.Header.Add(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue) } if s.metadata.cortexOrgID != "" { From cc06bb142522efa4db7e2d38b8f3ae180e7688b2 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 19:06:52 +0530 Subject: [PATCH 09/18] =?UTF-8?q?test(prometheus-scaler):=20=E2=9C=85=20up?= =?UTF-8?q?date=20tests=20for=20custom=20auth=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler_test.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index ec6c5eec99d..8416e988020 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -82,6 +82,12 @@ var testPrometheusAuthMetadata = []prometheusAuthMetadataTestData{ {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "tls, basic"}, map[string]string{"ca": "caaa", "cert": "ceert", "key": "keey", "username": "user", "password": "pass"}, false}, {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "tls,basic"}, map[string]string{"username": "user", "password": "pass"}, true}, + // success customAuth + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthHeader": "header", "customAuthValue": "value"}, false}, + // fail customAuth with no customAuthHeader + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthHeader": ""}, true}, + // fail customAuth with no customAuthValue + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthValue": ""}, true}, } func TestPrometheusParseMetadata(t *testing.T) { @@ -129,7 +135,8 @@ func TestPrometheusScalerAuthParams(t *testing.T) { if err == nil { if (meta.prometheusAuth.EnableBearerAuth && !strings.Contains(testData.metadata["authModes"], "bearer")) || (meta.prometheusAuth.EnableBasicAuth && !strings.Contains(testData.metadata["authModes"], "basic")) || - (meta.prometheusAuth.EnableTLS && !strings.Contains(testData.metadata["authModes"], "tls")) { + (meta.prometheusAuth.EnableTLS && !strings.Contains(testData.metadata["authModes"], "tls")) || + (meta.prometheusAuth.EnableCustomAuth && !strings.Contains(testData.metadata["authModes"], "customAuth")) { t.Error("wrong auth mode detected") } } @@ -343,9 +350,9 @@ func TestPrometheusScalerCustomHeaders(t *testing.T) { ignoreNullValues: true, } customHeadersValue := map[string]string{ - "X-Client-Id": "cid", - "X-Tenant-Id": "tid", - "X-Auth-Token": "authtoken", + "X-Client-Id": "cid", + "X-Tenant-Id": "tid", + "X-Organization-Token": "oid", } server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { for headerName, headerValue := range customHeadersValue { From e0c471f0be5a626adb6a41e0ad3ecd117c30c311 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 19:08:27 +0530 Subject: [PATCH 10/18] =?UTF-8?q?docs:=20=F0=9F=93=9D=20update=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfbfce03209..6cc073d67ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,10 +63,10 @@ Here is an overview of all new **experimental** features: - **General**: Add a warning when KEDA run outside supported k8s versions ([#4130](https://github.com/kedacore/keda/issues/4130)) - **General**: Use (self-signed) certificates for all the communications (internals and externals) ([#3931](https://github.com/kedacore/keda/issues/3931)) - **Hashicorp Vault**: Add support to secrets backend version 1 ([#2645](https://github.com/kedacore/keda/issues/2645)) +- **Prometheus Scaler**: Add custom headers and custom auth support ([#4208](https://github.com/kedacore/keda/issues/4208)) - **RabbitMQ Scaler**: Add TLS support ([#967](https://github.com/kedacore/keda/issues/967)) - **Redis Scalers**: Add support to Redis 7 ([#4052](https://github.com/kedacore/keda/issues/4052)) - **Selenium Grid Scaler**: Add 'platformName' to selenium-grid scaler metadata structure ([#4038](https://github.com/kedacore/keda/issues/4038)) -- **Prometheus Scaler**: Add custom headers support ([#4208](https://github.com/kedacore/keda/issues/4208)) ### Fixes From 7bfe021b40415fcb49bf3f28b040159f5adf987f Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 19:22:52 +0530 Subject: [PATCH 11/18] =?UTF-8?q?feat(prometheus-scaler):=20=F0=9F=9A=9A?= =?UTF-8?q?=20use=20custom=20instead=20of=20customAuth=20as=20auth=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/authentication/authentication_types.go | 2 +- pkg/scalers/prometheus_scaler_test.go | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/scalers/authentication/authentication_types.go b/pkg/scalers/authentication/authentication_types.go index 557e69c5132..d6484dce233 100644 --- a/pkg/scalers/authentication/authentication_types.go +++ b/pkg/scalers/authentication/authentication_types.go @@ -15,7 +15,7 @@ const ( // BearerAuthType is a auth type using a bearer token BearerAuthType Type = "bearer" // CustomAuthType is a auth type using a custom header - CustomAuthType Type = "customAuth" + CustomAuthType Type = "custom" ) // TransportType is type of http transport diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index 8416e988020..139822cd09c 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -82,12 +82,12 @@ var testPrometheusAuthMetadata = []prometheusAuthMetadataTestData{ {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "tls, basic"}, map[string]string{"ca": "caaa", "cert": "ceert", "key": "keey", "username": "user", "password": "pass"}, false}, {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "tls,basic"}, map[string]string{"username": "user", "password": "pass"}, true}, - // success customAuth - {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthHeader": "header", "customAuthValue": "value"}, false}, - // fail customAuth with no customAuthHeader - {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthHeader": ""}, true}, - // fail customAuth with no customAuthValue - {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "customAuth"}, map[string]string{"customAuthValue": ""}, true}, + // success custom auth + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "custom"}, map[string]string{"customAuthHeader": "header", "customAuthValue": "value"}, false}, + // fail custom auth with no customAuthHeader + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "custom"}, map[string]string{"customAuthHeader": ""}, true}, + // fail custom auth with no customAuthValue + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "authModes": "custom"}, map[string]string{"customAuthValue": ""}, true}, } func TestPrometheusParseMetadata(t *testing.T) { @@ -136,7 +136,7 @@ func TestPrometheusScalerAuthParams(t *testing.T) { if (meta.prometheusAuth.EnableBearerAuth && !strings.Contains(testData.metadata["authModes"], "bearer")) || (meta.prometheusAuth.EnableBasicAuth && !strings.Contains(testData.metadata["authModes"], "basic")) || (meta.prometheusAuth.EnableTLS && !strings.Contains(testData.metadata["authModes"], "tls")) || - (meta.prometheusAuth.EnableCustomAuth && !strings.Contains(testData.metadata["authModes"], "customAuth")) { + (meta.prometheusAuth.EnableCustomAuth && !strings.Contains(testData.metadata["authModes"], "custom")) { t.Error("wrong auth mode detected") } } From 593a20fa29a0c46ddd132b449f7164ab984b9991 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 7 Feb 2023 20:02:20 +0530 Subject: [PATCH 12/18] =?UTF-8?q?chore(prometheus-scaler):=20=F0=9F=8E=A8?= =?UTF-8?q?=20rewrite=20if-else=20to=20switch=20statement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 889886b7488..3fb55b5293f 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -236,11 +236,14 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error return -1, err } - if s.metadata.prometheusAuth != nil && s.metadata.prometheusAuth.EnableBearerAuth { + switch { + case s.metadata.prometheusAuth == nil: + break + case s.metadata.prometheusAuth.EnableBearerAuth: req.Header.Add("Authorization", authentication.GetBearerToken(s.metadata.prometheusAuth)) - } else if s.metadata.prometheusAuth != nil && s.metadata.prometheusAuth.EnableBasicAuth { + case s.metadata.prometheusAuth.EnableBasicAuth: req.SetBasicAuth(s.metadata.prometheusAuth.Username, s.metadata.prometheusAuth.Password) - } else if s.metadata.prometheusAuth != nil && s.metadata.prometheusAuth.EnableCustomAuth { + case s.metadata.prometheusAuth.EnableCustomAuth: req.Header.Add(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue) } From 7cb169432c5ff2f382ed763d3536d87193089252 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Wed, 22 Feb 2023 17:17:53 +0530 Subject: [PATCH 13/18] =?UTF-8?q?refactor(prometheus-scaler):=20?= =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20deprecate=20cortexOrgId=20metadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/loki_scaler_test.go | 4 +-- pkg/scalers/prometheus_scaler.go | 8 +----- pkg/scalers/prometheus_scaler_test.go | 36 +++------------------------ 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/pkg/scalers/loki_scaler_test.go b/pkg/scalers/loki_scaler_test.go index 1ed4d521411..2c70bf532c8 100644 --- a/pkg/scalers/loki_scaler_test.go +++ b/pkg/scalers/loki_scaler_test.go @@ -216,7 +216,7 @@ func TestLokiScalerExecuteLogQLQuery(t *testing.T) { } } -func TestLokiScalerCortexHeader(t *testing.T) { +func TestLokiScalerTenantHeader(t *testing.T) { testData := lokiQromQueryResultTestData{ name: "no values", bodyStr: `{"data":{"result":[]}}`, @@ -227,7 +227,7 @@ func TestLokiScalerCortexHeader(t *testing.T) { } tenantName := "Tenant1" server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { - reqHeader := request.Header.Get(promCortexHeaderKey) + reqHeader := request.Header.Get(tenantNameHeaderKey) assert.Equal(t, reqHeader, tenantName) writer.WriteHeader(testData.responseStatus) if _, err := writer.Write([]byte(testData.bodyStr)); err != nil { diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 3fb55b5293f..d85f287a0c4 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -27,7 +27,6 @@ const ( promActivationThreshold = "activationThreshold" promNamespace = "namespace" promCortexScopeOrgID = "cortexOrgID" - promCortexHeaderKey = "X-Scope-OrgID" promCustomHeaders = "customHeaders" ignoreNullValues = "ignoreNullValues" unsafeSsl = "unsafeSsl" @@ -53,7 +52,6 @@ type prometheusMetadata struct { prometheusAuth *authentication.AuthMeta namespace string scalerIndex int - cortexOrgID string customHeaders map[string]string // sometimes should consider there is an error we can accept // default value is true/t, to ignore the null value return from prometheus @@ -159,7 +157,7 @@ func parsePrometheusMetadata(config *ScalerConfig) (meta *prometheusMetadata, er } if val, ok := config.TriggerMetadata[promCortexScopeOrgID]; ok && val != "" { - meta.cortexOrgID = val + return nil, fmt.Errorf("cortexOrgID is deprecated, please use customHeaders instead") } if val, ok := config.TriggerMetadata[promCustomHeaders]; ok && val != "" { @@ -247,10 +245,6 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error req.Header.Add(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue) } - if s.metadata.cortexOrgID != "" { - req.Header.Add(promCortexHeaderKey, s.metadata.cortexOrgID) - } - for headerName, headerValue := range s.metadata.customHeaders { req.Header.Add(headerName, headerValue) } diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index 139822cd09c..dc51907b21c 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -48,6 +48,9 @@ var testPromMetadata = []parsePrometheusMetadataTestData{ {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "ignoreNullValues": "xxxx"}, true}, {map[string]string{"serverAddress": "https://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "unsafeSsl": "true"}, false}, + + // deprecated cortexOrgID + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "cortexOrgID": "my-org"}, true}, } var prometheusMetricIdentifiers = []prometheusMetricIdentifier{ @@ -307,39 +310,6 @@ func TestPrometheusScalerExecutePromQuery(t *testing.T) { } } -func TestPrometheusScalerCortexHeader(t *testing.T) { - testData := prometheusQromQueryResultTestData{ - name: "no values", - bodyStr: `{"data":{"result":[]}}`, - responseStatus: http.StatusOK, - expectedValue: 0, - isError: false, - ignoreNullValues: true, - } - cortexOrgValue := "my-org" - server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { - reqHeader := request.Header.Get(promCortexHeaderKey) - assert.Equal(t, reqHeader, cortexOrgValue) - writer.WriteHeader(testData.responseStatus) - if _, err := writer.Write([]byte(testData.bodyStr)); err != nil { - t.Fatal(err) - } - })) - - scaler := prometheusScaler{ - metadata: &prometheusMetadata{ - serverAddress: server.URL, - cortexOrgID: cortexOrgValue, - ignoreNullValues: testData.ignoreNullValues, - }, - httpClient: http.DefaultClient, - } - - _, err := scaler.ExecutePromQuery(context.TODO()) - - assert.NoError(t, err) -} - func TestPrometheusScalerCustomHeaders(t *testing.T) { testData := prometheusQromQueryResultTestData{ name: "no values", From b7f430bb6783add912ab3fc547df27a375c76d05 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Wed, 22 Feb 2023 17:32:52 +0530 Subject: [PATCH 14/18] =?UTF-8?q?docs:=20=F0=9F=93=9D=20update=20changelog?= =?UTF-8?q?=20to=20include=20cortexOrgId=20deprecation=20in=20prometheus?= =?UTF-8?q?=20scaler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c053c3d27..be5dbfa7ec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,7 +91,7 @@ You can find all deprecations in [this overview](https://github.com/kedacore/ked New deprecation(s): -- TODO +- **Prometheus Scaler**: `cortexOrgId` metadata deprecated in favor of custom headers ([#4208](https://github.com/kedacore/keda/issues/4208)) ### Other From 389e5657f2769f38af62f892f3889100340bcfb3 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Wed, 22 Feb 2023 20:08:35 +0530 Subject: [PATCH 15/18] =?UTF-8?q?test(prometheus-scaler):=20=E2=9C=85=20ad?= =?UTF-8?q?d=20test=20metadata=20for=20custom=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index dc51907b21c..7b8152bd934 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -46,9 +46,12 @@ var testPromMetadata = []parsePrometheusMetadataTestData{ {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": ""}, true}, // ignoreNullValues with wrong value {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "ignoreNullValues": "xxxx"}, true}, - + // unsafeSsl {map[string]string{"serverAddress": "https://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "unsafeSsl": "true"}, false}, - + // customHeaders + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "customHeaders": "key1=value1,key2=value2"}, false}, + // customHeaders with wrong format + {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "customHeaders": "key1=value1,key2"}, true}, // deprecated cortexOrgID {map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "cortexOrgID": "my-org"}, true}, } From 24da7bfb004ef82ee14fed57f9bcd632c08d540a Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Thu, 23 Feb 2023 18:51:31 +0530 Subject: [PATCH 16/18] =?UTF-8?q?chore(prometheus-scaler):=20=F0=9F=A9=B9?= =?UTF-8?q?=20handle=20duplicate=20keys=20in=20custom=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/util/parse_string.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/util/parse_string.go b/pkg/util/parse_string.go index e93563e9be0..864764d2192 100644 --- a/pkg/util/parse_string.go +++ b/pkg/util/parse_string.go @@ -76,9 +76,12 @@ func ParseStringList(pattern string) (map[string]string, error) { if len(keyvalue) != 2 { return nil, fmt.Errorf("error in key-value syntax, got '%s'", pair) } - keyvalue[0] = strings.TrimSpace(keyvalue[0]) - keyvalue[1] = strings.TrimSpace(keyvalue[1]) - parsed[keyvalue[0]] = keyvalue[1] + key := strings.TrimSpace(keyvalue[0]) + value := strings.TrimSpace(keyvalue[1]) + if _, ok := parsed[key]; ok { + return nil, fmt.Errorf("duplicate key found: %s", key) + } + parsed[key] = value } return parsed, nil } From 989dd306c4862675e24da805bd5c772b51ee0dd3 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Thu, 23 Feb 2023 18:52:49 +0530 Subject: [PATCH 17/18] =?UTF-8?q?test(prometheus-scaler):=20=E2=9C=85=20du?= =?UTF-8?q?plicate=20keys=20in=20custom=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/util/parse_string_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/util/parse_string_test.go b/pkg/util/parse_string_test.go index b64d1542f76..c087cdc6396 100644 --- a/pkg/util/parse_string_test.go +++ b/pkg/util/parse_string_test.go @@ -104,6 +104,7 @@ func TestParseStringList(t *testing.T) { {"success, two pairs", "key1=value1,key2=value2", map[string]string{"key1": "value1", "key2": "value2"}, false}, {"success, two pairs with spaces", "key1 = value1, key2 = value2", map[string]string{"key1": "value1", "key2": "value2"}, false}, {"failure, one key", "key1", nil, true}, + {"failure, duplicate keys", "key1=value1,key1=value2", nil, true}, {"failure, one key ending with two successive equals to", "key1==", nil, true}, {"failure, one valid pair and invalid one key", "key1=value1,key2", nil, true}, {"failure, two valid pairs and invalid two keys", "key1=value1,key2=value2,key3,key4", nil, true}, From f1cde719ccf131abedf2e06ce4208d6330a0c00d Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Thu, 23 Feb 2023 19:32:47 +0530 Subject: [PATCH 18/18] =?UTF-8?q?chore(prometheus-scaler):=20=F0=9F=A9=B9?= =?UTF-8?q?=20higher=20precedence=20to=20auth=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- pkg/scalers/prometheus_scaler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index d85f287a0c4..dcfb31f5010 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -234,19 +234,19 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error return -1, err } + for headerName, headerValue := range s.metadata.customHeaders { + req.Header.Add(headerName, headerValue) + } + switch { case s.metadata.prometheusAuth == nil: break case s.metadata.prometheusAuth.EnableBearerAuth: - req.Header.Add("Authorization", authentication.GetBearerToken(s.metadata.prometheusAuth)) + req.Header.Set("Authorization", authentication.GetBearerToken(s.metadata.prometheusAuth)) case s.metadata.prometheusAuth.EnableBasicAuth: req.SetBasicAuth(s.metadata.prometheusAuth.Username, s.metadata.prometheusAuth.Password) case s.metadata.prometheusAuth.EnableCustomAuth: - req.Header.Add(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue) - } - - for headerName, headerValue := range s.metadata.customHeaders { - req.Header.Add(headerName, headerValue) + req.Header.Set(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue) } r, err := s.httpClient.Do(req)