This is an automated email from the ASF dual-hosted git repository.
wenming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git
The following commit(s) were added to refs/heads/master by this push:
new c74e6c2 feature: supported `priority` for route. (#998)
c74e6c2 is described below
commit c74e6c2d3acab4f7af6b09a467c66df11c842cd4
Author: YuanSheng Wang <[email protected]>
AuthorDate: Sun Dec 29 17:11:38 2019 +0800
feature: supported `priority` for route. (#998)
---
doc/admin-api-cn.md | 1 +
doc/admin-api.md | 1 +
lua/apisix/http/router/radixtree_uri.lua | 5 +-
lua/apisix/schema_def.lua | 1 +
rockspec/apisix-master-0.rockspec | 2 +-
t/admin/routes.t | 85 +++++++++++++
t/router/radixtree-uri-priority.t | 197 +++++++++++++++++++++++++++++++
7 files changed, 290 insertions(+), 2 deletions(-)
diff --git a/doc/admin-api-cn.md b/doc/admin-api-cn.md
index feb211f..a6dfac1 100644
--- a/doc/admin-api-cn.md
+++ b/doc/admin-api-cn.md
@@ -57,6 +57,7 @@
|remote_addr|可选 |匹配规则|客户端请求 IP 地址: `192.168.1.101`、`192.168.1.102` 以及 CIDR
格式的支持 `192.168.1.0/24`。特别的,APISIX 也完整支持 IPv6 地址匹配:`::1`,`fe80::1`, `fe80::1/64`
等。|"192.168.1.0/24"|
|remote_addrs|可选 |匹配规则|列表形态的 `remote_addr`,表示允许有多个不同 IP
地址,符合其中任意一个即可。|{"127.0.0.1", "192.0.0.0/8", "::1"}|
|methods |可选 |匹配规则|如果为空或没有该选项,代表没有任何 `method` 限制,也可以是一个或多个的组合:`GET`, `POST`,
`PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`,`CONNECT`,`TRACE`。|{"GET", "POST"}|
+|priority |可选 |匹配规则|如果不同路由包含相同 `uri`,根据属性 `priority` 确定哪个 `route` 被优先匹配,默认值为
0。|priority = 10|
|vars |可选 |匹配规则(仅支持 `radixtree` 路由)|由一个或多个`{var, operator,
val}`元素组成的列表,类似这样:`{{var, operator, val}, {var, operator, val},
...}`。例如:`{"arg_name", "==", "json"}`,表示当前请求参数 `name` 是 `json`。这里的 `var` 与
Nginx 内部自身变量命名是保持一致,所以也可以使用 `request_uri`、`host` 等;对于 `operator` 部分,目前已支持的运算符有
`==`、`~=`、`>`、`<` 和 `~~`。对于`>`和`<`两个运算符,会把结果先转换成 number
然后再做比较。查看支持的[运算符列表](#运算符列表)|{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
|filter_func|可选|匹配规则|用户自定义的过滤函数。可以使用它来实现特殊场景的匹配要求实现。该函数默认接受一个名为 vars
的输入参数,可以用它来获取 Nginx 变量。|function(vars) return vars["arg_name"] == "json" end|
|plugins |可选 |Plugin|详见 [Plugin](architecture-design-cn.md#plugin) ||
diff --git a/doc/admin-api.md b/doc/admin-api.md
index 3032e6d..af2060a 100644
--- a/doc/admin-api.md
+++ b/doc/admin-api.md
@@ -56,6 +56,7 @@ Table of contents
|remote_addr|False |Match Rules|The client requests an IP address:
`192.168.1.101`, `192.168.1.102`, and CIDR format support `192.168.1.0/24`. In
particular, APISIX also fully supports IPv6 address matching: `::1`, `fe80::1`,
`fe80::1/64`, etc.|"192.168.1.0/24"|
|remote_addrs|False |Match Rules|The `remote_addr` in the form of a list
indicates that multiple different IP addresses are allowed, and match any one
of them.|{"127.0.0.1", "192.0.0.0/8", "::1"}|
|methods |False |Match Rules|If empty or without this option, there are no
`method` restrictions, and it can be a combination of one or more:
`GET`,`POST`,`PUT`,`DELETE`,`PATCH`,
`HEAD`,`OPTIONS`,`CONNECT`,`TRACE`.|{"GET", "POST"}|
+|priority |False |Match Rules|If different routes contain the same `uri`,
determine which route is matched first based on the attribute` priority`, the
default value is 0.|priority = 10|
|vars |False |Match Rules (only `radixtree` route is supported)|A list
of one or more `{var, operator, val}` elements, like this: `{{var, operator,
val}, {var, operator, val}, ...}`. For example: `{"arg_name", "==", "json"}`
means that the current request parameter `name` is `json`. The `var` here is
consistent with the internal variable name of Nginx, so you can also use
`request_uri`, `host`, etc. For the operator part, the currently supported
operators are `==`, `~=`,`>`, `<`, [...]
|filter_func|False|Match Rules|User-defined filtering function. You can use it
to achieve matching requirements for special scenarios. This function accepts
an input parameter named `vars` by default, which you can use to get Nginx
variables.|function(vars) return vars["arg_name"] == "json" end|
|plugins |False |Plugin|See [Plugin](architecture-design-cn.md#plugin) for
more ||
diff --git a/lua/apisix/http/router/radixtree_uri.lua
b/lua/apisix/http/router/radixtree_uri.lua
index ba40160..c84062e 100644
--- a/lua/apisix/http/router/radixtree_uri.lua
+++ b/lua/apisix/http/router/radixtree_uri.lua
@@ -26,7 +26,7 @@ local user_routes
local cached_version
-local _M = {version = 0.1}
+local _M = {version = 0.2}
local uri_routes = {}
@@ -63,9 +63,12 @@ local function create_radixtree_router(routes)
filter_fun = filter_fun()
end
+ core.log.info("insert uri route: ",
+ core.json.delay_encode(route.value))
core.table.insert(uri_routes, {
paths = route.value.uris or route.value.uri,
methods = route.value.methods,
+ priority = route.value.priority,
hosts = route.value.hosts or route.value.host,
remote_addrs = route.value.remote_addrs
or route.value.remote_addr,
diff --git a/lua/apisix/schema_def.lua b/lua/apisix/schema_def.lua
index 6a731ed..1406c49 100644
--- a/lua/apisix/schema_def.lua
+++ b/lua/apisix/schema_def.lua
@@ -283,6 +283,7 @@ _M.route = {
uniqueItems = true,
},
desc = {type = "string", maxLength = 256},
+ priority = {type = "integer", default = 0},
methods = {
type = "array",
diff --git a/rockspec/apisix-master-0.rockspec
b/rockspec/apisix-master-0.rockspec
index 7ef6bef..b7c2c25 100644
--- a/rockspec/apisix-master-0.rockspec
+++ b/rockspec/apisix-master-0.rockspec
@@ -40,7 +40,7 @@ dependencies = {
"lua-resty-cookie = 0.1.0",
"lua-resty-session = 2.24",
"opentracing-openresty = 0.1",
- "lua-resty-radixtree = 1.6-1",
+ "lua-resty-radixtree = 1.7",
"lua-protobuf = 0.3.1",
"lua-resty-openidc = 1.7.2-1",
"luafilesystem = 1.7.0-2",
diff --git a/t/admin/routes.t b/t/admin/routes.t
index e6354d3..48051c2 100644
--- a/t/admin/routes.t
+++ b/t/admin/routes.t
@@ -1505,3 +1505,88 @@ GET /t
{"error_msg":"invalid argument ttl: should be a number"}
--- no_error_log
[error]
+
+
+
+=== TEST 41: set route(id: 1, check priority)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "roundrobin"
+ },
+ "desc": "new route",
+ "uri": "/index.html"
+ }]],
+ [[{
+ "node": {
+ "value": {
+ "priority": 0
+ },
+ "key": "/apisix/routes/1"
+ },
+ "action": "set"
+ }]]
+ )
+
+ ngx.status = code
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 42: set route(id: 1 + priority: 0)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:8080": 1
+ },
+ "type": "roundrobin"
+ },
+ "desc": "new route",
+ "uri": "/index.html",
+ "priority": 1
+ }]],
+ [[{
+ "node": {
+ "value": {
+ "priority": 1
+ },
+ "key": "/apisix/routes/1"
+ },
+ "action": "set"
+ }]]
+ )
+
+ ngx.status = code
+ ngx.say(body)
+ }
+ }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
diff --git a/t/router/radixtree-uri-priority.t
b/t/router/radixtree-uri-priority.t
new file mode 100644
index 0000000..efae88c
--- /dev/null
+++ b/t/router/radixtree-uri-priority.t
@@ -0,0 +1,197 @@
+#
+# 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.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+log_level('info');
+worker_connections(256);
+no_root_location();
+no_shuffle();
+
+sub read_file($) {
+ my $infile = shift;
+ open my $in, $infile
+ or die "cannot open $infile for reading: $!";
+ my $cert = do { local $/; <$in> };
+ close $in;
+ $cert;
+}
+
+our $yaml_config = read_file("conf/config.yaml");
+$yaml_config =~ s/node_listen: 9080/node_listen: 1984/;
+$yaml_config =~ s/enable_heartbeat: true/enable_heartbeat: false/;
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: set route(id: 1 + priority: 2)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/server_port*",
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "priority": 2
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- yaml_config eval: $::yaml_config
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: hit routes
+--- request
+GET /server_port/aa
+--- yaml_config eval: $::yaml_config
+--- response_body eval
+1980
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: set route(id: 2 + priority: 1)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/2',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/server_port*",
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1981": 1
+ },
+ "type": "roundrobin"
+ },
+ "priority": 1
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- yaml_config eval: $::yaml_config
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 4: hit routes
+--- request
+GET /server_port/aa
+--- yaml_config eval: $::yaml_config
+--- response_body eval
+1980
+--- no_error_log
+[error]
+
+
+
+=== TEST 5: set route(id: 2 + priority: 3)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/2',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/server_port*",
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1981": 1
+ },
+ "type": "roundrobin"
+ },
+ "priority": 3
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- yaml_config eval: $::yaml_config
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 6: hit routes
+--- request
+GET /server_port/aa
+--- yaml_config eval: $::yaml_config
+--- response_body eval
+1981
+--- no_error_log
+[error]
+
+
+
+=== TEST 7: set route(id: 2 + priority: 3)
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/2',
+ ngx.HTTP_DELETE)
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- yaml_config eval: $::yaml_config
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]