From cc95674a04d085ce6cc17f58cfa6e25cdc62636c Mon Sep 17 00:00:00 2001 From: sosoftmandruszak Date: Wed, 10 Nov 2021 12:08:15 +0100 Subject: [PATCH] Validate values length for prometheus scaler (#2264) Signed-off-by: Magdalena Andruszak --- CHANGELOG.md | 1 + pkg/scalers/prometheus_scaler.go | 7 +++ pkg/scalers/prometheus_scaler_test.go | 87 +++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0af545f462..d2324c8bfad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ - Improve error message if `IdleReplicaCount` are equal to `MinReplicaCount` to be the same as the check ([#2212](https://github.com/kedacore/keda/pull/2212)) - Improve Cloudwatch Scaler metric exporting logic ([#2243](https://github.com/kedacore/keda/pull/2243)) - Refactor aws related scalers to reuse the aws clients instead of creating a new one for every GetMetrics call([#2255](https://github.com/kedacore/keda/pull/2255)) +- Validating values length in prometheus query response ([#2264](https://github.com/kedacore/keda/pull/2264)) ### Breaking Changes diff --git a/pkg/scalers/prometheus_scaler.go b/pkg/scalers/prometheus_scaler.go index 0a049a9b196..84c3dde3dd6 100644 --- a/pkg/scalers/prometheus_scaler.go +++ b/pkg/scalers/prometheus_scaler.go @@ -263,6 +263,13 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error return -1, fmt.Errorf("prometheus query %s returned multiple elements", s.metadata.query) } + valueLen := len(result.Data.Result[0].Value) + if valueLen == 0 { + return 0, nil + } else if valueLen < 2 { + return -1, fmt.Errorf("prometheus query %s didn't return enough values", s.metadata.query) + } + val := result.Data.Result[0].Value[1] if val != nil { s := val.(string) diff --git a/pkg/scalers/prometheus_scaler_test.go b/pkg/scalers/prometheus_scaler_test.go index 8ec064c9dde..3f4169502c0 100644 --- a/pkg/scalers/prometheus_scaler_test.go +++ b/pkg/scalers/prometheus_scaler_test.go @@ -3,8 +3,11 @@ package scalers import ( "context" "net/http" + "net/http/httptest" "strings" "testing" + + "github.com/stretchr/testify/assert" ) type parsePrometheusMetadataTestData struct { @@ -119,3 +122,87 @@ func TestPrometheusScalerAuthParams(t *testing.T) { } } } + +type prometheusQromQueryResultTestData struct { + name string + bodyStr string + responseStatus int + expectedValue float64 + isError bool +} + +var testPromQueryResult = []prometheusQromQueryResultTestData{ + { + name: "no results", + bodyStr: `{}`, + responseStatus: http.StatusOK, + expectedValue: 0, + isError: false, + }, + { + name: "no values", + bodyStr: `{"data":{"result":[]}}`, + responseStatus: http.StatusOK, + expectedValue: 0, + isError: false, + }, + { + name: "valid value", + bodyStr: `{"data":{"result":[{"value": ["1", "2"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: 2, + isError: false, + }, + { + name: "not enough values", + bodyStr: `{"data":{"result":[{"value": ["1"]}]}}`, + responseStatus: http.StatusOK, + expectedValue: -1, + isError: true, + }, + { + name: "multiple results", + bodyStr: `{"data":{"result":[{},{}]}}`, + responseStatus: http.StatusOK, + expectedValue: -1, + isError: true, + }, + { + name: "error status response", + bodyStr: `{}`, + responseStatus: http.StatusBadRequest, + expectedValue: -1, + isError: true, + }, +} + +func TestPrometheusScalerExecutePromQuery(t *testing.T) { + for _, testData := range testPromQueryResult { + t.Run(testData.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + writer.WriteHeader(testData.responseStatus) + + if _, err := writer.Write([]byte(testData.bodyStr)); err != nil { + t.Fatal(err) + } + })) + + scaler := prometheusScaler{ + metadata: &prometheusMetadata{ + serverAddress: server.URL, + }, + httpClient: http.DefaultClient, + } + + value, err := scaler.ExecutePromQuery(context.TODO()) + + assert.Equal(t, testData.expectedValue, value) + + if testData.isError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +}