Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow route to inherit hosts from service #4977

Merged
merged 2 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion apisix/http/route.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
local require = require
local radixtree = require("resty.radixtree")
local router = require("apisix.utils.router")
local service_fetch = require("apisix.http.service").get
local core = require("apisix.core")
local expr = require("resty.expr.v1")
local plugin_checker = require("apisix.plugin").plugin_checker
Expand Down Expand Up @@ -56,13 +57,25 @@ function _M.create_radixtree_uri_router(routes, uri_routes, with_parameter)
filter_fun = filter_fun()
end

local hosts = route.value.hosts or route.value.host
if not hosts and route.value.service_id then
local service = service_fetch(route.value.service_id)
if not service then
core.log.error("failed to fetch service configuration by ",
"id: ", route.value.service_id)
-- we keep the behavior that missing service won't affect the route matching
else
hosts = service.value.hosts
end
end

core.log.info("insert uri route: ",
core.json.delay_encode(route.value, true))
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,
hosts = hosts,
remote_addrs = route.value.remote_addrs
or route.value.remote_addr,
vars = route.value.vars,
Expand Down
32 changes: 27 additions & 5 deletions apisix/http/router/radixtree_host_uri.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
local require = require
local router = require("apisix.utils.router")
local core = require("apisix.core")
local get_services = require("apisix.http.service").services
local service_fetch = require("apisix.http.service").get
local ipairs = ipairs
local type = type
local tab_insert = table.insert
local loadstring = loadstring
local pairs = pairs
local cached_version
local cached_router_version
local cached_service_version
local host_router
local only_uri_router

Expand All @@ -49,7 +52,21 @@ local function push_host_router(route, host_routes, only_uri_routes)
filter_fun = filter_fun()
end

local hosts = route.value.hosts or {route.value.host}
local hosts = route.value.hosts
if not hosts then
if route.value.host then
hosts = {route.value.host}
elseif route.value.service_id then
local service = service_fetch(route.value.service_id)
if not service then
core.log.error("failed to fetch service configuration by ",
"id: ", route.value.service_id)
-- we keep the behavior that missing service won't affect the route matching
else
hosts = service.value.hosts
end
end
end

local radixtree_route = {
paths = route.value.uris or route.value.uri,
Expand All @@ -66,7 +83,7 @@ local function push_host_router(route, host_routes, only_uri_routes)
end
}

if #hosts == 0 then
if hosts == nil then
core.table.insert(only_uri_routes, radixtree_route)
return
end
Expand Down Expand Up @@ -124,11 +141,16 @@ end
local match_opts = {}
function _M.match(api_ctx)
local user_routes = _M.user_routes
if not cached_version or cached_version ~= user_routes.conf_version then
local _, service_version = get_services()
if not cached_router_version or cached_router_version ~= user_routes.conf_version
or not cached_service_version or cached_service_version ~= service_version
then
create_radixtree_router(user_routes.values)
cached_version = user_routes.conf_version
cached_router_version = user_routes.conf_version
cached_service_version = service_version
end


core.table.clear(match_opts)
match_opts.method = api_ctx.var.request_method
match_opts.remote_addr = api_ctx.var.remote_addr
Expand Down
12 changes: 9 additions & 3 deletions apisix/http/router/radixtree_uri.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
local require = require
local core = require("apisix.core")
local base_router = require("apisix.http.route")
local cached_version
local get_services = require("apisix.http.service").services
local cached_router_version
local cached_service_version


local _M = {version = 0.2}
Expand All @@ -28,10 +30,14 @@ local _M = {version = 0.2}
local match_opts = {}
function _M.match(api_ctx)
local user_routes = _M.user_routes
if not cached_version or cached_version ~= user_routes.conf_version then
local _, service_version = get_services()
if not cached_router_version or cached_router_version ~= user_routes.conf_version
or not cached_service_version or cached_service_version ~= service_version
then
uri_router = base_router.create_radixtree_uri_router(user_routes.values,
uri_routes, false)
cached_version = user_routes.conf_version
cached_router_version = user_routes.conf_version
cached_service_version = service_version
end

if not uri_router then
Expand Down
12 changes: 9 additions & 3 deletions apisix/http/router/radixtree_uri_with_parameter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
local require = require
local core = require("apisix.core")
local base_router = require("apisix.http.route")
local cached_version
local get_services = require("apisix.http.service").services
local cached_router_version
local cached_service_version


