diff --git a/pkg/providers/ingress/translation/annotations.go b/pkg/providers/ingress/translation/annotations.go index 6b9d3d8155..7ddbeddf1f 100644 --- a/pkg/providers/ingress/translation/annotations.go +++ b/pkg/providers/ingress/translation/annotations.go @@ -15,40 +15,54 @@ package translation import ( + "github.com/imdario/mergo" "go.uber.org/zap" "github.com/apache/apisix-ingress-controller/pkg/log" "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations/pluginconfig" + "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/websocket" apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) +// Structure extracted by Ingress Resource +type Ingress struct { + Plugins apisix.Plugins + UseRegex bool + EnableWebSocket bool + PluginConfigName string +} + var ( - _handlers = []annotations.Handler{ - annotations.NewCorsHandler(), - annotations.NewIPRestrictionHandler(), - annotations.NewRewriteHandler(), - annotations.NewRedirectHandler(), - annotations.NewForwardAuthHandler(), - annotations.NewBasicAuthHandler(), - annotations.NewKeyAuthHandler(), - annotations.NewCSRFHandler(), + _parsers = map[string]annotations.IngressAnnotationsParser{ + "Plugins": plugins.NewParser(), + "UseRegex": regex.NewParser(), + "EnableWebSocket": websocket.NewParser(), + "PluginConfigName": pluginconfig.NewParser(), } ) -func (t *translator) TranslateAnnotations(anno map[string]string) apisix.Plugins { +func (t *translator) TranslateAnnotations(anno map[string]string) *Ingress { + ing := &Ingress{} extractor := annotations.NewExtractor(anno) - plugins := make(apisix.Plugins) - for _, handler := range _handlers { - out, err := handler.Handle(extractor) + data := make(map[string]interface{}) + for name, parser := range _parsers { + out, err := parser.Parse(extractor) if err != nil { - log.Warnw("failed to handle annotations", + log.Warnw("failed to parse annotations", zap.Error(err), ) continue } if out != nil { - plugins[handler.PluginName()] = out + data[name] = out } } - return plugins + err := mergo.MapWithOverwrite(ing, data) + if err != nil { + log.Errorw("unexpected error merging extracted annotations", zap.Error(err)) + } + return ing } diff --git a/pkg/providers/ingress/translation/annotations/pluginconfig/pluginconfig.go b/pkg/providers/ingress/translation/annotations/pluginconfig/pluginconfig.go new file mode 100644 index 0000000000..1847625aca --- /dev/null +++ b/pkg/providers/ingress/translation/annotations/pluginconfig/pluginconfig.go @@ -0,0 +1,29 @@ +// 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 pluginconfig + +import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" +) + +type pluginconfig struct{} + +func NewParser() annotations.IngressAnnotationsParser { + return &pluginconfig{} +} + +func (w *pluginconfig) Parse(e annotations.Extractor) (interface{}, error) { + return e.GetStringAnnotation(annotations.AnnotationsPluginConfigName), nil +} diff --git a/pkg/providers/ingress/translation/annotations/authorization.go b/pkg/providers/ingress/translation/annotations/plugins/authorization.go similarity index 74% rename from pkg/providers/ingress/translation/annotations/authorization.go rename to pkg/providers/ingress/translation/annotations/plugins/authorization.go index c97567a4a5..246e754a0e 100644 --- a/pkg/providers/ingress/translation/annotations/authorization.go +++ b/pkg/providers/ingress/translation/annotations/plugins/authorization.go @@ -12,22 +12,18 @@ // 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 +package plugins import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - // auth-type: keyAuth | basicAuth - _authType = AnnotationsPrefix + "auth-type" -) - type basicAuth struct{} // NewkeyBasicHandler creates a handler to convert // annotations about basicAuth control to APISIX basic-auth plugin. -func NewBasicAuthHandler() Handler { +func NewBasicAuthHandler() PluginAnnotationsHandler { return &basicAuth{} } @@ -35,8 +31,8 @@ func (b *basicAuth) PluginName() string { return "basic-auth" } -func (b *basicAuth) Handle(e Extractor) (interface{}, error) { - if e.GetStringAnnotation(_authType) != "basicAuth" { +func (b *basicAuth) Handle(e annotations.Extractor) (interface{}, error) { + if e.GetStringAnnotation(annotations.AnnotationsAuthType) != "basicAuth" { return nil, nil } plugin := apisixv1.BasicAuthConfig{} @@ -47,7 +43,7 @@ type keyAuth struct{} // NewkeyAuthHandler creates a handler to convert // annotations about keyAuth control to APISIX key-auth plugin. -func NewKeyAuthHandler() Handler { +func NewKeyAuthHandler() PluginAnnotationsHandler { return &keyAuth{} } @@ -55,8 +51,8 @@ func (k *keyAuth) PluginName() string { return "key-auth" } -func (k *keyAuth) Handle(e Extractor) (interface{}, error) { - if e.GetStringAnnotation(_authType) != "keyAuth" { +func (k *keyAuth) Handle(e annotations.Extractor) (interface{}, error) { + if e.GetStringAnnotation(annotations.AnnotationsAuthType) != "keyAuth" { return nil, nil } plugin := apisixv1.KeyAuthConfig{} diff --git a/pkg/providers/ingress/translation/annotations/cors.go b/pkg/providers/ingress/translation/annotations/plugins/cors.go similarity index 66% rename from pkg/providers/ingress/translation/annotations/cors.go rename to pkg/providers/ingress/translation/annotations/plugins/cors.go index ee88e6c40d..42d63b716a 100644 --- a/pkg/providers/ingress/translation/annotations/cors.go +++ b/pkg/providers/ingress/translation/annotations/plugins/cors.go @@ -12,24 +12,18 @@ // 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 +package plugins import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _enableCors = AnnotationsPrefix + "enable-cors" - _corsAllowOrigin = AnnotationsPrefix + "cors-allow-origin" - _corsAllowHeaders = AnnotationsPrefix + "cors-allow-headers" - _corsAllowMethods = AnnotationsPrefix + "cors-allow-methods" -) - type cors struct{} // NewCorsHandler creates a handler to convert annotations about // CORS to APISIX cors plugin. -func NewCorsHandler() Handler { +func NewCorsHandler() PluginAnnotationsHandler { return &cors{} } @@ -37,13 +31,13 @@ func (c *cors) PluginName() string { return "cors" } -func (c *cors) Handle(e Extractor) (interface{}, error) { - if !e.GetBoolAnnotation(_enableCors) { +func (c *cors) Handle(e annotations.Extractor) (interface{}, error) { + if !e.GetBoolAnnotation(annotations.AnnotationsEnableCors) { return nil, nil } return &apisixv1.CorsConfig{ - AllowOrigins: e.GetStringAnnotation(_corsAllowOrigin), - AllowMethods: e.GetStringAnnotation(_corsAllowMethods), - AllowHeaders: e.GetStringAnnotation(_corsAllowHeaders), + AllowOrigins: e.GetStringAnnotation(annotations.AnnotationsCorsAllowOrigin), + AllowMethods: e.GetStringAnnotation(annotations.AnnotationsCorsAllowMethods), + AllowHeaders: e.GetStringAnnotation(annotations.AnnotationsCorsAllowHeaders), }, nil } diff --git a/pkg/providers/ingress/translation/annotations/cors_test.go b/pkg/providers/ingress/translation/annotations/plugins/cors_test.go similarity index 72% rename from pkg/providers/ingress/translation/annotations/cors_test.go rename to pkg/providers/ingress/translation/annotations/plugins/cors_test.go index 342c0f2967..cf6a9f95a7 100644 --- a/pkg/providers/ingress/translation/annotations/cors_test.go +++ b/pkg/providers/ingress/translation/annotations/plugins/cors_test.go @@ -12,25 +12,26 @@ // 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 +package plugins import ( "testing" "github.com/stretchr/testify/assert" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" 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", + anno := map[string]string{ + annotations.AnnotationsEnableCors: "true", + annotations.AnnotationsCorsAllowHeaders: "abc,def", + annotations.AnnotationsCorsAllowOrigin: "https://a.com", + annotations.AnnotationsCorsAllowMethods: "GET,HEAD", } p := NewCorsHandler() - out, err := p.Handle(NewExtractor(annotations)) + out, err := p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") config := out.(*apisixv1.CorsConfig) assert.Equal(t, "abc,def", config.AllowHeaders) @@ -39,8 +40,8 @@ func TestCorsHandler(t *testing.T) { assert.Equal(t, "cors", p.PluginName()) - annotations[_enableCors] = "false" - out, err = p.Handle(NewExtractor(annotations)) + anno[annotations.AnnotationsEnableCors] = "false" + out, err = p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") assert.Nil(t, out, "checking given output") } diff --git a/pkg/providers/ingress/translation/annotations/csrf.go b/pkg/providers/ingress/translation/annotations/plugins/csrf.go similarity index 76% rename from pkg/providers/ingress/translation/annotations/csrf.go rename to pkg/providers/ingress/translation/annotations/plugins/csrf.go index d3cc087b5c..b8d595f5b5 100644 --- a/pkg/providers/ingress/translation/annotations/csrf.go +++ b/pkg/providers/ingress/translation/annotations/plugins/csrf.go @@ -12,22 +12,18 @@ // 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 +package plugins import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _enableCsrf = AnnotationsPrefix + "enable-csrf" - _csrfKey = AnnotationsPrefix + "csrf-key" -) - type csrf struct{} // NewCSRFHandler creates a handler to convert annotations about // CSRF to APISIX csrf plugin. -func NewCSRFHandler() Handler { +func NewCSRFHandler() PluginAnnotationsHandler { return &csrf{} } @@ -35,12 +31,12 @@ func (c *csrf) PluginName() string { return "csrf" } -func (c *csrf) Handle(e Extractor) (interface{}, error) { - if !e.GetBoolAnnotation(_enableCsrf) { +func (c *csrf) Handle(e annotations.Extractor) (interface{}, error) { + if !e.GetBoolAnnotation(annotations.AnnotationsEnableCsrf) { return nil, nil } var plugin apisixv1.CSRFConfig - plugin.Key = e.GetStringAnnotation(_csrfKey) + plugin.Key = e.GetStringAnnotation(annotations.AnnotationsCsrfKey) if plugin.Key != "" { return &plugin, nil } diff --git a/pkg/providers/ingress/translation/annotations/forward_auth.go b/pkg/providers/ingress/translation/annotations/plugins/forward_auth.go similarity index 61% rename from pkg/providers/ingress/translation/annotations/forward_auth.go rename to pkg/providers/ingress/translation/annotations/plugins/forward_auth.go index c55016d455..b5a7543f10 100644 --- a/pkg/providers/ingress/translation/annotations/forward_auth.go +++ b/pkg/providers/ingress/translation/annotations/plugins/forward_auth.go @@ -12,25 +12,18 @@ // 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 +package plugins import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _forwardAuthURI = AnnotationsPrefix + "auth-uri" - _forwardAuthSSLVerify = AnnotationsPrefix + "auth-ssl-verify" - _forwardAuthRequestHeaders = AnnotationsPrefix + "auth-request-headers" - _forwardAuthUpstreamHeaders = AnnotationsPrefix + "auth-upstream-headers" - _forwardAuthClientHeaders = AnnotationsPrefix + "auth-client-headers" -) - type forwardAuth struct{} // NewForwardAuthHandler creates a handler to convert // annotations about forward authentication to APISIX forward-auth plugin. -func NewForwardAuthHandler() Handler { +func NewForwardAuthHandler() PluginAnnotationsHandler { return &forwardAuth{} } @@ -38,19 +31,19 @@ func (i *forwardAuth) PluginName() string { return "forward-auth" } -func (i *forwardAuth) Handle(e Extractor) (interface{}, error) { - uri := e.GetStringAnnotation(_forwardAuthURI) +func (i *forwardAuth) Handle(e annotations.Extractor) (interface{}, error) { + uri := e.GetStringAnnotation(annotations.AnnotationsForwardAuthURI) sslVerify := true - if e.GetStringAnnotation(_forwardAuthSSLVerify) == "false" { + if e.GetStringAnnotation(annotations.AnnotationsForwardAuthSSLVerify) == "false" { sslVerify = false } if len(uri) > 0 { return &apisixv1.ForwardAuthConfig{ URI: uri, SSLVerify: sslVerify, - RequestHeaders: e.GetStringsAnnotation(_forwardAuthRequestHeaders), - UpstreamHeaders: e.GetStringsAnnotation(_forwardAuthUpstreamHeaders), - ClientHeaders: e.GetStringsAnnotation(_forwardAuthClientHeaders), + RequestHeaders: e.GetStringsAnnotation(annotations.AnnotationsForwardAuthRequestHeaders), + UpstreamHeaders: e.GetStringsAnnotation(annotations.AnnotationsForwardAuthUpstreamHeaders), + ClientHeaders: e.GetStringsAnnotation(annotations.AnnotationsForwardAuthClientHeaders), }, nil } diff --git a/pkg/providers/ingress/translation/annotations/forward_auth_test.go b/pkg/providers/ingress/translation/annotations/plugins/forward_auth_test.go similarity index 70% rename from pkg/providers/ingress/translation/annotations/forward_auth_test.go rename to pkg/providers/ingress/translation/annotations/plugins/forward_auth_test.go index 06c6c744bb..3ee6b0cfee 100644 --- a/pkg/providers/ingress/translation/annotations/forward_auth_test.go +++ b/pkg/providers/ingress/translation/annotations/plugins/forward_auth_test.go @@ -12,25 +12,26 @@ // 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 +package plugins import ( "testing" "github.com/stretchr/testify/assert" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) func TestForwardAuthHandler(t *testing.T) { - annotations := map[string]string{ - _forwardAuthURI: "http://127.0.0.1:9080", - _forwardAuthRequestHeaders: "Authorization", - _forwardAuthClientHeaders: "Location", - _forwardAuthUpstreamHeaders: "X-User-ID", + anno := map[string]string{ + annotations.AnnotationsForwardAuthURI: "http://127.0.0.1:9080", + annotations.AnnotationsForwardAuthRequestHeaders: "Authorization", + annotations.AnnotationsForwardAuthClientHeaders: "Location", + annotations.AnnotationsForwardAuthUpstreamHeaders: "X-User-ID", } p := NewForwardAuthHandler() - out, err := p.Handle(NewExtractor(annotations)) + out, err := p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") config := out.(*apisixv1.ForwardAuthConfig) assert.Equal(t, "http://127.0.0.1:9080", config.URI) @@ -40,14 +41,14 @@ func TestForwardAuthHandler(t *testing.T) { assert.Equal(t, true, config.SSLVerify) assert.Equal(t, "forward-auth", p.PluginName()) - annotations[_forwardAuthSSLVerify] = "false" - out, err = p.Handle(NewExtractor(annotations)) + anno[annotations.AnnotationsForwardAuthSSLVerify] = "false" + out, err = p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") config = out.(*apisixv1.ForwardAuthConfig) assert.Equal(t, false, config.SSLVerify) - annotations[_forwardAuthURI] = "" - out, err = p.Handle(NewExtractor(annotations)) + anno[annotations.AnnotationsForwardAuthURI] = "" + out, err = p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") assert.Nil(t, out, "checking given output") } diff --git a/pkg/providers/ingress/translation/annotations/iprestriction.go b/pkg/providers/ingress/translation/annotations/plugins/iprestriction.go similarity index 76% rename from pkg/providers/ingress/translation/annotations/iprestriction.go rename to pkg/providers/ingress/translation/annotations/plugins/iprestriction.go index 1d17957b68..f3a3bd6fe5 100644 --- a/pkg/providers/ingress/translation/annotations/iprestriction.go +++ b/pkg/providers/ingress/translation/annotations/plugins/iprestriction.go @@ -12,22 +12,18 @@ // 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 +package plugins import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _allowlistSourceRange = AnnotationsPrefix + "allowlist-source-range" - _blocklistSourceRange = AnnotationsPrefix + "blocklist-source-range" -) - type ipRestriction struct{} // NewIPRestrictionHandler creates a handler to convert // annotations about client ips control to APISIX ip-restrict plugin. -func NewIPRestrictionHandler() Handler { +func NewIPRestrictionHandler() PluginAnnotationsHandler { return &ipRestriction{} } @@ -35,10 +31,10 @@ func (i *ipRestriction) PluginName() string { return "ip-restriction" } -func (i *ipRestriction) Handle(e Extractor) (interface{}, error) { +func (i *ipRestriction) Handle(e annotations.Extractor) (interface{}, error) { var plugin apisixv1.IPRestrictConfig - allowlist := e.GetStringsAnnotation(_allowlistSourceRange) - blocklist := e.GetStringsAnnotation(_blocklistSourceRange) + allowlist := e.GetStringsAnnotation(annotations.AnnotationsAllowlistSourceRange) + blocklist := e.GetStringsAnnotation(annotations.AnnotationsBlocklistSourceRange) if allowlist != nil || blocklist != nil { plugin.Allowlist = allowlist plugin.Blocklist = blocklist diff --git a/pkg/providers/ingress/translation/annotations/iprestriction_test.go b/pkg/providers/ingress/translation/annotations/plugins/iprestriction_test.go similarity index 76% rename from pkg/providers/ingress/translation/annotations/iprestriction_test.go rename to pkg/providers/ingress/translation/annotations/plugins/iprestriction_test.go index cfc3fca738..56a0dff7cd 100644 --- a/pkg/providers/ingress/translation/annotations/iprestriction_test.go +++ b/pkg/providers/ingress/translation/annotations/plugins/iprestriction_test.go @@ -12,22 +12,23 @@ // 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 +package plugins import ( "testing" "github.com/stretchr/testify/assert" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" 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", + anno := map[string]string{ + annotations.AnnotationsAllowlistSourceRange: "10.2.2.2,192.168.0.0/16", } p := NewIPRestrictionHandler() - out, err := p.Handle(NewExtractor(annotations)) + out, err := p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") config := out.(*apisixv1.IPRestrictConfig) assert.Len(t, config.Allowlist, 2, "checking size of white list") @@ -35,8 +36,8 @@ func TestIPRestrictionHandler(t *testing.T) { assert.Equal(t, "192.168.0.0/16", config.Allowlist[1]) assert.Equal(t, "ip-restriction", p.PluginName()) - annotations[_blocklistSourceRange] = "172.17.0.0/16,127.0.0.1" - out, err = p.Handle(NewExtractor(annotations)) + anno[annotations.AnnotationsBlocklistSourceRange] = "172.17.0.0/16,127.0.0.1" + out, err = p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") config = out.(*apisixv1.IPRestrictConfig) assert.Len(t, config.Allowlist, 2, "checking size of white list") @@ -46,9 +47,9 @@ func TestIPRestrictionHandler(t *testing.T) { assert.Equal(t, "172.17.0.0/16", config.Blocklist[0]) assert.Equal(t, "127.0.0.1", config.Blocklist[1]) - delete(annotations, _allowlistSourceRange) - delete(annotations, _blocklistSourceRange) - out, err = p.Handle(NewExtractor(annotations)) + delete(anno, annotations.AnnotationsAllowlistSourceRange) + delete(anno, annotations.AnnotationsBlocklistSourceRange) + out, err = p.Handle(annotations.NewExtractor(anno)) assert.Nil(t, err, "checking given error") assert.Nil(t, out, "checking the given ip-restrction plugin config") } diff --git a/pkg/providers/ingress/translation/annotations/plugins/plugins.go b/pkg/providers/ingress/translation/annotations/plugins/plugins.go new file mode 100644 index 0000000000..b4a4fd1195 --- /dev/null +++ b/pkg/providers/ingress/translation/annotations/plugins/plugins.go @@ -0,0 +1,70 @@ +// 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 plugins + +import ( + "go.uber.org/zap" + + "github.com/apache/apisix-ingress-controller/pkg/log" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" + apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" +) + +// Handler abstracts the behavior so that the apisix-ingress-controller knows +// how to parse some annotations and convert them to APISIX plugins. +type PluginAnnotationsHandler 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(annotations.Extractor) (interface{}, error) + // PluginName returns a string which indicates the target plugin name in APISIX. + PluginName() string +} + +var ( + _handlers = []PluginAnnotationsHandler{ + NewCorsHandler(), + NewIPRestrictionHandler(), + NewRewriteHandler(), + NewRedirectHandler(), + NewForwardAuthHandler(), + NewBasicAuthHandler(), + NewKeyAuthHandler(), + NewCSRFHandler(), + } +) + +type plugins struct{} + +func NewParser() annotations.IngressAnnotationsParser { + return &plugins{} +} + +func (p *plugins) Parse(e annotations.Extractor) (interface{}, error) { + plugins := make(apisix.Plugins) + for _, handler := range _handlers { + out, err := handler.Handle(e) + if err != nil { + log.Warnw("failed to handle annotations", + zap.Error(err), + ) + continue + } + if out != nil { + plugins[handler.PluginName()] = out + } + } + return plugins, nil +} diff --git a/pkg/providers/ingress/translation/annotations/redirect.go b/pkg/providers/ingress/translation/annotations/plugins/redirect.go similarity index 77% rename from pkg/providers/ingress/translation/annotations/redirect.go rename to pkg/providers/ingress/translation/annotations/plugins/redirect.go index 6f2ca9af06..1f073e8587 100644 --- a/pkg/providers/ingress/translation/annotations/redirect.go +++ b/pkg/providers/ingress/translation/annotations/plugins/redirect.go @@ -12,26 +12,21 @@ // 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 +package plugins import ( "net/http" "strconv" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _httpToHttps = AnnotationsPrefix + "http-to-https" - _httpRedirect = AnnotationsPrefix + "http-redirect" - _httpRedirectCode = AnnotationsPrefix + "http-redirect-code" -) - type redirect struct{} // NewRedirectHandler creates a handler to convert // annotations about redirect control to APISIX redirect plugin. -func NewRedirectHandler() Handler { +func NewRedirectHandler() PluginAnnotationsHandler { return &redirect{} } @@ -39,12 +34,12 @@ func (r *redirect) PluginName() string { return "redirect" } -func (r *redirect) Handle(e Extractor) (interface{}, error) { +func (r *redirect) Handle(e annotations.Extractor) (interface{}, error) { var plugin apisixv1.RedirectConfig - plugin.HttpToHttps = e.GetBoolAnnotation(_httpToHttps) - plugin.URI = e.GetStringAnnotation(_httpRedirect) + plugin.HttpToHttps = e.GetBoolAnnotation(annotations.AnnotationsHttpToHttps) + plugin.URI = e.GetStringAnnotation(annotations.AnnotationsHttpRedirect) // Transformation fail defaults to 0. - plugin.RetCode, _ = strconv.Atoi(e.GetStringAnnotation(_httpRedirectCode)) + plugin.RetCode, _ = strconv.Atoi(e.GetStringAnnotation(annotations.AnnotationsHttpRedirectCode)) // To avoid empty redirect plugin config, adding the check about the redirect. if plugin.HttpToHttps { return &plugin, nil diff --git a/pkg/providers/ingress/translation/annotations/rewrite.go b/pkg/providers/ingress/translation/annotations/plugins/rewrite.go similarity index 74% rename from pkg/providers/ingress/translation/annotations/rewrite.go rename to pkg/providers/ingress/translation/annotations/plugins/rewrite.go index 35a0f9477e..b02e97a273 100644 --- a/pkg/providers/ingress/translation/annotations/rewrite.go +++ b/pkg/providers/ingress/translation/annotations/plugins/rewrite.go @@ -12,25 +12,20 @@ // 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 +package plugins import ( "regexp" + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) -const ( - _rewriteTarget = AnnotationsPrefix + "rewrite-target" - _rewriteTargetRegex = AnnotationsPrefix + "rewrite-target-regex" - _rewriteTargetRegexTemplate = AnnotationsPrefix + "rewrite-target-regex-template" -) - type rewrite struct{} // NewRewriteHandler creates a handler to convert // annotations about request rewrite control to APISIX proxy-rewrite plugin. -func NewRewriteHandler() Handler { +func NewRewriteHandler() PluginAnnotationsHandler { return &rewrite{} } @@ -38,11 +33,11 @@ func (i *rewrite) PluginName() string { return "proxy-rewrite" } -func (i *rewrite) Handle(e Extractor) (interface{}, error) { +func (i *rewrite) Handle(e annotations.Extractor) (interface{}, error) { var plugin apisixv1.RewriteConfig - rewriteTarget := e.GetStringAnnotation(_rewriteTarget) - rewriteTargetRegex := e.GetStringAnnotation(_rewriteTargetRegex) - rewriteTemplate := e.GetStringAnnotation(_rewriteTargetRegexTemplate) + rewriteTarget := e.GetStringAnnotation(annotations.AnnotationsRewriteTarget) + rewriteTargetRegex := e.GetStringAnnotation(annotations.AnnotationsRewriteTargetRegex) + rewriteTemplate := e.GetStringAnnotation(annotations.AnnotationsRewriteTargetRegexTemplate) if rewriteTarget != "" || rewriteTargetRegex != "" || rewriteTemplate != "" { plugin.RewriteTarget = rewriteTarget if rewriteTargetRegex != "" && rewriteTemplate != "" { diff --git a/pkg/providers/ingress/translation/annotations/regex/regex.go b/pkg/providers/ingress/translation/annotations/regex/regex.go new file mode 100644 index 0000000000..a791cf127a --- /dev/null +++ b/pkg/providers/ingress/translation/annotations/regex/regex.go @@ -0,0 +1,29 @@ +// 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 regex + +import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" +) + +type regex struct{} + +func NewParser() annotations.IngressAnnotationsParser { + return ®ex{} +} + +func (r *regex) Parse(e annotations.Extractor) (interface{}, error) { + return e.GetBoolAnnotation(annotations.AnnotationsUseRegex), nil +} diff --git a/pkg/providers/ingress/translation/annotations/types.go b/pkg/providers/ingress/translation/annotations/types.go index 4f8f6421f9..d6c2d80ec2 100644 --- a/pkg/providers/ingress/translation/annotations/types.go +++ b/pkg/providers/ingress/translation/annotations/types.go @@ -21,8 +21,60 @@ import ( const ( // AnnotationsPrefix is the apisix annotation prefix AnnotationsPrefix = "k8s.apisix.apache.org/" + + // Supported annotations + AnnotationsUseRegex = AnnotationsPrefix + "use-regex" + AnnotationsEnableWebSocket = AnnotationsPrefix + "enable-websocket" + AnnotationsPluginConfigName = AnnotationsPrefix + "plugin-config-name" +) + +const ( + // Supported the annotations of the APISIX plugins + + // cors plugin + AnnotationsEnableCors = AnnotationsPrefix + "enable-cors" + AnnotationsCorsAllowOrigin = AnnotationsPrefix + "cors-allow-origin" + AnnotationsCorsAllowHeaders = AnnotationsPrefix + "cors-allow-headers" + AnnotationsCorsAllowMethods = AnnotationsPrefix + "cors-allow-methods" + + // csrf plugin + AnnotationsEnableCsrf = AnnotationsPrefix + "enable-csrf" + AnnotationsCsrfKey = AnnotationsPrefix + "csrf-key" + + // redirect plugin + AnnotationsHttpToHttps = AnnotationsPrefix + "http-to-https" + AnnotationsHttpRedirect = AnnotationsPrefix + "http-redirect" + AnnotationsHttpRedirectCode = AnnotationsPrefix + "http-redirect-code" + + // rewrite plugin + AnnotationsRewriteTarget = AnnotationsPrefix + "rewrite-target" + AnnotationsRewriteTargetRegex = AnnotationsPrefix + "rewrite-target-regex" + AnnotationsRewriteTargetRegexTemplate = AnnotationsPrefix + "rewrite-target-regex-template" + + // forward-auth plugin + AnnotationsForwardAuthURI = AnnotationsPrefix + "auth-uri" + AnnotationsForwardAuthSSLVerify = AnnotationsPrefix + "auth-ssl-verify" + AnnotationsForwardAuthRequestHeaders = AnnotationsPrefix + "auth-request-headers" + AnnotationsForwardAuthUpstreamHeaders = AnnotationsPrefix + "auth-upstream-headers" + AnnotationsForwardAuthClientHeaders = AnnotationsPrefix + "auth-client-headers" + + // ip-restriction plugin + AnnotationsAllowlistSourceRange = AnnotationsPrefix + "allowlist-source-range" + AnnotationsBlocklistSourceRange = AnnotationsPrefix + "blocklist-source-range" + + // key-auth plugin and basic-auth plugin + // auth-type: keyAuth | basicAuth + AnnotationsAuthType = AnnotationsPrefix + "auth-type" ) +// Handler abstracts the behavior so that the apisix-ingress-controller knows +type IngressAnnotationsParser 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. + Parse(Extractor) (interface{}, error) +} + // Extractor encapsulates some auxiliary methods to extract annotations. type Extractor interface { // GetStringAnnotation returns the string value of the target annotation. @@ -38,17 +90,6 @@ type Extractor interface { 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 } diff --git a/pkg/providers/ingress/translation/annotations/websocket/websocket.go b/pkg/providers/ingress/translation/annotations/websocket/websocket.go new file mode 100644 index 0000000000..ef73329c23 --- /dev/null +++ b/pkg/providers/ingress/translation/annotations/websocket/websocket.go @@ -0,0 +1,29 @@ +// 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 websocket + +import ( + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" +) + +type websocket struct{} + +func NewParser() annotations.IngressAnnotationsParser { + return &websocket{} +} + +func (w *websocket) Parse(e annotations.Extractor) (interface{}, error) { + return e.GetBoolAnnotation(annotations.AnnotationsEnableWebSocket), nil +} diff --git a/pkg/providers/ingress/translation/annotations_test.go b/pkg/providers/ingress/translation/annotations_test.go new file mode 100644 index 0000000000..f82d52fdc8 --- /dev/null +++ b/pkg/providers/ingress/translation/annotations_test.go @@ -0,0 +1,74 @@ +// 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 translation + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" + apisix "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" +) + +func TestAnnotationsPlugins(t *testing.T) { + anno := map[string]string{ + annotations.AnnotationsAuthType: "basicAuth", + } + + ingress := (&translator{}).TranslateAnnotations(anno) + assert.Len(t, ingress.Plugins, 1) + assert.Equal(t, apisix.Plugins{ + "basic-auth": &apisix.BasicAuthConfig{}, + }, ingress.Plugins) + + anno[annotations.AnnotationsEnableCsrf] = "true" + anno[annotations.AnnotationsCsrfKey] = "csrf-key" + ingress = (&translator{}).TranslateAnnotations(anno) + assert.Len(t, ingress.Plugins, 2) + assert.Equal(t, apisix.Plugins{ + "basic-auth": &apisix.BasicAuthConfig{}, + "csrf": &apisix.CSRFConfig{ + Key: "csrf-key", + }, + }, ingress.Plugins) +} + +func TestAnnotationsPluginConfigName(t *testing.T) { + anno := map[string]string{ + annotations.AnnotationsPluginConfigName: "plugin-config-echo", + } + + ingress := (&translator{}).TranslateAnnotations(anno) + assert.Equal(t, "plugin-config-echo", ingress.PluginConfigName) +} + +func TestAnnotationsEnableWebSocket(t *testing.T) { + anno := map[string]string{ + annotations.AnnotationsEnableWebSocket: "true", + } + + ingress := (&translator{}).TranslateAnnotations(anno) + assert.Equal(t, true, ingress.EnableWebSocket) +} + +func TestAnnotationsUseRegex(t *testing.T) { + anno := map[string]string{ + annotations.AnnotationsUseRegex: "true", + } + + ingress := (&translator{}).TranslateAnnotations(anno) + assert.Equal(t, true, ingress.UseRegex) +} diff --git a/pkg/providers/ingress/translation/translator.go b/pkg/providers/ingress/translation/translator.go index 48b2a87dfa..5a7712a991 100644 --- a/pkg/providers/ingress/translation/translator.go +++ b/pkg/providers/ingress/translation/translator.go @@ -40,7 +40,6 @@ import ( apisixconst "github.com/apache/apisix-ingress-controller/pkg/kube/apisix/const" "github.com/apache/apisix-ingress-controller/pkg/log" apisixtranslation "github.com/apache/apisix-ingress-controller/pkg/providers/apisix/translation" - "github.com/apache/apisix-ingress-controller/pkg/providers/ingress/translation/annotations" "github.com/apache/apisix-ingress-controller/pkg/providers/translation" apisixv1 "github.com/apache/apisix-ingress-controller/pkg/types/apisix/v1" ) @@ -102,11 +101,7 @@ const ( func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bool) (*translation.TranslateContext, error) { ctx := translation.DefaultEmptyTranslateContext() - plugins := t.TranslateAnnotations(ing.Annotations) - annoExtractor := annotations.NewExtractor(ing.Annotations) - useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex") - enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket") - pluginConfigName := annoExtractor.GetStringAnnotation(annotations.AnnotationsPrefix + "plugin-config-name") + ingress := t.TranslateAnnotations(ing.Annotations) // add https for _, tls := range ing.Spec.TLS { @@ -179,7 +174,7 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo prefix += "/*" } uris = append(uris, prefix) - } else if *pathRule.PathType == networkingv1.PathTypeImplementationSpecific && useRegex { + } else if *pathRule.PathType == networkingv1.PathTypeImplementationSpecific && ingress.UseRegex { nginxVars = append(nginxVars, kubev2.ApisixRouteHTTPMatchExpr{ Subject: kubev2.ApisixRouteHTTPMatchExprSubject{ Scope: apisixconst.ScopePath, @@ -195,7 +190,7 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo route.ID = id.GenID(route.Name) route.Host = rule.Host route.Uris = uris - route.EnableWebsocket = enableWebsocket + route.EnableWebsocket = ingress.EnableWebSocket if len(nginxVars) > 0 { routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars) if err != nil { @@ -204,12 +199,12 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo route.Vars = routeVars route.Priority = _regexPriority } - if len(plugins) > 0 { - route.Plugins = *(plugins.DeepCopy()) + if len(ingress.Plugins) > 0 { + route.Plugins = *(ingress.Plugins.DeepCopy()) } - if pluginConfigName != "" { - route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)) + if ingress.PluginConfigName != "" { + route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, ingress.PluginConfigName)) } if ups != nil { route.UpstreamId = ups.ID @@ -222,11 +217,7 @@ func (t *translator) translateIngressV1(ing *networkingv1.Ingress, skipVerify bo func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, skipVerify bool) (*translation.TranslateContext, error) { ctx := translation.DefaultEmptyTranslateContext() - plugins := t.TranslateAnnotations(ing.Annotations) - annoExtractor := annotations.NewExtractor(ing.Annotations) - useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex") - enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket") - pluginConfigName := annoExtractor.GetStringAnnotation(annotations.AnnotationsPrefix + "plugin-config-name") + ingress := t.TranslateAnnotations(ing.Annotations) // add https for _, tls := range ing.Spec.TLS { @@ -299,7 +290,7 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski prefix += "/*" } uris = append(uris, prefix) - } else if *pathRule.PathType == networkingv1beta1.PathTypeImplementationSpecific && useRegex { + } else if *pathRule.PathType == networkingv1beta1.PathTypeImplementationSpecific && ingress.UseRegex { nginxVars = append(nginxVars, kubev2.ApisixRouteHTTPMatchExpr{ Subject: kubev2.ApisixRouteHTTPMatchExprSubject{ Scope: apisixconst.ScopePath, @@ -315,7 +306,7 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski route.ID = id.GenID(route.Name) route.Host = rule.Host route.Uris = uris - route.EnableWebsocket = enableWebsocket + route.EnableWebsocket = ingress.EnableWebSocket if len(nginxVars) > 0 { routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars) if err != nil { @@ -324,12 +315,12 @@ func (t *translator) translateIngressV1beta1(ing *networkingv1beta1.Ingress, ski route.Vars = routeVars route.Priority = _regexPriority } - if len(plugins) > 0 { - route.Plugins = *(plugins.DeepCopy()) + if len(ingress.Plugins) > 0 { + route.Plugins = *(ingress.Plugins.DeepCopy()) } - if pluginConfigName != "" { - route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)) + if ingress.PluginConfigName != "" { + route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, ingress.PluginConfigName)) } if ups != nil { route.UpstreamId = ups.ID @@ -396,11 +387,7 @@ func (t *translator) translateUpstreamFromIngressV1(namespace string, backend *n func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.Ingress, skipVerify bool) (*translation.TranslateContext, error) { ctx := translation.DefaultEmptyTranslateContext() - plugins := t.TranslateAnnotations(ing.Annotations) - annoExtractor := annotations.NewExtractor(ing.Annotations) - useRegex := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "use-regex") - enableWebsocket := annoExtractor.GetBoolAnnotation(annotations.AnnotationsPrefix + "enable-websocket") - pluginConfigName := annoExtractor.GetStringAnnotation(annotations.AnnotationsPrefix + "plugin-config-name") + ingress := t.TranslateAnnotations(ing.Annotations) for _, rule := range ing.Spec.Rules { for _, pathRule := range rule.HTTP.Paths { @@ -444,7 +431,7 @@ func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In prefix += "/*" } uris = append(uris, prefix) - } else if *pathRule.PathType == extensionsv1beta1.PathTypeImplementationSpecific && useRegex { + } else if *pathRule.PathType == extensionsv1beta1.PathTypeImplementationSpecific && ingress.UseRegex { nginxVars = append(nginxVars, kubev2.ApisixRouteHTTPMatchExpr{ Subject: kubev2.ApisixRouteHTTPMatchExprSubject{ Scope: apisixconst.ScopePath, @@ -460,7 +447,7 @@ func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In route.ID = id.GenID(route.Name) route.Host = rule.Host route.Uris = uris - route.EnableWebsocket = enableWebsocket + route.EnableWebsocket = ingress.EnableWebSocket if len(nginxVars) > 0 { routeVars, err := t.ApisixTranslator.TranslateRouteMatchExprs(nginxVars) if err != nil { @@ -469,12 +456,12 @@ func (t *translator) translateIngressExtensionsV1beta1(ing *extensionsv1beta1.In route.Vars = routeVars route.Priority = _regexPriority } - if len(plugins) > 0 { - route.Plugins = *(plugins.DeepCopy()) + if len(ingress.Plugins) > 0 { + route.Plugins = *(ingress.Plugins.DeepCopy()) } - if pluginConfigName != "" { - route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, pluginConfigName)) + if ingress.PluginConfigName != "" { + route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ing.Namespace, ingress.PluginConfigName)) } if ups != nil {