Skip to content

Commit

Permalink
feature: supported priority for route. (#998)
Browse files Browse the repository at this point in the history
  • Loading branch information
membphis authored and moonming committed Dec 29, 2019
1 parent b40d3bc commit c74e6c2
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 2 deletions.
1 change: 1 addition & 0 deletions doc/admin-api-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) ||
Expand Down
1 change: 1 addition & 0 deletions doc/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `==`, `~=`,`>`, `<`, and `~~`. For the `>` and `<` operators, the result is first converted to `number` and then compared. See a list of [supported operators](#available-operators) |{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
|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 ||
Expand Down
5 changes: 4 additions & 1 deletion lua/apisix/http/router/radixtree_uri.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ local user_routes
local cached_version


local _M = {version = 0.1}
local _M = {version = 0.2}


local uri_routes = {}
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions lua/apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ _M.route = {
uniqueItems = true,
},
desc = {type = "string", maxLength = 256},
priority = {type = "integer", default = 0},

methods = {
type = "array",
Expand Down
2 changes: 1 addition & 1 deletion rockspec/apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
85 changes: 85 additions & 0 deletions t/admin/routes.t
Original file line number Diff line number Diff line change
Expand Up @@ -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]
197 changes: 197 additions & 0 deletions t/router/radixtree-uri-priority.t
Original file line number Diff line number Diff line change
@@ -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]

0 comments on commit c74e6c2

Please sign in to comment.