diff --git a/pkg/metrics/providers/prometheus.go b/pkg/metrics/providers/prometheus.go index 146022bb..f99131c7 100644 --- a/pkg/metrics/providers/prometheus.go +++ b/pkg/metrics/providers/prometheus.go @@ -15,6 +15,8 @@ import ( flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" ) +const prometheusOnlineQuery = "vector(1)" + // PrometheusProvider executes promQL queries type PrometheusProvider struct { timeout time.Duration @@ -132,41 +134,15 @@ func (p *PrometheusProvider) RunQuery(query string) (float64, error) { return *value, nil } -// IsOnline calls the Prometheus status endpoint and returns an error if the API is unreachable +// IsOnline run simple Prometheus query and returns an error if the API is unreachable func (p *PrometheusProvider) IsOnline() (bool, error) { - u, err := url.Parse("./api/v1/status/flags") + value, err := p.RunQuery(prometheusOnlineQuery) if err != nil { - return false, fmt.Errorf("url.Parse failed: %w", err) - } - u.Path = path.Join(p.url.Path, u.Path) - - u = p.url.ResolveReference(u) - - req, err := http.NewRequest("GET", u.String(), nil) - if err != nil { - return false, fmt.Errorf("http.NewRequest failed: %w", err) + return false, fmt.Errorf("running query failed: %w", err) } - if p.username != "" && p.password != "" { - req.SetBasicAuth(p.username, p.password) - } - - ctx, cancel := context.WithTimeout(req.Context(), p.timeout) - defer cancel() - - r, err := http.DefaultClient.Do(req.WithContext(ctx)) - if err != nil { - return false, fmt.Errorf("request failed: %w", err) - } - defer r.Body.Close() - - b, err := ioutil.ReadAll(r.Body) - if err != nil { - return false, fmt.Errorf("error reading body: %w", err) - } - - if 400 <= r.StatusCode { - return false, fmt.Errorf("error response: %s", string(b)) + if value != float64(1) { + return false, fmt.Errorf("value is not 1 for query: %s", prometheusOnlineQuery) } return true, nil diff --git a/pkg/metrics/providers/prometheus_test.go b/pkg/metrics/providers/prometheus_test.go index b5cae79a..ac42130d 100644 --- a/pkg/metrics/providers/prometheus_test.go +++ b/pkg/metrics/providers/prometheus_test.go @@ -147,22 +147,61 @@ func TestPrometheusProvider_RunQueryWithBasicAuth(t *testing.T) { } func TestPrometheusProvider_IsOnline(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusBadGateway) - })) - defer ts.Close() + t.Run("fail", func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusBadGateway) + })) + defer ts.Close() - clients := prometheusFake() + 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 - template.Spec.Provider.SecretRef = nil + template, err := clients.flaggerClient.FlaggerV1beta1().MetricTemplates("default").Get(context.TODO(), "prometheus", metav1.GetOptions{}) + require.NoError(t, err) + template.Spec.Provider.Address = ts.URL + template.Spec.Provider.SecretRef = nil - prom, err := NewPrometheusProvider(template.Spec.Provider, nil) - require.NoError(t, err) + prom, err := NewPrometheusProvider(template.Spec.Provider, nil) + require.NoError(t, err) - ok, err := prom.IsOnline() - assert.Error(t, err, "Got no error wanted %v", http.StatusBadGateway) - assert.False(t, ok) + ok, err := prom.IsOnline() + assert.Error(t, err, "Got no error wanted %v", http.StatusBadGateway) + assert.False(t, ok) + }) + + t.Run("ok", func(t *testing.T) { + expected := `vector(1)` + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + promql := r.URL.Query()["query"][0] + assert.Equal(t, expected, promql) + + if assert.Contains(t, r.Header, "Authorization") { + + } + header, ok := r.Header["Authorization"] + if assert.True(t, ok, "Authorization header not found") { + assert.True(t, strings.Contains(header[0], "Basic"), "Basic authorization header not found") + } + + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1545905245.458,"1"]}]}}` + 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) + + ok, err := prom.IsOnline() + require.NoError(t, err) + + assert.Equal(t, true, ok) + }) }