Repository: weaveworks/flagger (go)

Issue:
feature request: make mirrorPercentage configurable
`mirrorPercentage` is defined in istio's [v1alpha3/VirtualService](https://github.com/istio/api/blob/master/networking/v1alpha3/virtual_service.proto#L617-L620) and used for specifying the percentage of traffic mirrored. That is currently not configurable in flagger and defaults to `100%` when `mirror: true`.

This is useful for mirroring users having high volume traffic since mirroring 100% traffic doubles the load put onto your cluster

Pull request description:
istio router: make mirrorPercentage configurable for traffic mirroring 
resolves #487 


Patch:
diff --git a/artifacts/flagger/crd.yaml b/artifacts/flagger/crd.yaml
index 0c37ebc3..3ae25fa8 100644
--- a/artifacts/flagger/crd.yaml
+++ b/artifacts/flagger/crd.yaml
@@ -528,6 +528,9 @@ spec:
                 mirror:
                   description: Mirror traffic to canary
                   type: boolean
+                mirrorWeight:
+                  description: Percentage of traffic to be mirrored
+                  type: number
                 match:
                   description: A/B testing match conditions
                   type: array
diff --git a/charts/flagger/crds/crd.yaml b/charts/flagger/crds/crd.yaml
index 0c37ebc3..3ae25fa8 100644
--- a/charts/flagger/crds/crd.yaml
+++ b/charts/flagger/crds/crd.yaml
@@ -528,6 +528,9 @@ spec:
                 mirror:
                   description: Mirror traffic to canary
                   type: boolean
+                mirrorWeight:
+                  description: Percentage of traffic to be mirrored
+                  type: number
                 match:
                   description: A/B testing match conditions
                   type: array
diff --git a/docs/gitbook/tutorials/istio-progressive-delivery.md b/docs/gitbook/tutorials/istio-progressive-delivery.md
index 9cc930d6..39b6df63 100644
--- a/docs/gitbook/tutorials/istio-progressive-delivery.md
+++ b/docs/gitbook/tutorials/istio-progressive-delivery.md
@@ -324,6 +324,8 @@ spec:
     iterations: 10
     # enable traffic shadowing 
     mirror: true
+    # weight of the traffic mirrored to your canary (defaults to 100%)
+    mirrorWeight: 100
     metrics:
     - name: request-success-rate
       thresholdRange:
@@ -357,7 +359,7 @@ With the above configuration, Flagger will run a canary release with the followi
 * run the acceptance tests
 * abort the canary release if tests fail
 * start the load tests
-* mirror traffic from primary to canary
+* mirror 100% of the traffic from primary to canary
 * check request success rate and request duration every minute
 * abort the canary release if the metrics check failure threshold is reached
 * stop traffic mirroring after the number of iterations is reached
diff --git a/docs/gitbook/usage/deployment-strategies.md b/docs/gitbook/usage/deployment-strategies.md
index e46bd767..05cc4fd5 100644
--- a/docs/gitbook/usage/deployment-strategies.md
+++ b/docs/gitbook/usage/deployment-strategies.md
@@ -277,6 +277,8 @@ Istio example:
     threshold: 2
     # Traffic shadowing (compatible with Istio only)
     mirror: true
