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 2023/01/29 07:26:27 UTC

[apisix-ingress-controller] branch master updated: feat: add support for filter_func for ApisixRoute (#1545)

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 123d080d feat: add support for filter_func for ApisixRoute (#1545)
123d080d is described below

commit 123d080d4e92e7becb95da0835e7775365a71d2a
Author: Aryan <75...@users.noreply.github.com>
AuthorDate: Sun Jan 29 12:56:22 2023 +0530

    feat: add support for filter_func for ApisixRoute (#1545)
    
    Signed-off-by: Aryan <75...@users.noreply.github.com>
---
 pkg/kube/apisix/apis/config/v2/types.go          |  4 ++
 pkg/providers/apisix/translation/apisix_route.go |  3 +
 pkg/types/apisix/v1/types.go                     |  1 +
 samples/deploy/crd/v1/ApisixRoute.yaml           |  2 +
 test/e2e/suite-features/route_filter_func.go     | 79 ++++++++++++++++++++++++
 5 files changed, 89 insertions(+)

diff --git a/pkg/kube/apisix/apis/config/v2/types.go b/pkg/kube/apisix/apis/config/v2/types.go
index a4a43fbb..5bab54d8 100644
--- a/pkg/kube/apisix/apis/config/v2/types.go
+++ b/pkg/kube/apisix/apis/config/v2/types.go
@@ -131,6 +131,10 @@ type ApisixRouteHTTPMatch struct {
 	//       - "127.0.0.1"
 	//       - "10.0.5.11"
 	NginxVars []ApisixRouteHTTPMatchExpr `json:"exprs,omitempty" yaml:"exprs,omitempty"`
+	// Matches based on a user-defined filtering function.
+	// These functions can accept an input parameter `vars`
+	// which can be used to access the Nginx variables.
+	FilterFunc string `json:"filter_func,omitempty" yaml:"filter_func,omitempty"`
 }
 
 // ApisixRouteHTTPMatchExpr represents a binary route match expression .
diff --git a/pkg/providers/apisix/translation/apisix_route.go b/pkg/providers/apisix/translation/apisix_route.go
index 2706f0f8..6d1c3f26 100644
--- a/pkg/providers/apisix/translation/apisix_route.go
+++ b/pkg/providers/apisix/translation/apisix_route.go
@@ -325,9 +325,12 @@ func (t *translator) translateHTTPRouteV2(ctx *translation.TranslateContext, ar
 		route.EnableWebsocket = part.Websocket
 		route.Plugins = pluginMap
 		route.Timeout = timeout
+		route.FilterFunc = part.Match.FilterFunc
+
 		if part.PluginConfigName != "" {
 			route.PluginConfigId = id.GenID(apisixv1.ComposePluginConfigName(ar.Namespace, part.PluginConfigName))
 		}
+
 		for k, v := range ar.ObjectMeta.Labels {
 			route.Metadata.Labels[k] = v
 		}
diff --git a/pkg/types/apisix/v1/types.go b/pkg/types/apisix/v1/types.go
index cf7a2618..e59a2f19 100644
--- a/pkg/types/apisix/v1/types.go
+++ b/pkg/types/apisix/v1/types.go
@@ -115,6 +115,7 @@ type Route struct {
 	UpstreamId      string           `json:"upstream_id,omitempty" yaml:"upstream_id,omitempty"`
 	Plugins         Plugins          `json:"plugins,omitempty" yaml:"plugins,omitempty"`
 	PluginConfigId  string           `json:"plugin_config_id,omitempty" yaml:"plugin_config_id,omitempty"`
+	FilterFunc      string           `json:"filter_func,omitempty" yaml:"filter_func,omitempty"`
 }
 
 // Vars represents the route match expressions of APISIX.
diff --git a/samples/deploy/crd/v1/ApisixRoute.yaml b/samples/deploy/crd/v1/ApisixRoute.yaml
index e241bd5a..4d1f9870 100644
--- a/samples/deploy/crd/v1/ApisixRoute.yaml
+++ b/samples/deploy/crd/v1/ApisixRoute.yaml
@@ -450,6 +450,8 @@ spec:
                               oneOf:
                                 - required: ["subject", "op", "value"]
                                 - required: ["subject", "op", "set"]
+                          filter_func:
+                            type: string
                       websocket:
                         type: boolean
                       plugin_config_name:
diff --git a/test/e2e/suite-features/route_filter_func.go b/test/e2e/suite-features/route_filter_func.go
new file mode 100644
index 00000000..95c1d710
--- /dev/null
+++ b/test/e2e/suite-features/route_filter_func.go
@@ -0,0 +1,79 @@
+// 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 features
+
+import (
+	"fmt"
+	"net/http"
+
+	ginkgo "github.com/onsi/ginkgo/v2"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = ginkgo.Describe("suite-features: filter_func", func() {
+	suites := func(scaffoldFunc func() *scaffold.Scaffold) {
+		s := scaffoldFunc()
+		ginkgo.It("filter using body", func() {
+			backendSvc, backendPorts := s.DefaultHTTPBackend()
+			ar := fmt.Sprintf(`
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+ name: httpbin-route
+spec:
+ http:
+ - name: rule1
+   match:
+     hosts:
+     - httpbin.org
+     paths:
+       - /ip
+     filter_func: "function(vars)\n  local core = require ('apisix.core')\n  local body, err = core.request.get_body()\n  if not body then\n      return false\n  end\n\n  local data, err = core.json.decode(body)\n  if not data then\n      return false\n  end\n\n  if data['foo'] == 'bar' then\n      return true\n  end\n\n  return false\nend"
+   backends:
+   - serviceName: %s
+     servicePort: %d
+`, backendSvc, backendPorts[0])
+			assert.Nil(ginkgo.GinkgoT(), s.CreateVersionedApisixResource(ar))
+
+			err := s.EnsureNumApisixUpstreamsCreated(1)
+			assert.Nil(ginkgo.GinkgoT(), err, "Checking number of upstreams")
+			err = s.EnsureNumApisixRoutesCreated(1)
+			assert.Nil(ginkgo.GinkgoT(), err, "Checking number of routes")
+
+			_ = s.NewAPISIXClient().GET("/ip").
+				WithHeader("Host", "httpbin.org").
+				Expect().
+				Status(http.StatusNotFound).
+				Body().
+				Contains("404 Route Not Found")
+
+			type MyJSON struct {
+				Foo string `json:"foo"`
+			}
+
+			_ = s.NewAPISIXClient().GET("/ip").
+				WithHeader("Host", "httpbin.org").
+				WithJSON(MyJSON{Foo: "bar"}).
+				Expect().
+				Status(http.StatusOK)
+		})
+	}
+
+	ginkgo.Describe("suite-features: scaffold v2", func() {
+		suites(scaffold.NewDefaultV2Scaffold)
+	})
+})