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

kvn 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 8824bbd  chore: refactor the process of annotations (#443)
8824bbd is described below

commit 8824bbdf113bbf72649ccd5dc43af3a66773bf5b
Author: Alex Zhang <[email protected]>
AuthorDate: Fri May 14 11:15:45 2021 +0800

    chore: refactor the process of annotations (#443)
---
 docs/en/latest/concepts/annotations.md             |  55 ++++
 pkg/kube/translation/annotations.go                |  29 +-
 pkg/kube/translation/annotations/cors.go           |  47 ++--
 pkg/kube/translation/annotations/cors_test.go      |  46 ++++
 pkg/kube/translation/annotations/iprestriction.go  |  35 ++-
 .../translation/annotations/iprestriction_test.go  |  43 +++
 pkg/kube/translation/annotations/types.go          |  72 +++++
 pkg/kube/translation/apisix_route.go               |   2 +-
 pkg/kube/translation/ingress.go                    |  23 +-
 pkg/types/apisix/v1/plugin_types.go                |  49 ++++
 pkg/types/apisix/v1/types.go                       |  20 --
 pkg/types/apisix/v1/zz_generated.deepcopy.go       |  42 +++
 test/e2e/annotations/cors.go                       | 296 +++++++++++++++++++++
 test/e2e/annotations/iprestriction.go              | 119 +++++++++
 test/e2e/e2e.go                                    |   1 +
 15 files changed, 808 insertions(+), 71 deletions(-)

diff --git a/docs/en/latest/concepts/annotations.md 
b/docs/en/latest/concepts/annotations.md
new file mode 100644
index 0000000..c565c42
--- /dev/null
+++ b/docs/en/latest/concepts/annotations.md
@@ -0,0 +1,55 @@
+---
+title: Annotations
+---
+
+<!--
+#
+# 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.
+#
+-->
+
+This document describes all supported annotations and their functions. You can 
add these annotations in the 
[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) 
resources so that advanced features in [Apache 
APISIX](https://apisix.apache.org) can be combined into 
[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress) 
resources.
+
+> Note all keys and values of annotations are strings, so boolean value like 
`true` and `false` should be represented as `"true"` and `"false"`.
+
+CORS Support
+------------
+
+In order to enable 
[CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), the 
annotation `k8s.apisix.apache.org/enable-cors` should be set to `"true"`, also, 
there are some other annotations to customize the cors behavior.
+
+* `k8s.apisix.apache.org/cors-allow-origin`
+
+This annotation controls which origins will be allowed, multiple origins join 
together with `,`, for instance: `https://foo.com,http://bar.com:8080`
+
+Default value is `"*"`, which means all origins are allowed.
+
+* `k8s.apisix.apache.org/cors-allow-headers`
+
+This annotation controls which headers are accepted, multiple headers join 
together with `,`.
+
+Default is `"*"`, which means all headers are accepted.
+
+* `k8s.apisix.apache.org/cors-allow-methods`
+
+This annotation controls which methods are accepted, multiple methods join 
together with `,`.
+
+Default is `"*"`, which means all HTTP methods are accepted.
+
+Allowlist Source Range
+-----------------------
+
+You can specify the allowed client IP addresses or nets by the annotation 
`k8s.apisix.apache.org/allowlist-source-range`, multiple IP adddresses or nets 
join together with `,`,
+for instance, `k8s.apisix.apache.org/allowlist-source-range: 
10.0.5.0/16,127.0.0.1,192.168.3.98`. Default value is *empty*, which means the 
sources are unlimited.
diff --git a/pkg/kube/translation/annotations.go 
b/pkg/kube/translation/annotations.go
index 57a4c59..6d515ee 100644
--- a/pkg/kube/translation/annotations.go
+++ b/pkg/kube/translation/annotations.go
@@ -15,17 +15,34 @@
 package translation
 
 import (
+       "go.uber.org/zap"
+
        
"github.com/apache/apisix-ingress-controller/pkg/kube/translation/annotations"
+       "github.com/apache/apisix-ingress-controller/pkg/log"
        apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
 )
 
-func (t *translator) TranslateAnnotations(anno map[string]string) 
apisix.Plugins {
-       plugins := make(apisix.Plugins)
-       if cors := annotations.BuildCorsPlugin(anno); cors != nil {
-               plugins["cors"] = cors
+var (
+       _handlers = []annotations.Handler{
+               annotations.NewCorsHandler(),
+               annotations.NewIPRestrictionHandler(),
        }
-       if ipRestriction := annotations.BuildIpRestrictionPlugin(anno); 
ipRestriction != nil {
-               plugins["ip-restriction"] = ipRestriction
+)
+
+func (t *translator) translateAnnotations(anno map[string]string) 
apisix.Plugins {
+       extractor := annotations.NewExtractor(anno)
+       plugins := make(apisix.Plugins)
+       for _, handler := range _handlers {
+               out, err := handler.Handle(extractor)
+               if err != nil {
+                       log.Warnw("failed to handle annotations",
+                               zap.Error(err),
+                       )
+                       continue
+               }
+               if out != nil {
+                       plugins[handler.PluginName()] = out
+               }
        }
        return plugins
 }
diff --git a/pkg/kube/translation/annotations/cors.go 
b/pkg/kube/translation/annotations/cors.go
index 15bb1c6..51f8e87 100644
--- a/pkg/kube/translation/annotations/cors.go
+++ b/pkg/kube/translation/annotations/cors.go
@@ -14,37 +14,36 @@
 // limitations under the License.
 package annotations
 
-// CorsPlugin is the cors plugin.
-type CorsPlugin struct {
-       Origins string `json:"origins,omitempty"`
-       Headers string `json:"headers,omitempty"`
-       Methods string `json:"methods,omitempty"`
-       MaxAge  int64  `json:"max_age,omitempty"`
-}
+import (
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
 
-var (
+const (
        _enableCors       = "k8s.apisix.apache.org/enable-cors"
        _corsAllowOrigin  = "k8s.apisix.apache.org/cors-allow-origin"
        _corsAllowHeaders = "k8s.apisix.apache.org/cors-allow-headers"
        _corsAllowMethods = "k8s.apisix.apache.org/cors-allow-methods"
 )
 
-// BuildCorsPlugin build the cors plugin config body.
-func BuildCorsPlugin(annotations map[string]string) *CorsPlugin {
-       enable, ok := annotations[_enableCors]
-       if !ok || enable == "false" {
-               return nil
-       }
+type cors struct{}
 
-       var cors CorsPlugin
-       if ao, ok := annotations[_corsAllowOrigin]; ok {
-               cors.Origins = ao
-       }
-       if ah, ok := annotations[_corsAllowHeaders]; ok {
-               cors.Headers = ah
-       }
-       if am, ok := annotations[_corsAllowMethods]; ok {
-               cors.Methods = am
+// NewCorsHandler creates a handler to convert annotations about
+// cors to APISIX cors plugin.
+func NewCorsHandler() Handler {
+       return &cors{}
+}
+
+func (c *cors) PluginName() string {
+       return "cors"
+}
+
+func (c *cors) Handle(e Extractor) (interface{}, error) {
+       if !e.GetBoolAnnotation(_enableCors) {
+               return nil, nil
        }
-       return &cors
+       return &apisixv1.CorsConfig{
+               AllowOrigins: e.GetStringAnnotation(_corsAllowOrigin),
+               AllowMethods: e.GetStringAnnotation(_corsAllowMethods),
+               AllowHeaders: e.GetStringAnnotation(_corsAllowHeaders),
+       }, nil
 }
diff --git a/pkg/kube/translation/annotations/cors_test.go 
b/pkg/kube/translation/annotations/cors_test.go
new file mode 100644
index 0000000..d1b6b22
--- /dev/null
+++ b/pkg/kube/translation/annotations/cors_test.go
@@ -0,0 +1,46 @@
+// 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 (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+func TestCorsHandler(t *testing.T) {
+       annotations := map[string]string{
+               _enableCors:       "true",
+               _corsAllowHeaders: "abc,def",
+               _corsAllowOrigin:  "https://a.com";,
+               _corsAllowMethods: "GET,HEAD",
+       }
+       p := NewCorsHandler()
+       out, err := p.Handle(NewExtractor(annotations))
+       assert.Nil(t, err, "checking given error")
+       config := out.(*apisixv1.CorsConfig)
+       assert.Equal(t, config.AllowHeaders, "abc,def")
+       assert.Equal(t, config.AllowOrigins, "https://a.com";)
+       assert.Equal(t, config.AllowMethods, "GET,HEAD")
+
+       assert.Equal(t, p.PluginName(), "cors")
+
+       annotations[_enableCors] = "false"
+       out, err = p.Handle(NewExtractor(annotations))
+       assert.Nil(t, err, "checking given error")
+       assert.Nil(t, out, "checking given output")
+}
diff --git a/pkg/kube/translation/annotations/iprestriction.go 
b/pkg/kube/translation/annotations/iprestriction.go
index ddc7e02..73f98b5 100644
--- a/pkg/kube/translation/annotations/iprestriction.go
+++ b/pkg/kube/translation/annotations/iprestriction.go
@@ -14,23 +14,32 @@
 // limitations under the License.
 package annotations
 
-import "strings"
+import (
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
 
-var (
-       _whitelist = "k8s.apisix.apache.org/whitelist-source-range"
+const (
+       _allowlistSourceRange = "k8s.apisix.apache.org/allowlist-source-range"
 )
 
-// IpRestrictionPlugin is the ip-restriction plugin.
-type IpRestrictionPlugin struct {
-       Whitelist []string `json:"whitelist,omitempty"`
+type ipRestriction struct{}
+
+// NewIPRestrictionHandler creates a handler to convert
+// annotations about client ips control to APISIX ip-restrict plugin.
+func NewIPRestrictionHandler() Handler {
+       return &ipRestriction{}
+}
+
+func (i *ipRestriction) PluginName() string {
+       return "ip-restriction"
 }
 
-// BuildIpRestrictionPlugin builds the ip-restriction plugin from annotations.
-func BuildIpRestrictionPlugin(annotations map[string]string) 
*IpRestrictionPlugin {
-       if whitelist, ok := annotations[_whitelist]; ok {
-               return &IpRestrictionPlugin{
-                       Whitelist: strings.Split(whitelist, ","),
-               }
+func (i *ipRestriction) Handle(e Extractor) (interface{}, error) {
+       var plugin apisixv1.IPRestrictConfig
+       if allowlist := e.GetStringsAnnotation(_allowlistSourceRange); 
len(allowlist) > 0 {
+               plugin.Whitelist = allowlist
+       } else {
+               return nil, nil
        }
-       return nil
+       return &plugin, nil
 }
diff --git a/pkg/kube/translation/annotations/iprestriction_test.go 
b/pkg/kube/translation/annotations/iprestriction_test.go
new file mode 100644
index 0000000..a38f31e
--- /dev/null
+++ b/pkg/kube/translation/annotations/iprestriction_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 annotations
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+
+       apisixv1 
"github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1"
+)
+
+func TestIPRestrictionHandler(t *testing.T) {
+       annotations := map[string]string{
+               _allowlistSourceRange: "10.2.2.2,192.168.0.0/16",
+       }
+       p := NewIPRestrictionHandler()
+       out, err := p.Handle(NewExtractor(annotations))
+       assert.Nil(t, err, "checking given error")
+       config := out.(*apisixv1.IPRestrictConfig)
+       assert.Len(t, config.Whitelist, 2, "checking size of white list")
+       assert.Equal(t, config.Whitelist[0], "10.2.2.2")
+       assert.Equal(t, config.Whitelist[1], "192.168.0.0/16")
+
+       assert.Equal(t, p.PluginName(), "ip-restriction")
+
+       delete(annotations, _allowlistSourceRange)
+       out, err = p.Handle(NewExtractor(annotations))
+       assert.Nil(t, err, "checking given error")
+       assert.Nil(t, out, "checking the given ip-restrction plugin config")
+}
diff --git a/pkg/kube/translation/annotations/types.go 
b/pkg/kube/translation/annotations/types.go
new file mode 100644
index 0000000..3746759
--- /dev/null
+++ b/pkg/kube/translation/annotations/types.go
@@ -0,0 +1,72 @@
+// 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 (
+       "strings"
+)
+
+// Extractor encapsulates some auxiliary methods to extract annotations.
+type Extractor interface {
+       // GetStringAnnotation returns the string value of the target 
annotation.
+       // When the target annoatation is missing, empty string will be given.
+       GetStringAnnotation(string) string
+       // GetStringsAnnotation returns a string slice which splits the value 
of target
+       // annotation by the comma symbol. When the target annotation is 
missing, a nil
+       // slice will be given.
+       GetStringsAnnotation(string) []string
+       // GetBoolAnnotation returns a boolean value from the given annotation.
+       // When value is "true", true will be given, other values will be 
treated as
+       // false.
+       GetBoolAnnotation(string) bool
+}
+
+// Handler abstracts the behavior so that the apisix-ingress-controller knows
+// how to parse some annotations and convert them to APISIX plugins.
+type Handler interface {
+       // Handle parses the target annotation and converts it to the 
type-agnostic structure.
+       // The return value might be nil since some features have an explicit 
switch, users should
+       // judge whether Handle is failed by the second error value.
+       Handle(Extractor) (interface{}, error)
+       // PluginName returns a string which indicates the target plugin name 
in APISIX.
+       PluginName() string
+}
+
+type extractor struct {
+       annotations map[string]string
+}
+
+func (e *extractor) GetStringAnnotation(name string) string {
+       return e.annotations[name]
+}
+
+func (e *extractor) GetStringsAnnotation(name string) []string {
+       value := e.GetStringAnnotation(name)
+       if value == "" {
+               return nil
+       }
+       return strings.Split(e.annotations[name], ",")
+}
+
+func (e *extractor) GetBoolAnnotation(name string) bool {
+       return e.annotations[name] == "true"
+}
+
+// NewExtractor creates an annotations extractor.
+func NewExtractor(annotations map[string]string) Extractor {
+       return &extractor{
+               annotations: annotations,
+       }
+}
diff --git a/pkg/kube/translation/apisix_route.go 
b/pkg/kube/translation/apisix_route.go
index df5c9aa..dceda4f 100644
--- a/pkg/kube/translation/apisix_route.go
+++ b/pkg/kube/translation/apisix_route.go
@@ -31,7 +31,7 @@ func (t *translator) TranslateRouteV1(ar 
*configv1.ApisixRoute) (*TranslateConte
        ctx := &TranslateContext{
                upstreamMap: make(map[string]struct{}),
        }
-       plugins := t.TranslateAnnotations(ar.Annotations)
+       plugins := t.translateAnnotations(ar.Annotations)
 
        for _, r := range ar.Spec.Rules {
                for _, p := range r.Http.Paths {
diff --git a/pkg/kube/translation/ingress.go b/pkg/kube/translation/ingress.go
index 0590592..ab0ea6f 100644
--- a/pkg/kube/translation/ingress.go
+++ b/pkg/kube/translation/ingress.go
@@ -33,6 +33,7 @@ func (t *translator) translateIngressV1(ing 
*networkingv1.Ingress) (*TranslateCo
        ctx := &TranslateContext{
                upstreamMap: make(map[string]struct{}),
        }
+       plugins := t.translateAnnotations(ing.Annotations)
 
        for _, rule := range ing.Spec.Rules {
                for _, pathRule := range rule.HTTP.Paths {
@@ -75,6 +76,9 @@ func (t *translator) translateIngressV1(ing 
*networkingv1.Ingress) (*TranslateCo
                        route.ID = id.GenID(route.Name)
                        route.Host = rule.Host
                        route.Uris = uris
+                       if len(plugins) > 0 {
+                               route.Plugins = *(plugins.DeepCopy())
+                       }
                        if ups != nil {
                                route.UpstreamId = ups.ID
                        }
@@ -88,6 +92,7 @@ func (t *translator) translateIngressV1beta1(ing 
*networkingv1beta1.Ingress) (*T
        ctx := &TranslateContext{
                upstreamMap: make(map[string]struct{}),
        }
+       plugins := t.translateAnnotations(ing.Annotations)
 
        for _, rule := range ing.Spec.Rules {
                for _, pathRule := range rule.HTTP.Paths {
@@ -130,6 +135,9 @@ func (t *translator) translateIngressV1beta1(ing 
*networkingv1beta1.Ingress) (*T
                        route.ID = id.GenID(route.Name)
                        route.Host = rule.Host
                        route.Uris = uris
+                       if len(plugins) > 0 {
+                               route.Plugins = *(plugins.DeepCopy())
+                       }
                        if ups != nil {
                                route.UpstreamId = ups.ID
                        }
@@ -174,6 +182,7 @@ func (t *translator) translateIngressExtensionsV1beta1(ing 
*extensionsv1beta1.In
        ctx := &TranslateContext{
                upstreamMap: make(map[string]struct{}),
        }
+       plugins := t.translateAnnotations(ing.Annotations)
 
        for _, rule := range ing.Spec.Rules {
                for _, pathRule := range rule.HTTP.Paths {
@@ -212,14 +221,14 @@ func (t *translator) 
translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In
                                }
                                uris = append(uris, prefix)
                        }
-                       route := &apisixv1.Route{
-                               Metadata: apisixv1.Metadata{
-                                       Name: 
composeIngressRouteName(rule.Host, pathRule.Path),
-                               },
-                               Host: rule.Host,
-                               Uris: uris,
-                       }
+                       route := apisixv1.NewDefaultRoute()
+                       route.Name = composeIngressRouteName(rule.Host, 
pathRule.Path)
                        route.ID = id.GenID(route.Name)
+                       route.Host = rule.Host
+                       route.Uris = uris
+                       if len(plugins) > 0 {
+                               route.Plugins = *(plugins.DeepCopy())
+                       }
                        if ups != nil {
                                route.UpstreamId = ups.ID
                        }
diff --git a/pkg/types/apisix/v1/plugin_types.go 
b/pkg/types/apisix/v1/plugin_types.go
new file mode 100644
index 0000000..b1090db
--- /dev/null
+++ b/pkg/types/apisix/v1/plugin_types.go
@@ -0,0 +1,49 @@
+// 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 v1
+
+// TrafficSplitConfig is the config of traffic-split plugin.
+// +k8s:deepcopy-gen=true
+type TrafficSplitConfig struct {
+       Rules []TrafficSplitConfigRule `json:"rules"`
+}
+
+// TrafficSplitConfigRule is the rule config in traffic-split plugin config.
+// +k8s:deepcopy-gen=true
+type TrafficSplitConfigRule struct {
+       WeightedUpstreams []TrafficSplitConfigRuleWeightedUpstream 
`json:"weighted_upstreams"`
+}
+
+// TrafficSplitConfigRuleWeightedUpstream is the weighted upstream config in
+// the traffic split plugin rule.
+// +k8s:deepcopy-gen=true
+type TrafficSplitConfigRuleWeightedUpstream struct {
+       UpstreamID string `json:"upstream_id,omitempty"`
+       Weight     int    `json:"weight"`
+}
+
+// IPRestrictConfig is the rule config for ip-restriction plugin.
+// +k8s:deepcopy-gen=true
+type IPRestrictConfig struct {
+       Whitelist []string `json:"whitelist,omitempty"`
+}
+
+// CorsConfig is the rule config for cors plugin.
+// +k8s:deepcopy-gen=true
+type CorsConfig struct {
+       AllowOrigins string `json:"allow_origins,omitempty"`
+       AllowMethods string `json:"allow_methods,omitempty"`
+       AllowHeaders string `json:"allow_headers,omitempty"`
+}
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index 082beec..4dfc71f 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -303,26 +303,6 @@ type Ssl struct {
        Labels map[string]string `json:"labels,omitempty" 
yaml:"labels,omitempty"`
 }
 
-// TrafficSplitConfig is the config of traffic-split plugin.
-// +k8s:deepcopy-gen=true
-type TrafficSplitConfig struct {
-       Rules []TrafficSplitConfigRule `json:"rules"`
-}
-
-// TrafficSplitConfigRule is the rule config in traffic-split plugin config.
-// +k8s:deepcopy-gen=true
-type TrafficSplitConfigRule struct {
-       WeightedUpstreams []TrafficSplitConfigRuleWeightedUpstream 
`json:"weighted_upstreams"`
-}
-
-// TrafficSplitConfigRuleWeightedUpstream is the weighted upstream config in
-// the traffic split plugin rule.
-// +k8s:deepcopy-gen=true
-type TrafficSplitConfigRuleWeightedUpstream struct {
-       UpstreamID string `json:"upstream_id,omitempty"`
-       Weight     int    `json:"weight"`
-}
-
 // StreamRoute represents the stream_route object in APISIX.
 // +k8s:deepcopy-gen=true
 type StreamRoute struct {
diff --git a/pkg/types/apisix/v1/zz_generated.deepcopy.go 
b/pkg/types/apisix/v1/zz_generated.deepcopy.go
index a264ac0..b270fdb 100644
--- a/pkg/types/apisix/v1/zz_generated.deepcopy.go
+++ b/pkg/types/apisix/v1/zz_generated.deepcopy.go
@@ -21,6 +21,22 @@ limitations under the License.
 package v1
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *CorsConfig) DeepCopyInto(out *CorsConfig) {
+       *out = *in
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new CorsConfig.
+func (in *CorsConfig) DeepCopy() *CorsConfig {
+       if in == nil {
+               return nil
+       }
+       out := new(CorsConfig)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *GlobalRule) DeepCopyInto(out *GlobalRule) {
        *out = *in
        in.Plugins.DeepCopyInto(&out.Plugins)
@@ -38,6 +54,27 @@ func (in *GlobalRule) DeepCopy() *GlobalRule {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
+func (in *IPRestrictConfig) DeepCopyInto(out *IPRestrictConfig) {
+       *out = *in
+       if in.Whitelist != nil {
+               in, out := &in.Whitelist, &out.Whitelist
+               *out = make([]string, len(*in))
+               copy(*out, *in)
+       }
+       return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, 
creating a new IPRestrictConfig.
+func (in *IPRestrictConfig) DeepCopy() *IPRestrictConfig {
+       if in == nil {
+               return nil
+       }
+       out := new(IPRestrictConfig)
+       in.DeepCopyInto(out)
+       return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, 
writing into out. in must be non-nil.
 func (in *Metadata) DeepCopyInto(out *Metadata) {
        *out = *in
        if in.Labels != nil {
@@ -149,6 +186,11 @@ func (in *StreamRoute) DeepCopyInto(out *StreamRoute) {
                        (*out)[key] = val
                }
        }
+       if in.Upstream != nil {
+               in, out := &in.Upstream, &out.Upstream
+               *out = new(Upstream)
+               (*in).DeepCopyInto(*out)
+       }
        return
 }
 
diff --git a/test/e2e/annotations/cors.go b/test/e2e/annotations/cors.go
new file mode 100644
index 0000000..3c09eb2
--- /dev/null
+++ b/test/e2e/annotations/cors.go
@@ -0,0 +1,296 @@
+// 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 (
+       "fmt"
+       "net/http"
+       "time"
+
+       "github.com/onsi/ginkgo"
+       "github.com/stretchr/testify/assert"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("cors annotations", func() {
+       s := scaffold.NewDefaultScaffold()
+
+       ginkgo.It("enable 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/enable-cors: "true"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://baz.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               
resp.Header("Access-Control-Allow-Origin").Equal("https://foo.com";)
+               
resp.Header("Access-Control-Allow-Methods").Equal("GET,POST,PUT")
+               
resp.Header("Access-Control-Allow-Headers").Equal("x-foo-1,x-foo-2")
+       })
+
+       ginkgo.It("disable 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/enable-cors: "false"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+       })
+
+       ginkgo.It("enable 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/enable-cors: "true"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://baz.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               
resp.Header("Access-Control-Allow-Origin").Equal("https://foo.com";)
+               
resp.Header("Access-Control-Allow-Methods").Equal("GET,POST,PUT")
+               
resp.Header("Access-Control-Allow-Headers").Equal("x-foo-1,x-foo-2")
+       })
+
+       ginkgo.It("disable 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/enable-cors: "false"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+       })
+
+       ginkgo.It("enable 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/enable-cors: "true"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://baz.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+
+               resp = s.NewAPISIXClient().GET("/ip").WithHeader("Host", 
"httpbin.org").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               
resp.Header("Access-Control-Allow-Origin").Equal("https://foo.com";)
+               
resp.Header("Access-Control-Allow-Methods").Equal("GET,POST,PUT")
+               
resp.Header("Access-Control-Allow-Headers").Equal("x-foo-1,x-foo-2")
+       })
+
+       ginkgo.It("disable 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/enable-cors: "false"
+    k8s.apisix.apache.org/cors-allow-origin: https://foo.com,https://bar.com
+    k8s.apisix.apache.org/cors-allow-headers: x-foo-1,x-foo-2
+    k8s.apisix.apache.org/cors-allow-methods: GET,POST,PUT
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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").WithHeader("Origin", "https://foo.com";).Expect()
+               resp.Status(http.StatusOK)
+               // As httpbin itself adds this header, we don't check it here.
+               //resp.Header("Access-Control-Allow-Origin").Empty()
+               resp.Header("Access-Control-Allow-Methods").Empty()
+               resp.Header("Access-Control-Allow-Headers").Empty()
+       })
+})
diff --git a/test/e2e/annotations/iprestriction.go 
b/test/e2e/annotations/iprestriction.go
new file mode 100644
index 0000000..253b2bb
--- /dev/null
+++ b/test/e2e/annotations/iprestriction.go
@@ -0,0 +1,119 @@
+// 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 (
+       "fmt"
+       "net/http"
+       "time"
+
+       "github.com/onsi/ginkgo"
+       "github.com/stretchr/testify/assert"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("allowlist-source-range annotations", func() {
+       s := scaffold.NewDefaultScaffold()
+
+       ginkgo.It("enable 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/allowlist-source-range: "10.0.5.0/16"
+  name: ingress-v1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusForbidden)
+       })
+
+       ginkgo.It("enable 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/allowlist-source-range: "10.0.5.0/16"
+  name: ingress-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusForbidden)
+       })
+
+       ginkgo.It("enable 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/allowlist-source-range: "10.0.5.0/16"
+  name: ingress-extensions-v1beta1
+spec:
+  rules:
+  - host: httpbin.org
+    http:
+      paths:
+      - path: /ip
+        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.StatusForbidden)
+       })
+})
diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go
index d2ea114..8c5c597 100644
--- a/test/e2e/e2e.go
+++ b/test/e2e/e2e.go
@@ -15,6 +15,7 @@
 package e2e
 
 import (
+       _ "github.com/apache/apisix-ingress-controller/test/e2e/annotations"
        _ "github.com/apache/apisix-ingress-controller/test/e2e/endpoints"
        _ "github.com/apache/apisix-ingress-controller/test/e2e/features"
        _ "github.com/apache/apisix-ingress-controller/test/e2e/ingress"

Reply via email to