+    # Weight of the traffic mirrored to your canary (defaults to 100%)
+    mirrorWeight: 100
 ```
 
 Mirroring rollout steps for service mesh:
@@ -287,7 +289,7 @@ Mirroring rollout steps for service mesh:
 * run the acceptance tests
 * abort the canary release if tests fail
 * start the load tests
-* mirror traffic from primary to canary
+* mirror 100% of the traffic from primary to canary
 * check request success rate and request duration every minute
 * abort the canary release if the failure threshold is reached
 * stop traffic mirroring after the number of iterations is reached
diff --git a/kustomize/base/flagger/crd.yaml b/kustomize/base/flagger/crd.yaml
index 0c37ebc3..3ae25fa8 100644
--- a/kustomize/base/flagger/crd.yaml
+++ b/kustomize/base/flagger/crd.yaml
@@ -528,6 +528,9 @@ spec:
                 mirror:
                   description: Mirror traffic to canary
                   type: boolean
+                mirrorWeight:
+                  description: Percentage of traffic to be mirrored
+                  type: number
                 match:
                   description: A/B testing match conditions
                   type: array
diff --git a/pkg/apis/flagger/v1beta1/canary.go b/pkg/apis/flagger/v1beta1/canary.go
index f13bd908..dd9c891a 100644
--- a/pkg/apis/flagger/v1beta1/canary.go
+++ b/pkg/apis/flagger/v1beta1/canary.go
@@ -175,10 +175,14 @@ type CanaryAnalysis struct {
 	// +optional
 	Iterations int `json:"iterations,omitempty"`
 
-	//Enable traffic mirroring for Blue/Green
+	// Enable traffic mirroring for Blue/Green
 	// +optional
 	Mirror bool `json:"mirror,omitempty"`
 
+	// Percentage of the traffic to be mirrored in the range of [0, 100].
+	// +optional
+	MirrorWeight int `json:"mirrorWeight,omitempty"`
+
 	// Max traffic percentage routed to canary
 	// +optional
 	MaxWeight int `json:"maxWeight,omitempty"`
diff --git a/pkg/apis/istio/v1alpha3/virtual_service.go b/pkg/apis/istio/v1alpha3/virtual_service.go
index d800142b..7718ab07 100644
--- a/pkg/apis/istio/v1alpha3/virtual_service.go
+++ b/pkg/apis/istio/v1alpha3/virtual_service.go
@@ -325,6 +325,11 @@ type HTTPRoute struct {
 	// destination.
 	Mirror *Destination `json:"mirror,omitempty"`
 
+	// Percentage of the traffic to be mirrored by the `mirror` field.
+	// If this field is absent, all the traffic (100%) will be mirrored.
+	// Max value is 100.
+	MirrorPercentage *Percent `json:"mirrorPercentage,omitempty"`
+
 	// Cross-Origin Resource Sharing policy (CORS). Refer to
 	// https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
 	// for further details about cross origin resource sharing.
@@ -334,6 +339,11 @@ type HTTPRoute struct {
 	Headers *Headers `json:"headers,omitempty"`
 }
 
+// Percent specifies a percentage in the range of [0.0, 100.0].
+type Percent struct {
+	Value float64 `json:"value,omitempty"`
+}
+
 // Header manipulation rules
 type Headers struct {
 	// Header manipulation rules to apply before forwarding a request
diff --git a/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go
index 9447a78e..a187f416 100644
--- a/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go
+++ b/pkg/apis/istio/v1alpha3/zz_generated.deepcopy.go
@@ -421,6 +421,11 @@ func (in *HTTPRoute) DeepCopyInto(out *HTTPRoute) {
 		*out = new(Destination)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.MirrorPercentage != nil {
+		in, out := &in.MirrorPercentage, &out.MirrorPercentage
+		*out = new(Percent)
+		**out = **in
+	}
 	if in.CorsPolicy != nil {
 		in, out := &in.CorsPolicy, &out.CorsPolicy
 		*out = new(CorsPolicy)
@@ -628,6 +633,22 @@ func (in *OutlierDetection) DeepCopy() *OutlierDetection {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Percent) DeepCopyInto(out *Percent) {
+	*out = *in
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Percent.
+func (in *Percent) DeepCopy() *Percent {
+	if in == nil {
+		return nil
+	}
+	out := new(Percent)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *PortSelector) DeepCopyInto(out *PortSelector) {
 	*out = *in
diff --git a/pkg/router/istio.go b/pkg/router/istio.go
index c6d43b92..3cdfd220 100644
--- a/pkg/router/istio.go
+++ b/pkg/router/istio.go
@@ -206,7 +206,7 @@ func (ir *IstioRouter) reconcileVirtualService(canary *flaggerv1.Canary) error {
 			newSpec,
 			virtualService.Spec,
 			cmpopts.IgnoreFields(istiov1alpha3.DestinationWeight{}, "Weight"),
-			cmpopts.IgnoreFields(istiov1alpha3.HTTPRoute{}, "Mirror"),
+			cmpopts.IgnoreFields(istiov1alpha3.HTTPRoute{}, "Mirror", "MirrorPercentage"),
 		); diff != "" {
 			vtClone := virtualService.DeepCopy()
 			vtClone.Spec = newSpec
@@ -304,6 +304,10 @@ func (ir *IstioRouter) SetRoutes(
 		vsCopy.Spec.Http[0].Mirror = &istiov1alpha3.Destination{
 			Host: canaryName,
 		}
+
+		if mw := canary.GetAnalysis().MirrorWeight; mw > 0 {
+			vsCopy.Spec.Http[0].MirrorPercentage = &istiov1alpha3.Percent{Value: float64(mw)}
+		}
 	}
 
 	// fix routing (A/B testing)


Test patch:
diff --git a/pkg/canary/deployment_fixture_test.go b/pkg/canary/deployment_fixture_test.go
index 486b3472..b2a0d6a6 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{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
diff --git a/pkg/controller/scheduler_daemonset_fixture_test.go b/pkg/controller/scheduler_daemonset_fixture_test.go
index 65570ac8..62b61667 100644
--- a/pkg/controller/scheduler_daemonset_fixture_test.go
+++ b/pkg/controller/scheduler_daemonset_fixture_test.go
@@ -249,7 +249,7 @@ func newDaemonSetTestCanary() *flaggerv1.Canary {
 				Kind:       "DaemonSet",
 			}, Service: flaggerv1.CanaryService{
 				Port: 9898,
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
@@ -288,7 +288,7 @@ func newDaemonSetTestCanary() *flaggerv1.Canary {
 
 func newDaemonSetTestCanaryMirror() *flaggerv1.Canary {
 	cd := newDaemonSetTestCanary()
-	cd.Spec.CanaryAnalysis.Mirror = true
+	cd.Spec.Analysis.Mirror = true
 	return cd
 }
 
@@ -306,7 +306,7 @@ func newDaemonSetTestCanaryAB() *flaggerv1.Canary {
 				Kind:       "DaemonSet",
 			}, Service: flaggerv1.CanaryService{
 				Port: 9898,
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				Iterations: 10,
 				Match: []istiov1alpha3.HTTPMatchRequest{
diff --git a/pkg/controller/scheduler_daemonset_test.go b/pkg/controller/scheduler_daemonset_test.go
index 4ed0ea33..3d650f45 100644
--- a/pkg/controller/scheduler_daemonset_test.go
+++ b/pkg/controller/scheduler_daemonset_test.go
@@ -55,7 +55,7 @@ func TestScheduler_DaemonSetRollback(t *testing.T) {
 	require.NoError(t, err)
 
 	cd := c.DeepCopy()
-	cd.Spec.CanaryAnalysis.Metrics = append(c.Spec.CanaryAnalysis.Metrics, flaggerv1.CanaryMetric{
+	cd.Spec.Analysis.Metrics = append(c.Spec.Analysis.Metrics, flaggerv1.CanaryMetric{
 		Name:     "fail",
 		Interval: "1m",
 		ThresholdRange: &flaggerv1.CanaryThresholdRange{
@@ -437,7 +437,7 @@ func TestScheduler_DaemonSetAlerts(t *testing.T) {
 	defer ts.Close()
 
 	canary := newDaemonSetTestCanary()
-	canary.Spec.CanaryAnalysis.Alerts = []flaggerv1.CanaryAlert{
+	canary.Spec.Analysis.Alerts = []flaggerv1.CanaryAlert{
 		{
 			Name:     "slack-dev",
 			Severity: "info",
diff --git a/pkg/controller/scheduler_deployment_fixture_test.go b/pkg/controller/scheduler_deployment_fixture_test.go
index be7c10dd..77f7f3a5 100644
--- a/pkg/controller/scheduler_deployment_fixture_test.go
+++ b/pkg/controller/scheduler_deployment_fixture_test.go
@@ -256,7 +256,7 @@ func newDeploymentTestCanary() *flaggerv1.Canary {
 				Kind:       "HorizontalPodAutoscaler",
 			}, Service: flaggerv1.CanaryService{
 				Port: 9898,
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
@@ -295,7 +295,7 @@ func newDeploymentTestCanary() *flaggerv1.Canary {
 
 func newDeploymentTestCanaryMirror() *flaggerv1.Canary {
 	cd := newDeploymentTestCanary()
-	cd.Spec.CanaryAnalysis.Mirror = true
+	cd.Spec.Analysis.Mirror = true
 	return cd
 }
 
@@ -318,7 +318,7 @@ func newDeploymentTestCanaryAB() *flaggerv1.Canary {
 				Kind:       "HorizontalPodAutoscaler",
 			}, Service: flaggerv1.CanaryService{
 				Port: 9898,
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				Iterations: 10,
 				Match: []istiov1alpha3.HTTPMatchRequest{
diff --git a/pkg/controller/scheduler_deployment_test.go b/pkg/controller/scheduler_deployment_test.go
index d518956e..b65b6447 100644
--- a/pkg/controller/scheduler_deployment_test.go
+++ b/pkg/controller/scheduler_deployment_test.go
@@ -55,7 +55,7 @@ func TestScheduler_DeploymentRollback(t *testing.T) {
 	c, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Get("podinfo", metav1.GetOptions{})
 	require.NoError(t, err)
 	cd := c.DeepCopy()
-	cd.Spec.CanaryAnalysis.Metrics = append(c.Spec.CanaryAnalysis.Metrics, flaggerv1.CanaryMetric{
+	cd.Spec.Analysis.Metrics = append(c.Spec.Analysis.Metrics, flaggerv1.CanaryMetric{
 		Name:     "fail",
 		Interval: "1m",
 		ThresholdRange: &flaggerv1.CanaryThresholdRange{
@@ -519,7 +519,7 @@ func TestScheduler_DeploymentAlerts(t *testing.T) {
 	defer ts.Close()
 
 	canary := newDeploymentTestCanary()
-	canary.Spec.CanaryAnalysis.Alerts = []flaggerv1.CanaryAlert{
+	canary.Spec.Analysis.Alerts = []flaggerv1.CanaryAlert{
 		{
 			Name:     "slack-dev",
 			Severity: "info",
diff --git a/pkg/controller/scheduler_svc_test.go b/pkg/controller/scheduler_svc_test.go
index e552906b..d1214adb 100644
--- a/pkg/controller/scheduler_svc_test.go
+++ b/pkg/controller/scheduler_svc_test.go
@@ -98,7 +98,7 @@ func newTestServiceCanary() *flaggerv1.Canary {
 			Service: flaggerv1.CanaryService{
 				Port: 9898,
 			},
-			CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
diff --git a/pkg/router/contour_test.go b/pkg/router/contour_test.go
index 064073c1..2c0c6c6b 100644
--- a/pkg/router/contour_test.go
+++ b/pkg/router/contour_test.go
@@ -57,8 +57,8 @@ func TestContourRouter_Reconcile(t *testing.T) {
 	require.NoError(t, err)
 
 	cdClone = cd.DeepCopy()
-	cdClone.Spec.CanaryAnalysis.Iterations = 5
-	cdClone.Spec.CanaryAnalysis.Match = newTestABTest().Spec.CanaryAnalysis.Match
+	cdClone.Spec.Analysis.Iterations = 5
+	cdClone.Spec.Analysis.Match = newTestABTest().Spec.Analysis.Match
 	canary, err = mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cdClone)
 	require.NoError(t, err)
 
@@ -104,8 +104,8 @@ func TestContourRouter_Routes(t *testing.T) {
 
 	// test update to A/B
 	cdClone := cd.DeepCopy()
-	cdClone.Spec.CanaryAnalysis.Iterations = 5
-	cdClone.Spec.CanaryAnalysis.Match = newTestABTest().Spec.CanaryAnalysis.Match
+	cdClone.Spec.Analysis.Iterations = 5
+	cdClone.Spec.Analysis.Match = newTestABTest().Spec.Analysis.Match
 	canary, err := mocks.flaggerClient.FlaggerV1beta1().Canaries("default").Update(cdClone)
 	require.NoError(t, err)
 
diff --git a/pkg/router/istio_test.go b/pkg/router/istio_test.go
index e48967f0..0b9c3591 100644
--- a/pkg/router/istio_test.go
+++ b/pkg/router/istio_test.go
@@ -91,69 +91,78 @@ func TestIstioRouter_SetRoutes(t *testing.T) {
 	err := router.Reconcile(mocks.canary)
 	require.NoError(t, err)
 
-	p, c, m, err := router.GetRoutes(mocks.canary)
-	require.NoError(t, err)
-
-	p = 60
-	c = 40
-	m = false
-
-	err = router.SetRoutes(mocks.canary, p, c, m)
-	require.NoError(t, err)
-
-	vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get("podinfo", metav1.GetOptions{})
-	require.NoError(t, err)
-
 	pHost := fmt.Sprintf("%s-primary", mocks.canary.Spec.TargetRef.Name)
 	cHost := fmt.Sprintf("%s-canary", mocks.canary.Spec.TargetRef.Name)
-	pRoute := istiov1alpha3.DestinationWeight{}
-	cRoute := istiov1alpha3.DestinationWeight{}
-	var mirror *istiov1alpha3.Destination
 
-	for _, http := range vs.Spec.Http {
-		for _, route := range http.Route {
-			if route.Destination.Host == pHost {
-				pRoute = route
-			}
-			if route.Destination.Host == cHost {
-				cRoute = route
-				mirror = http.Mirror
-			}
-		}
-	}
+	t.Run("normal", func(t *testing.T) {
+		p, c := 60, 40
+		err := router.SetRoutes(mocks.canary, p, c, false)
+		require.NoError(t, err)
 
-	assert.Equal(t, p, pRoute.Weight)
-	assert.Equal(t, c, cRoute.Weight)
-	assert.Nil(t, mirror)
-
-	mirror = nil
-	p = 100
-	c = 0
-	m = true
+		vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get("podinfo", metav1.GetOptions{})
+		require.NoError(t, err)
 
-	err = router.SetRoutes(mocks.canary, p, c, m)
-	require.NoError(t, err)
+		var pRoute, cRoute istiov1alpha3.DestinationWeight
+		var mirror *istiov1alpha3.Destination
+		for _, http := range vs.Spec.Http {
+			for _, route := range http.Route {
+				if route.Destination.Host == pHost {
+					pRoute = route
+				}
+				if route.Destination.Host == cHost {
+					cRoute = route
+					mirror = http.Mirror
+				}
+			}
+		}
 
-	vs, err = mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get("podinfo", metav1.GetOptions{})
-	require.NoError(t, err)
+		assert.Equal(t, p, pRoute.Weight)
+		assert.Equal(t, c, cRoute.Weight)
+		assert.Nil(t, mirror)
+
+	})
+
+	t.Run("mirror", func(t *testing.T) {
+		for _, w := range []int{0, 10, 50} {
+			p, c := 100, 0
+
+			// set mirror weight
+			mocks.canary.Spec.Analysis.MirrorWeight = w
+			err := router.SetRoutes(mocks.canary, p, c, true)
+			require.NoError(t, err)
+
+			vs, err := mocks.meshClient.NetworkingV1alpha3().VirtualServices("default").Get("podinfo", metav1.GetOptions{})
+			require.NoError(t, err)
+
+			var pRoute, cRoute istiov1alpha3.DestinationWeight
+			var mirror *istiov1alpha3.Destination
+			var mirrorWeight *istiov1alpha3.Percent
+			for _, http := range vs.Spec.Http {
+				for _, route := range http.Route {
+					if route.Destination.Host == pHost {
+						pRoute = route
+					}
+					if route.Destination.Host == cHost {
+						cRoute = route
+						mirror = http.Mirror
+						mirrorWeight = http.MirrorPercentage
+					}
+				}
+			}
 
-	for _, http := range vs.Spec.Http {
-		for _, route := range http.Route {
-			if route.Destination.Host == pHost {
-				pRoute = route
+			assert.Equal(t, p, pRoute.Weight)
+			assert.Equal(t, c, cRoute.Weight)
+			if assert.NotNil(t, mirror) {
+				assert.Equal(t, cHost, mirror.Host)
 			}
-			if route.Destination.Host == cHost {
-				cRoute = route
-				mirror = http.Mirror
+
+			if w > 0 && assert.NotNil(t, mirrorWeight) {
+				assert.Equal(t, w, int(mirrorWeight.Value))
+			} else {
+				assert.Nil(t, mirrorWeight)
 			}
 		}
-	}
-
-	assert.Equal(t, p, pRoute.Weight)
-	assert.Equal(t, c, cRoute.Weight)
-	if assert.NotNil(t, mirror) {
-		assert.Equal(t, cHost, mirror.Host)
-	}
+	})
 }
 
 func TestIstioRouter_GetRoutes(t *testing.T) {
diff --git a/pkg/router/router_test.go b/pkg/router/router_test.go
index 205a8ab3..f2c07a48 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{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
@@ -158,7 +158,7 @@ func newTestCanaryAppMesh() *flaggerv1.Canary {
 					PerTryTimeout: "gateway-error",
 					RetryOn:       "5s",
 				},
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
@@ -203,7 +203,7 @@ func newTestSMICanary() *flaggerv1.Canary {
 				},
 				PortDiscovery: true,
 			},
-			CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,
@@ -247,7 +247,7 @@ func newTestABTest() *flaggerv1.Canary {
 			Service: flaggerv1.CanaryService{
 				Port:     9898,
 				MeshName: "global",
-			}, CanaryAnalysis: &flaggerv1.CanaryAnalysis{
+			}, Analysis: &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{
+			}, Analysis: &flaggerv1.CanaryAnalysis{
 				Threshold:  10,
 				StepWeight: 10,
 				MaxWeight:  50,