From e5dfbf4adc3fea0b4d8d14a595b2733f7f668176 Mon Sep 17 00:00:00 2001 From: Tanner Altares Date: Tue, 30 Apr 2024 12:45:10 -0500 Subject: [PATCH] Signed-off-by: Tanner Altares block panic when prom returns range vector --- pkg/metrics/providers/errors.go | 3 ++- pkg/metrics/providers/prometheus.go | 6 ++++- pkg/metrics/providers/prometheus_test.go | 33 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/pkg/metrics/providers/errors.go b/pkg/metrics/providers/errors.go index 355128399..fffc23070 100644 --- a/pkg/metrics/providers/errors.go +++ b/pkg/metrics/providers/errors.go @@ -19,5 +19,6 @@ package providers import "errors" var ( - ErrNoValuesFound = errors.New("no values found") + ErrNoValuesFound = errors.New("no values found") + ErrMultipleValuesReturned = errors.New("query returned multiple values") ) diff --git a/pkg/metrics/providers/prometheus.go b/pkg/metrics/providers/prometheus.go index 5254de692..270012e5d 100644 --- a/pkg/metrics/providers/prometheus.go +++ b/pkg/metrics/providers/prometheus.go @@ -51,7 +51,8 @@ type prometheusResponse struct { Metric struct { Name string `json:"name"` } - Value []interface{} `json:"value"` + Value []interface{} `json:"value"` + Values []interface{} `json:"values"` } } } @@ -147,6 +148,9 @@ func (p *PrometheusProvider) RunQuery(query string) (float64, error) { var value *float64 for _, v := range result.Data.Result { + if v.Values != nil { + return 0, fmt.Errorf("%w", ErrMultipleValuesReturned) + } metricValue := v.Value[1] switch metricValue.(type) { case string: diff --git a/pkg/metrics/providers/prometheus_test.go b/pkg/metrics/providers/prometheus_test.go index 484fc16df..1a4f475a0 100644 --- a/pkg/metrics/providers/prometheus_test.go +++ b/pkg/metrics/providers/prometheus_test.go @@ -180,6 +180,39 @@ func TestPrometheusProvider_RunQueryWithBasicAuth(t *testing.T) { }) } + multipleResultTests := []struct { + name string + queryResult string + }{ + {name: "values instead of value", queryResult: `{"status": "success","data": {"resultType": "matrix","result": [{"metric": {"__name__": "processTime_seconds:avg"},"values": [[1714404069.294,"NaN"],[1714404071.3,"NaN"],[1714404099.294,"NaN"],[1714404101.3,"NaN"]]},{"metric": {"__name__": "processTime_seconds:avg"},"values": [[1714404069.294,"NaN"],[1714404071.3,"NaN"],[1714404099.294,"NaN"],[1714404101.3,"NaN"]]}]}}`}, + } + + for _, tt := range multipleResultTests { + t.Run(tt.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + json := tt.queryResult + w.Write([]byte(json)) + })) + defer ts.Close() + + clients := prometheusFake() + + template, err := clients.flaggerClient.FlaggerV1beta1(). + MetricTemplates("default").Get(context.TODO(), "prometheus", metav1.GetOptions{}) + require.NoError(t, err) + template.Spec.Provider.Address = ts.URL + + secret, err := clients.kubeClient.CoreV1().Secrets("default").Get(context.TODO(), "prometheus", metav1.GetOptions{}) + require.NoError(t, err) + + prom, err := NewPrometheusProvider(template.Spec.Provider, secret.Data) + require.NoError(t, err) + + _, err = prom.RunQuery(template.Spec.Query) + require.True(t, errors.Is(err, ErrMultipleValuesReturned)) + }) + } + } func TestPrometheusProvider_RunQueryWithBearerAuth(t *testing.T) {