diff --git a/docs/features/traffic-management/istio.md b/docs/features/traffic-management/istio.md index 415313841a..9d146d545c 100644 --- a/docs/features/traffic-management/istio.md +++ b/docs/features/traffic-management/istio.md @@ -473,6 +473,18 @@ help address this problem. The proposed solution is to introduce an annotation t indicates to Argo CD to respect and preserve the differences at a specified path, in order to allow other controllers (e.g. Argo Rollouts) controller manage them instead. +## Ping Pong + +!!! important + + Available since v1.7 + +Argo Rollouts also supports ping pong when using Istio this was added to support configuring both ALB and +Istio traffic routers at the same time. When using an ALB, ping-pong is generally a best practice especially with ALB readiness +gates enabled. However, when we change the service selectors when a rollout is aborted back to stable pod hash it causes a blip +of traffic outage because the ALB controller will set the pod readiness gates to false for a short while due to the label changes. +If we configure both ALB and Istio with ping-pong this selector change does not happen and hence we do not see any outages. + ## Alternatives Considered ### Rollout ownership over the Virtual Service diff --git a/pkg/apis/rollouts/validation/validation.go b/pkg/apis/rollouts/validation/validation.go index 76ab8d6c66..9bb3f24af6 100644 --- a/pkg/apis/rollouts/validation/validation.go +++ b/pkg/apis/rollouts/validation/validation.go @@ -81,8 +81,8 @@ const ( DuplicatedPingPongServicesMessage = "This rollout uses the same service for the ping and pong services, but two different services are required." // MissedAlbRootServiceMessage indicates that the rollout with ALB TrafficRouting and ping pong feature enabled must have root service provided MissedAlbRootServiceMessage = "Root service field is required for the configuration with ALB and ping-pong feature enabled" - // PingPongWithAlbOnlyMessage At this moment ping-pong feature works with the ALB traffic routing only - PingPongWithAlbOnlyMessage = "Ping-pong feature works with the ALB traffic routing only" + // PingPongWithRouterOnlyMessage At this moment ping-pong feature works with the ALB traffic routing only + PingPongWithRouterOnlyMessage = "Ping-pong feature works with the ALB and Istio traffic routers only" // InvalideStepRouteNameNotFoundInManagedRoutes A step has been configured that requires managedRoutes and the route name // is missing from managedRoutes InvalideStepRouteNameNotFoundInManagedRoutes = "Steps define a route that does not exist in spec.strategy.canary.trafficRouting.managedRoutes" @@ -241,7 +241,7 @@ func requireCanaryStableServices(rollout *v1alpha1.Rollout) bool { switch { case canary.TrafficRouting.ALB != nil && canary.PingPong == nil, - canary.TrafficRouting.Istio != nil && canary.TrafficRouting.Istio.DestinationRule == nil, + canary.TrafficRouting.Istio != nil && canary.TrafficRouting.Istio.DestinationRule == nil && canary.PingPong == nil, canary.TrafficRouting.SMI != nil, canary.TrafficRouting.Apisix != nil, canary.TrafficRouting.Ambassador != nil, @@ -262,8 +262,8 @@ func ValidateRolloutStrategyCanary(rollout *v1alpha1.Rollout, fldPath *field.Pat allErrs = append(allErrs, field.Invalid(fldPath.Child("stableService"), canary.StableService, DuplicatedServicesCanaryMessage)) } if canary.PingPong != nil { - if canary.TrafficRouting != nil && canary.TrafficRouting.ALB == nil { - allErrs = append(allErrs, field.Invalid(fldPath.Child("trafficRouting").Child("alb"), canary.TrafficRouting.ALB, PingPongWithAlbOnlyMessage)) + if canary.TrafficRouting != nil && canary.TrafficRouting.ALB == nil && canary.TrafficRouting.Istio == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("trafficRouting").Child("alb"), canary.TrafficRouting.ALB, PingPongWithRouterOnlyMessage)) } if canary.PingPong.PingService == "" { allErrs = append(allErrs, field.Invalid(fldPath.Child("pingPong").Child("pingService"), canary.PingPong.PingService, InvalidPingPongProvidedMessage)) diff --git a/pkg/apis/rollouts/validation/validation_test.go b/pkg/apis/rollouts/validation/validation_test.go index 5d5c19be5e..c9fc9ad923 100644 --- a/pkg/apis/rollouts/validation/validation_test.go +++ b/pkg/apis/rollouts/validation/validation_test.go @@ -290,6 +290,21 @@ func TestValidateRolloutStrategyCanary(t *testing.T) { assert.Empty(t, allErrs) }) + t.Run("valid Istio with ping pong", func(t *testing.T) { + validRo := ro.DeepCopy() + validRo.Spec.Strategy.Canary.Steps[0].SetWeight = pointer.Int32(10) + validRo.Spec.Strategy.Canary.CanaryService = "" + validRo.Spec.Strategy.Canary.StableService = "" + validRo.Spec.Strategy.Canary.PingPong = &v1alpha1.PingPongSpec{ + PingService: "ping", + PongService: "pong", + } + validRo.Spec.Strategy.Canary.TrafficRouting.Istio = &v1alpha1.IstioTrafficRouting{DestinationRule: &v1alpha1.IstioDestinationRule{Name: "destination-rule"}} + validRo.Spec.Strategy.Canary.TrafficRouting.ALB = nil + allErrs := ValidateRolloutStrategyCanary(validRo, field.NewPath("")) + assert.Empty(t, allErrs) + }) + t.Run("valid PingPong missing canary and stable service", func(t *testing.T) { validRo := ro.DeepCopy() validRo.Spec.Strategy.Canary.Steps[0].SetWeight = pointer.Int32(10) @@ -368,7 +383,7 @@ func TestValidateRolloutStrategyCanary(t *testing.T) { Nginx: &v1alpha1.NginxTrafficRouting{StableIngress: "stable-ingress"}, } allErrs := ValidateRolloutStrategyCanary(invalidRo, field.NewPath("")) - assert.Equal(t, PingPongWithAlbOnlyMessage, allErrs[0].Detail) + assert.Equal(t, PingPongWithRouterOnlyMessage, allErrs[0].Detail) }) t.Run("invalid traffic routing", func(t *testing.T) { diff --git a/rollout/trafficrouting/istio/istio.go b/rollout/trafficrouting/istio/istio.go index dd44da7b25..5308d59a42 100644 --- a/rollout/trafficrouting/istio/istio.go +++ b/rollout/trafficrouting/istio/istio.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + "github.com/argoproj/argo-rollouts/rollout/trafficrouting" + jsonpatch "github.com/evanphx/json-patch/v5" "github.com/mitchellh/mapstructure" log "github.com/sirupsen/logrus" @@ -123,8 +125,7 @@ func (patches virtualServicePatches) patchVirtualService(httpRoutes []any, tlsRo } func (r *Reconciler) generateVirtualServicePatches(rolloutVsvcRouteNames []string, httpRoutes []VirtualServiceHTTPRoute, rolloutVsvcTLSRoutes []v1alpha1.TLSRoute, tlsRoutes []VirtualServiceTLSRoute, rolloutVsvcTCPRoutes []v1alpha1.TCPRoute, tcpRoutes []VirtualServiceTCPRoute, desiredWeight int64, additionalDestinations ...v1alpha1.WeightDestination) virtualServicePatches { - canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService - stableSvc := r.rollout.Spec.Strategy.Canary.StableService + stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout) canarySubset := "" stableSubset := "" if r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.DestinationRule != nil { @@ -717,7 +718,7 @@ func (r *Reconciler) reconcileVirtualServiceHeaderRoutes(virtualService v1alpha1 return err } - canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService + _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout) if destRuleHost != "" { canarySvc = destRuleHost } @@ -1022,8 +1023,7 @@ func searchTcpRoute(tcpRoute v1alpha1.TCPRoute, istioTcpRoutes []VirtualServiceT // ValidateHTTPRoutes ensures that all the routes in the rollout exist func ValidateHTTPRoutes(r *v1alpha1.Rollout, routeNames []string, httpRoutes []VirtualServiceHTTPRoute) error { - stableSvc := r.Spec.Strategy.Canary.StableService - canarySvc := r.Spec.Strategy.Canary.CanaryService + stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r) routeIndexesToPatch, err := getHttpRouteIndexesToPatch(routeNames, httpRoutes) if err != nil { @@ -1060,8 +1060,7 @@ func ValidateHTTPRoutes(r *v1alpha1.Rollout, routeNames []string, httpRoutes []V // ValidateTlsRoutes ensures that all the routes in the rollout exist and they only have two destinations func ValidateTlsRoutes(r *v1alpha1.Rollout, vsvcTLSRoutes []v1alpha1.TLSRoute, tlsRoutes []VirtualServiceTLSRoute) error { - stableSvc := r.Spec.Strategy.Canary.StableService - canarySvc := r.Spec.Strategy.Canary.CanaryService + stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r) routeIndexesToPatch, err := getTlsRouteIndexesToPatch(vsvcTLSRoutes, tlsRoutes) if err != nil { @@ -1082,8 +1081,7 @@ func ValidateTlsRoutes(r *v1alpha1.Rollout, vsvcTLSRoutes []v1alpha1.TLSRoute, t // ValidateTcpRoutes ensures that all the routes in the rollout exist and they only have two destinations func ValidateTcpRoutes(r *v1alpha1.Rollout, vsvcTCPRoutes []v1alpha1.TCPRoute, tcpRoutes []VirtualServiceTCPRoute) error { - stableSvc := r.Spec.Strategy.Canary.StableService - canarySvc := r.Spec.Strategy.Canary.CanaryService + stableSvc, canarySvc := trafficrouting.GetStableAndCanaryServices(r) routeIndexesToPatch, err := getTcpRouteIndexesToPatch(vsvcTCPRoutes, tcpRoutes) if err != nil { @@ -1191,7 +1189,7 @@ func (r *Reconciler) reconcileVirtualServiceMirrorRoutes(virtualService v1alpha1 if err != nil { return fmt.Errorf("[reconcileVirtualServiceMirrorRoutes] failed to get destination rule host: %w", err) } - canarySvc := r.rollout.Spec.Strategy.Canary.CanaryService + _, canarySvc := trafficrouting.GetStableAndCanaryServices(r.rollout) if destRuleHost != "" { canarySvc = destRuleHost } diff --git a/rollout/trafficrouting/istio/istio_test.go b/rollout/trafficrouting/istio/istio_test.go index c18cdedae5..c6c0f8d9a1 100644 --- a/rollout/trafficrouting/istio/istio_test.go +++ b/rollout/trafficrouting/istio/istio_test.go @@ -64,6 +64,31 @@ func rollout(stableSvc, canarySvc string, istioVirtualService *v1alpha1.IstioVir } } +func rolloutPingPong(istioVirtualService *v1alpha1.IstioVirtualService) *v1alpha1.Rollout { + return &v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + Name: "rollout", + Namespace: "default", + }, + Spec: v1alpha1.RolloutSpec{ + Strategy: v1alpha1.RolloutStrategy{ + Canary: &v1alpha1.CanaryStrategy{ + PingPong: &v1alpha1.PingPongSpec{ + PingService: "ping", + PongService: "pong", + }, + TrafficRouting: &v1alpha1.RolloutTrafficRouting{ + Istio: &v1alpha1.IstioTrafficRouting{ + VirtualService: istioVirtualService, + }, + }, + }, + }, + }, + Status: v1alpha1.RolloutStatus{Canary: v1alpha1.CanaryStatus{StablePingPong: "ping"}}, + } +} + func rolloutWithHttpRoutes(stableSvc, canarySvc, vsvc string, httpRoutes []string) *v1alpha1.Rollout { istioVirtualService := &v1alpha1.IstioVirtualService{ Name: vsvc, @@ -98,6 +123,16 @@ func rolloutWithHttpAndTlsAndTcpRoutes(stableSvc, canarySvc, vsvc string, httpRo return rollout(stableSvc, canarySvc, istioVirtualService) } +func rolloutWithHttpAndTlsAndTcpRoutesPingPong(vsvc string, httpRoutes []string, tlsRoutes []v1alpha1.TLSRoute, tcpRoutes []v1alpha1.TCPRoute) *v1alpha1.Rollout { + istioVirtualService := &v1alpha1.IstioVirtualService{ + Name: vsvc, + Routes: httpRoutes, + TLSRoutes: tlsRoutes, + TCPRoutes: tcpRoutes, + } + return rolloutPingPong(istioVirtualService) +} + func checkDestination(t *testing.T, destinations []VirtualServiceRouteDestination, svc string, expectWeight int) { for _, destination := range destinations { if destination.Destination.Host == svc { @@ -263,6 +298,72 @@ spec: host: canary weight: 0` +const regularMixedVsvcPingPong = `apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: vsvc + namespace: default +spec: + gateways: + - istio-rollout-gateway + hosts: + - istio-rollout.dev.argoproj.io + http: + - name: primary + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0 + - name: secondary + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0 + tls: + - match: + - port: 3000 + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0 + - match: + - port: 3001 + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0 + tcp: + - match: + - port: 3000 + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0 + - match: + - port: 3001 + route: + - destination: + host: 'ping' + weight: 100 + - destination: + host: pong + weight: 0` + const regularMixedVsvcTwoHttpRoutes = `apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: @@ -597,6 +698,14 @@ func extractTcpRoutes(t *testing.T, modifiedObj *unstructured.Unstructured) []Vi } func assertTcpRouteWeightChanges(t *testing.T, tcpRoute VirtualServiceTCPRoute, portNum, canaryWeight, stableWeight int) { + assertTcpRouteWeightChangesBase(t, tcpRoute, portNum, canaryWeight, stableWeight, "stable", "canary") +} + +func assertTcpRouteWeightChangesPingPong(t *testing.T, tcpRoute VirtualServiceTCPRoute, portNum, canaryWeight, stableWeight int) { + assertTcpRouteWeightChangesBase(t, tcpRoute, portNum, canaryWeight, stableWeight, "ping", "pong") +} + +func assertTcpRouteWeightChangesBase(t *testing.T, tcpRoute VirtualServiceTCPRoute, portNum, canaryWeight, stableWeight int, stableSvc, canarySvc string) { portsMap := make(map[int64]bool) for _, routeMatch := range tcpRoute.Match { if routeMatch.Port != 0 { @@ -610,8 +719,8 @@ func assertTcpRouteWeightChanges(t *testing.T, tcpRoute VirtualServiceTCPRoute, if portNum != 0 { assert.Equal(t, portNum, port) } - checkDestination(t, tcpRoute.Route, "stable", stableWeight) - checkDestination(t, tcpRoute.Route, "canary", canaryWeight) + checkDestination(t, tcpRoute.Route, stableSvc, stableWeight) + checkDestination(t, tcpRoute.Route, canarySvc, canaryWeight) } func extractHttpRoutes(t *testing.T, modifiedObj *unstructured.Unstructured) []VirtualServiceHTTPRoute { @@ -643,6 +752,14 @@ func extractTlsRoutes(t *testing.T, modifiedObj *unstructured.Unstructured) []Vi } func assertTlsRouteWeightChanges(t *testing.T, tlsRoute VirtualServiceTLSRoute, snis []string, portNum, canaryWeight, stableWeight int) { + assertTlsRouteWeightChangesBase(t, tlsRoute, snis, portNum, canaryWeight, stableWeight, "stable", "canary") +} + +func assertTlsRouteWeightChangesPingPong(t *testing.T, tlsRoute VirtualServiceTLSRoute, snis []string, portNum, canaryWeight, stableWeight int) { + assertTlsRouteWeightChangesBase(t, tlsRoute, snis, portNum, canaryWeight, stableWeight, "ping", "pong") +} + +func assertTlsRouteWeightChangesBase(t *testing.T, tlsRoute VirtualServiceTLSRoute, snis []string, portNum, canaryWeight, stableWeight int, stableSvc, canarySvc string) { portsMap := make(map[int64]bool) sniHostsMap := make(map[string]bool) for _, routeMatch := range tlsRoute.Match { @@ -667,8 +784,8 @@ func assertTlsRouteWeightChanges(t *testing.T, tlsRoute VirtualServiceTLSRoute, if len(snis) != 0 { assert.Equal(t, evalUtils.Equal(snis, sniHosts), true) } - checkDestination(t, tlsRoute.Route, "stable", stableWeight) - checkDestination(t, tlsRoute.Route, "canary", canaryWeight) + checkDestination(t, tlsRoute.Route, stableSvc, stableWeight) + checkDestination(t, tlsRoute.Route, canarySvc, canaryWeight) } func TestHttpReconcileWeightsBaseCase(t *testing.T) { @@ -1104,6 +1221,57 @@ func TestReconcileWeightsBaseCase(t *testing.T) { assertTcpRouteWeightChanges(t, tcpRoutes[1], 3001, 0, 100) } +func TestReconcileWeightsPingPongBaseCase(t *testing.T) { + r := &Reconciler{ + rollout: rolloutWithHttpAndTlsAndTcpRoutesPingPong("vsvc", []string{"primary"}, + []v1alpha1.TLSRoute{ + { + Port: 3000, + }, + }, + []v1alpha1.TCPRoute{ + { + Port: 3000, + }, + }, + ), + } + obj := unstructuredutil.StrToUnstructuredUnsafe(regularMixedVsvcPingPong) + vsvcRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Routes + vsvcTLSRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TLSRoutes + vsvcTCPRoutes := r.rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.TCPRoutes + modifiedObj, _, err := r.reconcileVirtualService(obj, vsvcRoutes, vsvcTLSRoutes, vsvcTCPRoutes, 20) + assert.Nil(t, err) + assert.NotNil(t, modifiedObj) + + // HTTP Routes + httpRoutes := extractHttpRoutes(t, modifiedObj) + + // Assertions + assert.Equal(t, httpRoutes[0].Name, "primary") + checkDestination(t, httpRoutes[0].Route, "ping", 80) + checkDestination(t, httpRoutes[0].Route, "pong", 20) + + //assertHttpRouteWeightChanges(t, httpRoutes[1], "secondary", 0, 100) + assert.Equal(t, httpRoutes[1].Name, "secondary") + checkDestination(t, httpRoutes[1].Route, "ping", 100) + checkDestination(t, httpRoutes[1].Route, "pong", 0) + + // TLS Routes + tlsRoutes := extractTlsRoutes(t, modifiedObj) + // + // Assestions + assertTlsRouteWeightChangesPingPong(t, tlsRoutes[0], nil, 3000, 20, 80) + assertTlsRouteWeightChangesPingPong(t, tlsRoutes[1], nil, 3001, 0, 100) + // + // TCP Routes + tcpRoutes := extractTcpRoutes(t, modifiedObj) + + // Assestions + assertTcpRouteWeightChangesPingPong(t, tcpRoutes[0], 3000, 20, 80) + assertTcpRouteWeightChangesPingPong(t, tcpRoutes[1], 3001, 0, 100) +} + func TestReconcileUpdateVirtualService(t *testing.T) { ro := rolloutWithHttpRoutes("stable", "canary", "vsvc", []string{"primary"}) AssertReconcileUpdateVirtualService(t, regularVsvc, ro) diff --git a/test/e2e/istio/istio-host-split-ping-pong.yaml b/test/e2e/istio/istio-host-split-ping-pong.yaml new file mode 100644 index 0000000000..b9eb38ad37 --- /dev/null +++ b/test/e2e/istio/istio-host-split-ping-pong.yaml @@ -0,0 +1,84 @@ +apiVersion: v1 +kind: Service +metadata: + name: pong +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: ping +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split + http: + - name: primary + route: + - destination: + host: ping + weight: 100 + - destination: + host: pong + weight: 0 + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + pingPong: + pingService: ping + pongService: pong + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 25 + - pause: { duration: 5s } + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: nginx:1.19-alpine + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/test/e2e/istio_test.go b/test/e2e/istio_test.go index 610feab03f..9797b3e503 100644 --- a/test/e2e/istio_test.go +++ b/test/e2e/istio_test.go @@ -493,6 +493,57 @@ func (s *IstioSuite) TestIstioSubsetSplitExperimentStep() { s.TearDownSuite() } +func (s *IstioSuite) TestIstioPingPongUpdate() { + s.Given(). + RolloutObjects("@istio/istio-host-split-ping-pong.yaml"). + When().ApplyManifests().WaitForRolloutStatus("Healthy"). + Then(). + //Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight) + assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) + }). + // Update 1. Test the weight switch from ping => pong + When().UpdateSpec(). + WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then(). + //Assert(assertWeights(s, "ping-service", "pong-service", 75, 25)). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(75), vsvc.Spec.HTTP[0].Route[0].Weight) + assert.Equal(s.T(), int64(25), vsvc.Spec.HTTP[0].Route[1].Weight) + }). + When().PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + //Assert(assertWeights(s, "ping-service", "pong-service", 0, 100)). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[0].Weight) + assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[1].Weight) + }). + // Update 2. Test the weight switch from pong => ping + When().UpdateSpec(). + WaitForRolloutCanaryStepIndex(1).Sleep(1 * time.Second).Then(). + //Assert(assertWeights(s, "ping-service", "pong-service", 25, 75)). + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(25), vsvc.Spec.HTTP[0].Route[0].Weight) + assert.Equal(s.T(), int64(75), vsvc.Spec.HTTP[0].Route[1].Weight) + }). + When().PromoteRollout(). + WaitForRolloutStatus("Healthy"). + Sleep(1 * time.Second). + Then(). + //Assert(assertWeights(s, "ping-service", "pong-service", 100, 0)) + Assert(func(t *fixtures.Then) { + vsvc := t.GetVirtualService() + assert.Equal(s.T(), int64(100), vsvc.Spec.HTTP[0].Route[0].Weight) + assert.Equal(s.T(), int64(0), vsvc.Spec.HTTP[0].Route[1].Weight) + }) +} + func (s *IstioSuite) TestIstioSubsetSplitInStableDownscaleAfterCanaryAbort() { s.Given(). RolloutObjects("@istio/istio-subset-split-in-stable-downscale-after-canary-abort.yaml").