You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2022/05/11 03:25:54 UTC

[apisix-ingress-controller] branch master updated: feat: update an redirect annotation for ingress resource (#975)

This is an automated email from the ASF dual-hosted git repository.

zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git


The following commit(s) were added to refs/heads/master by this push:
     new 78efb006 feat: update an redirect annotation for  ingress resource (#975)
78efb006 is described below

commit 78efb006a4285a9c558cb50524478f944f849906
Author: Xin Rong <79...@users.noreply.github.com>
AuthorDate: Wed May 11 11:25:49 2022 +0800

    feat: update an redirect annotation for  ingress resource (#975)
---
 pkg/kube/translation/annotations/redirect.go |  17 ++-
 pkg/types/apisix/v1/plugin_types.go          |   4 +-
 test/e2e/suite-annotations/redirect.go       | 200 +++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 2 deletions(-)

diff --git a/pkg/kube/translation/annotations/redirect.go b/pkg/kube/translation/annotations/redirect.go
index c162d84a..6f2ca9af 100644
--- a/pkg/kube/translation/annotations/redirect.go
+++ b/pkg/kube/translation/annotations/redirect.go
@@ -15,11 +15,16 @@
 package annotations
 
 import (
+	"net/http"
+	"strconv"
+
 	apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
 const (
-	_httpToHttps = AnnotationsPrefix + "http-to-https"
+	_httpToHttps      = AnnotationsPrefix + "http-to-https"
+	_httpRedirect     = AnnotationsPrefix + "http-redirect"
+	_httpRedirectCode = AnnotationsPrefix + "http-redirect-code"
 )
 
 type redirect struct{}
@@ -37,9 +42,19 @@ func (r *redirect) PluginName() string {
 func (r *redirect) Handle(e Extractor) (interface{}, error) {
 	var plugin apisixv1.RedirectConfig
 	plugin.HttpToHttps = e.GetBoolAnnotation(_httpToHttps)
+	plugin.URI = e.GetStringAnnotation(_httpRedirect)
+	// Transformation fail defaults to 0.
+	plugin.RetCode, _ = strconv.Atoi(e.GetStringAnnotation(_httpRedirectCode))
 	// To avoid empty redirect plugin config, adding the check about the redirect.
 	if plugin.HttpToHttps {
 		return &plugin, nil
 	}
+	if plugin.URI != "" {
+		// Default is http.StatusMovedPermanently, the allowed value is between http.StatusMultipleChoices and http.StatusPermanentRedirect.
+		if plugin.RetCode < http.StatusMovedPermanently || plugin.RetCode > http.StatusPermanentRedirect {
+			plugin.RetCode = http.StatusMovedPermanently
+		}
+		return &plugin, nil
+	}
 	return nil, nil
 }
diff --git a/pkg/types/apisix/v1/plugin_types.go b/pkg/types/apisix/v1/plugin_types.go
index daf0c432..51346b78 100644
--- a/pkg/types/apisix/v1/plugin_types.go
+++ b/pkg/types/apisix/v1/plugin_types.go
@@ -85,7 +85,9 @@ type RewriteConfig struct {
 // RedirectConfig is the rule config for redirect plugin.
 // +k8s:deepcopy-gen=true
 type RedirectConfig struct {
-	HttpToHttps bool `json:"http_to_https,omitempty"`
+	HttpToHttps bool   `json:"http_to_https,omitempty"`
+	URI         string `json:"uri,omitempty"`
+	RetCode     int    `json:"ret_code,omitempty"`
 }
 
 // ForwardAuthConfig is the rule config for forward-auth plugin.
diff --git a/test/e2e/suite-annotations/redirect.go b/test/e2e/suite-annotations/redirect.go
index 02275117..6fade7d2 100644
--- a/test/e2e/suite-annotations/redirect.go
+++ b/test/e2e/suite-annotations/redirect.go
@@ -19,6 +19,7 @@ import (
 	"net/http"
 	"time"
 
+	"github.com/gavv/httpexpect/v2"
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 
@@ -119,4 +120,203 @@ spec:
 		resp.Status(http.StatusMovedPermanently)
 		resp.Header("Location").Equal("https://httpbin.org/sample")
 	})
+
+	ginkgo.It("redirect http-redirect in ingress networking/v1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "/anything$uri"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          service:
+            name: %s
+            port:
+              number: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		resp.Header("Location").Equal("/anything/ip")
+	})
+
+	ginkgo.It("redirect http-redirect in ingress networking/v1beta1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "/anything$uri"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		resp.Header("Location").Equal("/anything/ip")
+	})
+
+	ginkgo.It("redirect http-redirect in ingress extensions/v1beta1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "/anything$uri"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		resp.Header("Location").Equal("/anything/ip")
+	})
+
+	ginkgo.It("redirect http-redirect external link in ingress networking/v1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "https://httpbin.org/get"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          service:
+            name: %s
+            port:
+              number: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		url := resp.Header("Location").Equal("https://httpbin.org/get").Raw()
+
+		body := httpexpect.New(ginkgo.GinkgoT(), url).GET("").Expect().Status(http.StatusOK).Body().Raw()
+		assert.Contains(ginkgo.GinkgoT(), body, "https://httpbin.org/get")
+	})
+
+	ginkgo.It("redirect http-redirect external link in ingress networking/v1beta1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "https://httpbin.org/get"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		url := resp.Header("Location").Equal("https://httpbin.org/get").Raw()
+
+		body := httpexpect.New(ginkgo.GinkgoT(), url).GET("").Expect().Status(http.StatusOK).Body().Raw()
+		assert.Contains(ginkgo.GinkgoT(), body, "https://httpbin.org/get")
+	})
+
+	ginkgo.It("redirect http-redirect external link in ingress extensions/v1beta1", func() {
+		backendSvc, backendPort := s.DefaultHTTPBackend()
+		ing := fmt.Sprintf(`
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/http-redirect: "https://httpbin.org/get"
+    k8s.apisix.apache.org/http-redirect-code: "308"
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /*
+        pathType: Exact
+        backend:
+          serviceName: %s
+          servicePort: %d
+`, backendSvc, backendPort[0])
+		err := s.CreateResourceFromString(ing)
+		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
+		time.Sleep(5 * time.Second)
+
+		resp := s.NewAPISIXClient().GET("/ip").WithHeader("Host", "httpbin.org").Expect()
+		resp.Status(http.StatusPermanentRedirect)
+		url := resp.Header("Location").Equal("https://httpbin.org/get").Raw()
+
+		body := httpexpect.New(ginkgo.GinkgoT(), url).GET("").Expect().Status(http.StatusOK).Body().Raw()
+		assert.Contains(ginkgo.GinkgoT(), body, "https://httpbin.org/get")
+	})
 })