mirror of
https://github.com/fluxcd/flagger.git
synced 2026-04-15 06:57:34 +00:00
gatewayapi: add support for b/g mirroring
Add support for mirroring requests while performing B/G deployments with Gateway API. A `RequestMirror` filter pointing to the canary service is added to the HTTPRoute during a Canary run. During the Canary run, drift correction for `.spec.rules[].filters` is disabled to avoid removing the mirror filter. Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
This commit is contained in:
@@ -187,6 +187,16 @@ func (gwr *GatewayAPIV1Beta1Router) Reconcile(canary *flaggerv1.Canary) error {
|
||||
ignoreCmpOptions = append(ignoreCmpOptions, cmpopts.IgnoreFields(v1beta1.HTTPBackendRef{}, "Filters"))
|
||||
}
|
||||
|
||||
if canary.GetAnalysis().Mirror {
|
||||
// If a Canary run is in progress, the HTTPRoute rule will have an extra filter of type RequestMirror
|
||||
// which needs to be ignored so that the requests are mirrored to the canary deployment.
|
||||
inProgress := canary.Status.Phase == flaggerv1.CanaryPhaseWaiting || canary.Status.Phase == flaggerv1.CanaryPhaseProgressing ||
|
||||
canary.Status.Phase == flaggerv1.CanaryPhaseWaitingPromotion
|
||||
if inProgress {
|
||||
ignoreCmpOptions = append(ignoreCmpOptions, cmpopts.IgnoreFields(v1beta1.HTTPRouteRule{}, "Filters"))
|
||||
}
|
||||
}
|
||||
|
||||
if httpRoute != nil {
|
||||
specDiff := cmp.Diff(
|
||||
httpRoute.Spec, httpRouteSpec,
|
||||
@@ -249,6 +259,12 @@ func (gwr *GatewayAPIV1Beta1Router) GetRoutes(canary *flaggerv1.Canary) (
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, filter := range rule.Filters {
|
||||
if filter.Type == v1beta1.HTTPRouteFilterRequestMirror && filter.RequestMirror != nil &&
|
||||
string(filter.RequestMirror.BackendRef.Name) == canarySvcName {
|
||||
mirrored = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if weightedRule != nil {
|
||||
@@ -307,6 +323,23 @@ func (gwr *GatewayAPIV1Beta1Router) SetRoutes(
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// If B/G mirroring is enabled, then add a route filter which mirrors the traffic
|
||||
// to the canary service.
|
||||
if mirrored && canary.GetAnalysis().Iterations > 0 {
|
||||
weightedRouteRule.Filters = append(weightedRouteRule.Filters, v1beta1.HTTPRouteFilter{
|
||||
Type: v1beta1.HTTPRouteFilterRequestMirror,
|
||||
RequestMirror: &v1beta1.HTTPRequestMirrorFilter{
|
||||
BackendRef: v1beta1.BackendObjectReference{
|
||||
Group: (*v1beta1.Group)(&backendRefGroup),
|
||||
Kind: (*v1beta1.Kind)(&backendRefKind),
|
||||
Name: v1beta1.ObjectName(canarySvcName),
|
||||
Port: (*v1beta1.PortNumber)(&canary.Spec.Service.Port),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
httpRouteSpec := v1beta1.HTTPRouteSpec{
|
||||
CommonRouteSpec: v1beta1.CommonRouteSpec{
|
||||
ParentRefs: canary.Spec.Service.GatewayRefs,
|
||||
|
||||
@@ -233,6 +233,44 @@ func TestGatewayAPIV1Beta1Router_Routes(t *testing.T) {
|
||||
}
|
||||
assert.True(t, found)
|
||||
})
|
||||
|
||||
t.Run("b/g mirror", func(t *testing.T) {
|
||||
canary := mocks.canary.DeepCopy()
|
||||
canary.Spec.Analysis.Mirror = true
|
||||
canary.Spec.Analysis.Iterations = 5
|
||||
_, _, cSvcName := canary.GetServiceNames()
|
||||
|
||||
err = router.SetRoutes(canary, 100, 0, true)
|
||||
hr, err := mocks.meshClient.GatewayapiV1beta1().HTTPRoutes("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, hr.Spec.Rules, 1)
|
||||
|
||||
rule := hr.Spec.Rules[0]
|
||||
var found bool
|
||||
for _, filter := range rule.Filters {
|
||||
if filter.Type == v1beta1.HTTPRouteFilterRequestMirror && filter.RequestMirror != nil &&
|
||||
string(filter.RequestMirror.BackendRef.Name) == cSvcName {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
assert.True(t, found, "could not find request mirror filter in HTTPRoute")
|
||||
|
||||
// Mark the status as progressing to assert that request mirror filter is ignored.
|
||||
canary.Status.Phase = flaggerv1.CanaryPhaseProgressing
|
||||
err = router.Reconcile(canary)
|
||||
require.NoError(t, err)
|
||||
|
||||
hr, err = mocks.meshClient.GatewayapiV1beta1().HTTPRoutes("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, hr.Spec.Rules, 1)
|
||||
assert.Empty(t, cmp.Diff(hr.Spec.Rules[0], rule))
|
||||
|
||||
err = router.SetRoutes(canary, 100, 0, false)
|
||||
hr, err = mocks.meshClient.GatewayapiV1beta1().HTTPRoutes("default").Get(context.TODO(), "podinfo", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, hr.Spec.Rules, 1)
|
||||
assert.Len(t, hr.Spec.Rules[0].Filters, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGatewayAPIV1Beta1Router_getSessionAffinityRouteRules(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user