From 64efd56ce916c858dc36493e53c8dafbd960bfdc Mon Sep 17 00:00:00 2001 From: mathetake Date: Sun, 8 Mar 2020 10:56:35 +0900 Subject: [PATCH] pkg/metrics/observers: wrap errors --- pkg/controller/scheduler.go | 6 +- pkg/metrics/observers/appmesh.go | 9 +-- pkg/metrics/observers/contour.go | 9 +-- pkg/metrics/observers/crossover.go | 5 +- pkg/metrics/observers/crossover_service.go | 9 +-- pkg/metrics/observers/errors.go | 7 -- pkg/metrics/observers/gloo.go | 9 +-- pkg/metrics/observers/http.go | 5 +- pkg/metrics/observers/istio.go | 9 +-- pkg/metrics/observers/linkerd.go | 9 +-- pkg/metrics/observers/nginx.go | 9 +-- pkg/metrics/observers/nginx_test.go | 74 ++++++++++++++-------- pkg/metrics/observers/render.go | 8 +-- 13 files changed, 97 insertions(+), 71 deletions(-) delete mode 100644 pkg/metrics/observers/errors.go diff --git a/pkg/controller/scheduler.go b/pkg/controller/scheduler.go index 65d2dcb2..0a200491 100644 --- a/pkg/controller/scheduler.go +++ b/pkg/controller/scheduler.go @@ -824,7 +824,7 @@ func (c *Controller) runBuiltinMetricChecks(canary *flaggerv1.Canary) bool { if metric.Name == "request-success-rate" { val, err := observer.GetRequestSuccessRate(toMetricModel(canary, metric.Interval)) if err != nil { - if errors.Is(err, observers.ErrNoValuesFound) { + if errors.Is(err, providers.ErrNoValuesFound) { c.recordEventWarningf(canary, "Halt advancement no values found for %s metric %s probably %s.%s is not receiving traffic: %v", metricsProvider, metric.Name, canary.Spec.TargetRef.Name, canary.Namespace, err) @@ -856,7 +856,7 @@ func (c *Controller) runBuiltinMetricChecks(canary *flaggerv1.Canary) bool { if metric.Name == "request-duration" { val, err := observer.GetRequestDuration(toMetricModel(canary, metric.Interval)) if err != nil { - if errors.Is(err, observers.ErrNoValuesFound) { + if errors.Is(err, providers.ErrNoValuesFound) { c.recordEventWarningf(canary, "Halt advancement no values found for %s metric %s probably %s.%s is not receiving traffic", metricsProvider, metric.Name, canary.Spec.TargetRef.Name, canary.Namespace) } else { @@ -887,7 +887,7 @@ func (c *Controller) runBuiltinMetricChecks(canary *flaggerv1.Canary) bool { if metric.Query != "" { val, err := observerFactory.Client.RunQuery(metric.Query) if err != nil { - if errors.Is(err, observers.ErrNoValuesFound) { + if errors.Is(err, providers.ErrNoValuesFound) { c.recordEventWarningf(canary, "Halt advancement no values found for metric: %s", metric.Name) } else { diff --git a/pkg/metrics/observers/appmesh.go b/pkg/metrics/observers/appmesh.go index 4d4a0362..b8e672f7 100644 --- a/pkg/metrics/observers/appmesh.go +++ b/pkg/metrics/observers/appmesh.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -49,12 +50,12 @@ type AppMeshObserver struct { func (ob *AppMeshObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(appMeshQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -63,12 +64,12 @@ func (ob *AppMeshObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateM func (ob *AppMeshObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(appMeshQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/contour.go b/pkg/metrics/observers/contour.go index 919797bf..819b40cb 100644 --- a/pkg/metrics/observers/contour.go +++ b/pkg/metrics/observers/contour.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -48,12 +49,12 @@ type ContourObserver struct { func (ob *ContourObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(contourQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -62,12 +63,12 @@ func (ob *ContourObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateM func (ob *ContourObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(contourQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/crossover.go b/pkg/metrics/observers/crossover.go index ac985201..0ecf3d15 100644 --- a/pkg/metrics/observers/crossover.go +++ b/pkg/metrics/observers/crossover.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -63,12 +64,12 @@ func (ob *CrossoverObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplat func (ob *CrossoverObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(crossoverQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/crossover_service.go b/pkg/metrics/observers/crossover_service.go index c8c3565f..0aa27a6a 100644 --- a/pkg/metrics/observers/crossover_service.go +++ b/pkg/metrics/observers/crossover_service.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -49,12 +50,12 @@ type CrossoverServiceObserver struct { func (ob *CrossoverServiceObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(crossoverServiceQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -63,12 +64,12 @@ func (ob *CrossoverServiceObserver) GetRequestSuccessRate(model flaggerv1.Metric func (ob *CrossoverServiceObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(crossoverServiceQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/errors.go b/pkg/metrics/observers/errors.go deleted file mode 100644 index 1e3993a6..00000000 --- a/pkg/metrics/observers/errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package observers - -import "errors" - -var ( - ErrNoValuesFound = errors.New("no values found") -) diff --git a/pkg/metrics/observers/gloo.go b/pkg/metrics/observers/gloo.go index 116787a0..90350edb 100644 --- a/pkg/metrics/observers/gloo.go +++ b/pkg/metrics/observers/gloo.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -48,12 +49,12 @@ type GlooObserver struct { func (ob *GlooObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(glooQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -62,12 +63,12 @@ func (ob *GlooObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateMode func (ob *GlooObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(glooQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/http.go b/pkg/metrics/observers/http.go index 632fa72c..24dbc4b7 100644 --- a/pkg/metrics/observers/http.go +++ b/pkg/metrics/observers/http.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -63,12 +64,12 @@ func (ob *HttpObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateMode func (ob *HttpObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(httpQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value*1000)) * time.Millisecond diff --git a/pkg/metrics/observers/istio.go b/pkg/metrics/observers/istio.go index 52945ea4..26084451 100644 --- a/pkg/metrics/observers/istio.go +++ b/pkg/metrics/observers/istio.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -52,12 +53,12 @@ type IstioObserver struct { func (ob *IstioObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(istioQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -66,12 +67,12 @@ func (ob *IstioObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateMod func (ob *IstioObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(istioQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value*1000)) * time.Millisecond diff --git a/pkg/metrics/observers/linkerd.go b/pkg/metrics/observers/linkerd.go index 5257a7c6..d27ffa6c 100644 --- a/pkg/metrics/observers/linkerd.go +++ b/pkg/metrics/observers/linkerd.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -52,12 +53,12 @@ type LinkerdObserver struct { func (ob *LinkerdObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(linkerdQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -66,12 +67,12 @@ func (ob *LinkerdObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateM func (ob *LinkerdObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(linkerdQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/nginx.go b/pkg/metrics/observers/nginx.go index 442dc5d1..41667086 100644 --- a/pkg/metrics/observers/nginx.go +++ b/pkg/metrics/observers/nginx.go @@ -1,6 +1,7 @@ package observers import ( + "fmt" "time" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -56,12 +57,12 @@ type NginxObserver struct { func (ob *NginxObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateModel) (float64, error) { query, err := RenderQuery(nginxQueries["request-success-rate"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } return value, nil @@ -70,12 +71,12 @@ func (ob *NginxObserver) GetRequestSuccessRate(model flaggerv1.MetricTemplateMod func (ob *NginxObserver) GetRequestDuration(model flaggerv1.MetricTemplateModel) (time.Duration, error) { query, err := RenderQuery(nginxQueries["request-duration"], model) if err != nil { - return 0, err + return 0, fmt.Errorf("rendering query failed: %w", err) } value, err := ob.client.RunQuery(query) if err != nil { - return 0, err + return 0, fmt.Errorf("running query failed: %w", err) } ms := time.Duration(int64(value)) * time.Millisecond diff --git a/pkg/metrics/observers/nginx_test.go b/pkg/metrics/observers/nginx_test.go index 10724c0d..75df49c3 100644 --- a/pkg/metrics/observers/nginx_test.go +++ b/pkg/metrics/observers/nginx_test.go @@ -1,6 +1,7 @@ package observers import ( + "errors" "net/http" "net/http/httptest" "testing" @@ -14,38 +15,61 @@ import ( ) func TestNginxObserver_GetRequestSuccessRate(t *testing.T) { - expected := ` sum( rate( nginx_ingress_controller_requests{ namespace="nginx", ingress="podinfo", status!~"5.*" }[1m] ) ) / sum( rate( nginx_ingress_controller_requests{ namespace="nginx", ingress="podinfo" }[1m] ) ) * 100` + t.Run("ok", func(t *testing.T) { + expected := ` sum( rate( nginx_ingress_controller_requests{ namespace="nginx", ingress="podinfo", status!~"5.*" }[1m] ) ) / sum( rate( nginx_ingress_controller_requests{ namespace="nginx", ingress="podinfo" }[1m] ) ) * 100` + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + promql := r.URL.Query()["query"][0] + assert.Equal(t, expected, promql) - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - promql := r.URL.Query()["query"][0] - assert.Equal(t, expected, promql) + json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1,"100"]}]}}` + w.Write([]byte(json)) + })) + defer ts.Close() - json := `{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1,"100"]}]}}` - w.Write([]byte(json)) - })) - defer ts.Close() + client, err := providers.NewPrometheusProvider(flaggerv1.MetricTemplateProvider{ + Type: "prometheus", + Address: ts.URL, + SecretRef: nil, + }, nil) + require.NoError(t, err) - client, err := providers.NewPrometheusProvider(flaggerv1.MetricTemplateProvider{ - Type: "prometheus", - Address: ts.URL, - SecretRef: nil, - }, nil) - require.NoError(t, err) + observer := &NginxObserver{ + client: client, + } - observer := &NginxObserver{ - client: client, - } + val, err := observer.GetRequestSuccessRate(flaggerv1.MetricTemplateModel{ + Name: "podinfo", + Namespace: "nginx", + Target: "podinfo", + Ingress: "podinfo", + Interval: "1m", + }) + require.NoError(t, err) - val, err := observer.GetRequestSuccessRate(flaggerv1.MetricTemplateModel{ - Name: "podinfo", - Namespace: "nginx", - Target: "podinfo", - Ingress: "podinfo", - Interval: "1m", + assert.Equal(t, float64(100), val) }) - require.NoError(t, err) - assert.Equal(t, float64(100), val) + t.Run("no values", func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + json := `{"status":"success","data":{"resultType":"vector","result":[]}}` + w.Write([]byte(json)) + })) + defer ts.Close() + + client, err := providers.NewPrometheusProvider(flaggerv1.MetricTemplateProvider{ + Type: "prometheus", + Address: ts.URL, + SecretRef: nil, + }, nil) + require.NoError(t, err) + + observer := &NginxObserver{ + client: client, + } + + _, err = observer.GetRequestSuccessRate(flaggerv1.MetricTemplateModel{}) + require.True(t, errors.Is(err, providers.ErrNoValuesFound)) + }) } func TestNginxObserver_GetRequestDuration(t *testing.T) { diff --git a/pkg/metrics/observers/render.go b/pkg/metrics/observers/render.go index ca3aadd4..bcf11b57 100644 --- a/pkg/metrics/observers/render.go +++ b/pkg/metrics/observers/render.go @@ -3,6 +3,7 @@ package observers import ( "bufio" "bytes" + "fmt" "text/template" flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1" @@ -11,19 +12,18 @@ import ( func RenderQuery(queryTemplate string, model flaggerv1.MetricTemplateModel) (string, error) { t, err := template.New("tmpl").Funcs(model.TemplateFunctions()).Parse(queryTemplate) if err != nil { - return "", err + return "", fmt.Errorf("template parsing failed: %w", err) } var data bytes.Buffer b := bufio.NewWriter(&data) if err := t.Execute(b, nil); err != nil { - return "", err + return "", fmt.Errorf("template excution failed: %w", err) } err = b.Flush() if err != nil { - return "", err + return "", fmt.Errorf("buffer flush failed: %w", err) } - return data.String(), nil }