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]

Reply via email to