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/12/08 07:21:59 UTC

[apisix-ingress-controller] branch master updated: feat: ingress annotations supports the specified upstream schema (#1451)

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 931ab069 feat: ingress annotations supports the specified upstream schema (#1451)
931ab069 is described below

commit 931ab0699ff1d5791484928492f101101365aee9
Author: seven dickens <la...@163.com>
AuthorDate: Thu Dec 8 15:21:54 2022 +0800

    feat: ingress annotations supports the specified upstream schema (#1451)
---
 docs/en/latest/concepts/annotations.md             |  26 ++++
 pkg/providers/ingress/translation/annotations.go   |   3 +
 .../ingress/translation/annotations/types.go       |   1 +
 .../annotations/upstreamscheme/upstreamscheme.go   |  44 ++++++
 .../upstreamscheme/upstreamscheme_test.go          |  43 ++++++
 pkg/providers/ingress/translation/translator.go    |   9 ++
 pkg/types/apisix/v1/types.go                       |   7 +
 test/e2e/suite-annotations/upstreamprotocol.go     | 161 +++++++++++++++++++++
 8 files changed, 294 insertions(+)

diff --git a/docs/en/latest/concepts/annotations.md b/docs/en/latest/concepts/annotations.md
index d7327907..230996de 100644
--- a/docs/en/latest/concepts/annotations.md
+++ b/docs/en/latest/concepts/annotations.md
@@ -294,3 +294,29 @@ spec:
                 port:
                   number: 80
 ```
+
+## Upstream scheme
+
+The scheme used when communicating with the Upstream. this value can be one of 'http', 'https', 'grpc', 'grpcs'. Defaults to 'http'.
+
+```yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/upstream-scheme: grpcs
+  name: ingress-v1
+spec:
+  rules:
+  - host: e2e.apisix.local
+    http:
+      paths:
+      - path: /helloworld.Greeter/SayHello
+        pathType: ImplementationSpecific
+        backend:
+          service:
+            name: test-backend-service-e2e-test
+            port:
+              number: 50053
+```
diff --git a/pkg/providers/ingress/translation/annotations.go b/pkg/providers/ingress/translation/annotations.go
index 008aab8e..b341dfc6 100644
--- a/pkg/providers/ingress/translation/annotations.go
+++ b/pkg/providers/ingress/translation/annotations.go
@@ -24,6 +24,7 @@ import (
 	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/plugins"
 	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/regex"
 	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/servicenamespace"
+	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/upstreamscheme"
 	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/websocket"
 	apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
@@ -35,6 +36,7 @@ type Ingress struct {
 	EnableWebSocket  bool
 	PluginConfigName string
 	ServiceNamespace string
+	UpstreamScheme   string
 }
 
 var (
@@ -44,6 +46,7 @@ var (
 		"EnableWebSocket":  websocket.NewParser(),
 		"PluginConfigName": pluginconfig.NewParser(),
 		"ServiceNamespace": servicenamespace.NewParser(),
+		"UpstreamScheme":   upstreamscheme.NewParser(),
 	}
 )
 
diff --git a/pkg/providers/ingress/translation/annotations/types.go b/pkg/providers/ingress/translation/annotations/types.go
index 89168f55..750c7df3 100644
--- a/pkg/providers/ingress/translation/annotations/types.go
+++ b/pkg/providers/ingress/translation/annotations/types.go
@@ -26,6 +26,7 @@ const (
 	AnnotationsUseRegex         = AnnotationsPrefix + "use-regex"
 	AnnotationsEnableWebSocket  = AnnotationsPrefix + "enable-websocket"
 	AnnotationsPluginConfigName = AnnotationsPrefix + "plugin-config-name"
+	AnnotationsUpstreamScheme   = AnnotationsPrefix + "upstream-scheme"
 )
 
 const (
diff --git a/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme.go b/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme.go
new file mode 100644
index 00000000..2e183c4f
--- /dev/null
+++ b/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme.go
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package upstreamscheme
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
+	apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+type upstreamscheme struct{}
+
+func NewParser() annotations.IngressAnnotationsParser {
+	return &upstreamscheme{}
+}
+
+func (w *upstreamscheme) Parse(e annotations.Extractor) (interface{}, error) {
+	scheme := strings.ToLower(e.GetStringAnnotation(annotations.AnnotationsUpstreamScheme))
+	_, ok := apisixv1.ValidSchemes[scheme]
+	if ok {
+		return scheme, nil
+	}
+
+	keys := make([]string, 0, len(apisixv1.ValidSchemes))
+	for key := range apisixv1.ValidSchemes {
+		keys = append(keys, key)
+	}
+
+	return nil, fmt.Errorf("scheme %s is not supported, Only { %s } are supported", scheme, strings.Join(keys, ", "))
+}
diff --git a/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme_test.go b/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme_test.go
new file mode 100644
index 00000000..1a762109
--- /dev/null
+++ b/pkg/providers/ingress/translation/annotations/upstreamscheme/upstreamscheme_test.go
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package upstreamscheme
+
+import (
+	"testing"
+
+	"github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIPRestrictionHandler(t *testing.T) {
+	anno := map[string]string{
+		annotations.AnnotationsUpstreamScheme: "grpcs",
+	}
+	u := NewParser()
+
+	out, err := u.Parse(annotations.NewExtractor(anno))
+	assert.Nil(t, err, "checking given error")
+	assert.Equal(t, "grpcs", out)
+
+	anno[annotations.AnnotationsUpstreamScheme] = "gRPC"
+	out, err = u.Parse(annotations.NewExtractor(anno))
+	assert.Nil(t, err, "checking given error")
+	assert.Equal(t, "grpc", out)
+
+	anno[annotations.AnnotationsUpstreamScheme] = "nothing"
+	out, err = u.Parse(annotations.NewExtractor(anno))
+	assert.NotNil(t, err, "checking given error")
+	assert.Nil(t, out, "checking given output")
+}
diff --git a/pkg/providers/ingress/translation/translator.go b/pkg/providers/ingress/translation/translator.go
index c5441af4..4a6e05ff 100644
--- a/pkg/providers/ingress/translation/translator.go
+++ b/pkg/providers/ingress/translation/translator.go
@@ -162,6 +162,9 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo
 						return nil, err
 					}
 				}
+				if ingress.UpstreamScheme != "" {
+					ups.Scheme = ingress.UpstreamScheme
+				}
 				ctx.AddUpstream(ups)
 			}
 			uris := []string{pathRule.Path}
@@ -264,6 +267,9 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski
 						return nil, err
 					}
 				}
+				if ingress.UpstreamScheme != "" {
+					ups.Scheme = ingress.UpstreamScheme
+				}
 				ctx.AddUpstream(ups)
 			}
 			uris := []string{pathRule.Path}
@@ -421,6 +427,9 @@ func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In
 						return nil, err
 					}
 				}
+				if ingress.UpstreamScheme != "" {
+					ups.Scheme = ingress.UpstreamScheme
+				}
 				ctx.AddUpstream(ups)
 			}
 			uris := []string{pathRule.Path}
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index 36caa318..cf7a2618 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -81,6 +81,13 @@ const (
 	DefaultUpstreamTimeout = 60
 )
 
+var ValidSchemes map[string]struct{} = map[string]struct{}{
+	SchemeHTTP:  {},
+	SchemeHTTPS: {},
+	SchemeGRPC:  {},
+	SchemeGRPCS: {},
+}
+
 // Metadata contains all meta information about resources.
 // +k8s:deepcopy-gen=true
 type Metadata struct {
diff --git a/test/e2e/suite-annotations/upstreamprotocol.go b/test/e2e/suite-annotations/upstreamprotocol.go
new file mode 100644
index 00000000..a8d7bd4a
--- /dev/null
+++ b/test/e2e/suite-annotations/upstreamprotocol.go
@@ -0,0 +1,161 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package annotations
+
+import (
+	"time"
+
+	ginkgo "github.com/onsi/ginkgo/v2"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("suite-annotations: annotations.networking/v1 upstream scheme", func() {
+	s := scaffold.NewDefaultScaffold()
+	ginkgo.It("sanity", func() {
+		ing := `
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/upstream-scheme: grpcs
+  name: ingress-v1
+spec:
+  rules:
+  - host: e2e.apisix.local
+    http:
+      paths:
+      - path: /helloworld.Greeter/SayHello
+        pathType: ImplementationSpecific
+        backend:
+          service:
+            name: test-backend-service-e2e-test
+            port:
+              number: 50053
+`
+		assert.NoError(ginkgo.GinkgoT(), s.CreateResourceFromString(ing))
+		err := s.EnsureNumApisixUpstreamsCreated(1)
+		assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+		time.Sleep(2 * time.Second)
+		ups, err := s.ListApisixUpstreams()
+		assert.Nil(ginkgo.GinkgoT(), err)
+		assert.Len(ginkgo.GinkgoT(), ups, 1)
+		assert.Equal(ginkgo.GinkgoT(), ups[0].Scheme, "grpcs")
+	})
+})
+
+var _ = ginkgo.Describe("suite-annotations-error: annotations.networking/v1 upstream scheme error", func() {
+	s := scaffold.NewDefaultScaffold()
+	ginkgo.It("sanity", func() {
+		ing := `
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/upstream-scheme: nothing
+  name: ingress-v1
+spec:
+  rules:
+  - host: e2e.apisix.local
+    http:
+      paths:
+      - path: /helloworld.Greeter/SayHello
+        pathType: ImplementationSpecific
+        backend:
+          service:
+            name: test-backend-service-e2e-test
+            port:
+              number: 50053
+`
+		assert.NoError(ginkgo.GinkgoT(), s.CreateResourceFromString(ing))
+		err := s.EnsureNumApisixUpstreamsCreated(1)
+		assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+		time.Sleep(2 * time.Second)
+		ups, err := s.ListApisixUpstreams()
+		assert.Nil(ginkgo.GinkgoT(), err)
+		assert.Len(ginkgo.GinkgoT(), ups, 1)
+		assert.Equal(ginkgo.GinkgoT(), ups[0].Scheme, "http")
+	})
+})
+
+var _ = ginkgo.Describe("suite-annotations: annotations.networking/v1beta1 upstream scheme", func() {
+	s := scaffold.NewDefaultScaffold()
+	ginkgo.It("sanity", func() {
+		ing := `
+apiVersion: networking.k8s.io/v1beta1
+kind: Ingress
+metadata:
+  name: ingress-v1beta1
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/upstream-scheme: grpcs
+spec:
+  rules:
+  - host: e2e.apisix.local
+    http:
+      paths:
+      - path: /helloworld.Greeter/SayHello
+        pathType: ImplementationSpecific
+        backend:
+          serviceName: test-backend-service-e2e-test
+          servicePort: 50053
+`
+		assert.NoError(ginkgo.GinkgoT(), s.CreateResourceFromString(ing))
+		err := s.EnsureNumApisixUpstreamsCreated(1)
+		assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+		time.Sleep(2 * time.Second)
+		ups, err := s.ListApisixUpstreams()
+		assert.Nil(ginkgo.GinkgoT(), err)
+		assert.Len(ginkgo.GinkgoT(), ups, 1)
+		assert.Equal(ginkgo.GinkgoT(), ups[0].Scheme, "grpcs")
+	})
+})
+
+var _ = ginkgo.Describe("suite-annotations: annotations.extensions/v1beta1 upstream scheme", func() {
+	s := scaffold.NewDefaultScaffold()
+	ginkgo.It("sanity", func() {
+		ing := `
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  annotations:
+    kubernetes.io/ingress.class: apisix
+    k8s.apisix.apache.org/upstream-scheme: grpcs
+  name: ingress-ext-v1beta1
+spec:
+  rules:
+  - host: e2e.apisix.local
+    http:
+      paths:
+      - path: /helloworld.Greeter/SayHello
+        pathType: ImplementationSpecific
+        backend:
+          serviceName: test-backend-service-e2e-test
+          servicePort: 50053
+`
+		assert.NoError(ginkgo.GinkgoT(), s.CreateResourceFromString(ing))
+		err := s.EnsureNumApisixUpstreamsCreated(1)
+		assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+		time.Sleep(2 * time.Second)
+		ups, err := s.ListApisixUpstreams()
+		assert.Nil(ginkgo.GinkgoT(), err)
+		assert.Len(ginkgo.GinkgoT(), ups, 1)
+		assert.Equal(ginkgo.GinkgoT(), ups[0].Scheme, "grpcs")
+	})
+})