diff --git a/internal/controller/decoredirect_controller.go b/internal/controller/decoredirect_controller.go index 16a4482..718dce3 100644 --- a/internal/controller/decoredirect_controller.go +++ b/internal/controller/decoredirect_controller.go @@ -6,7 +6,6 @@ import ( "fmt" "net" "net/http" - "strconv" "strings" "time" @@ -137,11 +136,12 @@ func (r *DecoRedirectReconciler) reconcileIngress(ctx context.Context, rd *decos code = *rd.Spec.RedirectCode } - // nginx returns the configured redirect code (default 307) via the permanent-redirect annotation before reaching any backend. + // server-snippet injects a raw nginx return directive that preserves the full request path and + // query string via $request_uri. The permanent-redirect annotation cannot be used here because + // the nginx admission webhook rejects values containing nginx variables (e.g. $request_uri). _, err := controllerutil.CreateOrUpdate(ctx, r.Client, ingress, func() error { ingress.Annotations = map[string]string{ - "nginx.ingress.kubernetes.io/permanent-redirect": rd.Spec.To, - "nginx.ingress.kubernetes.io/permanent-redirect-code": strconv.Itoa(code), + "nginx.ingress.kubernetes.io/server-snippet": fmt.Sprintf("return %d %s$request_uri;", code, rd.Spec.To), } ingress.Spec = networkingv1.IngressSpec{ IngressClassName: &r.IngressClass, diff --git a/internal/controller/decoredirect_controller_test.go b/internal/controller/decoredirect_controller_test.go index a3846db..d66b0e1 100644 --- a/internal/controller/decoredirect_controller_test.go +++ b/internal/controller/decoredirect_controller_test.go @@ -71,7 +71,7 @@ var _ = Describe("DecoRedirect Controller", func() { Expect(cert.Spec.SecretName).To(Equal("tls-client-com")) }) - It("should create an Ingress with permanent-redirect annotation", func() { + It("should create an Ingress with server-snippet redirect preserving path", func() { _, err := newReconciler().Reconcile(ctx, reconcile.Request{NamespacedName: nn}) Expect(err).NotTo(HaveOccurred()) @@ -80,7 +80,7 @@ var _ = Describe("DecoRedirect Controller", func() { Name: "redirect-client-com", Namespace: rdNS, }, ing)).To(Succeed()) Expect(*ing.Spec.IngressClassName).To(Equal("nginx")) - Expect(ing.Annotations["nginx.ingress.kubernetes.io/permanent-redirect"]).To(Equal(toDomain)) + Expect(ing.Annotations["nginx.ingress.kubernetes.io/server-snippet"]).To(Equal("return 307 " + toDomain + "$request_uri;")) Expect(ing.Spec.TLS[0].Hosts).To(ContainElement(fromDomain)) Expect(ing.Spec.TLS[0].SecretName).To(Equal("tls-client-com")) Expect(ing.Spec.Rules[0].Host).To(Equal(fromDomain)) @@ -149,7 +149,7 @@ var _ = Describe("DecoRedirect Controller", func() { Expect(count).To(Equal(1)) }) - It("should set permanent-redirect-code to 307 by default", func() { + It("should use return 307 in server-snippet by default", func() { _, err := newReconciler().Reconcile(ctx, reconcile.Request{NamespacedName: nn}) Expect(err).NotTo(HaveOccurred()) @@ -157,10 +157,10 @@ var _ = Describe("DecoRedirect Controller", func() { Expect(k8sClient.Get(ctx, types.NamespacedName{ Name: "redirect-client-com", Namespace: rdNS, }, ing)).To(Succeed()) - Expect(ing.Annotations["nginx.ingress.kubernetes.io/permanent-redirect-code"]).To(Equal("307")) + Expect(ing.Annotations["nginx.ingress.kubernetes.io/server-snippet"]).To(ContainSubstring("return 307 ")) }) - It("should use redirectCode 301 in the Ingress annotation when specified", func() { + It("should use return 301 in server-snippet when redirectCode is 301", func() { code := 301 rd301 := &decositesv1alpha1.DecoRedirect{ ObjectMeta: metav1.ObjectMeta{Name: "test-redirect-301", Namespace: rdNS}, @@ -181,7 +181,7 @@ var _ = Describe("DecoRedirect Controller", func() { Expect(k8sClient.Get(ctx, types.NamespacedName{ Name: "redirect-redirect301-com", Namespace: rdNS, }, ing)).To(Succeed()) - Expect(ing.Annotations["nginx.ingress.kubernetes.io/permanent-redirect-code"]).To(Equal("301")) + Expect(ing.Annotations["nginx.ingress.kubernetes.io/server-snippet"]).To(ContainSubstring("return 301 ")) }) })