This is an automated email from the ASF dual-hosted git repository. membphis 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 c7f9fdf feature: support to specify TTL for route。 (#807) c7f9fdf is described below commit c7f9fdf9d756e93ad609bb4161d98717cf46958c Author: YuanSheng Wang <membp...@gmail.com> AuthorDate: Fri Dec 6 11:13:24 2019 +0800 feature: support to specify TTL for route。 (#807) Fix #443. --- doc/admin-api-cn.md | 28 ++++++++- lua/apisix/admin/init.lua | 14 ++++- lua/apisix/admin/routes.lua | 12 ++-- lua/apisix/core/etcd.lua | 8 +-- t/admin/routes.t | 144 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+), 14 deletions(-) diff --git a/doc/admin-api-cn.md b/doc/admin-api-cn.md index 2af0580..feb211f 100644 --- a/doc/admin-api-cn.md +++ b/doc/admin-api-cn.md @@ -25,7 +25,7 @@ ## Route -*地址*:/apisix/admin/routes/{id} +*地址*:/apisix/admin/routes/{id}?ttl=0 *说明*:Route 字面意思就是路由,通过定义一些规则来匹配客户端的请求,然后根据匹配结果加载并执行相应的 插件,并把请求转发给到指定 Upstream。 @@ -40,7 +40,13 @@ |DELETE |/apisix/admin/routes/{id}|无|删除资源| |PATCH |/apisix/admin/routes/{id}/{path}|{...}|修改已有 Route 的部分内容,其他不涉及部分会原样保留。| -> 请求参数: +> uri 请求参数: + +|名字 |可选项 |类型 |说明 |示例| +|---------|---------|----|-----------|----| +|ttl |可选 |辅助 |超过这个时间会被自动删除,单位:秒|ttl=1| + +> body 请求参数: |名字 |可选项 |类型 |说明 |示例| |---------|---------|----|-----------|----| @@ -64,6 +70,7 @@ 示例: ```shell +# 创建一个路由 $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -i -d ' { "uri": "/index.html", @@ -81,6 +88,23 @@ $ curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -i -d ' HTTP/1.1 201 Created Date: Sat, 31 Aug 2019 01:17:15 GMT ... + +# 创建一个有效期为 60 秒的路由,过期后自动删除 +$ curl http://127.0.0.1:9080/apisix/admin/routes/2?ttl=60 -X PUT -i -d ' +{ + "uri": "/aa/index.html", + "upstream": { + "type": "roundrobin", + "nodes": { + "39.97.63.215:80": 1 + } + } +}' + +HTTP/1.1 201 Created +Date: Sat, 31 Aug 2019 01:17:15 GMT +... + ``` > 应答参数 diff --git a/lua/apisix/admin/init.lua b/lua/apisix/admin/init.lua index 128340f..ee4ebea 100644 --- a/lua/apisix/admin/init.lua +++ b/lua/apisix/admin/init.lua @@ -17,10 +17,11 @@ local core = require("apisix.core") local route = require("resty.radixtree") local plugin = require("apisix.plugin") +local ngx = ngx local get_method = ngx.req.get_method +local tonumber = tonumber local str_lower = string.lower local require = require -local ngx = ngx local reload_event = "/apisix/admin/plugins/reload" local events @@ -80,7 +81,16 @@ local function run() req_body = data end - local code, data = resource[method](seg_id, req_body, seg_sub_path) + local uri_args = ngx.req.get_uri_args() or {} + if uri_args.ttl then + if not tonumber(uri_args.ttl) then + core.response.exit(400, {error_msg = "invalid argument ttl: " + .. "should be a number"}) + end + end + + local code, data = resource[method](seg_id, req_body, seg_sub_path, + uri_args) if code then core.response.exit(code, data) end diff --git a/lua/apisix/admin/routes.lua b/lua/apisix/admin/routes.lua index e27e33a..34ab758 100644 --- a/lua/apisix/admin/routes.lua +++ b/lua/apisix/admin/routes.lua @@ -117,14 +117,14 @@ local function check_conf(id, conf, need_id) end -function _M.put(id, conf) +function _M.put(id, conf, sub_path, args) local id, err = check_conf(id, conf, true) if not id then return 400, err end local key = "/routes/" .. id - local res, err = core.etcd.set(key, conf) + local res, err = core.etcd.set(key, conf, args.ttl) if not res then core.log.error("failed to put route[", key, "]: ", err) return 500, {error_msg = err} @@ -150,7 +150,7 @@ function _M.get(id) end -function _M.post(id, conf) +function _M.post(id, conf, sub_path, args) local id, err = check_conf(id, conf, false) if not id then return 400, err @@ -158,7 +158,7 @@ function _M.post(id, conf) local key = "/routes" -- core.log.info("key: ", key) - local res, err = core.etcd.push("/routes", conf) + local res, err = core.etcd.push("/routes", conf, args.ttl) if not res then core.log.error("failed to post route[", key, "]: ", err) return 500, {error_msg = err} @@ -185,7 +185,7 @@ function _M.delete(id) end -function _M.patch(id, conf, sub_path) +function _M.patch(id, conf, sub_path, args) if not id then return 400, {error_msg = "missing route id"} end @@ -250,7 +250,7 @@ function _M.patch(id, conf, sub_path) end -- TODO: this is not safe, we need to use compare-set - local res, err = core.etcd.set(key, node_value) + local res, err = core.etcd.set(key, node_value, args.ttl) if not res then core.log.error("failed to set new route[", key, "]: ", err) return 500, {error_msg = err} diff --git a/lua/apisix/core/etcd.lua b/lua/apisix/core/etcd.lua index 311ceb5..3e34144 100644 --- a/lua/apisix/core/etcd.lua +++ b/lua/apisix/core/etcd.lua @@ -52,23 +52,23 @@ function _M.get(key) end -function _M.set(key, value) +function _M.set(key, value, ttl) local etcd_cli, prefix, err = new() if not etcd_cli then return nil, err end - return etcd_cli:set(prefix .. key, value) + return etcd_cli:set(prefix .. key, value, ttl) end -function _M.push(key, value) +function _M.push(key, value, ttl) local etcd_cli, prefix, err = new() if not etcd_cli then return nil, err end - return etcd_cli:push(prefix .. key, value) + return etcd_cli:push(prefix .. key, value, ttl) end diff --git a/t/admin/routes.t b/t/admin/routes.t index 1b8d8ac..e6354d3 100644 --- a/t/admin/routes.t +++ b/t/admin/routes.t @@ -1361,3 +1361,147 @@ GET /t passed --- no_error_log [error] + + + +=== TEST 38: set route with ttl +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + -- set + local code, body, res = t('/apisix/admin/routes/1?ttl=1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin" + }, + "uri": "/index.html" + }]] + ) + + if code >= 300 then ngx.print("code: ", code, " ") end + ngx.say(body) + + -- get + code, body = t('/apisix/admin/routes/1?ttl=1', + ngx.HTTP_GET, + nil, + [[{ + "node": { + "value": { + "uri": "/index.html" + }, + "key": "/apisix/routes/1" + } + }]] + ) + + if code >= 300 then ngx.print("code: ", code, " ") end + ngx.say(body) + + ngx.sleep(2) + + -- get again + code, body, res = t('/apisix/admin/routes/1', ngx.HTTP_GET) + + if code >= 300 then ngx.print("code: ", code, " ") end + ngx.print(body) + } +} +--- request +GET /t +--- response_body_like eval +qr$passed +passed +code: 404 {"cause":"\\/apisix\\/routes\\/1","index":\d+,"errorCode":100,"message":"Key not found"}$ +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 39: post route with ttl +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body, res = t('/apisix/admin/routes?ttl=1', + ngx.HTTP_POST, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin" + }, + "uri": "/index.html" + }]], + [[{"action": "create"}]] + ) + + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + ngx.say("[push] succ: ", body) + ngx.sleep(2) + + local id = string.sub(res.node.key, #"/apisix/routes/" + 1) + code, body = t('/apisix/admin/routes/' .. id, ngx.HTTP_GET) + + if code >= 300 then ngx.print("code: ", code, " ") end + ngx.print(body) + } +} +--- request +GET /t +--- response_body_like eval +qr$succ: passed +code: 404 {"cause":"\\/apisix\\/routes\\/\d+","index":\d+,"errorCode":100,"message":"Key not found"}$ +--- no_error_log +[error] +--- timeout: 5 + + + +=== TEST 40: invalid argument: ttl +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body, res = t('/apisix/admin/routes?ttl=xxx', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin" + }, + "uri": "/index.html" + }]] + ) + + if code >= 300 then + ngx.status = code + ngx.print(body) + return + end + + ngx.say("[push] succ: ", body) + } +} +--- request +GET /t +--- error_code: 400 +--- response_body +{"error_msg":"invalid argument ttl: should be a number"} +--- no_error_log +[error]