Skip to content

Commit

Permalink
Add query parameters in prometheus scaler (kedacore#4957)
Browse files Browse the repository at this point in the history
Signed-off-by: Henrique Piccolo <henriquepiccolo@hotmail.com.br>
Signed-off-by: Axel Paschoa <apaschoabarres@gmail.com>
Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
Co-authored-by: Axel Paschoa <apaschoabarres@gmail.com>
Signed-off-by: anton.lysina <alysina@gmail.com>
  • Loading branch information
3 people authored and toniiiik committed Jan 15, 2024
1 parent 9c65f62 commit 9833eb6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Here is an overview of all new **experimental** features:

### Improvements

- **General**: Add parameter queryParameters to prometheus-scaler ([#4962](https://github.com/kedacore/keda/issues/4962))
- **General**: TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX))
- **Kafka Scaler**: Add support for Kerberos authentication (SASL / GSSAPI) ([#4836](https://github.com/kedacore/keda/issues/4836))

Expand Down
17 changes: 17 additions & 0 deletions pkg/scalers/prometheus_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
const (
promServerAddress = "serverAddress"
promQuery = "query"
promQueryParameters = "queryParameters"
promThreshold = "threshold"
promActivationThreshold = "activationThreshold"
promNamespace = "namespace"
Expand All @@ -48,6 +49,7 @@ type prometheusScaler struct {
type prometheusMetadata struct {
serverAddress string
query string
queryParameters map[string]string
threshold float64
activationThreshold float64
prometheusAuth *authentication.AuthMeta
Expand Down Expand Up @@ -151,6 +153,15 @@ func parsePrometheusMetadata(config *ScalerConfig) (meta *prometheusMetadata, er
return nil, fmt.Errorf("no %s given", promQuery)
}

if val, ok := config.TriggerMetadata[promQueryParameters]; ok && val != "" {
queryParameters, err := kedautil.ParseStringList(val)
if err != nil {
return nil, fmt.Errorf("error parsing %s: %w", promQueryParameters, err)
}

meta.queryParameters = queryParameters
}

if val, ok := config.TriggerMetadata[promThreshold]; ok && val != "" {
t, err := strconv.ParseFloat(val, 64)
if err != nil {
Expand Down Expand Up @@ -266,6 +277,12 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error
url = fmt.Sprintf("%s&namespace=%s", url, s.metadata.namespace)
}

for queryParameterKey, queryParameterValue := range s.metadata.queryParameters {
queryParameterKeyEscaped := url_pkg.QueryEscape(queryParameterKey)
queryParameterValueEscaped := url_pkg.QueryEscape(queryParameterValue)
url = fmt.Sprintf("%s&%s=%s", url, queryParameterKeyEscaped, queryParameterValueEscaped)
}

req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return -1, err
Expand Down
48 changes: 48 additions & 0 deletions pkg/scalers/prometheus_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"

"github.com/go-logr/logr"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -60,6 +61,10 @@ var testPromMetadata = []parsePrometheusMetadataTestData{
{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},
// queryParameters
{map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "queryParameters": "key1=value1,key2=value2"}, false},
// queryParameters with wrong format
{map[string]string{"serverAddress": "http://localhost:9090", "metricName": "http_requests_total", "threshold": "100", "query": "up", "queryParameters": "key1=value1,key2"}, true},
}

var prometheusMetricIdentifiers = []prometheusMetricIdentifier{
Expand Down Expand Up @@ -372,6 +377,49 @@ func TestPrometheusScalerCustomHeaders(t *testing.T) {
assert.NoError(t, err)
}

func TestPrometheusScalerExecutePromQueryParameters(t *testing.T) {
testData := prometheusQromQueryResultTestData{
name: "no values",
bodyStr: `{"data":{"result":[]}}`,
responseStatus: http.StatusOK,
expectedValue: 0,
isError: false,
ignoreNullValues: true,
}
queryParametersValue := map[string]string{
"first": "foo",
"second": "bar",
}
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
time := time.Now().UTC().Format(time.RFC3339)
expectedPath := fmt.Sprintf("/api/v1/query?query=&time=%s&first=foo&second=bar", time)
for queryParameterName, queryParameterValue := range queryParametersValue {
queryParameter := request.URL.Query()
queryParameter.Add(queryParameterName, queryParameterValue)
}

if request.RequestURI != expectedPath {
t.Error("Expect request path to =", expectedPath, "but it is", request.RequestURI)
}

writer.WriteHeader(testData.responseStatus)
if _, err := writer.Write([]byte(testData.bodyStr)); err != nil {
t.Fatal(err)
}
}))
scaler := prometheusScaler{
metadata: &prometheusMetadata{
serverAddress: server.URL,
queryParameters: queryParametersValue,
ignoreNullValues: testData.ignoreNullValues,
},
httpClient: http.DefaultClient,
}
_, err := scaler.ExecutePromQuery(context.TODO())

assert.NoError(t, err)
}

func TestPrometheusScaler_ExecutePromQuery_WithGCPNativeAuthentication(t *testing.T) {
fakeGoogleOAuthServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `{"token_type": "Bearer", "access_token": "fake_access_token"}`)
Expand Down

0 comments on commit 9833eb6

Please sign in to comment.