diff --git a/apisix/admin/v3_adapter.lua b/apisix/admin/v3_adapter.lua index f55df73a4e45..aa9226a8345d 100644 --- a/apisix/admin/v3_adapter.lua +++ b/apisix/admin/v3_adapter.lua @@ -22,6 +22,8 @@ local request = require("apisix.core.request") local response = require("apisix.core.response") local table = require("apisix.core.table") local tonumber = tonumber +local re_find = ngx.re.find +local pairs = pairs local _M = {} @@ -81,12 +83,7 @@ local function sort(l, r) end -function _M.filter(body) - if not enable_v3() then - return - end - - local args = request.get_uri_args() +local function pagination(body, args) args.page = tonumber(args.page) args.page_size = tonumber(args.page_size) if not args.page or not args.page_size then @@ -122,4 +119,71 @@ function _M.filter(body) end +local function filter(body, args) + if not args.name and not args.label and not args.uri then + return + end + + for i = #body.list, 1, -1 do + local name_matched = true + local label_matched = true + local uri_matched = true + if args.name then + name_matched = false + local matched = re_find(body.list[i].value.name, args.name, "jo") + if matched then + name_matched = true + end + end + + if args.label then + label_matched = false + if body.list[i].value.labels then + for k, _ in pairs(body.list[i].value.labels) do + if k == args.label then + label_matched = true + break + end + end + end + end + + if args.uri then + uri_matched = false + if body.list[i].value.uri then + local matched = re_find(body.list[i].value.uri, args.uri, "jo") + if matched then + uri_matched = true + end + end + + if body.list[i].value.uris then + for _, uri in pairs(body.list[i].value.uris) do + if re_find(uri, args.uri, "jo") then + uri_matched = true + break + end + end + end + end + + if not name_matched or not label_matched or not uri_matched then + table.remove(body.list, i) + end + end +end + + +function _M.filter(body) + if not enable_v3() then + return + end + + local args = request.get_uri_args() + + pagination(body, args) + filter(body, args) +end + + return _M diff --git a/t/admin/filter.t b/t/admin/filter.t index decf463d38a2..ea2b004f697f 100644 --- a/t/admin/filter.t +++ b/t/admin/filter.t @@ -246,3 +246,509 @@ passed } --- response_body passed + + + +=== TEST 6: only search name or labels +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + for i = 1, 11 do + local code, body = t('/apisix/admin/services/' .. i, + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "name": "]] .. i .. [[", + "labels": {"]] .. i .. '":"' .. i .. [["} + }]] + ) + end + + ngx.sleep(0.5) + + local matched = {1, 10, 11} + + local code, body, res = t('/apisix/admin/services/?name=1', + ngx.HTTP_GET + ) + res = json.decode(res) + -- match the name are 1, 10, 11 + assert(#res.list == 3) + + for _, node in ipairs(res.list) do + assert(core.table.array_find(matched, tonumber(node.value.name))) + end + + code, body, res = t('/apisix/admin/services/?label=1', + ngx.HTTP_GET + ) + res = json.decode(res) + -- match the label are 1, 10, 11 + assert(#res.list == 1) + assert(res.list[1].value.id == "1") + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 7: services filter +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + for i = 1, 11 do + local code, body = t('/apisix/admin/services/' .. i, + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "name": "]] .. i .. [[" + }]] + ) + end + + ngx.sleep(0.5) + + local code, body, res = t('/apisix/admin/services/?name=1', + ngx.HTTP_GET + ) + res = json.decode(res) + + -- match the name and label are 1, 10, 11 + assert(#res.list == 3) + + local matched = {1, 10, 11} + for _, node in ipairs(res.list) do + assert(core.table.array_find(matched, tonumber(node.value.name))) + end + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 8: routes filter +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + for i = 1, 11 do + local code, body = t('/apisix/admin/routes/' .. i, + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "name": "]] .. i .. [[", + "uri": "]] .. i .. [[" + }]] + ) + end + + ngx.sleep(0.5) + + local code, body, res = t('/apisix/admin/services/?name=1', + ngx.HTTP_GET + ) + res = json.decode(res) + + -- match the name and label are 1, 10, 11 + assert(#res.list == 3) + + local matched = {1, 10, 11} + for _, node in ipairs(res.list) do + assert(core.table.array_find(matched, tonumber(node.value.name))) + end + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 9: filter with pagination +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local code, body, res = t('/apisix/admin/services/?name=1&page=1&page_size=10', + ngx.HTTP_GET + ) + res = json.decode(res) + + -- match the name and label are 1, 10 + assert(#res.list == 2) + + local matched = {1, 10} + for _, node in ipairs(res.list) do + assert(core.table.array_find(matched, tonumber(node.value.name))) + end + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 10: routes filter with uri +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + for i = 1, 11 do + local code, body = t('/apisix/admin/routes/' .. i, + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "name": "]] .. i .. [[", + "uri": "]] .. i .. [[" + }]] + ) + end + + ngx.sleep(0.5) + + local code, body, res = t('/apisix/admin/routes/?uri=1', + ngx.HTTP_GET + ) + res = json.decode(res) + + -- match the name and label are 1, 10, 11 + assert(#res.list == 3) + + local matched = {1, 10, 11} + for _, node in ipairs(res.list) do + assert(core.table.array_find(matched, tonumber(node.value.name))) + end + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 11: match labels +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello", + "labels": { + "env": "production" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello2", + "labels": { + "env2": "production" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + ngx.sleep(0.5) + + -- only match labels' keys + local code, body, res = t('/apisix/admin/routes/?label=env', + ngx.HTTP_GET + ) + res = json.decode(res) + assert(#res.list == 1) + assert(res.list[1].value.id == "1") + + -- don't match labels' values + code, body, res = t('/apisix/admin/routes/?label=production', + ngx.HTTP_GET + ) + res = json.decode(res) + assert(#res.list == 0) + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 12: match uris +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uris": ["/hello", "/world"] + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uris": ["/foo", "/bar"] + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + ngx.sleep(0.5) + + local code, body, res = t('/apisix/admin/routes/?uri=world', + ngx.HTTP_GET + ) + res = json.decode(res) + assert(#res.list == 1) + assert(res.list[1].value.id == "1") + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 13: match uris & labels +# uris are same in different routes, filter by labels +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uris": ["/hello", "/world"], + "labels": { + "env": "production" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uris": ["/hello", "/world"], + "labels": { + "build": "16" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + ngx.sleep(0.5) + + -- only match route 1 + local code, body, res = t('/apisix/admin/routes/?uri=world&label=env', + ngx.HTTP_GET + ) + res = json.decode(res) + assert(#res.list == 1) + assert(res.list[1].value.id == "1") + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 14: match uri & labels +# uri is same in different routes, filter by labels +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local core = require("apisix.core") + local t = require("lib.test_admin").test + + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello", + "labels": { + "env": "production" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + code, body = t('/apisix/admin/routes/2', + ngx.HTTP_PUT, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello", + "labels": { + "env2": "production" + } + }]] + ) + if code >= 300 then + ngx.status = code + ngx.say(body) + return + end + + ngx.sleep(0.5) + + local code, body, res = t('/apisix/admin/routes/?uri=hello&label=env', + ngx.HTTP_GET + ) + res = json.decode(res) + assert(#res.list == 1) + assert(res.list[1].value.id == "1") + + ngx.status = code + ngx.say(body) + } + } +--- response_body +passed