local _M = {}
Expand All @@ -28,10 +30,14 @@ local _M = {}
local match_opts = {}
function _M.match(api_ctx)
local user_routes = _M.user_routes
if not cached_version or cached_version ~= user_routes.conf_version then
local _, service_version = get_services()
if not cached_router_version or cached_router_version ~= user_routes.conf_version
or not cached_service_version or cached_service_version ~= service_version
then
uri_router = base_router.create_radixtree_uri_router(user_routes.values,
uri_routes, true)
cached_version = user_routes.conf_version
cached_router_version = user_routes.conf_version
cached_service_version = service_version
end

if not uri_router then
Expand Down
7 changes: 7 additions & 0 deletions apisix/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,13 @@ local function merge_service_route(service_conf, route_conf)
new_conf.value.name = nil
end

if route_conf.value.hosts then
new_conf.value.hosts = route_conf.value.hosts
end
if not new_conf.value.hosts and route_conf.value.host then
new_conf.value.host = route_conf.value.host
end

-- core.log.info("merged conf : ", core.json.delay_encode(new_conf))
return new_conf
end
Expand Down
7 changes: 6 additions & 1 deletion apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,12 @@ _M.service = {
description = "enable websocket for request",
type = "boolean",
},

hosts = {
type = "array",
items = host_def,
minItems = 1,
uniqueItems = true,
},
},
}

Expand Down
4 changes: 3 additions & 1 deletion docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,13 @@ Return response from etcd currently.
| desc | False | Auxiliary | service usage scenarios, and more. | service xxxx |
| labels | False | Match Rules | Key/value pairs to specify attributes | {"version":"v2","build":"16","env":"production"} |
| enable_websocket | False | Auxiliary | enable `websocket`(boolean), default `false`. | |
| hosts | False | Match Rules | The `host` in the form of a non-empty list means that multiple different hosts are allowed, and match any one of them.| ["foo.com", "*.bar.com"] |
| create_time | False | Auxiliary | epoch timestamp in second, will be created automatically if missing | 1602883670 |
| update_time | False | Auxiliary | epoch timestamp in second, will be created automatically if missing | 1602883670 |

Config Example:

```shell
```json
{
"id": "1", # id
"plugins": {}, # Bound plugin
Expand All @@ -337,6 +338,7 @@ Config Example:
"name": "service-test",
"desc": "hello world",
"enable_websocket": true,
"hosts": ["foo.com"]
}
```

Expand Down
4 changes: 3 additions & 1 deletion docs/zh/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,13 @@ HTTP/1.1 200 OK
| desc | 可选 | 辅助 | 服务描述、使用场景等。 | |
| labels | 可选 | 匹配规则 | 标识附加属性的键值对 | {"version":"v2","build":"16","env":"production"} |
| enable_websocket | 可选 | 辅助 | 是否启用 `websocket`(boolean), 缺省 `false`. | |
| hosts | 可选 | 匹配规则 | 非空列表形态的 `host`,表示允许有多个不同 `host`,匹配其中任意一个即可。| ["foo.com", "\*.bar.com"] |
| create_time | 可选 | 辅助 | 单位为秒的 epoch 时间戳,如果不指定则自动创建 | 1602883670 |
| update_time | 可选 | 辅助 | 单位为秒的 epoch 时间戳,如果不指定则自动创建 | 1602883670 |

service 对象 json 配置内容:

```shell
```json
{
"id": "1", # id
"plugins": {}, # 指定 service 绑定的插件
Expand All @@ -339,6 +340,7 @@ service 对象 json 配置内容:
"name": "测试svc", # service 名称
"desc": "hello world", # service 描述
"enable_websocket": true, #启动 websocket 功能
"hosts": ["foo.com"]
}
```

Expand Down
36 changes: 36 additions & 0 deletions t/router/radixtree-host-uri2.t
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,39 @@ GET /server_port
Host: test.com
--- no_error_log
[error]



=== TEST 14: inherit hosts from services
--- yaml_config eval: $::yaml_config
--- apisix_yaml
services:
- id: 1
hosts:
- bar.com
tzssangglass marked this conversation as resolved.
Show resolved Hide resolved
upstreams:
- id: 1
nodes:
"127.0.0.1:1980": 1
type: roundrobin
routes:
-
service_id: 1
upstream_id: 1
uri: /hello
plugins:
proxy-rewrite:
uri: /hello1
-
upstream_id: 1
uri: /hello
priority: -1
#END
--- more_headers
Host: www.foo.com
--- request
GET /hello
--- response_body
hello world
--- no_error_log
[error]
Loading