From bd280b9d18c57198182581954a706461579fce2d Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Mon, 5 Feb 2024 23:38:31 +0100 Subject: [PATCH 01/12] feat: support multiple routes per rollout Signed-off-by: Stepan Rakitin --- pkg/plugin/httproute.go | 4 +-- pkg/plugin/plugin.go | 55 +++++++++++++++++++++++++++++++++------ pkg/plugin/plugin_test.go | 50 +++++++++++++++++++++++++---------- pkg/plugin/tcproute.go | 4 +-- pkg/plugin/types.go | 3 +++ 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/pkg/plugin/httproute.go b/pkg/plugin/httproute.go index 61e6780..a0a5c6c 100644 --- a/pkg/plugin/httproute.go +++ b/pkg/plugin/httproute.go @@ -10,14 +10,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting) pluginTypes.RpcError { +func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting, routeName string) pluginTypes.RpcError { ctx := context.TODO() httpRouteClient := r.HTTPRouteClient if !r.IsTest { gatewayV1beta1 := r.Client.GatewayV1beta1() httpRouteClient = gatewayV1beta1.HTTPRoutes(gatewayAPIConfig.Namespace) } - httpRoute, err := httpRouteClient.Get(ctx, gatewayAPIConfig.HTTPRoute, metav1.GetOptions{}) + httpRoute, err := httpRouteClient.Get(ctx, routeName, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index d79d0eb..6d52ee5 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -2,10 +2,12 @@ package plugin import ( "encoding/json" + "fmt" "github.com/argoproj-labs/rollouts-plugin-trafficrouter-gatewayapi/utils" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" pluginTypes "github.com/argoproj/argo-rollouts/utils/plugin/types" + "sigs.k8s.io/gateway-api/apis/v1beta1" gatewayApiClientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned" ) @@ -15,7 +17,10 @@ const ( PluginName = "argoproj-labs/gatewayAPI" GatewayAPIUpdateError = "GatewayAPIUpdateError" - GatewayAPIManifestError = "httpRoute and tcpRoute fields are empty. tcpRoute or httpRoute should be set" + GatewayAPIManifestError = "No routes configured. One of 'routes', 'tcpRoute' or 'httpRoute' should be set" + + HTTPRouteKind = "HTTPRoute" + TCPRouteKind = "TCPRoute" ) func (r *RpcPlugin) InitPlugin() pluginTypes.RpcError { @@ -43,22 +48,56 @@ func (r *RpcPlugin) UpdateHash(rollout *v1alpha1.Rollout, canaryHash, stableHash } func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination) pluginTypes.RpcError { - gatewayAPIConfig := GatewayAPITrafficRouting{} - err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], &gatewayAPIConfig) - if err != nil { + gatewayAPIConfig := &GatewayAPITrafficRouting{} + if err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], gatewayAPIConfig); err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), } } + if gatewayAPIConfig.HTTPRoute != "" { - return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &gatewayAPIConfig) + gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, v1beta1.LocalObjectReference{ + Kind: HTTPRouteKind, + Name: v1beta1.ObjectName(gatewayAPIConfig.HTTPRoute), + }) } + if gatewayAPIConfig.TCPRoute != "" { - return r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, &gatewayAPIConfig) + gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, v1beta1.LocalObjectReference{ + Kind: TCPRouteKind, + Name: v1beta1.ObjectName(gatewayAPIConfig.TCPRoute), + }) + } + + if len(gatewayAPIConfig.Routes) == 0 { + return pluginTypes.RpcError{ + ErrorString: GatewayAPIManifestError, + } } - return pluginTypes.RpcError{ - ErrorString: GatewayAPIManifestError, + + var err pluginTypes.RpcError + for _, ref := range gatewayAPIConfig.Routes { + if ref.Kind == "" { + // Assume HTTPRoute by default + ref.Kind = HTTPRouteKind + } + + switch ref.Kind { + case HTTPRouteKind: + err = r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig, string(ref.Name)) + case TCPRouteKind: + err = r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig, string(ref.Name)) + default: + r.LogCtx.Warnf("unsupported kind %q for route %q, supported values: %q, %q", ref.Kind, ref.Name, HTTPRouteKind, TCPRouteKind) + } + if err.HasError() { + return pluginTypes.RpcError{ + ErrorString: fmt.Sprintf("set weight for %s %q: %s", ref.Kind, ref.Name, err), + } + } } + + return err } func (r *RpcPlugin) SetHeaderRoute(rollout *v1alpha1.Rollout, headerRouting *v1alpha1.SetHeaderRoute) pluginTypes.RpcError { diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 9d5baf6..6c258a8 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -14,6 +14,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" log "github.com/sirupsen/logrus" + "sigs.k8s.io/gateway-api/apis/v1beta1" gwFake "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/fake" goPlugin "github.com/hashicorp/go-plugin" @@ -104,7 +105,10 @@ func TestRunSuccessfully(t *testing.T) { } t.Run("SetHTTPRouteWeight", func(t *testing.T) { var desiredWeight int32 = 30 - err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, mocks.HTTPRoute, mocks.HTTPRouteName), desiredWeight, []v1alpha1.WeightDestination{}) + err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ + Namespace: mocks.Namespace, + HTTPRoute: mocks.HTTPRouteName, + }), desiredWeight, []v1alpha1.WeightDestination{}) assert.Empty(t, err.Error()) assert.Equal(t, 100-desiredWeight, *(rpcPluginImp.UpdatedHTTPRouteMock.Spec.Rules[0].BackendRefs[0].Weight)) @@ -112,9 +116,36 @@ func TestRunSuccessfully(t *testing.T) { }) t.Run("SetTCPRouteWeight", func(t *testing.T) { var desiredWeight int32 = 30 - err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, mocks.TCPRoute, mocks.TCPRouteName), desiredWeight, []v1alpha1.WeightDestination{}) + err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, + &GatewayAPITrafficRouting{ + Namespace: mocks.Namespace, + TCPRoute: mocks.TCPRouteName, + }), desiredWeight, []v1alpha1.WeightDestination{}) + + assert.Empty(t, err.Error()) + assert.Equal(t, 100-desiredWeight, *(rpcPluginImp.UpdatedTCPRouteMock.Spec.Rules[0].BackendRefs[0].Weight)) + assert.Equal(t, desiredWeight, *(rpcPluginImp.UpdatedTCPRouteMock.Spec.Rules[0].BackendRefs[1].Weight)) + }) + t.Run("SetWeightViaRoutes", func(t *testing.T) { + var desiredWeight int32 = 30 + err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, + &GatewayAPITrafficRouting{ + Namespace: mocks.Namespace, + Routes: []v1beta1.LocalObjectReference{ + { + Kind: HTTPRouteKind, + Name: mocks.HTTPRouteName, + }, + { + Kind: TCPRouteKind, + Name: mocks.TCPRouteName, + }, + }, + }), desiredWeight, []v1alpha1.WeightDestination{}) assert.Empty(t, err.Error()) + assert.Equal(t, 100-desiredWeight, *(rpcPluginImp.UpdatedHTTPRouteMock.Spec.Rules[0].BackendRefs[0].Weight)) + assert.Equal(t, desiredWeight, *(rpcPluginImp.UpdatedHTTPRouteMock.Spec.Rules[0].BackendRefs[1].Weight)) assert.Equal(t, 100-desiredWeight, *(rpcPluginImp.UpdatedTCPRouteMock.Spec.Rules[0].BackendRefs[0].Weight)) assert.Equal(t, desiredWeight, *(rpcPluginImp.UpdatedTCPRouteMock.Spec.Rules[0].BackendRefs[1].Weight)) }) @@ -124,17 +155,8 @@ func TestRunSuccessfully(t *testing.T) { <-closeCh } -func newRollout(stableSvc, canarySvc, routeType, routeName string) *v1alpha1.Rollout { - gatewayAPIConfig := GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, - } - switch routeType { - case mocks.HTTPRoute: - gatewayAPIConfig.HTTPRoute = routeName - case mocks.TCPRoute: - gatewayAPIConfig.TCPRoute = routeName - } - encodedGatewayAPIConfig, err := json.Marshal(gatewayAPIConfig) +func newRollout(stableSvc, canarySvc string, config *GatewayAPITrafficRouting) *v1alpha1.Rollout { + encodedConfig, err := json.Marshal(config) if err != nil { log.Fatal(err) } @@ -150,7 +172,7 @@ func newRollout(stableSvc, canarySvc, routeType, routeName string) *v1alpha1.Rol CanaryService: canarySvc, TrafficRouting: &v1alpha1.RolloutTrafficRouting{ Plugins: map[string]json.RawMessage{ - PluginName: encodedGatewayAPIConfig, + PluginName: encodedConfig, }, }, }, diff --git a/pkg/plugin/tcproute.go b/pkg/plugin/tcproute.go index c9d6790..2279dcb 100644 --- a/pkg/plugin/tcproute.go +++ b/pkg/plugin/tcproute.go @@ -10,14 +10,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting) pluginTypes.RpcError { +func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting, routeName string) pluginTypes.RpcError { ctx := context.TODO() tcpRouteClient := r.TCPRouteClient if !r.IsTest { gatewayV1alpha2 := r.Client.GatewayV1alpha2() tcpRouteClient = gatewayV1alpha2.TCPRoutes(gatewayAPIConfig.Namespace) } - tcpRoute, err := tcpRouteClient.Get(ctx, gatewayAPIConfig.TCPRoute, metav1.GetOptions{}) + tcpRoute, err := tcpRouteClient.Get(ctx, routeName, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index bdb7561..e7f39c5 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -20,6 +20,9 @@ type RpcPlugin struct { } type GatewayAPITrafficRouting struct { + // Routes refers to HTTPRoute and TCPRoute resources used to route traffic + // to the service + Routes []v1beta1.LocalObjectReference `json:"routes,omitempty"` // HTTPRoute refers to the name of the HTTPRoute used to route traffic to the // service HTTPRoute string `json:"httpRoute,omitempty"` From 3d7db80b3e31c359621ac16e32c850f3c2c4a653 Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Tue, 6 Feb 2024 15:24:39 +0100 Subject: [PATCH 02/12] Move route ref into its own struct Signed-off-by: Stepan Rakitin --- pkg/plugin/httproute.go | 4 ++-- pkg/plugin/plugin.go | 31 +++++++++++++++++-------------- pkg/plugin/plugin_test.go | 3 +-- pkg/plugin/tcproute.go | 4 ++-- pkg/plugin/types.go | 14 +++++++++++++- 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/pkg/plugin/httproute.go b/pkg/plugin/httproute.go index a0a5c6c..67e54e0 100644 --- a/pkg/plugin/httproute.go +++ b/pkg/plugin/httproute.go @@ -10,14 +10,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting, routeName string) pluginTypes.RpcError { +func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig GatewayAPITrafficRouting) pluginTypes.RpcError { ctx := context.TODO() httpRouteClient := r.HTTPRouteClient if !r.IsTest { gatewayV1beta1 := r.Client.GatewayV1beta1() httpRouteClient = gatewayV1beta1.HTTPRoutes(gatewayAPIConfig.Namespace) } - httpRoute, err := httpRouteClient.Get(ctx, routeName, metav1.GetOptions{}) + httpRoute, err := httpRouteClient.Get(ctx, gatewayAPIConfig.HTTPRoute, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 6d52ee5..6323a5c 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -7,7 +7,6 @@ import ( "github.com/argoproj-labs/rollouts-plugin-trafficrouter-gatewayapi/utils" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" pluginTypes "github.com/argoproj/argo-rollouts/utils/plugin/types" - "sigs.k8s.io/gateway-api/apis/v1beta1" gatewayApiClientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned" ) @@ -18,9 +17,6 @@ const ( GatewayAPIUpdateError = "GatewayAPIUpdateError" GatewayAPIManifestError = "No routes configured. One of 'routes', 'tcpRoute' or 'httpRoute' should be set" - - HTTPRouteKind = "HTTPRoute" - TCPRouteKind = "TCPRoute" ) func (r *RpcPlugin) InitPlugin() pluginTypes.RpcError { @@ -49,23 +45,24 @@ func (r *RpcPlugin) UpdateHash(rollout *v1alpha1.Rollout, canaryHash, stableHash func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination) pluginTypes.RpcError { gatewayAPIConfig := &GatewayAPITrafficRouting{} - if err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], gatewayAPIConfig); err != nil { + err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], gatewayAPIConfig) + if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), } } if gatewayAPIConfig.HTTPRoute != "" { - gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, v1beta1.LocalObjectReference{ + gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, GatewayAPIRouteReference{ Kind: HTTPRouteKind, - Name: v1beta1.ObjectName(gatewayAPIConfig.HTTPRoute), + Name: gatewayAPIConfig.HTTPRoute, }) } if gatewayAPIConfig.TCPRoute != "" { - gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, v1beta1.LocalObjectReference{ + gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, GatewayAPIRouteReference{ Kind: TCPRouteKind, - Name: v1beta1.ObjectName(gatewayAPIConfig.TCPRoute), + Name: gatewayAPIConfig.TCPRoute, }) } @@ -75,7 +72,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad } } - var err pluginTypes.RpcError + var rpcErr pluginTypes.RpcError for _, ref := range gatewayAPIConfig.Routes { if ref.Kind == "" { // Assume HTTPRoute by default @@ -84,20 +81,26 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad switch ref.Kind { case HTTPRouteKind: - err = r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig, string(ref.Name)) + rpcErr = r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + Namespace: gatewayAPIConfig.Namespace, + HTTPRoute: ref.Name, + }) case TCPRouteKind: - err = r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig, string(ref.Name)) + rpcErr = r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + Namespace: gatewayAPIConfig.Namespace, + TCPRoute: ref.Name, + }) default: r.LogCtx.Warnf("unsupported kind %q for route %q, supported values: %q, %q", ref.Kind, ref.Name, HTTPRouteKind, TCPRouteKind) } - if err.HasError() { + if rpcErr.HasError() { return pluginTypes.RpcError{ ErrorString: fmt.Sprintf("set weight for %s %q: %s", ref.Kind, ref.Name, err), } } } - return err + return rpcErr } func (r *RpcPlugin) SetHeaderRoute(rollout *v1alpha1.Rollout, headerRouting *v1alpha1.SetHeaderRoute) pluginTypes.RpcError { diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 6c258a8..98fd93c 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -14,7 +14,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" log "github.com/sirupsen/logrus" - "sigs.k8s.io/gateway-api/apis/v1beta1" gwFake "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/fake" goPlugin "github.com/hashicorp/go-plugin" @@ -131,7 +130,7 @@ func TestRunSuccessfully(t *testing.T) { err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ Namespace: mocks.Namespace, - Routes: []v1beta1.LocalObjectReference{ + Routes: []GatewayAPIRouteReference{ { Kind: HTTPRouteKind, Name: mocks.HTTPRouteName, diff --git a/pkg/plugin/tcproute.go b/pkg/plugin/tcproute.go index 2279dcb..a9c0b0e 100644 --- a/pkg/plugin/tcproute.go +++ b/pkg/plugin/tcproute.go @@ -10,14 +10,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting, routeName string) pluginTypes.RpcError { +func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig GatewayAPITrafficRouting) pluginTypes.RpcError { ctx := context.TODO() tcpRouteClient := r.TCPRouteClient if !r.IsTest { gatewayV1alpha2 := r.Client.GatewayV1alpha2() tcpRouteClient = gatewayV1alpha2.TCPRoutes(gatewayAPIConfig.Namespace) } - tcpRoute, err := tcpRouteClient.Get(ctx, routeName, metav1.GetOptions{}) + tcpRoute, err := tcpRouteClient.Get(ctx, gatewayAPIConfig.TCPRoute, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index e7f39c5..e3fa3ac 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -9,6 +9,11 @@ import ( gatewayApiv1beta1 "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/typed/apis/v1beta1" ) +const ( + HTTPRouteKind = "HTTPRoute" + TCPRouteKind = "TCPRoute" +) + type RpcPlugin struct { IsTest bool LogCtx *logrus.Entry @@ -19,10 +24,17 @@ type RpcPlugin struct { TCPRouteClient gatewayApiv1alpha2.TCPRouteInterface } +type GatewayAPIRouteReference struct { + // Kind is kind of the route resource. For example "HTTPRoute" or "TCPRoute". + Kind string + // Name is the name of the route resource. + Name string +} + type GatewayAPITrafficRouting struct { // Routes refers to HTTPRoute and TCPRoute resources used to route traffic // to the service - Routes []v1beta1.LocalObjectReference `json:"routes,omitempty"` + Routes []GatewayAPIRouteReference `json:"routes,omitempty"` // HTTPRoute refers to the name of the HTTPRoute used to route traffic to the // service HTTPRoute string `json:"httpRoute,omitempty"` From 851fca2fe863910e6a569f5d4dfaeca188d127d1 Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Tue, 6 Feb 2024 16:27:30 +0100 Subject: [PATCH 03/12] Use dedicated fields for each route kind Signed-off-by: Stepan Rakitin --- pkg/plugin/plugin.go | 58 ++++++++++++++++----------------------- pkg/plugin/plugin_test.go | 14 ++-------- pkg/plugin/types.go | 21 ++++---------- 3 files changed, 32 insertions(+), 61 deletions(-) diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 6323a5c..8a1e5ea 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -44,8 +44,8 @@ func (r *RpcPlugin) UpdateHash(rollout *v1alpha1.Rollout, canaryHash, stableHash } func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination) pluginTypes.RpcError { - gatewayAPIConfig := &GatewayAPITrafficRouting{} - err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], gatewayAPIConfig) + gatewayAPIConfig := GatewayAPITrafficRouting{} + err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], &gatewayAPIConfig) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), @@ -53,54 +53,42 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad } if gatewayAPIConfig.HTTPRoute != "" { - gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, GatewayAPIRouteReference{ - Kind: HTTPRouteKind, - Name: gatewayAPIConfig.HTTPRoute, - }) + gatewayAPIConfig.HTTPRoutes = append(gatewayAPIConfig.HTTPRoutes, gatewayAPIConfig.HTTPRoute) } if gatewayAPIConfig.TCPRoute != "" { - gatewayAPIConfig.Routes = append(gatewayAPIConfig.Routes, GatewayAPIRouteReference{ - Kind: TCPRouteKind, - Name: gatewayAPIConfig.TCPRoute, - }) + gatewayAPIConfig.TCPRoutes = append(gatewayAPIConfig.TCPRoutes, gatewayAPIConfig.TCPRoute) } - if len(gatewayAPIConfig.Routes) == 0 { + if len(gatewayAPIConfig.HTTPRoutes) == 0 && len(gatewayAPIConfig.TCPRoutes) == 0 { return pluginTypes.RpcError{ ErrorString: GatewayAPIManifestError, } } - var rpcErr pluginTypes.RpcError - for _, ref := range gatewayAPIConfig.Routes { - if ref.Kind == "" { - // Assume HTTPRoute by default - ref.Kind = HTTPRouteKind - } - - switch ref.Kind { - case HTTPRouteKind: - rpcErr = r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ - Namespace: gatewayAPIConfig.Namespace, - HTTPRoute: ref.Name, - }) - case TCPRouteKind: - rpcErr = r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ - Namespace: gatewayAPIConfig.Namespace, - TCPRoute: ref.Name, - }) - default: - r.LogCtx.Warnf("unsupported kind %q for route %q, supported values: %q, %q", ref.Kind, ref.Name, HTTPRouteKind, TCPRouteKind) + for _, name := range gatewayAPIConfig.HTTPRoutes { + err := r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + Namespace: gatewayAPIConfig.Namespace, + HTTPRoute: name, + }) + if err.HasError() { + return pluginTypes.RpcError{ + ErrorString: fmt.Sprintf("set weight for HTTPRoute %q: %s", name, err), + } } - if rpcErr.HasError() { + } + for _, name := range gatewayAPIConfig.TCPRoutes { + err := r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + Namespace: gatewayAPIConfig.Namespace, + TCPRoute: name, + }) + if err.HasError() { return pluginTypes.RpcError{ - ErrorString: fmt.Sprintf("set weight for %s %q: %s", ref.Kind, ref.Name, err), + ErrorString: fmt.Sprintf("set weight for TCPRoute %q: %s", name, err), } } } - - return rpcErr + return pluginTypes.RpcError{} } func (r *RpcPlugin) SetHeaderRoute(rollout *v1alpha1.Rollout, headerRouting *v1alpha1.SetHeaderRoute) pluginTypes.RpcError { diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 98fd93c..27db91c 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -129,17 +129,9 @@ func TestRunSuccessfully(t *testing.T) { var desiredWeight int32 = 30 err := pluginInstance.SetWeight(newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, - Routes: []GatewayAPIRouteReference{ - { - Kind: HTTPRouteKind, - Name: mocks.HTTPRouteName, - }, - { - Kind: TCPRouteKind, - Name: mocks.TCPRouteName, - }, - }, + Namespace: mocks.Namespace, + HTTPRoutes: []string{mocks.HTTPRouteName}, + TCPRoutes: []string{mocks.TCPRouteName}, }), desiredWeight, []v1alpha1.WeightDestination{}) assert.Empty(t, err.Error()) diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index e3fa3ac..411b869 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -9,11 +9,6 @@ import ( gatewayApiv1beta1 "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/typed/apis/v1beta1" ) -const ( - HTTPRouteKind = "HTTPRoute" - TCPRouteKind = "TCPRoute" -) - type RpcPlugin struct { IsTest bool LogCtx *logrus.Entry @@ -24,17 +19,13 @@ type RpcPlugin struct { TCPRouteClient gatewayApiv1alpha2.TCPRouteInterface } -type GatewayAPIRouteReference struct { - // Kind is kind of the route resource. For example "HTTPRoute" or "TCPRoute". - Kind string - // Name is the name of the route resource. - Name string -} - type GatewayAPITrafficRouting struct { - // Routes refers to HTTPRoute and TCPRoute resources used to route traffic - // to the service - Routes []GatewayAPIRouteReference `json:"routes,omitempty"` + // HTTPRoutes refer to names of HTTPRoute resources used to route traffic to the + // service + HTTPRoutes []string `json:"httpRoutes,omitempty"` + // TCPRoutes refer to names of TCPRoute resources used to route traffic to the + // service + TCPRoutes []string `json:"tcpRoutes,omitempty"` // HTTPRoute refers to the name of the HTTPRoute used to route traffic to the // service HTTPRoute string `json:"httpRoute,omitempty"` From 1c01231e2494a677757287c84a966ddf0a76bc03 Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Tue, 6 Feb 2024 16:28:15 +0100 Subject: [PATCH 04/12] Update error message Signed-off-by: Stepan Rakitin --- pkg/plugin/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 8a1e5ea..1d48fec 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -16,7 +16,7 @@ const ( PluginName = "argoproj-labs/gatewayAPI" GatewayAPIUpdateError = "GatewayAPIUpdateError" - GatewayAPIManifestError = "No routes configured. One of 'routes', 'tcpRoute' or 'httpRoute' should be set" + GatewayAPIManifestError = "No routes configured. One of 'tcpRoutes', 'httpRoutes', 'tcpRoute' or 'httpRoute' should be set" ) func (r *RpcPlugin) InitPlugin() pluginTypes.RpcError { From 683d697ecbf42ad9f5be42ed83ff849fd9175405 Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Tue, 6 Feb 2024 16:38:59 +0100 Subject: [PATCH 05/12] Remove changes to setter signatures Signed-off-by: Stepan Rakitin --- pkg/plugin/httproute.go | 2 +- pkg/plugin/plugin.go | 4 ++-- pkg/plugin/tcproute.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/plugin/httproute.go b/pkg/plugin/httproute.go index 67e54e0..61e6780 100644 --- a/pkg/plugin/httproute.go +++ b/pkg/plugin/httproute.go @@ -10,7 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig GatewayAPITrafficRouting) pluginTypes.RpcError { +func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting) pluginTypes.RpcError { ctx := context.TODO() httpRouteClient := r.HTTPRouteClient if !r.IsTest { diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 1d48fec..f97c9b8 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -67,7 +67,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad } for _, name := range gatewayAPIConfig.HTTPRoutes { - err := r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + err := r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ Namespace: gatewayAPIConfig.Namespace, HTTPRoute: name, }) @@ -78,7 +78,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad } } for _, name := range gatewayAPIConfig.TCPRoutes { - err := r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, GatewayAPITrafficRouting{ + err := r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ Namespace: gatewayAPIConfig.Namespace, TCPRoute: name, }) diff --git a/pkg/plugin/tcproute.go b/pkg/plugin/tcproute.go index a9c0b0e..c9d6790 100644 --- a/pkg/plugin/tcproute.go +++ b/pkg/plugin/tcproute.go @@ -10,7 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig GatewayAPITrafficRouting) pluginTypes.RpcError { +func (r *RpcPlugin) setTCPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting) pluginTypes.RpcError { ctx := context.TODO() tcpRouteClient := r.TCPRouteClient if !r.IsTest { From 0cada4cf5b1df726467a770e5b6b85b24763446d Mon Sep 17 00:00:00 2001 From: Stepan Rakitin Date: Tue, 6 Feb 2024 17:00:27 +0100 Subject: [PATCH 06/12] Move for loop into function Signed-off-by: Stepan Rakitin --- pkg/plugin/plugin.go | 45 +++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index f97c9b8..34296e2 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -55,38 +55,30 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad if gatewayAPIConfig.HTTPRoute != "" { gatewayAPIConfig.HTTPRoutes = append(gatewayAPIConfig.HTTPRoutes, gatewayAPIConfig.HTTPRoute) } - if gatewayAPIConfig.TCPRoute != "" { gatewayAPIConfig.TCPRoutes = append(gatewayAPIConfig.TCPRoutes, gatewayAPIConfig.TCPRoute) } - - if len(gatewayAPIConfig.HTTPRoutes) == 0 && len(gatewayAPIConfig.TCPRoutes) == 0 { + if configHasNoRoutesConfigured(&gatewayAPIConfig) { return pluginTypes.RpcError{ ErrorString: GatewayAPIManifestError, } } - for _, name := range gatewayAPIConfig.HTTPRoutes { - err := r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ + if err := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(routeName string) pluginTypes.RpcError { + return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ Namespace: gatewayAPIConfig.Namespace, - HTTPRoute: name, + HTTPRoute: routeName, }) - if err.HasError() { - return pluginTypes.RpcError{ - ErrorString: fmt.Sprintf("set weight for HTTPRoute %q: %s", name, err), - } - } + }); err.HasError() { + return err } - for _, name := range gatewayAPIConfig.TCPRoutes { - err := r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ + if err := forEachGatewayAPIRoute(gatewayAPIConfig.TCPRoutes, func(routeName string) pluginTypes.RpcError { + return r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ Namespace: gatewayAPIConfig.Namespace, - TCPRoute: name, + TCPRoute: routeName, }) - if err.HasError() { - return pluginTypes.RpcError{ - ErrorString: fmt.Sprintf("set weight for TCPRoute %q: %s", name, err), - } - } + }); err.HasError() { + return err } return pluginTypes.RpcError{} } @@ -138,3 +130,18 @@ func getBackendRef[T GatewayAPIBackendRef](backendRefName string, backendRefList } return selectedService, nil } + +func configHasNoRoutesConfigured(config *GatewayAPITrafficRouting) bool { + return len(config.HTTPRoutes) == 0 && len(config.TCPRoutes) == 0 +} + +func forEachGatewayAPIRoute(names []string, fn func(routeName string) pluginTypes.RpcError) pluginTypes.RpcError { + for _, name := range names { + if err := fn(name); err.HasError() { + return pluginTypes.RpcError{ + ErrorString: fmt.Sprintf("set weight for route %q: %s", name, err), + } + } + } + return pluginTypes.RpcError{} +} From 6d1393f9bd4333a57ab2542614cd238e796fc3e1 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Sun, 18 Feb 2024 01:25:11 +0500 Subject: [PATCH 07/12] refactor: linting Signed-off-by: Philipp Plotnikov --- pkg/plugin/plugin.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 0bdddf6..aa703f1 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -13,8 +13,6 @@ import ( gatewayApiClientset "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned" ) -// TODO: think about reference of GatewayAPI or simply structure - const ( Type = "GatewayAPI" PluginName = "argoproj-labs/gatewayAPI" @@ -63,7 +61,6 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad ErrorString: GatewayAPIManifestError, } } - // TODO: Add at the begining how many routes we accepted rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ Namespace: gatewayAPIConfig.Namespace, From 04360ba8aa7e14f4ad34175da180296564992b6a Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Wed, 21 Feb 2024 08:59:13 +0500 Subject: [PATCH 08/12] feat: add support multiroutes for setHeaderRoute function Signed-off-by: Philipp Plotnikov --- pkg/mocks/plugin.go | 8 ++--- pkg/plugin/httproute.go | 30 ++++++++--------- pkg/plugin/plugin.go | 68 ++++++++++++++++++++++----------------- pkg/plugin/plugin_test.go | 18 +++++------ pkg/plugin/types.go | 10 +++--- 5 files changed, 71 insertions(+), 63 deletions(-) diff --git a/pkg/mocks/plugin.go b/pkg/mocks/plugin.go index 061a055..fc71595 100644 --- a/pkg/mocks/plugin.go +++ b/pkg/mocks/plugin.go @@ -16,7 +16,7 @@ const ( CanaryServiceName = "argo-rollouts-canary-service" HTTPRouteName = "argo-rollouts-http-route" TCPRouteName = "argo-rollouts-tcp-route" - Namespace = "default" + RolloutNamespace = "default" ConfigMapName = "test-config" HTTPManagedRouteName = "test-http-header-route" ) @@ -35,7 +35,7 @@ var ( var HTTPRouteObj = v1beta1.HTTPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: HTTPRouteName, - Namespace: Namespace, + Namespace: RolloutNamespace, }, Spec: v1beta1.HTTPRouteSpec{ CommonRouteSpec: v1beta1.CommonRouteSpec{ @@ -80,7 +80,7 @@ var HTTPRouteObj = v1beta1.HTTPRoute{ var TCPPRouteObj = v1alpha2.TCPRoute{ ObjectMeta: metav1.ObjectMeta{ Name: TCPRouteName, - Namespace: Namespace, + Namespace: RolloutNamespace, }, Spec: v1alpha2.TCPRouteSpec{ CommonRouteSpec: v1alpha2.CommonRouteSpec{ @@ -116,6 +116,6 @@ var TCPPRouteObj = v1alpha2.TCPRoute{ var ConfigMapObj = v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: ConfigMapName, - Namespace: Namespace, + Namespace: RolloutNamespace, }, } diff --git a/pkg/plugin/httproute.go b/pkg/plugin/httproute.go index aa8fb65..aec9717 100644 --- a/pkg/plugin/httproute.go +++ b/pkg/plugin/httproute.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "sync" "github.com/argoproj-labs/rollouts-plugin-trafficrouter-gatewayapi/internal/utils" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" @@ -17,13 +16,6 @@ const ( HTTPConfigMapKey = "httpManagedRoutes" ) -var ( - httpHeaderRoute = HTTPHeaderRoute{ - mutex: sync.Mutex{}, - managedRouteMap: make(map[string]int), - } -) - func (r *RpcPlugin) setHTTPRouteWeight(rollout *v1alpha1.Rollout, desiredWeight int32, additionalDestinations []v1alpha1.WeightDestination, gatewayAPIConfig *GatewayAPITrafficRouting) pluginTypes.RpcError { ctx := context.TODO() httpRouteClient := r.HTTPRouteClient @@ -77,7 +69,8 @@ func (r *RpcPlugin) setHTTPHeaderRoute(rollout *v1alpha1.Rollout, headerRouting } ctx := context.TODO() httpRouteClient := r.HTTPRouteClient - managedRouteMap := httpHeaderRoute.managedRouteMap + managedRouteMap := make(ManagedRouteMap) + httpRouteName := gatewayAPIConfig.HTTPRoute clientset := r.TestClientset if !r.IsTest { gatewayV1beta1 := r.GatewayAPIClientset.GatewayV1beta1() @@ -99,7 +92,7 @@ func (r *RpcPlugin) setHTTPHeaderRoute(rollout *v1alpha1.Rollout, headerRouting ErrorString: err.Error(), } } - httpRoute, err := httpRouteClient.Get(ctx, gatewayAPIConfig.HTTPRoute, metav1.GetOptions{}) + httpRoute, err := httpRouteClient.Get(ctx, httpRouteName, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), @@ -126,6 +119,7 @@ func (r *RpcPlugin) setHTTPHeaderRoute(rollout *v1alpha1.Rollout, headerRouting backendRef := httpRouteRule.BackendRefs[i] if canaryServiceName == backendRef.Name { canaryBackendRef = (*HTTPBackendRef)(&backendRef) + break } } httpHeaderRouteRule := v1beta1.HTTPRouteRule{ @@ -154,7 +148,7 @@ func (r *RpcPlugin) setHTTPHeaderRoute(rollout *v1alpha1.Rollout, headerRouting httpRouteRuleList = append(httpRouteRuleList, httpHeaderRouteRule) oldHTTPRuleList := httpRoute.Spec.Rules httpRoute.Spec.Rules = httpRouteRuleList - oldConfigMapData := make(map[string]int) + oldConfigMapData := make(ManagedRouteMap) err = utils.GetConfigMapData(configMap, HTTPConfigMapKey, &oldConfigMapData) if err != nil { return pluginTypes.RpcError{ @@ -187,7 +181,10 @@ func (r *RpcPlugin) setHTTPHeaderRoute(rollout *v1alpha1.Rollout, headerRouting }, { Action: func() error { - managedRouteMap[headerRouting.Name] = len(httpRouteRuleList) - 1 + if managedRouteMap[headerRouting.Name] == nil { + managedRouteMap[headerRouting.Name] = make(map[string]int) + } + managedRouteMap[headerRouting.Name][httpRouteName] = len(httpRouteRuleList) - 1 err = utils.UpdateConfigMapData(configMap, managedRouteMap, utils.UpdateConfigMapOptions{ Clientset: clientset, ConfigMapKey: HTTPConfigMapKey, @@ -253,7 +250,8 @@ func (r *RpcPlugin) removeHTTPManagedRoutes(managedRouteNameList []v1alpha1.Mang ctx := context.TODO() httpRouteClient := r.HTTPRouteClient clientset := r.TestClientset - managedRouteMap := httpHeaderRoute.managedRouteMap + httpRouteName := gatewayAPIConfig.HTTPRoute + managedRouteMap := make(ManagedRouteMap) if !r.IsTest { gatewayV1beta1 := r.GatewayAPIClientset.GatewayV1beta1() httpRouteClient = gatewayV1beta1.HTTPRoutes(gatewayAPIConfig.Namespace) @@ -274,7 +272,7 @@ func (r *RpcPlugin) removeHTTPManagedRoutes(managedRouteNameList []v1alpha1.Mang ErrorString: err.Error(), } } - httpRoute, err := httpRouteClient.Get(ctx, gatewayAPIConfig.HTTPRoute, metav1.GetOptions{}) + httpRoute, err := httpRouteClient.Get(ctx, httpRouteName, metav1.GetOptions{}) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), @@ -290,7 +288,7 @@ func (r *RpcPlugin) removeHTTPManagedRoutes(managedRouteNameList []v1alpha1.Mang continue } isHTTPRouteRuleListChanged = true - httpRouteRuleList, err = removeManagedRouteEntry(managedRouteMap, httpRouteRuleList, managedRouteName) + httpRouteRuleList, err = removeManagedRouteEntry(managedRouteMap, httpRouteRuleList, managedRouteName, httpRouteName) if err != nil { return pluginTypes.RpcError{ ErrorString: err.Error(), @@ -302,7 +300,7 @@ func (r *RpcPlugin) removeHTTPManagedRoutes(managedRouteNameList []v1alpha1.Mang } oldHTTPRuleList := httpRoute.Spec.Rules httpRoute.Spec.Rules = httpRouteRuleList - oldConfigMapData := make(map[string]int) + oldConfigMapData := make(ManagedRouteMap) err = utils.GetConfigMapData(configMap, HTTPConfigMapKey, &oldConfigMapData) if err != nil { return pluginTypes.RpcError{ diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index aa703f1..ddd7654 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -62,19 +62,15 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad } } rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { - return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ - Namespace: gatewayAPIConfig.Namespace, - HTTPRoute: route.Name, - }) + gatewayAPIConfig.HTTPRoute = route.Name + return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig) }) if rpcError.HasError() { return rpcError } rpcError = forEachGatewayAPIRoute(gatewayAPIConfig.TCPRoutes, func(route TCPRoute) pluginTypes.RpcError { - return r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, &GatewayAPITrafficRouting{ - Namespace: gatewayAPIConfig.Namespace, - TCPRoute: route.Name, - }) + gatewayAPIConfig.TCPRoute = route.Name + return r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig) }) return rpcError } @@ -87,16 +83,19 @@ func (r *RpcPlugin) SetHeaderRoute(rollout *v1alpha1.Rollout, headerRouting *v1a } } if gatewayAPIConfig.HTTPRoutes != nil { - httpHeaderRoute.mutex.Lock() + gatewayAPIConfig.ConfigMapRWMutex.Lock() rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { + if !route.UseHeaderRoutes { + return pluginTypes.RpcError{} + } gatewayAPIConfig.HTTPRoute = route.Name - return r.setHTTPHeaderRoute(rollout, headerRouting, &gatewayAPIConfig) + return r.setHTTPHeaderRoute(rollout, headerRouting, gatewayAPIConfig) }) if rpcError.HasError() { - httpHeaderRoute.mutex.Unlock() + gatewayAPIConfig.ConfigMapRWMutex.Unlock() return rpcError } - httpHeaderRoute.mutex.Unlock() + gatewayAPIConfig.ConfigMapRWMutex.Unlock() } return pluginTypes.RpcError{} } @@ -117,16 +116,19 @@ func (r *RpcPlugin) RemoveManagedRoutes(rollout *v1alpha1.Rollout) pluginTypes.R } } if gatewayAPIConfig.HTTPRoutes != nil { - httpHeaderRoute.mutex.Lock() + gatewayAPIConfig.ConfigMapRWMutex.Lock() rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { + if !route.UseHeaderRoutes { + return pluginTypes.RpcError{} + } gatewayAPIConfig.HTTPRoute = route.Name - return r.removeHTTPManagedRoutes(rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, &gatewayAPIConfig) + return r.removeHTTPManagedRoutes(rollout.Spec.Strategy.Canary.TrafficRouting.ManagedRoutes, gatewayAPIConfig) }) if rpcError.HasError() { - httpHeaderRoute.mutex.Unlock() + gatewayAPIConfig.ConfigMapRWMutex.Unlock() return rpcError } - httpHeaderRoute.mutex.Unlock() + gatewayAPIConfig.ConfigMapRWMutex.Unlock() } return pluginTypes.RpcError{} } @@ -135,24 +137,24 @@ func (r *RpcPlugin) Type() string { return Type } -func getGatewayAPITracfficRoutingConfig(rollout *v1alpha1.Rollout) (GatewayAPITrafficRouting, error) { +func getGatewayAPITracfficRoutingConfig(rollout *v1alpha1.Rollout) (*GatewayAPITrafficRouting, error) { validate := validator.New(validator.WithRequiredStructEnabled()) gatewayAPIConfig := GatewayAPITrafficRouting{ ConfigMap: defaults.ConfigMap, } err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], &gatewayAPIConfig) if err != nil { - return gatewayAPIConfig, err + return &gatewayAPIConfig, err } - gatewayAPIConfig = insertGatewayAPIRouteLists(gatewayAPIConfig) + insertGatewayAPIRouteLists(&gatewayAPIConfig) err = validate.Struct(&gatewayAPIConfig) if err != nil { - return gatewayAPIConfig, err + return &gatewayAPIConfig, err } - return gatewayAPIConfig, err + return &gatewayAPIConfig, err } -func insertGatewayAPIRouteLists(gatewayAPIConfig GatewayAPITrafficRouting) GatewayAPITrafficRouting { +func insertGatewayAPIRouteLists(gatewayAPIConfig *GatewayAPITrafficRouting) { if gatewayAPIConfig.HTTPRoute != "" { gatewayAPIConfig.HTTPRoutes = append(gatewayAPIConfig.HTTPRoutes, HTTPRoute{ Name: gatewayAPIConfig.HTTPRoute, @@ -165,7 +167,6 @@ func insertGatewayAPIRouteLists(gatewayAPIConfig GatewayAPITrafficRouting) Gatew UseHeaderRoutes: true, }) } - return gatewayAPIConfig } func getRouteRule[T1 GatewayAPIBackendRef, T2 GatewayAPIRouteRule[T1], T3 GatewayAPIRouteRuleList[T1, T2]](routeRuleList T3, backendRefNameList ...string) (T2, error) { @@ -211,22 +212,31 @@ func getBackendRef[T1 GatewayAPIBackendRef, T2 GatewayAPIRouteRule[T1], T3 Gatew return nil, routeRuleList.Error() } -func removeManagedRouteEntry(managedRouteMap map[string]int, routeRuleList HTTPRouteRuleList, managedRouteName string) (HTTPRouteRuleList, error) { - managedRouteIndex, isOk := managedRouteMap[managedRouteName] +func removeManagedRouteEntry(managedRouteMap ManagedRouteMap, routeRuleList HTTPRouteRuleList, managedRouteName string, httpRouteName string) (HTTPRouteRuleList, error) { + routeManagedRouteMap, isOk := managedRouteMap[managedRouteName] if !isOk { return nil, fmt.Errorf(ManagedRouteMapEntryDeleteError, managedRouteName, managedRouteName) } - delete(managedRouteMap, managedRouteName) - for key, value := range managedRouteMap { + managedRouteIndex, isOk := routeManagedRouteMap[httpRouteName] + if !isOk { + managedRouteMapKey := managedRouteName + "." + httpRouteName + return nil, fmt.Errorf(ManagedRouteMapEntryDeleteError, managedRouteMapKey, managedRouteMapKey) + } + delete(routeManagedRouteMap, httpRouteName) + if len(managedRouteMap[managedRouteName]) == 0 { + delete(managedRouteMap, managedRouteName) + } + for _, currentRouteManagedRouteMap := range managedRouteMap { + value := currentRouteManagedRouteMap[httpRouteName] if value > managedRouteIndex { - managedRouteMap[key]-- + currentRouteManagedRouteMap[httpRouteName]-- } } routeRuleList = utils.RemoveIndex(routeRuleList, managedRouteIndex) return routeRuleList, nil } -func isConfigHasRoutes(config GatewayAPITrafficRouting) bool { +func isConfigHasRoutes(config *GatewayAPITrafficRouting) bool { return len(config.HTTPRoutes) > 0 || len(config.TCPRoutes) > 0 } diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index 7b5e7f7..97031bb 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -38,9 +38,9 @@ func TestRunSuccessfully(t *testing.T) { rpcPluginImp := &RpcPlugin{ LogCtx: logCtx, IsTest: true, - HTTPRouteClient: gwFake.NewSimpleClientset(&mocks.HTTPRouteObj).GatewayV1beta1().HTTPRoutes(mocks.Namespace), - TCPRouteClient: gwFake.NewSimpleClientset(&mocks.TCPPRouteObj).GatewayV1alpha2().TCPRoutes(mocks.Namespace), - TestClientset: fake.NewSimpleClientset(&mocks.ConfigMapObj).CoreV1().ConfigMaps(mocks.Namespace), + HTTPRouteClient: gwFake.NewSimpleClientset(&mocks.HTTPRouteObj).GatewayV1beta1().HTTPRoutes(mocks.RolloutNamespace), + TCPRouteClient: gwFake.NewSimpleClientset(&mocks.TCPPRouteObj).GatewayV1alpha2().TCPRoutes(mocks.RolloutNamespace), + TestClientset: fake.NewSimpleClientset(&mocks.ConfigMapObj).CoreV1().ConfigMaps(mocks.RolloutNamespace), } // pluginMap is the map of plugins we can dispense. @@ -108,7 +108,7 @@ func TestRunSuccessfully(t *testing.T) { t.Run("SetHTTPRouteWeight", func(t *testing.T) { var desiredWeight int32 = 30 rollout := newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, HTTPRoute: mocks.HTTPRouteName, }) err := pluginInstance.SetWeight(rollout, desiredWeight, []v1alpha1.WeightDestination{}) @@ -121,7 +121,7 @@ func TestRunSuccessfully(t *testing.T) { var desiredWeight int32 = 30 rollout := newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, TCPRoute: mocks.TCPRouteName, }) err := pluginInstance.SetWeight(rollout, desiredWeight, []v1alpha1.WeightDestination{}) @@ -134,7 +134,7 @@ func TestRunSuccessfully(t *testing.T) { var desiredWeight int32 = 30 rollout := newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, HTTPRoutes: []HTTPRoute{ { Name: mocks.HTTPRouteName, @@ -174,7 +174,7 @@ func TestRunSuccessfully(t *testing.T) { }, } rollout := newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, HTTPRoute: mocks.HTTPRouteName, ConfigMap: mocks.ConfigMapName, }) @@ -187,7 +187,7 @@ func TestRunSuccessfully(t *testing.T) { }) t.Run("RemoveHTTPManagedRoutes", func(t *testing.T) { rollout := newRollout(mocks.StableServiceName, mocks.CanaryServiceName, &GatewayAPITrafficRouting{ - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, HTTPRoute: mocks.HTTPRouteName, ConfigMap: mocks.ConfigMapName, }) @@ -210,7 +210,7 @@ func newRollout(stableSvc, canarySvc string, config *GatewayAPITrafficRouting) * return &v1alpha1.Rollout{ ObjectMeta: metav1.ObjectMeta{ Name: "rollout", - Namespace: mocks.Namespace, + Namespace: mocks.RolloutNamespace, }, Spec: v1alpha1.RolloutSpec{ Strategy: v1alpha1.RolloutStrategy{ diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index a4b2a21..f68024b 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -40,8 +40,11 @@ type GatewayAPITrafficRouting struct { TCPRoutes []TCPRoute `json:"tcpRoutes,omitempty"` // Namespace refers to the namespace of the specified resource Namespace string `json:"namespace" validate:"required"` - // ConfigMap name refers to the config map where plugin stores data about managed routes + // ConfigMap refers to the config map where plugin stores data about managed routes ConfigMap string `json:"configMap,omitempty"` + // ConfigMapRWMutex refers to the RWMutex that we use to enter to the critical section + // critical section is config map + ConfigMapRWMutex sync.RWMutex } type HTTPRoute struct { @@ -60,10 +63,7 @@ type TCPRoute struct { UseHeaderRoutes bool `json:"useHeaderRoutes"` } -type HTTPHeaderRoute struct { - mutex sync.Mutex - managedRouteMap map[string]int -} +type ManagedRouteMap map[string]map[string]int type HTTPRouteRule v1beta1.HTTPRouteRule From 95ceb8a57a08ff553539b09d951f06ab24b0b2e1 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Wed, 21 Feb 2024 22:16:31 +0500 Subject: [PATCH 09/12] feat: add logs about plugin controls what routes for every supported feature Signed-off-by: Philipp Plotnikov --- main.go | 1 - pkg/plugin/httproute.go | 4 ++++ pkg/plugin/plugin.go | 24 ++++++++++++++++++------ pkg/plugin/tcproute.go | 4 ++++ pkg/plugin/types.go | 1 + 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index f43027e..e2f01cd 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,6 @@ func main() { var pluginMap = map[string]goPlugin.Plugin{ "RpcTrafficRouterPlugin": &rolloutsPlugin.RpcTrafficRouterPlugin{Impl: rpcPluginImp}, } - logCtx.Debug("message from plugin", "foo", "bar") goPlugin.Serve(&goPlugin.ServeConfig{ HandshakeConfig: handshakeConfig, Plugins: pluginMap, diff --git a/pkg/plugin/httproute.go b/pkg/plugin/httproute.go index aec9717..28a39e1 100644 --- a/pkg/plugin/httproute.go +++ b/pkg/plugin/httproute.go @@ -400,3 +400,7 @@ func (r HTTPRouteRuleList) Error() error { func (r *HTTPBackendRef) GetName() string { return string(r.Name) } + +func (r HTTPRoute) GetName() string { + return r.Name +} diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index ddd7654..e82723c 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -61,6 +61,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad ErrorString: GatewayAPIManifestError, } } + r.LogCtx.Info(fmt.Sprintf("[SetWeight] plugin %q controls HTTPRoutes: %v", PluginName, getGatewayAPIRouteNameList(gatewayAPIConfig.HTTPRoutes))) rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { gatewayAPIConfig.HTTPRoute = route.Name return r.setHTTPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig) @@ -68,6 +69,7 @@ func (r *RpcPlugin) SetWeight(rollout *v1alpha1.Rollout, desiredWeight int32, ad if rpcError.HasError() { return rpcError } + r.LogCtx.Info(fmt.Sprintf("[SetWeight] plugin %q controls TCPRoutes: %v", PluginName, getGatewayAPIRouteNameList(gatewayAPIConfig.TCPRoutes))) rpcError = forEachGatewayAPIRoute(gatewayAPIConfig.TCPRoutes, func(route TCPRoute) pluginTypes.RpcError { gatewayAPIConfig.TCPRoute = route.Name return r.setTCPRouteWeight(rollout, desiredWeight, additionalDestinations, gatewayAPIConfig) @@ -84,6 +86,7 @@ func (r *RpcPlugin) SetHeaderRoute(rollout *v1alpha1.Rollout, headerRouting *v1a } if gatewayAPIConfig.HTTPRoutes != nil { gatewayAPIConfig.ConfigMapRWMutex.Lock() + r.LogCtx.Info(fmt.Sprintf("[SetHeaderRoute] plugin %q controls HTTPRoutes: %v", PluginName, getGatewayAPIRouteNameList(gatewayAPIConfig.HTTPRoutes))) rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { if !route.UseHeaderRoutes { return pluginTypes.RpcError{} @@ -117,6 +120,7 @@ func (r *RpcPlugin) RemoveManagedRoutes(rollout *v1alpha1.Rollout) pluginTypes.R } if gatewayAPIConfig.HTTPRoutes != nil { gatewayAPIConfig.ConfigMapRWMutex.Lock() + r.LogCtx.Info(fmt.Sprintf("[RemoveManagedRoutes] plugin %q controls HTTPRoutes: %v", PluginName, getGatewayAPIRouteNameList(gatewayAPIConfig.HTTPRoutes))) rpcError := forEachGatewayAPIRoute(gatewayAPIConfig.HTTPRoutes, func(route HTTPRoute) pluginTypes.RpcError { if !route.UseHeaderRoutes { return pluginTypes.RpcError{} @@ -139,19 +143,19 @@ func (r *RpcPlugin) Type() string { func getGatewayAPITracfficRoutingConfig(rollout *v1alpha1.Rollout) (*GatewayAPITrafficRouting, error) { validate := validator.New(validator.WithRequiredStructEnabled()) - gatewayAPIConfig := GatewayAPITrafficRouting{ + gatewayAPIConfig := &GatewayAPITrafficRouting{ ConfigMap: defaults.ConfigMap, } err := json.Unmarshal(rollout.Spec.Strategy.Canary.TrafficRouting.Plugins[PluginName], &gatewayAPIConfig) if err != nil { - return &gatewayAPIConfig, err + return gatewayAPIConfig, err } - insertGatewayAPIRouteLists(&gatewayAPIConfig) - err = validate.Struct(&gatewayAPIConfig) + insertGatewayAPIRouteLists(gatewayAPIConfig) + err = validate.Struct(gatewayAPIConfig) if err != nil { - return &gatewayAPIConfig, err + return gatewayAPIConfig, err } - return &gatewayAPIConfig, err + return gatewayAPIConfig, err } func insertGatewayAPIRouteLists(gatewayAPIConfig *GatewayAPITrafficRouting) { @@ -249,3 +253,11 @@ func forEachGatewayAPIRoute[T1 GatewayAPIRoute](routeList []T1, fn func(route T1 } return pluginTypes.RpcError{} } + +func getGatewayAPIRouteNameList[T1 GatewayAPIRoute](gatewayAPIRouteList []T1) []string { + gatewayAPIRouteNameList := make([]string, len(gatewayAPIRouteList)) + for index, value := range gatewayAPIRouteList { + gatewayAPIRouteNameList[index] = value.GetName() + } + return gatewayAPIRouteNameList +} diff --git a/pkg/plugin/tcproute.go b/pkg/plugin/tcproute.go index 7a9aa3a..2335075 100644 --- a/pkg/plugin/tcproute.go +++ b/pkg/plugin/tcproute.go @@ -87,3 +87,7 @@ func (r TCPRouteRuleList) Error() error { func (r *TCPBackendRef) GetName() string { return string(r.Name) } + +func (r TCPRoute) GetName() string { + return r.Name +} diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index f68024b..a634023 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -79,6 +79,7 @@ type TCPBackendRef v1beta1.BackendRef type GatewayAPIRoute interface { HTTPRoute | TCPRoute + GetName() string } type GatewayAPIRouteRule[T1 GatewayAPIBackendRef] interface { From 283fb63ba5f8c009572d48c6fc5228630065cf14 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Wed, 21 Feb 2024 22:56:12 +0500 Subject: [PATCH 10/12] docs: added information about setHeaderRoute and multi routes features Signed-off-by: Philipp Plotnikov --- examples/traefik/README.md | 71 +++++++++++++++++++++++++++++++++++++- pkg/plugin/types.go | 2 +- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/examples/traefik/README.md b/examples/traefik/README.md index 3c8e925..f39f94c 100644 --- a/examples/traefik/README.md +++ b/examples/traefik/README.md @@ -271,6 +271,75 @@ Apply all the yaml files to your cluster ## Step 8 - Test the canary -Perform a deployment like any other Rollout and the Gateway plugin will split the traffic to your canary by instructing Traefik proxy via the Gateway API +Perform a deployment like any other Rollout and the Gateway plugin will split the traffic to your canary by instructing Traefik proxy via the Gateway API. +### Notice +GatewayAPI plugin supports traffic routing based on a header values for canary, so you can also use setHeaderRoute step in Argo Rollouts manifest. It also means that plugin should control managed routes. It creates ConfigMap in the specified namespace in **namespace** field with specified name in **configMap** field for that. +```yaml +plugins: + argoproj-labs/gatewayAPI: + namespace: test + httpRoute: http-route + configMap: test-gateway # default value is argo-gatewayapi-configmap +``` + +## How to use multiple routes per rollout + +## Step 1 - Create several routes + +```yaml +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: first-route +spec: + parentRefs: + - name: gateway + rules: + - matches: + - path: + type: PathPrefix + value: /first + backendRefs: + - name: argo-rollouts-stable-service + kind: Service + port: 80 + - name: argo-rollouts-canary-service + kind: Service + port: 80 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute +metadata: + name: second-route +spec: + parentRefs: + - name: gateway + rules: + - matches: + - path: + type: PathPrefix + value: /second + backendRefs: + - name: argo-rollouts-stable-service + kind: Service + port: 80 + - name: argo-rollouts-canary-service + kind: Service + port: 80 +``` + +## Step 2 - Change argoproj-labs/gatewayAPI field in Argo Rollout manifest + +```yaml +plugins: + argoproj-labs/gatewayAPI: + httpRoutes: + - name: first-route # required + useHeaderRoutes: true + - name: second-route +``` +You can control for what routes you need to add header routes during step of setHeaderRoute in Argo Rollout. + +**Notice** All these features work also with TCPRoutes diff --git a/pkg/plugin/types.go b/pkg/plugin/types.go index a634023..bc2a69c 100644 --- a/pkg/plugin/types.go +++ b/pkg/plugin/types.go @@ -39,7 +39,7 @@ type GatewayAPITrafficRouting struct { // service TCPRoutes []TCPRoute `json:"tcpRoutes,omitempty"` // Namespace refers to the namespace of the specified resource - Namespace string `json:"namespace" validate:"required"` + Namespace string `json:"namespace,omitempty"` // ConfigMap refers to the config map where plugin stores data about managed routes ConfigMap string `json:"configMap,omitempty"` // ConfigMapRWMutex refers to the RWMutex that we use to enter to the critical section From a626d3a11711b734435c7a698ec102312e719e03 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Wed, 21 Feb 2024 22:58:27 +0500 Subject: [PATCH 11/12] docs: added information about setHeaderRoute and multi routes features Signed-off-by: Philipp Plotnikov --- examples/traefik/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/traefik/README.md b/examples/traefik/README.md index f39f94c..a3c0c7a 100644 --- a/examples/traefik/README.md +++ b/examples/traefik/README.md @@ -342,4 +342,4 @@ plugins: ``` You can control for what routes you need to add header routes during step of setHeaderRoute in Argo Rollout. -**Notice** All these features work also with TCPRoutes +**Notice** All these features except traffic routing based on a header values for canary work also with TCPRoutes From b6eec00eec88753bc6763f1abb2b1315177e6653 Mon Sep 17 00:00:00 2001 From: Philipp Plotnikov Date: Wed, 21 Feb 2024 23:00:58 +0500 Subject: [PATCH 12/12] docs: added information about namespace default value Signed-off-by: Philipp Plotnikov --- examples/traefik/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/traefik/README.md b/examples/traefik/README.md index a3c0c7a..acd081f 100644 --- a/examples/traefik/README.md +++ b/examples/traefik/README.md @@ -279,7 +279,7 @@ GatewayAPI plugin supports traffic routing based on a header values for canary, ```yaml plugins: argoproj-labs/gatewayAPI: - namespace: test + namespace: test # default value is default httpRoute: http-route configMap: test-gateway # default value is argo-gatewayapi-configmap ```