diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e26907066..d2739a08e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -78,7 +78,7 @@ jobs: - name: Create k8s Kind Cluster uses: helm/kind-action@v1.2.0 with: - version: v0.20.0 + version: v0.22.0 config: utils/kind-cluster.yaml cluster_name: ${{ env.KIND_CLUSTER_NAME }} wait: 120s diff --git a/Makefile b/Makefile index 4b5fe625d..b7895bf26 100644 --- a/Makefile +++ b/Makefile @@ -229,7 +229,7 @@ $(OPM): opm: $(OPM) ## Download opm locally if necessary. KIND = $(PROJECT_PATH)/bin/kind -KIND_VERSION = v0.20.0 +KIND_VERSION = v0.22.0 $(KIND): $(call go-install-tool,$(KIND),sigs.k8s.io/kind@$(KIND_VERSION)) diff --git a/controllers/ratelimitpolicy_controller_test.go b/controllers/ratelimitpolicy_controller_test.go index 8b65bb46e..5027a1e17 100644 --- a/controllers/ratelimitpolicy_controller_test.go +++ b/controllers/ratelimitpolicy_controller_test.go @@ -577,6 +577,116 @@ var _ = Describe("RateLimitPolicy controller", func() { }) }) + Context("RLP Defaults", func() { + It("HTTPRoute atomic default taking precedence over Gateway defaults", func(ctx SpecContext) { + // create httproute + httpRoute := testBuildBasicHttpRoute(routeName, gwName, testNamespace, []string{"*.example.com"}) + Expect(k8sClient.Create(ctx, httpRoute)).To(Succeed()) + Eventually(testRouteIsAccepted(client.ObjectKeyFromObject(httpRoute))).WithContext(ctx).Should(BeTrue()) + + // create GW RLP + gwRLP := policyFactory(func(policy *kuadrantv1beta2.RateLimitPolicy) { + policy.Spec.TargetRef.Kind = "Gateway" + policy.Spec.TargetRef.Name = gatewayapiv1.ObjectName(gwName) + }) + Expect(k8sClient.Create(ctx, gwRLP)).To(Succeed()) + rlpKey := client.ObjectKey{Name: gwRLP.Name, Namespace: testNamespace} + Eventually(testRLPIsAccepted(rlpKey)).WithContext(ctx).Should(BeTrue()) + + // Create HTTPRoute RLP with new default limits + routeRLP := policyFactory(func(policy *kuadrantv1beta2.RateLimitPolicy) { + policy.Name = "httproute-rlp" + policy.Spec.Defaults.Limits = map[string]kuadrantv1beta2.Limit{ + "l1": { + Rates: []kuadrantv1beta2.Rate{ + { + Limit: 10, Duration: 5, Unit: kuadrantv1beta2.TimeUnit("second"), + }, + }, + }, + } + }) + Expect(k8sClient.Create(ctx, routeRLP)).To(Succeed()) + rlpKey = client.ObjectKey{Name: routeRLP.Name, Namespace: testNamespace} + Eventually(testRLPIsAccepted(rlpKey)).WithContext(ctx).Should(BeTrue()) + + // Check Gateway direct back reference + gwKey := client.ObjectKeyFromObject(gateway) + existingGateway := &gatewayapiv1.Gateway{} + Expect(k8sClient.Get(ctx, gwKey, existingGateway)).To(Succeed()) + Expect(existingGateway.GetAnnotations()).To(HaveKeyWithValue( + gwRLP.DirectReferenceAnnotationName(), client.ObjectKeyFromObject(gwRLP).String())) + + // check limits + limitadorKey := client.ObjectKey{Name: common.LimitadorName, Namespace: testNamespace} + existingLimitador := &limitadorv1alpha1.Limitador{} + Expect(k8sClient.Get(ctx, limitadorKey, existingLimitador)).To(Succeed()) + Expect(existingLimitador.Spec.Limits).To(ContainElements(limitadorv1alpha1.RateLimit{ + MaxValue: 10, + Seconds: 5, + Namespace: rlptools.LimitsNamespaceFromRLP(routeRLP), + Conditions: []string{`limit.l1__2804bad6 == "1"`}, + Variables: []string{}, + Name: rlptools.LimitsNameFromRLP(routeRLP), + })) + + // Check wasm plugin + wasmPluginKey := client.ObjectKey{Name: rlptools.WASMPluginName(gateway), Namespace: testNamespace} + Eventually(testWasmPluginIsAvailable(wasmPluginKey)).WithContext(ctx).Should(BeTrue()) + existingWasmPlugin := &istioclientgoextensionv1alpha1.WasmPlugin{} + Expect(k8sClient.Get(ctx, wasmPluginKey, existingWasmPlugin)).To(Succeed()) + existingWASMConfig, err := rlptools.WASMPluginFromStruct(existingWasmPlugin.Spec.PluginConfig) + Expect(err).ToNot(HaveOccurred()) + Expect(existingWASMConfig).To(Equal(&wasm.Plugin{ + FailureMode: wasm.FailureModeDeny, + RateLimitPolicies: []wasm.RateLimitPolicy{ + { + Name: rlpKey.String(), + Domain: rlptools.LimitsNamespaceFromRLP(routeRLP), + Rules: []wasm.Rule{ + { + Conditions: []wasm.Condition{ + { + AllOf: []wasm.PatternExpression{ + { + Selector: "request.url_path", + Operator: wasm.PatternOperator(kuadrantv1beta2.StartsWithOperator), + Value: "/toy", + }, + { + Selector: "request.method", + Operator: wasm.PatternOperator(kuadrantv1beta2.EqualOperator), + Value: "GET", + }, + }, + }, + }, + Data: []wasm.DataItem{ + { + Static: &wasm.StaticSpec{ + Key: `limit.l1__2804bad6`, + Value: "1", + }, + }, + }, + }, + }, + Hostnames: []string{"*.example.com"}, + Service: common.KuadrantRateLimitClusterName, + }, + }, + })) + + // Gateway should contain HTTPRoute RLP in backreference + Expect(k8sClient.Get(ctx, gwKey, existingGateway)).To(Succeed()) + serialized, err := json.Marshal(rlpKey) + Expect(err).ToNot(HaveOccurred()) + Expect(existingGateway.GetAnnotations()).To(HaveKey(routeRLP.BackReferenceAnnotationName())) + Expect(existingGateway.GetAnnotations()[routeRLP.BackReferenceAnnotationName()]).To(ContainSubstring(string(serialized))) + + }, SpecTimeout(1*time.Minute)) + }) + Context("RLP accepted condition reasons", func() { assertAcceptedConditionFalse := func(rlp *kuadrantv1beta2.RateLimitPolicy, reason, message string) func() bool { return func() bool { diff --git a/doc/development.md b/doc/development.md index 1e2f1dc35..6aa6f4a62 100644 --- a/doc/development.md +++ b/doc/development.md @@ -3,7 +3,7 @@ ## Technology stack required for development * [operator-sdk] version v1.28.1 -* [kind] version v0.20.0 +* [kind] version v0.22.0 * [git][git_tool] * [go] version 1.21+ * [kubernetes] version v1.19+ diff --git a/utils/kind-cluster.yaml b/utils/kind-cluster.yaml index 4697238ef..ba3d385d3 100644 --- a/utils/kind-cluster.yaml +++ b/utils/kind-cluster.yaml @@ -3,4 +3,4 @@ kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - image: kindest/node:v1.27.3 + image: kindest/node:v1.29.2