diff --git a/controllers/rate_limiting_wasmplugin_controller.go b/controllers/rate_limiting_istio_wasmplugin_controller.go similarity index 69% rename from controllers/rate_limiting_wasmplugin_controller.go rename to controllers/rate_limiting_istio_wasmplugin_controller.go index 7ef4ddab6..e4815d153 100644 --- a/controllers/rate_limiting_wasmplugin_controller.go +++ b/controllers/rate_limiting_istio_wasmplugin_controller.go @@ -28,7 +28,7 @@ import ( istioclientgoextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/ptr" + "k8s.io/utils/env" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/handler" @@ -45,12 +45,16 @@ import ( "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" ) -const ( - HTTPRouteGatewayParentField = ".metadata.parentRefs.gateway" +var ( + WASMFilterImageURL = env.GetString("RELATED_IMAGE_WASMSHIM", "oci://quay.io/kuadrant/wasm-shim:latest") ) -// RateLimitingWASMPluginReconciler reconciles a WASMPlugin object for rate limiting -type RateLimitingWASMPluginReconciler struct { +func WASMPluginName(gw *gatewayapiv1.Gateway) string { + return fmt.Sprintf("kuadrant-%s", gw.Name) +} + +// RateLimitingIstioWASMPluginReconciler reconciles a WASMPlugin object for rate limiting +type RateLimitingIstioWASMPluginReconciler struct { *reconcilers.BaseReconciler } @@ -61,7 +65,7 @@ type RateLimitingWASMPluginReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile -func (r *RateLimitingWASMPluginReconciler) Reconcile(eventCtx context.Context, req ctrl.Request) (ctrl.Result, error) { +func (r *RateLimitingIstioWASMPluginReconciler) Reconcile(eventCtx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := r.Logger().WithValues("Gateway", req.NamespacedName, "request id", uuid.NewString()) logger.Info("Reconciling rate limiting WASMPlugin") ctx := logr.NewContext(eventCtx, logger) @@ -89,7 +93,7 @@ func (r *RateLimitingWASMPluginReconciler) Reconcile(eventCtx context.Context, r return ctrl.Result{}, err } - err = r.ReconcileResource(ctx, &istioclientgoextensionv1alpha1.WasmPlugin{}, desired, rlptools.WASMPluginMutator) + err = r.ReconcileResource(ctx, &istioclientgoextensionv1alpha1.WasmPlugin{}, desired, kuadrantistioutils.WASMPluginMutator) if err != nil { return ctrl.Result{}, err } @@ -98,7 +102,7 @@ func (r *RateLimitingWASMPluginReconciler) Reconcile(eventCtx context.Context, r return ctrl.Result{}, nil } -func (r *RateLimitingWASMPluginReconciler) desiredRateLimitingWASMPlugin(ctx context.Context, gw *gatewayapiv1.Gateway) (*istioclientgoextensionv1alpha1.WasmPlugin, error) { +func (r *RateLimitingIstioWASMPluginReconciler) desiredRateLimitingWASMPlugin(ctx context.Context, gw *gatewayapiv1.Gateway) (*istioclientgoextensionv1alpha1.WasmPlugin, error) { baseLogger, err := logr.FromContext(ctx) if err != nil { return nil, err @@ -110,12 +114,12 @@ func (r *RateLimitingWASMPluginReconciler) desiredRateLimitingWASMPlugin(ctx con APIVersion: "extensions.istio.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: rlptools.WASMPluginName(gw), + Name: WASMPluginName(gw), Namespace: gw.Namespace, }, Spec: istioextensionsv1alpha1.WasmPlugin{ TargetRef: kuadrantistioutils.PolicyTargetRefFromGateway(gw), - Url: rlptools.WASMFilterImageURL, + Url: WASMFilterImageURL, PluginConfig: nil, // Insert plugin before Istio stats filters and after Istio authorization filters. Phase: istioextensionsv1alpha1.PluginPhase_STATS, @@ -150,18 +154,18 @@ func (r *RateLimitingWASMPluginReconciler) desiredRateLimitingWASMPlugin(ctx con return wasmPlugin, nil } -func (r *RateLimitingWASMPluginReconciler) wasmPluginConfig(ctx context.Context, gw *gatewayapiv1.Gateway) (*wasm.Plugin, error) { +func (r *RateLimitingIstioWASMPluginReconciler) wasmPluginConfig(ctx context.Context, gw *gatewayapiv1.Gateway) (*wasm.Config, error) { logger, err := logr.FromContext(ctx) if err != nil { return nil, err } - wasmPlugin := &wasm.Plugin{ + config := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: make([]wasm.RateLimitPolicy, 0), } - t, err := r.topologyIndexesFromGateway(ctx, gw) + t, err := rlptools.TopologyIndexesFromGateway(ctx, r.Client(), gw) if err != nil { return nil, err } @@ -185,60 +189,13 @@ func (r *RateLimitingWASMPluginReconciler) wasmPluginConfig(ctx context.Context, continue } - wasmPlugin.RateLimitPolicies = append(wasmPlugin.RateLimitPolicies, *wasmRLP) - } - - return wasmPlugin, nil -} - -func (r *RateLimitingWASMPluginReconciler) topologyIndexesFromGateway(ctx context.Context, gw *gatewayapiv1.Gateway) (*kuadrantgatewayapi.TopologyIndexes, error) { - logger, err := logr.FromContext(ctx) - if err != nil { - return nil, err - } - - routeList := &gatewayapiv1.HTTPRouteList{} - // Get all the routes having the gateway as parent - err = r.Client().List(ctx, routeList, client.MatchingFields{HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String()}) - logger.V(1).Info("topologyIndexesFromGateway: list httproutes from gateway", - "gateway", client.ObjectKeyFromObject(gw), - "#HTTPRoutes", len(routeList.Items), - "err", err) - if err != nil { - return nil, err - } - - rlpList := &kuadrantv1beta2.RateLimitPolicyList{} - // Get all the rate limit policies - err = r.Client().List(ctx, rlpList) - logger.V(1).Info("topologyIndexesFromGateway: list rate limit policies", - "#RLPS", len(rlpList.Items), - "err", err) - if err != nil { - return nil, err - } - - policies := utils.Map(rlpList.Items, func(p kuadrantv1beta2.RateLimitPolicy) kuadrantgatewayapi.Policy { return &p }) - - topology, err := kuadrantgatewayapi.NewTopology( - kuadrantgatewayapi.WithGateways([]*gatewayapiv1.Gateway{gw}), - kuadrantgatewayapi.WithRoutes(utils.Map(routeList.Items, ptr.To[gatewayapiv1.HTTPRoute])), - kuadrantgatewayapi.WithPolicies(policies), - kuadrantgatewayapi.WithLogger(logger), - ) - if err != nil { - return nil, err - } - - overriddenTopology, err := rlptools.ApplyOverrides(topology, gw) - if err != nil { - return nil, err + config.RateLimitPolicies = append(config.RateLimitPolicies, *wasmRLP) } - return kuadrantgatewayapi.NewTopologyIndexes(overriddenTopology), nil + return config, nil } -func (r *RateLimitingWASMPluginReconciler) wasmRateLimitPolicy(ctx context.Context, t *kuadrantgatewayapi.TopologyIndexes, rlp *kuadrantv1beta2.RateLimitPolicy, gw *gatewayapiv1.Gateway) (*wasm.RateLimitPolicy, error) { +func (r *RateLimitingIstioWASMPluginReconciler) wasmRateLimitPolicy(ctx context.Context, t *kuadrantgatewayapi.TopologyIndexes, rlp *kuadrantv1beta2.RateLimitPolicy, gw *gatewayapiv1.Gateway) (*wasm.RateLimitPolicy, error) { route, err := r.routeFromRLP(ctx, t, rlp, gw) if err != nil { return nil, err @@ -271,7 +228,7 @@ func (r *RateLimitingWASMPluginReconciler) wasmRateLimitPolicy(ctx context.Conte routeWithEffectiveHostnames := route.DeepCopy() routeWithEffectiveHostnames.Spec.Hostnames = hostnames - rules := rlptools.WasmRules(rlp, routeWithEffectiveHostnames) + rules := wasm.Rules(rlp, routeWithEffectiveHostnames) if len(rules) == 0 { // no need to add the policy if there are no rules; a rlp can return no rules if all its limits fail to match any route rule return nil, nil @@ -286,7 +243,7 @@ func (r *RateLimitingWASMPluginReconciler) wasmRateLimitPolicy(ctx context.Conte }, nil } -func (r *RateLimitingWASMPluginReconciler) routeFromRLP(ctx context.Context, t *kuadrantgatewayapi.TopologyIndexes, rlp *kuadrantv1beta2.RateLimitPolicy, gw *gatewayapiv1.Gateway) (*gatewayapiv1.HTTPRoute, error) { +func (r *RateLimitingIstioWASMPluginReconciler) routeFromRLP(ctx context.Context, t *kuadrantgatewayapi.TopologyIndexes, rlp *kuadrantv1beta2.RateLimitPolicy, gw *gatewayapiv1.Gateway) (*gatewayapiv1.HTTPRoute, error) { logger, err := logr.FromContext(ctx) if err != nil { return nil, err @@ -325,34 +282,8 @@ func (r *RateLimitingWASMPluginReconciler) routeFromRLP(ctx context.Context, t * return route, nil } -// addHTTPRouteByGatewayIndexer declares an index key that we can later use with the client as a pseudo-field name, -// allowing to query all the routes parented by a given gateway -// to prevent creating the same index field multiple times, the function is declared private to be -// called only by this controller -func addHTTPRouteByGatewayIndexer(mgr ctrl.Manager, baseLogger logr.Logger) error { - if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayapiv1.HTTPRoute{}, HTTPRouteGatewayParentField, func(rawObj client.Object) []string { - // grab the route object, extract the parents - route, assertionOk := rawObj.(*gatewayapiv1.HTTPRoute) - if !assertionOk { - baseLogger.V(1).Error(fmt.Errorf("%T is not a *gatewayapiv1.HTTPRoute", rawObj), "cannot map") - return nil - } - - logger := baseLogger.WithValues("route", client.ObjectKeyFromObject(route).String()) - - return utils.Map(kuadrantgatewayapi.GetRouteAcceptedGatewayParentKeys(route), func(key client.ObjectKey) string { - logger.V(1).Info("new gateway added", "key", key.String()) - return key.String() - }) - }); err != nil { - return err - } - - return nil -} - // SetupWithManager sets up the controller with the Manager. -func (r *RateLimitingWASMPluginReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *RateLimitingIstioWASMPluginReconciler) SetupWithManager(mgr ctrl.Manager) error { ok, err := kuadrantistioutils.IsWASMPluginInstalled(mgr.GetRESTMapper()) if err != nil { return err @@ -371,12 +302,6 @@ func (r *RateLimitingWASMPluginReconciler) SetupWithManager(mgr ctrl.Manager) er return nil } - // Add custom indexer - err = addHTTPRouteByGatewayIndexer(mgr, r.Logger().WithName("routeByGatewayIndexer")) - if err != nil { - return err - } - httpRouteToParentGatewaysEventMapper := mappers.NewHTTPRouteToParentGatewaysEventMapper( mappers.WithLogger(r.Logger().WithName("httpRouteToParentGatewaysEventMapper")), ) diff --git a/controllers/ratelimitpolicy_controller_test.go b/controllers/ratelimitpolicy_controller_test.go index 5b8cd1796..4f438e4ce 100644 --- a/controllers/ratelimitpolicy_controller_test.go +++ b/controllers/ratelimitpolicy_controller_test.go @@ -24,6 +24,7 @@ import ( "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/rlptools" + "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" "github.com/kuadrant/kuadrant-operator/tests" ) @@ -160,7 +161,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 3 * 60, Namespace: rlptools.LimitsNamespaceFromRLP(rlp), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlp), })) @@ -246,7 +247,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 3 * 60, Namespace: rlptools.LimitsNamespaceFromRLP(rlp), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlp), })) @@ -296,7 +297,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 3 * 60, Namespace: rlptools.LimitsNamespaceFromRLP(rlp), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlp), })) @@ -371,7 +372,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 10, Seconds: 5, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -486,7 +487,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 180, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -508,7 +509,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 10, Seconds: 5, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -543,7 +544,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 180, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -582,7 +583,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 10, Seconds: 5, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -605,7 +606,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 180, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -631,7 +632,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1, Seconds: 180, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "l1"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -654,7 +655,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 10, Seconds: 5, Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "route"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(routeRLP), })).WithContext(ctx).Should(Succeed()) @@ -1322,7 +1323,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1000, Seconds: 1, Namespace: rlptools.LimitsNamespaceFromRLP(rlpTargetedRoute), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpTargetedRoute), "gw-a-1000rps"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpTargetedRoute), "gw-a-1000rps"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlpTargetedRoute), }, @@ -1330,7 +1331,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 100, Seconds: 1, Namespace: rlptools.LimitsNamespaceFromRLP(rlpTargetedRoute), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpTargetedRoute), "gw-b-100rps"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpTargetedRoute), "gw-b-100rps"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlpTargetedRoute), }, @@ -1338,7 +1339,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 1000, Seconds: 1, Namespace: rlptools.LimitsNamespaceFromRLP(rlpGatewayA), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpGatewayA), "gw-a-1000rps"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpGatewayA), "gw-a-1000rps"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlpGatewayA), }, @@ -1346,7 +1347,7 @@ var _ = Describe("RateLimitPolicy controller", Ordered, func() { MaxValue: 100, Seconds: 1, Namespace: rlptools.LimitsNamespaceFromRLP(rlpGatewayB), - Conditions: []string{fmt.Sprintf(`%s == "1"`, rlptools.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpGatewayB), "gw-b-100rps"))}, + Conditions: []string{fmt.Sprintf(`%s == "1"`, wasm.LimitNameToLimitadorIdentifier(client.ObjectKeyFromObject(rlpGatewayB), "gw-b-100rps"))}, Variables: []string{}, Name: rlptools.LimitsNameFromRLP(rlpGatewayB), }, diff --git a/controllers/ratelimitpolicy_enforced_status_controller.go b/controllers/ratelimitpolicy_enforced_status_controller.go index a8552b81b..457633c04 100644 --- a/controllers/ratelimitpolicy_enforced_status_controller.go +++ b/controllers/ratelimitpolicy_enforced_status_controller.go @@ -24,6 +24,7 @@ import ( gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" + "github.com/kuadrant/kuadrant-operator/pkg/library/fieldindexers" kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/library/mappers" @@ -180,7 +181,12 @@ func (r *RateLimitPolicyEnforcedStatusReconciler) buildTopology(ctx context.Cont routeList := &gatewayapiv1.HTTPRouteList{} // Get all the routes having the gateway as parent - err = r.Client().List(ctx, routeList, client.MatchingFields{HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String()}) + err = r.Client().List( + ctx, + routeList, + client.MatchingFields{ + fieldindexers.HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String(), + }) logger.V(1).Info("list routes by gateway", "#routes", len(routeList.Items), "err", err) if err != nil { return nil, err diff --git a/controllers/target_status_controller.go b/controllers/target_status_controller.go index 0265040f1..3790a484d 100644 --- a/controllers/target_status_controller.go +++ b/controllers/target_status_controller.go @@ -39,6 +39,7 @@ import ( kuadrantv1alpha1 "github.com/kuadrant/kuadrant-operator/api/v1alpha1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" + "github.com/kuadrant/kuadrant-operator/pkg/library/fieldindexers" kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/library/mappers" @@ -203,7 +204,7 @@ func (r *TargetStatusReconciler) buildTopology(ctx context.Context, gw *gatewaya routeList := &gatewayapiv1.HTTPRouteList{} // Get all the routes having the gateway as parent - err = r.Client().List(ctx, routeList, client.MatchingFields{HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String()}) + err = r.Client().List(ctx, routeList, client.MatchingFields{fieldindexers.HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String()}) logger.V(1).Info("list routes by gateway", "#routes", len(routeList.Items), "err", err) if err != nil { return nil, err diff --git a/controllers/test_common.go b/controllers/test_common.go index da948308d..a2732aede 100644 --- a/controllers/test_common.go +++ b/controllers/test_common.go @@ -47,6 +47,7 @@ import ( kuadrantv1alpha1 "github.com/kuadrant/kuadrant-operator/api/v1alpha1" kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" + "github.com/kuadrant/kuadrant-operator/pkg/library/fieldindexers" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/library/reconcilers" ) @@ -104,6 +105,12 @@ func SetupKuadrantOperatorForTest(s *runtime.Scheme, cfg *rest.Config) { }) Expect(err).ToNot(HaveOccurred()) + err = fieldindexers.HTTPRouteIndexByGateway( + mgr, + log.Log.WithName("kuadrant").WithName("indexer").WithName("routeIndexByGateway"), + ) + Expect(err).ToNot(HaveOccurred()) + authPolicyBaseReconciler := reconcilers.NewBaseReconciler( mgr.GetClient(), mgr.GetScheme(), mgr.GetAPIReader(), log.Log.WithName("authpolicy"), @@ -193,14 +200,14 @@ func SetupKuadrantOperatorForTest(s *runtime.Scheme, cfg *rest.Config) { Expect(err).NotTo(HaveOccurred()) - rateLimitingWASMPluginBaseReconciler := reconcilers.NewBaseReconciler( + rateLimitingIstioWASMPluginBaseReconciler := reconcilers.NewBaseReconciler( mgr.GetClient(), mgr.GetScheme(), mgr.GetAPIReader(), log.Log.WithName("ratelimitpolicy").WithName("wasmplugin"), - mgr.GetEventRecorderFor("RateLimitingWASMPlugin"), + mgr.GetEventRecorderFor("RateLimitingIstioWASMPlugin"), ) - err = (&RateLimitingWASMPluginReconciler{ - BaseReconciler: rateLimitingWASMPluginBaseReconciler, + err = (&RateLimitingIstioWASMPluginReconciler{ + BaseReconciler: rateLimitingIstioWASMPluginBaseReconciler, }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) diff --git a/main.go b/main.go index be2f21f2a..6b04ec7fa 100644 --- a/main.go +++ b/main.go @@ -50,6 +50,7 @@ import ( kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" "github.com/kuadrant/kuadrant-operator/controllers" + "github.com/kuadrant/kuadrant-operator/pkg/library/fieldindexers" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/library/reconcilers" "github.com/kuadrant/kuadrant-operator/pkg/log" @@ -70,6 +71,7 @@ func init() { utilruntime.Must(authorinoapi.AddToScheme(scheme)) utilruntime.Must(istionetworkingv1alpha3.AddToScheme(scheme)) utilruntime.Must(istiosecurityv1beta1.AddToScheme(scheme)) + utilruntime.Must(istiov1alpha1.AddToScheme(scheme)) utilruntime.Must(gatewayapiv1.Install(scheme)) utilruntime.Must(istioextensionv1alpha1.AddToScheme(scheme)) utilruntime.Must(apiextv1.AddToScheme(scheme)) @@ -132,6 +134,14 @@ func main() { os.Exit(1) } + if err := fieldindexers.HTTPRouteIndexByGateway( + mgr, + log.Log.WithName("kuadrant").WithName("indexer").WithName("routeIndexByGateway"), + ); err != nil { + setupLog.Error(err, "unable to add indexer") + os.Exit(1) + } + kuadrantBaseReconciler := reconcilers.NewBaseReconciler( mgr.GetClient(), mgr.GetScheme(), mgr.GetAPIReader(), log.Log.WithName("kuadrant"), @@ -229,16 +239,16 @@ func main() { os.Exit(1) } - rateLimitingWASMPluginBaseReconciler := reconcilers.NewBaseReconciler( + rateLimitingIstioWASMPluginBaseReconciler := reconcilers.NewBaseReconciler( mgr.GetClient(), mgr.GetScheme(), mgr.GetAPIReader(), log.Log.WithName("ratelimitpolicy").WithName("wasmplugin"), - mgr.GetEventRecorderFor("RateLimitingWASMPlugin"), + mgr.GetEventRecorderFor("RateLimitingIstioWASMPlugin"), ) - if err = (&controllers.RateLimitingWASMPluginReconciler{ - BaseReconciler: rateLimitingWASMPluginBaseReconciler, + if err = (&controllers.RateLimitingIstioWASMPluginReconciler{ + BaseReconciler: rateLimitingIstioWASMPluginBaseReconciler, }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "RateLimitingWASMPlugin") + setupLog.Error(err, "unable to create controller", "controller", "RateLimitingIstioWASMPlugin") os.Exit(1) } diff --git a/pkg/istio/mutators.go b/pkg/istio/mutators.go new file mode 100644 index 000000000..3126c131f --- /dev/null +++ b/pkg/istio/mutators.go @@ -0,0 +1,41 @@ +package istio + +import ( + "fmt" + "reflect" + + istioclientgoextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" +) + +func WASMPluginMutator(existingObj, desiredObj client.Object) (bool, error) { + update := false + existing, ok := existingObj.(*istioclientgoextensionv1alpha1.WasmPlugin) + if !ok { + return false, fmt.Errorf("%T is not a *istioclientgoextensionv1alpha1.WasmPlugin", existingObj) + } + desired, ok := desiredObj.(*istioclientgoextensionv1alpha1.WasmPlugin) + if !ok { + return false, fmt.Errorf("%T is not a *istioclientgoextensionv1alpha1.WasmPlugin", desiredObj) + } + + existingWasmConfig, err := wasm.ConfigFromStruct(existing.Spec.PluginConfig) + if err != nil { + return false, err + } + + desiredWasmConfig, err := wasm.ConfigFromStruct(desired.Spec.PluginConfig) + if err != nil { + return false, err + } + + // TODO(eastizle): reflect.DeepEqual does not work well with lists without order + if !reflect.DeepEqual(desiredWasmConfig, existingWasmConfig) { + update = true + existing.Spec.PluginConfig = desired.Spec.PluginConfig + } + + return update, nil +} diff --git a/pkg/library/fieldindexers/httproute_parents.go b/pkg/library/fieldindexers/httproute_parents.go new file mode 100644 index 000000000..6fd910073 --- /dev/null +++ b/pkg/library/fieldindexers/httproute_parents.go @@ -0,0 +1,53 @@ +package fieldindexers + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" + "github.com/kuadrant/kuadrant-operator/pkg/library/utils" +) + +const ( + HTTPRouteGatewayParentField = ".metadata.parentRefs.gateway" +) + +// HTTPRouteByGatewayIndexer declares an index key that we can later use with the client as a pseudo-field name, +// allowing to query all the routes parented by a given gateway +// to prevent creating the same index field multiple times, the function is declared private to be +// called only by this controller +func HTTPRouteIndexByGateway(mgr ctrl.Manager, baseLogger logr.Logger) error { + ok, err := kuadrantgatewayapi.IsGatewayAPIInstalled(mgr.GetRESTMapper()) + if err != nil { + return err + } + if !ok { + baseLogger.Info("HTTPRouteIndexByGateway index disabled. GatewayAPI was not found") + return nil + } + + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &gatewayapiv1.HTTPRoute{}, HTTPRouteGatewayParentField, func(rawObj client.Object) []string { + // grab the route object, extract the parents + route, assertionOk := rawObj.(*gatewayapiv1.HTTPRoute) + if !assertionOk { + baseLogger.V(1).Error(fmt.Errorf("%T is not a *gatewayapiv1.HTTPRoute", rawObj), "cannot map") + return nil + } + + logger := baseLogger.WithValues("route", client.ObjectKeyFromObject(route).String()) + + return utils.Map(kuadrantgatewayapi.GetRouteAcceptedGatewayParentKeys(route), func(key client.ObjectKey) string { + logger.V(1).Info("new gateway added", "key", key.String()) + return key.String() + }) + }); err != nil { + return err + } + + return nil +} diff --git a/pkg/rlptools/topology_index.go b/pkg/rlptools/topology_index.go new file mode 100644 index 000000000..03a11da00 --- /dev/null +++ b/pkg/rlptools/topology_index.go @@ -0,0 +1,67 @@ +package rlptools + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" + + kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" + "github.com/kuadrant/kuadrant-operator/pkg/library/fieldindexers" + kuadrantgatewayapi "github.com/kuadrant/kuadrant-operator/pkg/library/gatewayapi" + "github.com/kuadrant/kuadrant-operator/pkg/library/utils" +) + +func TopologyIndexesFromGateway(ctx context.Context, cl client.Client, gw *gatewayapiv1.Gateway) (*kuadrantgatewayapi.TopologyIndexes, error) { + logger, err := logr.FromContext(ctx) + if err != nil { + return nil, err + } + + routeList := &gatewayapiv1.HTTPRouteList{} + // Get all the routes having the gateway as parent + err = cl.List( + ctx, + routeList, + client.MatchingFields{ + fieldindexers.HTTPRouteGatewayParentField: client.ObjectKeyFromObject(gw).String(), + }) + logger.V(1).Info("topologyIndexesFromGateway: list httproutes from gateway", + "gateway", client.ObjectKeyFromObject(gw), + "#HTTPRoutes", len(routeList.Items), + "err", err) + if err != nil { + return nil, err + } + + rlpList := &kuadrantv1beta2.RateLimitPolicyList{} + // Get all the rate limit policies + err = cl.List(ctx, rlpList) + logger.V(1).Info("topologyIndexesFromGateway: list rate limit policies", + "#RLPS", len(rlpList.Items), + "err", err) + if err != nil { + return nil, err + } + + policies := utils.Map(rlpList.Items, func(p kuadrantv1beta2.RateLimitPolicy) kuadrantgatewayapi.Policy { return &p }) + + topology, err := kuadrantgatewayapi.NewTopology( + kuadrantgatewayapi.WithGateways([]*gatewayapiv1.Gateway{gw}), + kuadrantgatewayapi.WithRoutes(utils.Map(routeList.Items, ptr.To)), + kuadrantgatewayapi.WithPolicies(policies), + kuadrantgatewayapi.WithLogger(logger), + ) + if err != nil { + return nil, err + } + + overriddenTopology, err := ApplyOverrides(topology, gw) + if err != nil { + return nil, err + } + + return kuadrantgatewayapi.NewTopologyIndexes(overriddenTopology), nil +} diff --git a/pkg/rlptools/utils.go b/pkg/rlptools/utils.go index e743010ac..b90653287 100644 --- a/pkg/rlptools/utils.go +++ b/pkg/rlptools/utils.go @@ -1,40 +1,29 @@ package rlptools import ( - "crypto/sha256" - "encoding/hex" "fmt" - "unicode" limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" - "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" "github.com/kuadrant/kuadrant-operator/pkg/library/utils" + "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" ) -const ( - LimitadorRateLimitIdentifierPrefix = "limit." -) - -func LimitNameToLimitadorIdentifier(rlpKey types.NamespacedName, uniqueLimitName string) string { - identifier := LimitadorRateLimitIdentifierPrefix - - // sanitize chars that are not allowed in limitador identifiers - for _, c := range uniqueLimitName { - if unicode.IsLetter(c) || unicode.IsDigit(c) || c == '_' { - identifier += string(c) - } else { - identifier += "_" - } - } +func LimitsNameFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) string { + return LimitsNamespaceFromRLP(rlp) +} - // to avoid breaking the uniqueness of the limit name after sanitization, we add a hash of the original name - hash := sha256.Sum256([]byte(fmt.Sprintf("%s/%s", rlpKey.String(), uniqueLimitName))) - identifier += "__" + hex.EncodeToString(hash[:4]) +var timeUnitMap = map[kuadrantv1beta2.TimeUnit]int{ + kuadrantv1beta2.TimeUnit("second"): 1, + kuadrantv1beta2.TimeUnit("minute"): 60, + kuadrantv1beta2.TimeUnit("hour"): 60 * 60, + kuadrantv1beta2.TimeUnit("day"): 60 * 60 * 24, +} - return identifier +func LimitsNamespaceFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) string { + return fmt.Sprintf("%s/%s", rlp.GetNamespace(), rlp.GetName()) } // LimitadorRateLimitsFromRLP converts rate limits from a Kuadrant RateLimitPolicy into a list of Limitador rate limit @@ -45,7 +34,7 @@ func LimitadorRateLimitsFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) []limitado rateLimits := make([]limitadorv1alpha1.RateLimit, 0) for limitKey, limit := range rlp.Spec.CommonSpec().Limits { - limitIdentifier := LimitNameToLimitadorIdentifier(rlpKey, limitKey) + limitIdentifier := wasm.LimitNameToLimitadorIdentifier(rlpKey, limitKey) for _, rate := range limit.Rates { maxValue, seconds := rateToSeconds(rate) rateLimits = append(rateLimits, limitadorv1alpha1.RateLimit{ @@ -61,21 +50,6 @@ func LimitadorRateLimitsFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) []limitado return rateLimits } -func LimitsNamespaceFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) string { - return fmt.Sprintf("%s/%s", rlp.GetNamespace(), rlp.GetName()) -} - -func LimitsNameFromRLP(rlp *kuadrantv1beta2.RateLimitPolicy) string { - return LimitsNamespaceFromRLP(rlp) -} - -var timeUnitMap = map[kuadrantv1beta2.TimeUnit]int{ - kuadrantv1beta2.TimeUnit("second"): 1, - kuadrantv1beta2.TimeUnit("minute"): 60, - kuadrantv1beta2.TimeUnit("hour"): 60 * 60, - kuadrantv1beta2.TimeUnit("day"): 60 * 60 * 24, -} - // rateToSeconds converts from RLP Rate API (limit, duration and unit) // to Limitador's Limit format (maxValue, Seconds) func rateToSeconds(rate kuadrantv1beta2.Rate) (maxValue int, seconds int) { diff --git a/pkg/rlptools/utils_test.go b/pkg/rlptools/utils_test.go index cc0635e64..3bb10fbbb 100644 --- a/pkg/rlptools/utils_test.go +++ b/pkg/rlptools/utils_test.go @@ -4,12 +4,10 @@ package rlptools import ( "reflect" - "regexp" "testing" limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" "github.com/kuadrant/kuadrant-operator/pkg/library/utils" @@ -144,60 +142,6 @@ func testRLP_1Limit_1Rate_1Counter(ns, name string) *kuadrantv1beta2.RateLimitPo } } -func TestLimitNameToLimitadorIdentifier(t *testing.T) { - testCases := []struct { - name string - rlpKey types.NamespacedName - uniqueLimitName string - expected *regexp.Regexp - }{ - { - name: "prepends the limitador limit identifier prefix", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, - uniqueLimitName: "foo", - expected: regexp.MustCompile(`^limit\.foo.+`), - }, - { - name: "sanitizes invalid chars", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, - uniqueLimitName: "my/limit-0", - expected: regexp.MustCompile(`^limit\.my_limit_0.+$`), - }, - { - name: "sanitizes the dot char (.) even though it is a valid char in limitador identifiers", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, - uniqueLimitName: "my.limit", - expected: regexp.MustCompile(`^limit\.my_limit.+$`), - }, - { - name: "appends a hash of the original name to avoid breaking uniqueness", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, - uniqueLimitName: "foo", - expected: regexp.MustCompile(`^.+__1da6e70a$`), - }, - { - name: "different rlp keys result in different identifiers", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpB"}, - uniqueLimitName: "foo", - expected: regexp.MustCompile(`^.+__2c1520b6$`), - }, - { - name: "empty string", - rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, - uniqueLimitName: "", - expected: regexp.MustCompile(`^limit.__6d5e49dc$`), - }, - } - for _, tc := range testCases { - t.Run(tc.name, func(subT *testing.T) { - identifier := LimitNameToLimitadorIdentifier(tc.rlpKey, tc.uniqueLimitName) - if !tc.expected.MatchString(identifier) { - subT.Errorf("identifier does not match, expected(%s), got (%s)", tc.expected, identifier) - } - }) - } -} - func TestLimitadorRateLimitsFromRLP(t *testing.T) { testCases := []struct { name string diff --git a/pkg/rlptools/wasm/types.go b/pkg/rlptools/wasm/types.go index 52deee790..ea9d007e2 100644 --- a/pkg/rlptools/wasm/types.go +++ b/pkg/rlptools/wasm/types.go @@ -2,6 +2,7 @@ package wasm import ( "encoding/json" + "errors" _struct "google.golang.org/protobuf/types/known/structpb" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -97,20 +98,38 @@ const ( FailureModeAllow FailureModeType = "allow" ) -type Plugin struct { +type Config struct { FailureMode FailureModeType `json:"failureMode"` RateLimitPolicies []RateLimitPolicy `json:"rateLimitPolicies"` } -func (w *Plugin) ToStruct() (*_struct.Struct, error) { - wasmPluginJSON, err := json.Marshal(w) +func (w *Config) ToStruct() (*_struct.Struct, error) { + configJSON, err := json.Marshal(w) if err != nil { return nil, err } - pluginConfigStruct := &_struct.Struct{} - if err := pluginConfigStruct.UnmarshalJSON(wasmPluginJSON); err != nil { + configStruct := &_struct.Struct{} + if err := configStruct.UnmarshalJSON(configJSON); err != nil { return nil, err } - return pluginConfigStruct, nil + return configStruct, nil +} + +func ConfigFromStruct(structure *_struct.Struct) (*Config, error) { + if structure == nil { + return nil, errors.New("cannot desestructure config from nil") + } + // Serialize struct into json + configJSON, err := structure.MarshalJSON() + if err != nil { + return nil, err + } + // Deserialize protobuf struct into Config struct + config := &Config{} + if err := json.Unmarshal(configJSON, config); err != nil { + return nil, err + } + + return config, nil } diff --git a/pkg/rlptools/wasm_utils.go b/pkg/rlptools/wasm/utils.go similarity index 59% rename from pkg/rlptools/wasm_utils.go rename to pkg/rlptools/wasm/utils.go index 8d4b71490..787c01b83 100644 --- a/pkg/rlptools/wasm_utils.go +++ b/pkg/rlptools/wasm/utils.go @@ -1,33 +1,36 @@ -package rlptools +package wasm import ( - "encoding/json" + "crypto/sha256" + "encoding/hex" "errors" "fmt" - "reflect" "slices" "strings" + "unicode" "github.com/samber/lo" - _struct "google.golang.org/protobuf/types/known/structpb" - istioclientgoextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" + "k8s.io/apimachinery/pkg/types" "k8s.io/utils/env" "sigs.k8s.io/controller-runtime/pkg/client" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" - "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" +) + +const ( + LimitadorRateLimitIdentifierPrefix = "limit." ) var ( WASMFilterImageURL = env.GetString("RELATED_IMAGE_WASMSHIM", "oci://quay.io/kuadrant/wasm-shim:latest") ) -// WasmRules computes WASM rules from the policy and the targeted route. +// Rules computes WASM rules from the policy and the targeted route. // It returns an empty list of wasm rules if the policy specifies no limits or if all limits specified in the policy // fail to match any route rule according to the limits route selectors. -func WasmRules(rlp *kuadrantv1beta2.RateLimitPolicy, route *gatewayapiv1.HTTPRoute) []wasm.Rule { - rules := make([]wasm.Rule, 0) +func Rules(rlp *kuadrantv1beta2.RateLimitPolicy, route *gatewayapiv1.HTTPRoute) []Rule { + rules := make([]Rule, 0) if rlp == nil { return rules } @@ -52,8 +55,27 @@ func WasmRules(rlp *kuadrantv1beta2.RateLimitPolicy, route *gatewayapiv1.HTTPRou return rules } -func ruleFromLimit(limitIdentifier string, limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPRoute) (wasm.Rule, error) { - rule := wasm.Rule{} +func LimitNameToLimitadorIdentifier(rlpKey types.NamespacedName, uniqueLimitName string) string { + identifier := LimitadorRateLimitIdentifierPrefix + + // sanitize chars that are not allowed in limitador identifiers + for _, c := range uniqueLimitName { + if unicode.IsLetter(c) || unicode.IsDigit(c) || c == '_' { + identifier += string(c) + } else { + identifier += "_" + } + } + + // to avoid breaking the uniqueness of the limit name after sanitization, we add a hash of the original name + hash := sha256.Sum256([]byte(fmt.Sprintf("%s/%s", rlpKey.String(), uniqueLimitName))) + identifier += "__" + hex.EncodeToString(hash[:4]) + + return identifier +} + +func ruleFromLimit(limitIdentifier string, limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPRoute) (Rule, error) { + rule := Rule{} conditions, err := conditionsFromLimit(limit, route) if err != nil { @@ -62,19 +84,19 @@ func ruleFromLimit(limitIdentifier string, limit *kuadrantv1beta2.Limit, route * rule.Conditions = conditions - if data := dataFromLimt(limitIdentifier, limit); data != nil { + if data := dataFromLimit(limitIdentifier, limit); data != nil { rule.Data = data } return rule, nil } -func conditionsFromLimit(limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPRoute) ([]wasm.Condition, error) { +func conditionsFromLimit(limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPRoute) ([]Condition, error) { if limit == nil { return nil, errors.New("limit should not be nil") } - routeConditions := make([]wasm.Condition, 0) + routeConditions := make([]Condition, 0) if len(limit.RouteSelectors) > 0 { // build conditions from the rules selected by the route selectors @@ -105,7 +127,7 @@ func conditionsFromLimit(limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPR if len(routeConditions) > 0 { // merge the 'when' conditions into each route level one - mergedConditions := make([]wasm.Condition, len(routeConditions)) + mergedConditions := make([]Condition, len(routeConditions)) for _, when := range limit.When { for idx := range routeConditions { mergedCondition := routeConditions[idx] @@ -117,9 +139,9 @@ func conditionsFromLimit(limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPR } // build conditions only from the 'when' field - whenConditions := make([]wasm.Condition, len(limit.When)) + whenConditions := make([]Condition, len(limit.When)) for idx, when := range limit.When { - whenConditions[idx] = wasm.Condition{AllOf: []wasm.PatternExpression{patternExpresionFromWhen(when)}} + whenConditions[idx] = Condition{AllOf: []PatternExpression{patternExpresionFromWhen(when)}} } return whenConditions, nil } @@ -128,20 +150,20 @@ func conditionsFromLimit(limit *kuadrantv1beta2.Limit, route *gatewayapiv1.HTTPR // each combination of a rule match and hostname yields one condition // rules that specify no explicit match are assumed to match all request (i.e. implicit catch-all rule) // empty list of hostnames yields a condition without a hostname pattern expression -func conditionsFromRule(rule gatewayapiv1.HTTPRouteRule, hostnames []gatewayapiv1.Hostname) (conditions []wasm.Condition) { +func conditionsFromRule(rule gatewayapiv1.HTTPRouteRule, hostnames []gatewayapiv1.Hostname) (conditions []Condition) { if len(rule.Matches) == 0 { for _, hostname := range hostnames { if hostname == "*" { continue } - condition := wasm.Condition{AllOf: []wasm.PatternExpression{patternExpresionFromHostname(hostname)}} + condition := Condition{AllOf: []PatternExpression{patternExpresionFromHostname(hostname)}} conditions = append(conditions, condition) } return } for _, match := range rule.Matches { - condition := wasm.Condition{AllOf: patternExpresionsFromMatch(match)} + condition := Condition{AllOf: patternExpresionsFromMatch(match)} if len(hostnames) > 0 { for _, hostname := range hostnames { @@ -161,8 +183,8 @@ func conditionsFromRule(rule gatewayapiv1.HTTPRouteRule, hostnames []gatewayapiv return } -func patternExpresionsFromMatch(match gatewayapiv1.HTTPRouteMatch) []wasm.PatternExpression { - expressions := make([]wasm.PatternExpression, 0) +func patternExpresionsFromMatch(match gatewayapiv1.HTTPRouteMatch) []PatternExpression { + expressions := make([]PatternExpression, 0) if match.Path != nil { expressions = append(expressions, patternExpresionFromPathMatch(*match.Path)) @@ -177,10 +199,10 @@ func patternExpresionsFromMatch(match gatewayapiv1.HTTPRouteMatch) []wasm.Patter return expressions } -func patternExpresionFromPathMatch(pathMatch gatewayapiv1.HTTPPathMatch) wasm.PatternExpression { +func patternExpresionFromPathMatch(pathMatch gatewayapiv1.HTTPPathMatch) PatternExpression { var ( - operator = wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator) // default value - value = "/" // default value + operator = PatternOperator(kuadrantv1beta2.StartsWithOperator) // default value + value = "/" // default value ) if pathMatch.Value != nil { @@ -188,113 +210,59 @@ func patternExpresionFromPathMatch(pathMatch gatewayapiv1.HTTPPathMatch) wasm.Pa } if pathMatch.Type != nil { - if val, ok := wasm.PathMatchTypeMap[*pathMatch.Type]; ok { + if val, ok := PathMatchTypeMap[*pathMatch.Type]; ok { operator = val } } - return wasm.PatternExpression{ + return PatternExpression{ Selector: "request.url_path", Operator: operator, Value: value, } } -func patternExpresionFromMethod(method gatewayapiv1.HTTPMethod) wasm.PatternExpression { - return wasm.PatternExpression{ +func patternExpresionFromMethod(method gatewayapiv1.HTTPMethod) PatternExpression { + return PatternExpression{ Selector: "request.method", - Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Operator: PatternOperator(kuadrantv1beta2.EqualOperator), Value: string(method), } } -func patternExpresionFromHostname(hostname gatewayapiv1.Hostname) wasm.PatternExpression { +func patternExpresionFromHostname(hostname gatewayapiv1.Hostname) PatternExpression { value := string(hostname) operator := "eq" if strings.HasPrefix(value, "*.") { operator = "endswith" value = value[1:] } - return wasm.PatternExpression{ + return PatternExpression{ Selector: "request.host", - Operator: wasm.PatternOperator(operator), + Operator: PatternOperator(operator), Value: value, } } -func patternExpresionFromWhen(when kuadrantv1beta2.WhenCondition) wasm.PatternExpression { - return wasm.PatternExpression{ +func patternExpresionFromWhen(when kuadrantv1beta2.WhenCondition) PatternExpression { + return PatternExpression{ Selector: when.Selector, - Operator: wasm.PatternOperator(when.Operator), + Operator: PatternOperator(when.Operator), Value: when.Value, } } -func dataFromLimt(limitIdentifier string, limit *kuadrantv1beta2.Limit) (data []wasm.DataItem) { +func dataFromLimit(limitIdentifier string, limit *kuadrantv1beta2.Limit) (data []DataItem) { if limit == nil { return } // static key representing the limit - data = append(data, wasm.DataItem{Static: &wasm.StaticSpec{Key: limitIdentifier, Value: "1"}}) + data = append(data, DataItem{Static: &StaticSpec{Key: limitIdentifier, Value: "1"}}) for _, counter := range limit.Counters { - data = append(data, wasm.DataItem{Selector: &wasm.SelectorSpec{Selector: counter}}) + data = append(data, DataItem{Selector: &SelectorSpec{Selector: counter}}) } return data } - -func WASMPluginFromStruct(structure *_struct.Struct) (*wasm.Plugin, error) { - if structure == nil { - return nil, errors.New("cannot desestructure WASMPlugin from nil") - } - // Serialize struct into json - configJSON, err := structure.MarshalJSON() - if err != nil { - return nil, err - } - // Deserialize struct into PluginConfig struct - wasmPlugin := &wasm.Plugin{} - if err := json.Unmarshal(configJSON, wasmPlugin); err != nil { - return nil, err - } - - return wasmPlugin, nil -} - -type WasmRulesByDomain map[string][]wasm.Rule - -func WASMPluginMutator(existingObj, desiredObj client.Object) (bool, error) { - update := false - existing, ok := existingObj.(*istioclientgoextensionv1alpha1.WasmPlugin) - if !ok { - return false, fmt.Errorf("%T is not a *istioclientgoextensionv1alpha1.WasmPlugin", existingObj) - } - desired, ok := desiredObj.(*istioclientgoextensionv1alpha1.WasmPlugin) - if !ok { - return false, fmt.Errorf("%T is not a *istioclientgoextensionv1alpha1.WasmPlugin", desiredObj) - } - - existingWASMPlugin, err := WASMPluginFromStruct(existing.Spec.PluginConfig) - if err != nil { - return false, err - } - - desiredWASMPlugin, err := WASMPluginFromStruct(desired.Spec.PluginConfig) - if err != nil { - return false, err - } - - // TODO(eastizle): reflect.DeepEqual does not work well with lists without order - if !reflect.DeepEqual(desiredWASMPlugin, existingWASMPlugin) { - update = true - existing.Spec.PluginConfig = desired.Spec.PluginConfig - } - - return update, nil -} - -func WASMPluginName(gw *gatewayapiv1.Gateway) string { - return fmt.Sprintf("kuadrant-%s", gw.Name) -} diff --git a/pkg/rlptools/wasm_utils_test.go b/pkg/rlptools/wasm/utils_test.go similarity index 65% rename from pkg/rlptools/wasm_utils_test.go rename to pkg/rlptools/wasm/utils_test.go index be2a6f15c..a6485143a 100644 --- a/pkg/rlptools/wasm_utils_test.go +++ b/pkg/rlptools/wasm/utils_test.go @@ -1,21 +1,22 @@ //go:build unit -package rlptools +package wasm import ( + "regexp" "testing" "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" - "github.com/kuadrant/kuadrant-operator/pkg/rlptools/wasm" ) // TODO(eastizle): missing WASMPluginMutator tests // TODO(eastizle): missing TestWasmRules use cases tests. Only happy path -func TestWasmRules(t *testing.T) { +func TestRules(t *testing.T) { httpRoute := &gatewayapiv1.HTTPRoute{ Spec: gatewayapiv1.HTTPRouteSpec{ Hostnames: []gatewayapiv1.Hostname{ @@ -69,7 +70,7 @@ func TestWasmRules(t *testing.T) { name string rlp *kuadrantv1beta2.RateLimitPolicy route *gatewayapiv1.HTTPRoute - expectedRules []wasm.Rule + expectedRules []Rule }{ { name: "minimal RLP", @@ -79,27 +80,27 @@ func TestWasmRules(t *testing.T) { }, }), route: httpRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { - Conditions: []wasm.Condition{ + Conditions: []Condition{ { - AllOf: []wasm.PatternExpression{ + AllOf: []PatternExpression{ { Selector: "request.url_path", - Operator: wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator), + Operator: PatternOperator(kuadrantv1beta2.StartsWithOperator), Value: "/toy", }, { Selector: "request.method", - Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Operator: PatternOperator(kuadrantv1beta2.EqualOperator), Value: "GET", }, }, }, }, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps__36e9aa4c", Value: "1", }, @@ -124,32 +125,32 @@ func TestWasmRules(t *testing.T) { }, }), route: httpRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { - Conditions: []wasm.Condition{ + Conditions: []Condition{ { - AllOf: []wasm.PatternExpression{ + AllOf: []PatternExpression{ { Selector: "request.url_path", - Operator: wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator), + Operator: PatternOperator(kuadrantv1beta2.StartsWithOperator), Value: "/toy", }, { Selector: "request.method", - Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Operator: PatternOperator(kuadrantv1beta2.EqualOperator), Value: "GET", }, { Selector: "request.host", - Operator: wasm.PatternOperator(kuadrantv1beta2.EndsWithOperator), + Operator: PatternOperator(kuadrantv1beta2.EndsWithOperator), Value: ".example.com", }, }, }, }, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps_for_selected_hostnames__ac4044ab", Value: "1", }, @@ -179,27 +180,27 @@ func TestWasmRules(t *testing.T) { }, }), route: httpRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { - Conditions: []wasm.Condition{ + Conditions: []Condition{ { - AllOf: []wasm.PatternExpression{ + AllOf: []PatternExpression{ { Selector: "request.url_path", - Operator: wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator), + Operator: PatternOperator(kuadrantv1beta2.StartsWithOperator), Value: "/toy", }, { Selector: "request.method", - Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Operator: PatternOperator(kuadrantv1beta2.EqualOperator), Value: "GET", }, }, }, }, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps_for_selected_route__db289136", Value: "1", }, @@ -228,27 +229,27 @@ func TestWasmRules(t *testing.T) { }, }), route: httpRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { - Conditions: []wasm.Condition{ + Conditions: []Condition{ { - AllOf: []wasm.PatternExpression{ + AllOf: []PatternExpression{ { Selector: "request.url_path", - Operator: wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator), + Operator: PatternOperator(kuadrantv1beta2.StartsWithOperator), Value: "/toy", }, { Selector: "request.method", - Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Operator: PatternOperator(kuadrantv1beta2.EqualOperator), Value: "GET", }, }, }, }, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps_for_selected_path__38eb97a4", Value: "1", }, @@ -274,7 +275,7 @@ func TestWasmRules(t *testing.T) { }, }), route: httpRoute, - expectedRules: []wasm.Rule{}, + expectedRules: []Rule{}, }, { name: "HTTPRouteRules without rule matches", @@ -284,12 +285,12 @@ func TestWasmRules(t *testing.T) { }, }), route: catchAllHTTPRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { Conditions: nil, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps__783b9343", Value: "1", }, @@ -307,18 +308,18 @@ func TestWasmRules(t *testing.T) { }, }), route: catchAllHTTPRoute, - expectedRules: []wasm.Rule{ + expectedRules: []Rule{ { Conditions: nil, - Data: []wasm.DataItem{ + Data: []DataItem{ { - Static: &wasm.StaticSpec{ + Static: &StaticSpec{ Key: "limit.50rps_per_username__d681f6c3", Value: "1", }, }, { - Selector: &wasm.SelectorSpec{ + Selector: &SelectorSpec{ Selector: "auth.identity.username", }, }, @@ -330,10 +331,64 @@ func TestWasmRules(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - computedRules := WasmRules(tc.rlp, tc.route) + computedRules := Rules(tc.rlp, tc.route) if diff := cmp.Diff(tc.expectedRules, computedRules); diff != "" { t.Errorf("unexpected wasm rules (-want +got):\n%s", diff) } }) } } + +func TestLimitNameToLimitadorIdentifier(t *testing.T) { + testCases := []struct { + name string + rlpKey types.NamespacedName + uniqueLimitName string + expected *regexp.Regexp + }{ + { + name: "prepends the limitador limit identifier prefix", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, + uniqueLimitName: "foo", + expected: regexp.MustCompile(`^limit\.foo.+`), + }, + { + name: "sanitizes invalid chars", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, + uniqueLimitName: "my/limit-0", + expected: regexp.MustCompile(`^limit\.my_limit_0.+$`), + }, + { + name: "sanitizes the dot char (.) even though it is a valid char in limitador identifiers", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, + uniqueLimitName: "my.limit", + expected: regexp.MustCompile(`^limit\.my_limit.+$`), + }, + { + name: "appends a hash of the original name to avoid breaking uniqueness", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, + uniqueLimitName: "foo", + expected: regexp.MustCompile(`^.+__1da6e70a$`), + }, + { + name: "different rlp keys result in different identifiers", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpB"}, + uniqueLimitName: "foo", + expected: regexp.MustCompile(`^.+__2c1520b6$`), + }, + { + name: "empty string", + rlpKey: types.NamespacedName{Namespace: "testNS", Name: "rlpA"}, + uniqueLimitName: "", + expected: regexp.MustCompile(`^limit.__6d5e49dc$`), + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(subT *testing.T) { + identifier := LimitNameToLimitadorIdentifier(tc.rlpKey, tc.uniqueLimitName) + if !tc.expected.MatchString(identifier) { + subT.Errorf("identifier does not match, expected(%s), got (%s)", tc.expected, identifier) + } + }) + } +} diff --git a/tests/istio/rate_limiting_wasmplugin_controller_test.go b/tests/istio/rate_limiting_istio_wasmplugin_controller_test.go similarity index 93% rename from tests/istio/rate_limiting_wasmplugin_controller_test.go rename to tests/istio/rate_limiting_istio_wasmplugin_controller_test.go index b77e6e2bb..bfaa3d283 100644 --- a/tests/istio/rate_limiting_wasmplugin_controller_test.go +++ b/tests/istio/rate_limiting_istio_wasmplugin_controller_test.go @@ -20,6 +20,7 @@ import ( gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" kuadrantv1beta2 "github.com/kuadrant/kuadrant-operator/api/v1beta2" + "github.com/kuadrant/kuadrant-operator/controllers" "github.com/kuadrant/kuadrant-operator/pkg/common" "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" "github.com/kuadrant/kuadrant-operator/pkg/rlptools" @@ -123,7 +124,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, rlpKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey)).WithContext(ctx).Should(BeTrue()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err = testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -133,9 +134,9 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Expect(existingWasmPlugin.Spec.TargetRef.Group).To(Equal("gateway.networking.k8s.io")) Expect(existingWasmPlugin.Spec.TargetRef.Kind).To(Equal("Gateway")) Expect(existingWasmPlugin.Spec.TargetRef.Name).To(Equal(gateway.Name)) - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) Expect(err).ToNot(HaveOccurred()) - Expect(existingWASMConfig).To(Equal(&wasm.Plugin{ + Expect(existingWASMConfig).To(Equal(&wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -162,7 +163,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -287,13 +288,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, rlpKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey)).WithContext(ctx).Should(BeTrue()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err = testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) // must exist Expect(err).ToNot(HaveOccurred()) - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) Expect(err).ToNot(HaveOccurred()) Expect(existingWASMConfig.FailureMode).To(Equal(wasm.FailureModeDeny)) Expect(existingWASMConfig.RateLimitPolicies).To(HaveLen(1)) @@ -354,7 +355,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "toys"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "toys"), Value: "1", }, }, @@ -380,7 +381,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "assets"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "assets"), Value: "1", }, }, @@ -430,15 +431,15 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, rlpKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey)).WithContext(ctx).Should(BeTrue()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err = testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) // must exist Expect(err).ToNot(HaveOccurred()) - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) Expect(err).ToNot(HaveOccurred()) - Expect(existingWASMConfig).To(Equal(&wasm.Plugin{ + Expect(existingWASMConfig).To(Equal(&wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -465,7 +466,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -531,7 +532,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Expect(tests.RLPEnforcedCondition(ctx, testClient(), rlpKey, kuadrant.PolicyReasonUnknown, "RateLimitPolicy has encountered some issues: no free routes to enforce policy")) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} // Wait a bit to catch cases where wasmplugin is created and takes a bit to be created Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey), 20*time.Second, 5*time.Second).Should(BeFalse()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} @@ -610,7 +611,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, rlpKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} // Wait a bit to catch cases where wasmplugin is created and takes a bit to be created Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey), 20*time.Second, 5*time.Second).Should(BeFalse()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} @@ -739,7 +740,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -747,13 +748,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -780,7 +781,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpAKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpAKey, "l1"), Value: "1", }, }, @@ -887,7 +888,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -895,13 +896,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -928,7 +929,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -954,7 +955,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gwB), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gwB), Namespace: testNamespace} existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) if err == nil { @@ -984,7 +985,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // Check wasm plugin for gateway A no longer exists // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) if err == nil { @@ -1003,7 +1004,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // There is not RLP targeting Gateway B or any route parented by Gateway B // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gwB), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gwB), Namespace: testNamespace} existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) if err == nil { @@ -1082,7 +1083,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1090,13 +1091,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1123,7 +1124,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -1149,7 +1150,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gwB), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gwB), Namespace: testNamespace} existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) if err == nil { @@ -1179,7 +1180,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // Check wasm plugin for gateway A no longer exists // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) if err == nil { @@ -1198,7 +1199,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gwB), Namespace: testNamespace, + Name: controllers.WASMPluginName(gwB), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1206,13 +1207,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1239,7 +1240,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -1379,7 +1380,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1387,13 +1388,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1420,7 +1421,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -1458,7 +1459,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1466,13 +1467,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1499,7 +1500,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -1614,7 +1615,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1622,13 +1623,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1655,7 +1656,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlp1Key, "gatewaylimit"), + Key: wasm.LimitNameToLimitadorIdentifier(rlp1Key, "gatewaylimit"), Value: "1", }, }, @@ -1718,7 +1719,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1726,13 +1727,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1759,7 +1760,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), + Key: wasm.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), Value: "1", }, }, @@ -1908,7 +1909,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -1916,13 +1917,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -1949,7 +1950,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), + Key: wasm.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), Value: "1", }, }, @@ -2002,7 +2003,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // it may take some reconciliation loops to get to that, so checking it with eventually Eventually(func() bool { wasmPluginKey := client.ObjectKey{ - Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace, + Name: controllers.WASMPluginName(gateway), Namespace: testNamespace, } existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err := testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) @@ -2010,13 +2011,13 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { logf.Log.V(1).Info("wasmplugin not read", "key", wasmPluginKey, "error", err) return false } - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) if err != nil { logf.Log.V(1).Info("wasmplugin could not be deserialized", "key", wasmPluginKey, "error", err) return false } - expectedPlugin := &wasm.Plugin{ + expectedPlugin := &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { // First RLP 1 as the controller will sort based on RLP name @@ -2043,7 +2044,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlp1Key, "gatewaylimit"), + Key: wasm.LimitNameToLimitadorIdentifier(rlp1Key, "gatewaylimit"), Value: "1", }, }, @@ -2077,7 +2078,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), + Key: wasm.LimitNameToLimitadorIdentifier(rlp2Key, "routelimit"), Value: "1", }, }, @@ -2170,15 +2171,15 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, rlpKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey)).WithContext(ctx).Should(BeTrue()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} err = testClient().Get(ctx, wasmPluginKey, existingWasmPlugin) // must exist Expect(err).ToNot(HaveOccurred()) - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) Expect(err).ToNot(HaveOccurred()) - Expect(existingWASMConfig).To(Equal(&wasm.Plugin{ + Expect(existingWASMConfig).To(Equal(&wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -2205,7 +2206,7 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Data: []wasm.DataItem{ { Static: &wasm.StaticSpec{ - Key: rlptools.LimitNameToLimitadorIdentifier(rlpKey, "l1"), + Key: wasm.LimitNameToLimitadorIdentifier(rlpKey, "l1"), Value: "1", }, }, @@ -2236,8 +2237,8 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(tests.GatewayIsReady(ctx, testClient(), gateway)).WithContext(ctx).Should(BeTrue()) } - expectedWasmPluginConfig := func(rlpKey client.ObjectKey, rlp *kuadrantv1beta2.RateLimitPolicy, key, hostname string) *wasm.Plugin { - return &wasm.Plugin{ + expectedWasmPluginConfig := func(rlpKey client.ObjectKey, rlp *kuadrantv1beta2.RateLimitPolicy, key, hostname string) *wasm.Config { + return &wasm.Config{ FailureMode: wasm.FailureModeDeny, RateLimitPolicies: []wasm.RateLimitPolicy{ { @@ -2318,14 +2319,14 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { Eventually(assertPolicyIsAcceptedAndEnforced(ctx, gwRLPKey)).WithContext(ctx).Should(BeTrue()) // Check wasm plugin - wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + wasmPluginKey := client.ObjectKey{Name: controllers.WASMPluginName(gateway), Namespace: testNamespace} Eventually(tests.WasmPluginIsAvailable(ctx, testClient(), wasmPluginKey)).WithContext(ctx).Should(BeTrue()) existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} // must exist Expect(testClient().Get(ctx, wasmPluginKey, existingWasmPlugin)).To(Succeed()) - existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err := wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) Expect(err).ToNot(HaveOccurred()) - Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(gwRLPKey, gwRLP, rlptools.LimitNameToLimitadorIdentifier(gwRLPKey, "gateway"), "*"))) + Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(gwRLPKey, gwRLP, wasm.LimitNameToLimitadorIdentifier(gwRLPKey, "gateway"), "*"))) // Create Route RLP routeRLP := &kuadrantv1beta2.RateLimitPolicy{ @@ -2359,9 +2360,9 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // Wasm plugin config should now use route RLP limit key Eventually(func(g Gomega) { g.Expect(testClient().Get(ctx, wasmPluginKey, existingWasmPlugin)).To(Succeed()) - existingWASMConfig, err = rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err = wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(routeRLPKey, routeRLP, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "route"), "*.example.com"))) + g.Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(routeRLPKey, routeRLP, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "route"), "*.example.com"))) }).WithContext(ctx).Should(Succeed()) // Update GW RLP to overrides @@ -2376,9 +2377,9 @@ var _ = Describe("Rate Limiting WasmPlugin controller", Ordered, func() { // Wasm plugin config should now use GW RLP limit key for route Eventually(func(g Gomega) { g.Expect(testClient().Get(ctx, wasmPluginKey, existingWasmPlugin)).To(Succeed()) - existingWASMConfig, err = rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + existingWASMConfig, err = wasm.ConfigFromStruct(existingWasmPlugin.Spec.PluginConfig) g.Expect(err).ToNot(HaveOccurred()) - g.Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(routeRLPKey, routeRLP, rlptools.LimitNameToLimitadorIdentifier(routeRLPKey, "gateway"), "*.example.com"))) + g.Expect(existingWASMConfig).To(Equal(expectedWasmPluginConfig(routeRLPKey, routeRLP, wasm.LimitNameToLimitadorIdentifier(routeRLPKey, "gateway"), "*.example.com"))) }).WithContext(ctx).Should(Succeed()) }, testTimeOut)