From 287977c2b523bfc382971236b9261c4b635c5c59 Mon Sep 17 00:00:00 2001 From: stefanprodan Date: Fri, 28 Feb 2020 11:24:38 +0200 Subject: [PATCH] Deprecate spec.canaryAnalysis replaced by spec.analysis - add analysis field to Canary spec - deprecate canaryAnalysis filed (to be removed in the next API version) - maintain backwards compatibility with v1alpha3 by using spec.canaryAnalysis if spec.analysis is nil - set analysis threshold default value to 1 --- pkg/apis/flagger/v1beta1/canary.go | 37 ++++++++-- .../flagger/v1beta1/zz_generated.deepcopy.go | 11 ++- pkg/canary/daemonset_controller.go | 2 +- pkg/canary/deployment_controller.go | 2 +- pkg/canary/deployment_fixture_test.go | 2 +- pkg/controller/events.go | 22 +++--- pkg/controller/scheduler.go | 72 +++++++++---------- .../scheduler_daemonset_fixture_test.go | 4 +- .../scheduler_deployment_fixture_test.go | 4 +- pkg/controller/scheduler_svc_test.go | 2 +- pkg/router/appmesh.go | 4 +- pkg/router/contour.go | 8 +-- pkg/router/ingress.go | 6 +- pkg/router/istio.go | 8 +-- pkg/router/router_test.go | 12 ++-- 15 files changed, 117 insertions(+), 79 deletions(-) diff --git a/pkg/apis/flagger/v1beta1/canary.go b/pkg/apis/flagger/v1beta1/canary.go index f370f55e..f13bd908 100644 --- a/pkg/apis/flagger/v1beta1/canary.go +++ b/pkg/apis/flagger/v1beta1/canary.go @@ -80,8 +80,11 @@ type CanarySpec struct { // Service defines how ClusterIP services, service mesh or ingress routing objects are generated Service CanaryService `json:"service"` - // CanaryAnalysis defines how the analysis should be performed - CanaryAnalysis CanaryAnalysis `json:"canaryAnalysis"` + // Analysis defines the validation process of a release + Analysis *CanaryAnalysis `json:"analysis,omitempty"` + + // Deprecated: replaced by Analysis + CanaryAnalysis *CanaryAnalysis `json:"canaryAnalysis,omitempty"` // ProgressDeadlineSeconds represents the maximum time in seconds for a // canary deployment to make progress before it is considered to be failed @@ -352,13 +355,22 @@ func (c *Canary) GetProgressDeadlineSeconds() int { return ProgressDeadlineSeconds } +// GetAnalysis returns the analysis v1beta1 or v1alpha3 +// to be removed along with spec.canaryAnalysis in v1 +func (c *Canary) GetAnalysis() *CanaryAnalysis { + if c.Spec.Analysis != nil { + return c.Spec.Analysis + } + return c.Spec.CanaryAnalysis +} + // GetAnalysisInterval returns the canary analysis interval (default 60s) func (c *Canary) GetAnalysisInterval() time.Duration { - if c.Spec.CanaryAnalysis.Interval == "" { + if c.GetAnalysis().Interval == "" { return AnalysisInterval } - interval, err := time.ParseDuration(c.Spec.CanaryAnalysis.Interval) + interval, err := time.ParseDuration(c.GetAnalysis().Interval) if err != nil { return AnalysisInterval } @@ -370,7 +382,24 @@ func (c *Canary) GetAnalysisInterval() time.Duration { return interval } +// GetAnalysisThreshold returns the canary threshold (default 1) +func (c *Canary) GetAnalysisThreshold() int { + if c.GetAnalysis().Threshold > 0 { + return c.GetAnalysis().Threshold + } + return 1 +} + // GetMetricInterval returns the metric interval default value (1m) func (c *Canary) GetMetricInterval() string { return MetricInterval } + +// SkipAnalysis returns true if the analysis is nil +// or if spec.SkipAnalysis is true +func (c *Canary) SkipAnalysis() bool { + if c.Spec.Analysis == nil && c.Spec.CanaryAnalysis == nil { + return true + } + return c.Spec.SkipAnalysis +} diff --git a/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go b/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go index c825b121..86fb45e7 100644 --- a/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/flagger/v1beta1/zz_generated.deepcopy.go @@ -392,7 +392,16 @@ func (in *CanarySpec) DeepCopyInto(out *CanarySpec) { **out = **in } in.Service.DeepCopyInto(&out.Service) - in.CanaryAnalysis.DeepCopyInto(&out.CanaryAnalysis) + if in.Analysis != nil { + in, out := &in.Analysis, &out.Analysis + *out = new(CanaryAnalysis) + (*in).DeepCopyInto(*out) + } + if in.CanaryAnalysis != nil { + in, out := &in.CanaryAnalysis, &out.CanaryAnalysis + *out = new(CanaryAnalysis) + (*in).DeepCopyInto(*out) + } if in.ProgressDeadlineSeconds != nil { in, out := &in.ProgressDeadlineSeconds, &out.ProgressDeadlineSeconds *out = new(int32) diff --git a/pkg/canary/daemonset_controller.go b/pkg/canary/daemonset_controller.go index 1c07c7fc..0041247b 100644 --- a/pkg/canary/daemonset_controller.go +++ b/pkg/canary/daemonset_controller.go @@ -91,7 +91,7 @@ func (c *DaemonSetController) Initialize(cd *flaggerv1.Canary, skipLivenessCheck } if cd.Status.Phase == "" || cd.Status.Phase == flaggerv1.CanaryPhaseInitializing { - if !skipLivenessChecks && !cd.Spec.SkipAnalysis { + if !skipLivenessChecks && !cd.SkipAnalysis() { _, readyErr := c.IsPrimaryReady(cd) if readyErr != nil { return readyErr diff --git a/pkg/canary/deployment_controller.go b/pkg/canary/deployment_controller.go index e27dbc63..96b6b77f 100644 --- a/pkg/canary/deployment_controller.go +++ b/pkg/canary/deployment_controller.go @@ -37,7 +37,7 @@ func (c *DeploymentController) Initialize(cd *flaggerv1.Canary, skipLivenessChec } if cd.Status.Phase == "" || cd.Status.Phase == flaggerv1.CanaryPhaseInitializing { - if !skipLivenessChecks && !cd.Spec.SkipAnalysis { + if !skipLivenessChecks && !cd.SkipAnalysis() { _, readyErr := c.IsPrimaryReady(cd) if readyErr != nil { return readyErr diff --git a/pkg/canary/deployment_fixture_test.go b/pkg/canary/deployment_fixture_test.go index 62e2a2b9..486b3472 100644 --- a/pkg/canary/deployment_fixture_test.go +++ b/pkg/canary/deployment_fixture_test.go @@ -207,7 +207,7 @@ func newDeploymentControllerTestCanary() *flaggerv1.Canary { Kind: "HorizontalPodAutoscaler", }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, diff --git a/pkg/controller/events.go b/pkg/controller/events.go index 00fe49a1..afa5175d 100644 --- a/pkg/controller/events.go +++ b/pkg/controller/events.go @@ -30,8 +30,8 @@ func (c *Controller) recordEventWarningf(r *flaggerv1.Canary, template string, a func (c *Controller) sendEventToWebhook(r *flaggerv1.Canary, eventType, template string, args []interface{}) { webhookOverride := false - if len(r.Spec.CanaryAnalysis.Webhooks) > 0 { - for _, canaryWebhook := range r.Spec.CanaryAnalysis.Webhooks { + if len(r.GetAnalysis().Webhooks) > 0 { + for _, canaryWebhook := range r.GetAnalysis().Webhooks { if canaryWebhook.Type == flaggerv1.EventHook { webhookOverride = true err := CallEventWebhook(r, canaryWebhook.URL, fmt.Sprintf(template, args...), eventType) @@ -51,7 +51,7 @@ func (c *Controller) sendEventToWebhook(r *flaggerv1.Canary, eventType, template } func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bool, severity flaggerv1.AlertSeverity) { - if c.notifier == nil && len(canary.Spec.CanaryAnalysis.Alerts) == 0 { + if c.notifier == nil && len(canary.GetAnalysis().Alerts) == 0 { return } @@ -61,7 +61,7 @@ func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bo } // send alert with the global notifier - if len(canary.Spec.CanaryAnalysis.Alerts) == 0 { + if len(canary.GetAnalysis().Alerts) == 0 { err := c.notifier.Post(canary.Name, canary.Namespace, message, fields, string(severity)) if err != nil { c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). @@ -72,7 +72,7 @@ func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bo } // send canary alerts - for _, alert := range canary.Spec.CanaryAnalysis.Alerts { + for _, alert := range canary.GetAnalysis().Alerts { // determine if alert should be sent based on severity level shouldAlert := false if alert.Severity == flaggerv1.SeverityInfo { @@ -161,7 +161,7 @@ func alertMetadata(canary *flaggerv1.Canary) []notifier.Field { }, notifier.Field{ Name: "Failed checks threshold", - Value: fmt.Sprintf("%v", canary.Spec.CanaryAnalysis.Threshold), + Value: fmt.Sprintf("%v", canary.GetAnalysisThreshold()), }, notifier.Field{ Name: "Progress deadline", @@ -169,19 +169,19 @@ func alertMetadata(canary *flaggerv1.Canary) []notifier.Field { }, ) - if canary.Spec.CanaryAnalysis.StepWeight > 0 { + if canary.GetAnalysis().StepWeight > 0 { fields = append(fields, notifier.Field{ Name: "Traffic routing", Value: fmt.Sprintf("Weight step: %v max: %v", - canary.Spec.CanaryAnalysis.StepWeight, - canary.Spec.CanaryAnalysis.MaxWeight), + canary.GetAnalysis().StepWeight, + canary.GetAnalysis().MaxWeight), }) - } else if len(canary.Spec.CanaryAnalysis.Match) > 0 { + } else if len(canary.GetAnalysis().Match) > 0 { fields = append(fields, notifier.Field{ Name: "Traffic routing", Value: "A/B Testing", }) - } else if canary.Spec.CanaryAnalysis.Iterations > 0 { + } else if canary.GetAnalysis().Iterations > 0 { fields = append(fields, notifier.Field{ Name: "Traffic routing", Value: "Blue/Green", diff --git a/pkg/controller/scheduler.go b/pkg/controller/scheduler.go index f930f0e1..6d393b06 100644 --- a/pkg/controller/scheduler.go +++ b/pkg/controller/scheduler.go @@ -157,12 +157,12 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh // set max weight default value to 100% maxWeight := 100 - if cd.Spec.CanaryAnalysis.MaxWeight > 0 { - maxWeight = cd.Spec.CanaryAnalysis.MaxWeight + if cd.GetAnalysis().MaxWeight > 0 { + maxWeight = cd.GetAnalysis().MaxWeight } // check primary status - if !skipLivenessChecks && !cd.Spec.SkipAnalysis { + if !skipLivenessChecks && !cd.SkipAnalysis() { if _, err := canaryController.IsPrimaryReady(cd); err != nil { c.recordEventWarningf(cd, "%v", err) return @@ -278,7 +278,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh // check if the number of failed checks reached the threshold if cd.Status.Phase == flaggerv1.CanaryPhaseProgressing && - (!retriable || cd.Status.FailedChecks >= cd.Spec.CanaryAnalysis.Threshold) { + (!retriable || cd.Status.FailedChecks >= cd.GetAnalysisThreshold()) { if !retriable { c.recordEventWarningf(cd, "Rolling back %s.%s progress deadline exceeded %v", cd.Name, cd.Namespace, err) @@ -297,7 +297,7 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh // check if the canary success rate is above the threshold // skip check if no traffic is routed or mirrored to canary if canaryWeight == 0 && cd.Status.Iterations == 0 && - (cd.Spec.CanaryAnalysis.Mirror == false || mirrored == false) { + (cd.GetAnalysis().Mirror == false || mirrored == false) { c.recordEventInfof(cd, "Starting canary analysis for %s.%s", cd.Spec.TargetRef.Name, cd.Namespace) // run pre-rollout web hooks @@ -320,31 +320,31 @@ func (c *Controller) advanceCanary(name string, namespace string, skipLivenessCh // use blue/green strategy for kubernetes provider if provider == "kubernetes" { - if len(cd.Spec.CanaryAnalysis.Match) > 0 { + if len(cd.GetAnalysis().Match) > 0 { c.recordEventWarningf(cd, "A/B testing is not supported when using the kubernetes provider") - cd.Spec.CanaryAnalysis.Match = nil + cd.GetAnalysis().Match = nil } - if cd.Spec.CanaryAnalysis.Iterations < 1 { + if cd.GetAnalysis().Iterations < 1 { c.recordEventWarningf(cd, "Progressive traffic is not supported when using the kubernetes provider") c.recordEventWarningf(cd, "Setting canaryAnalysis.iterations: 10") - cd.Spec.CanaryAnalysis.Iterations = 10 + cd.GetAnalysis().Iterations = 10 } } // strategy: A/B testing - if len(cd.Spec.CanaryAnalysis.Match) > 0 && cd.Spec.CanaryAnalysis.Iterations > 0 { + if len(cd.GetAnalysis().Match) > 0 && cd.GetAnalysis().Iterations > 0 { c.runAB(cd, canaryController, meshRouter, provider) return } // strategy: Blue/Green - if cd.Spec.CanaryAnalysis.Iterations > 0 { + if cd.GetAnalysis().Iterations > 0 { c.runBlueGreen(cd, canaryController, meshRouter, provider, mirrored) return } // strategy: Canary progressive traffic increase - if cd.Spec.CanaryAnalysis.StepWeight > 0 { + if cd.GetAnalysis().StepWeight > 0 { c.runCanary(cd, canaryController, meshRouter, provider, mirrored, canaryWeight, primaryWeight, maxWeight) } @@ -358,25 +358,25 @@ func (c *Controller) runCanary(canary *flaggerv1.Canary, canaryController canary // If in "mirror" mode, do one step of mirroring before shifting traffic to canary. // When mirroring, all requests go to primary and canary, but only responses from // primary go back to the user. - if canary.Spec.CanaryAnalysis.Mirror && canaryWeight == 0 { + if canary.GetAnalysis().Mirror && canaryWeight == 0 { if mirrored == false { mirrored = true primaryWeight = 100 canaryWeight = 0 } else { mirrored = false - primaryWeight = 100 - canary.Spec.CanaryAnalysis.StepWeight - canaryWeight = canary.Spec.CanaryAnalysis.StepWeight + primaryWeight = 100 - canary.GetAnalysis().StepWeight + canaryWeight = canary.GetAnalysis().StepWeight } c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)). Infof("Running mirror step %d/%d/%t", primaryWeight, canaryWeight, mirrored) } else { - primaryWeight -= canary.Spec.CanaryAnalysis.StepWeight + primaryWeight -= canary.GetAnalysis().StepWeight if primaryWeight < 0 { primaryWeight = 0 } - canaryWeight += canary.Spec.CanaryAnalysis.StepWeight + canaryWeight += canary.GetAnalysis().StepWeight if canaryWeight > 100 { canaryWeight = 100 } @@ -424,7 +424,7 @@ func (c *Controller) runAB(canary *flaggerv1.Canary, canaryController canary.Con primaryName := fmt.Sprintf("%s-primary", canary.Spec.TargetRef.Name) // route traffic to canary and increment iterations - if canary.Spec.CanaryAnalysis.Iterations > canary.Status.Iterations { + if canary.GetAnalysis().Iterations > canary.Status.Iterations { if err := meshRouter.SetRoutes(canary, 0, 100, false); err != nil { c.recordEventWarningf(canary, "%v", err) return @@ -436,7 +436,7 @@ func (c *Controller) runAB(canary *flaggerv1.Canary, canaryController canary.Con return } c.recordEventInfof(canary, "Advance %s.%s canary iteration %v/%v", - canary.Name, canary.Namespace, canary.Status.Iterations+1, canary.Spec.CanaryAnalysis.Iterations) + canary.Name, canary.Namespace, canary.Status.Iterations+1, canary.GetAnalysis().Iterations) return } @@ -446,7 +446,7 @@ func (c *Controller) runAB(canary *flaggerv1.Canary, canaryController canary.Con } // promote canary - max iterations reached - if canary.Spec.CanaryAnalysis.Iterations == canary.Status.Iterations { + if canary.GetAnalysis().Iterations == canary.Status.Iterations { c.recordEventInfof(canary, "Copying %s.%s template spec to %s.%s", canary.Spec.TargetRef.Name, canary.Namespace, primaryName, canary.Namespace) if err := canaryController.Promote(canary); err != nil { @@ -466,10 +466,10 @@ func (c *Controller) runBlueGreen(canary *flaggerv1.Canary, canaryController can primaryName := fmt.Sprintf("%s-primary", canary.Spec.TargetRef.Name) // increment iterations - if canary.Spec.CanaryAnalysis.Iterations > canary.Status.Iterations { + if canary.GetAnalysis().Iterations > canary.Status.Iterations { // If in "mirror" mode, mirror requests during the entire B/G canary test if provider != "kubernetes" && - canary.Spec.CanaryAnalysis.Mirror == true && mirrored == false { + canary.GetAnalysis().Mirror == true && mirrored == false { if err := meshRouter.SetRoutes(canary, 100, 0, true); err != nil { c.recordEventWarningf(canary, "%v", err) } @@ -481,7 +481,7 @@ func (c *Controller) runBlueGreen(canary *flaggerv1.Canary, canaryController can return } c.recordEventInfof(canary, "Advance %s.%s canary iteration %v/%v", - canary.Name, canary.Namespace, canary.Status.Iterations+1, canary.Spec.CanaryAnalysis.Iterations) + canary.Name, canary.Namespace, canary.Status.Iterations+1, canary.GetAnalysis().Iterations) return } @@ -491,9 +491,9 @@ func (c *Controller) runBlueGreen(canary *flaggerv1.Canary, canaryController can } // route all traffic to canary - max iterations reached - if canary.Spec.CanaryAnalysis.Iterations == canary.Status.Iterations { + if canary.GetAnalysis().Iterations == canary.Status.Iterations { if provider != "kubernetes" { - if canary.Spec.CanaryAnalysis.Mirror { + if canary.GetAnalysis().Mirror { c.recordEventInfof(canary, "Stop traffic mirroring and route all traffic to canary") } else { c.recordEventInfof(canary, "Routing all traffic to canary") @@ -514,7 +514,7 @@ func (c *Controller) runBlueGreen(canary *flaggerv1.Canary, canaryController can } // promote canary - max iterations reached - if canary.Spec.CanaryAnalysis.Iterations < canary.Status.Iterations { + if canary.GetAnalysis().Iterations < canary.Status.Iterations { c.recordEventInfof(canary, "Copying %s.%s template spec to %s.%s", canary.Spec.TargetRef.Name, canary.Namespace, primaryName, canary.Namespace) if err := canaryController.Promote(canary); err != nil { @@ -532,7 +532,7 @@ func (c *Controller) runBlueGreen(canary *flaggerv1.Canary, canaryController can } func (c *Controller) shouldSkipAnalysis(canary *flaggerv1.Canary, canaryController canary.Controller, meshRouter router.Interface, primaryWeight int, canaryWeight int) bool { - if !canary.Spec.SkipAnalysis { + if !canary.SkipAnalysis() { return false } @@ -656,7 +656,7 @@ func (c *Controller) hasCanaryRevisionChanged(canary *flaggerv1.Canary, canaryCo } func (c *Controller) runConfirmRolloutHooks(canary *flaggerv1.Canary, canaryController canary.Controller) bool { - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == flaggerv1.ConfirmRolloutHook { err := CallWebhook(canary.Name, canary.Namespace, flaggerv1.CanaryPhaseProgressing, webhook) if err != nil { @@ -685,7 +685,7 @@ func (c *Controller) runConfirmRolloutHooks(canary *flaggerv1.Canary, canaryCont } func (c *Controller) runConfirmPromotionHooks(canary *flaggerv1.Canary) bool { - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == flaggerv1.ConfirmPromotionHook { err := CallWebhook(canary.Name, canary.Namespace, flaggerv1.CanaryPhaseProgressing, webhook) if err != nil { @@ -702,7 +702,7 @@ func (c *Controller) runConfirmPromotionHooks(canary *flaggerv1.Canary) bool { } func (c *Controller) runPreRolloutHooks(canary *flaggerv1.Canary) bool { - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == flaggerv1.PreRolloutHook { err := CallWebhook(canary.Name, canary.Namespace, flaggerv1.CanaryPhaseProgressing, webhook) if err != nil { @@ -718,7 +718,7 @@ func (c *Controller) runPreRolloutHooks(canary *flaggerv1.Canary) bool { } func (c *Controller) runPostRolloutHooks(canary *flaggerv1.Canary, phase flaggerv1.CanaryPhase) bool { - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == flaggerv1.PostRolloutHook { err := CallWebhook(canary.Name, canary.Namespace, phase, webhook) if err != nil { @@ -733,7 +733,7 @@ func (c *Controller) runPostRolloutHooks(canary *flaggerv1.Canary, phase flagger } func (c *Controller) runRollbackHooks(canary *flaggerv1.Canary, phase flaggerv1.CanaryPhase) bool { - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == flaggerv1.RollbackHook { err := CallWebhook(canary.Name, canary.Namespace, phase, webhook) if err != nil { @@ -749,7 +749,7 @@ func (c *Controller) runRollbackHooks(canary *flaggerv1.Canary, phase flaggerv1. func (c *Controller) runAnalysis(canary *flaggerv1.Canary) bool { // run external checks - for _, webhook := range canary.Spec.CanaryAnalysis.Webhooks { + for _, webhook := range canary.GetAnalysis().Webhooks { if webhook.Type == "" || webhook.Type == flaggerv1.RolloutHook { err := CallWebhook(canary.Name, canary.Namespace, flaggerv1.CanaryPhaseProgressing, webhook) if err != nil { @@ -812,7 +812,7 @@ func (c *Controller) runBuiltinMetricChecks(canary *flaggerv1.Canary) bool { observer := observerFactory.Observer(metricsProvider) // run metrics checks - for _, metric := range canary.Spec.CanaryAnalysis.Metrics { + for _, metric := range canary.GetAnalysis().Metrics { if metric.Interval == "" { metric.Interval = canary.GetMetricInterval() } @@ -914,7 +914,7 @@ func (c *Controller) runBuiltinMetricChecks(canary *flaggerv1.Canary) bool { } func (c *Controller) runMetricChecks(canary *flaggerv1.Canary) bool { - for _, metric := range canary.Spec.CanaryAnalysis.Metrics { + for _, metric := range canary.GetAnalysis().Metrics { if metric.TemplateRef != nil { namespace := canary.Namespace if metric.TemplateRef.Namespace != "" { @@ -1007,7 +1007,7 @@ func toMetricModel(r *flaggerv1.Canary, interval string) flaggerv1.MetricTemplat } func (c *Controller) rollback(canary *flaggerv1.Canary, canaryController canary.Controller, meshRouter router.Interface) { - if canary.Status.FailedChecks >= canary.Spec.CanaryAnalysis.Threshold { + if canary.Status.FailedChecks >= canary.GetAnalysisThreshold() { c.recordEventWarningf(canary, "Rolling back %s.%s failed checks threshold reached %v", canary.Name, canary.Namespace, canary.Status.FailedChecks) c.alert(canary, fmt.Sprintf("Failed checks threshold reached %v", canary.Status.FailedChecks), diff --git a/pkg/controller/scheduler_daemonset_fixture_test.go b/pkg/controller/scheduler_daemonset_fixture_test.go index 8e0b2478..8d2cdd6d 100644 --- a/pkg/controller/scheduler_daemonset_fixture_test.go +++ b/pkg/controller/scheduler_daemonset_fixture_test.go @@ -250,7 +250,7 @@ func newDaemonSetTestCanary() *flaggerv1.Canary { Kind: "DaemonSet", }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, @@ -307,7 +307,7 @@ func newDaemonSetTestCanaryAB() *flaggerv1.Canary { Kind: "DaemonSet", }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, Iterations: 10, Match: []istiov1alpha3.HTTPMatchRequest{ diff --git a/pkg/controller/scheduler_deployment_fixture_test.go b/pkg/controller/scheduler_deployment_fixture_test.go index a3f2db50..74a7321e 100644 --- a/pkg/controller/scheduler_deployment_fixture_test.go +++ b/pkg/controller/scheduler_deployment_fixture_test.go @@ -257,7 +257,7 @@ func newDeploymentTestCanary() *flaggerv1.Canary { Kind: "HorizontalPodAutoscaler", }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, @@ -319,7 +319,7 @@ func newDeploymentTestCanaryAB() *flaggerv1.Canary { Kind: "HorizontalPodAutoscaler", }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, Iterations: 10, Match: []istiov1alpha3.HTTPMatchRequest{ diff --git a/pkg/controller/scheduler_svc_test.go b/pkg/controller/scheduler_svc_test.go index 5e11d9fc..0db42439 100644 --- a/pkg/controller/scheduler_svc_test.go +++ b/pkg/controller/scheduler_svc_test.go @@ -142,7 +142,7 @@ func newTestServiceCanary() *flaggerv1.Canary { Service: flaggerv1.CanaryService{ Port: 9898, }, - CanaryAnalysis: flaggerv1.CanaryAnalysis{ + CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, diff --git a/pkg/router/appmesh.go b/pkg/router/appmesh.go index 1d13fff8..2f096417 100644 --- a/pkg/router/appmesh.go +++ b/pkg/router/appmesh.go @@ -203,7 +203,7 @@ func (ar *AppMeshRouter) reconcileVirtualService(canary *flaggerv1.Canary, name } // A/B testing - header based routing - if len(canary.Spec.CanaryAnalysis.Match) > 0 && canaryWeight == 0 { + if len(canary.GetAnalysis().Match) > 0 && canaryWeight == 0 { routes = []appmeshv1.Route{ { Name: fmt.Sprintf("%s-a", apexName), @@ -451,7 +451,7 @@ func makeRetryPolicy(canary *flaggerv1.Canary) *appmeshv1.HttpRetryPolicy { func (ar *AppMeshRouter) makeHeaders(canary *flaggerv1.Canary) []appmeshv1.HttpRouteHeader { headers := []appmeshv1.HttpRouteHeader{} - for _, m := range canary.Spec.CanaryAnalysis.Match { + for _, m := range canary.GetAnalysis().Match { for key, value := range m.Headers { header := appmeshv1.HttpRouteHeader{ Name: key, diff --git a/pkg/router/contour.go b/pkg/router/contour.go index 50bbee2a..8ad846ab 100644 --- a/pkg/router/contour.go +++ b/pkg/router/contour.go @@ -64,7 +64,7 @@ func (cr *ContourRouter) Reconcile(canary *flaggerv1.Canary) error { }, } - if len(canary.Spec.CanaryAnalysis.Match) > 0 { + if len(canary.GetAnalysis().Match) > 0 { newSpec = contourv1.HTTPProxySpec{ Routes: []contourv1.Route{ { @@ -277,7 +277,7 @@ func (cr *ContourRouter) SetRoutes( }, } - if len(canary.Spec.CanaryAnalysis.Match) > 0 { + if len(canary.GetAnalysis().Match) > 0 { proxy.Spec = contourv1.HTTPProxySpec{ Routes: []contourv1.Route{ { @@ -364,8 +364,8 @@ func (cr *ContourRouter) makePrefix(canary *flaggerv1.Canary) string { func (cr *ContourRouter) makeConditions(canary *flaggerv1.Canary) []contourv1.Condition { list := []contourv1.Condition{} - if len(canary.Spec.CanaryAnalysis.Match) > 0 { - for _, match := range canary.Spec.CanaryAnalysis.Match { + if len(canary.GetAnalysis().Match) > 0 { + for _, match := range canary.GetAnalysis().Match { for s, stringMatch := range match.Headers { h := &contourv1.HeaderCondition{ Name: s, diff --git a/pkg/router/ingress.go b/pkg/router/ingress.go index 22e8b9b8..e97d68c4 100644 --- a/pkg/router/ingress.go +++ b/pkg/router/ingress.go @@ -117,7 +117,7 @@ func (i *IngressRouter) GetRoutes(canary *flaggerv1.Canary) ( } // A/B testing - if len(canary.Spec.CanaryAnalysis.Match) > 0 { + if len(canary.GetAnalysis().Match) > 0 { for k := range canaryIngress.Annotations { if k == i.GetAnnotationWithPrefix("canary-by-cookie") || k == i.GetAnnotationWithPrefix("canary-by-header") { return 0, 100, false, nil @@ -158,11 +158,11 @@ func (i *IngressRouter) SetRoutes( iClone := canaryIngress.DeepCopy() // A/B testing - if len(canary.Spec.CanaryAnalysis.Match) > 0 { + if len(canary.GetAnalysis().Match) > 0 { cookie := "" header := "" headerValue := "" - for _, m := range canary.Spec.CanaryAnalysis.Match { + for _, m := range canary.GetAnalysis().Match { for k, v := range m.Headers { if k == "cookie" { cookie = v.Exact diff --git a/pkg/router/istio.go b/pkg/router/istio.go index 015698cf..df809313 100644 --- a/pkg/router/istio.go +++ b/pkg/router/istio.go @@ -152,8 +152,8 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error { }, } - if len(canary.Spec.CanaryAnalysis.Match) > 0 { - canaryMatch := mergeMatchConditions(canary.Spec.CanaryAnalysis.Match, canary.Spec.Service.Match) + if len(canary.GetAnalysis().Match) > 0 { + canaryMatch := mergeMatchConditions(canary.GetAnalysis().Match, canary.Spec.Service.Match) newSpec.Http = []istiov1alpha3.HTTPRoute{ { Match: canaryMatch, @@ -323,9 +323,9 @@ func (ir *IstioRouter) SetRoutes( } // fix routing (A/B testing) - if len(canary.Spec.CanaryAnalysis.Match) > 0 { + if len(canary.GetAnalysis().Match) > 0 { // merge the common routes with the canary ones - canaryMatch := mergeMatchConditions(canary.Spec.CanaryAnalysis.Match, canary.Spec.Service.Match) + canaryMatch := mergeMatchConditions(canary.GetAnalysis().Match, canary.Spec.Service.Match) vsCopy.Spec.Http = []istiov1alpha3.HTTPRoute{ { Match: canaryMatch, diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go index 9e4ad3ef..205a8ab3 100644 --- a/pkg/router/router_test.go +++ b/pkg/router/router_test.go @@ -112,7 +112,7 @@ func newTestCanary() *flaggerv1.Canary { "public-gateway.istio", "mesh", }, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, @@ -158,7 +158,7 @@ func newTestCanaryAppMesh() *flaggerv1.Canary { PerTryTimeout: "gateway-error", RetryOn: "5s", }, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, @@ -203,7 +203,7 @@ func newTestSMICanary() *flaggerv1.Canary { }, PortDiscovery: true, }, - CanaryAnalysis: flaggerv1.CanaryAnalysis{ + CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50, @@ -227,7 +227,7 @@ func newTestSMICanary() *flaggerv1.Canary { func newTestMirror() *flaggerv1.Canary { cd := newTestCanary() - cd.Spec.CanaryAnalysis.Mirror = true + cd.GetAnalysis().Mirror = true return cd } @@ -247,7 +247,7 @@ func newTestABTest() *flaggerv1.Canary { Service: flaggerv1.CanaryService{ Port: 9898, MeshName: "global", - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, Iterations: 2, Match: []istiov1alpha3.HTTPMatchRequest{ @@ -397,7 +397,7 @@ func newTestCanaryIngress() *flaggerv1.Canary { }, Service: flaggerv1.CanaryService{ Port: 9898, - }, CanaryAnalysis: flaggerv1.CanaryAnalysis{ + }, CanaryAnalysis: &flaggerv1.CanaryAnalysis{ Threshold: 10, StepWeight: 10, MaxWeight: 50,