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(fault-injection): support Nginx variable in abort.body #2986

Merged
merged 1 commit into from
Dec 8, 2020
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
41 changes: 41 additions & 0 deletions apisix/core/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core_str = require("apisix.core.string")
local table = require("apisix.core.table")
local ngx_re = require("ngx.re")
local resolver = require("resty.dns.resolver")
Expand All @@ -25,6 +26,8 @@ local math = math
local sub_str = string.sub
local str_byte = string.byte
local tonumber = tonumber
local tostring = tostring
local re_gsub = ngx.re.gsub
local type = type
local C = ffi.C
local ffi_string = ffi.string
Expand Down Expand Up @@ -219,4 +222,42 @@ end
_M.sleep = sleep


local resolve_var
do
local _ctx
local pat = [[(?<!\\)\$(\w+)]]

local function resolve(m)
local v = _ctx[m[1]]
if v == nil then
return ""
end
return tostring(v)
end

function resolve_var(tpl, ctx)
if not tpl then
return tpl
end

local from = core_str.find(tpl, "$")
if not from then
return tpl
end

-- avoid creating temporary function
_ctx = ctx
local res, _, err = re_gsub(tpl, pat, resolve, "jo")
_ctx = nil
if not res then
return nil, err
end

return res
end
end
-- Resolve ngx.var in the given string
_M.resolve_var = resolve_var


return _M
16 changes: 5 additions & 11 deletions apisix/plugins/fault-injection.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ local schema = {
body = {type = "string", minLength = 0},
percentage = {type = "integer", minimum = 0, maximum = 100}
},
minProperties = 1,
required = {"http_status"},
},
delay = {
type = "object",
properties = {
duration = {type = "number", minimum = 0},
percentage = {type = "integer", minimum = 0, maximum = 100}
},
minProperties = 1,
required = {"duration"},
}
},
minProperties = 1,
Expand Down Expand Up @@ -77,18 +77,12 @@ end
function _M.rewrite(conf, ctx)
core.log.info("plugin rewrite phase, conf: ", core.json.delay_encode(conf))

if conf.delay
and conf.delay.duration ~= nil
and sample_hit(conf.delay.percentage)
then
if conf.delay and sample_hit(conf.delay.percentage) then
sleep(conf.delay.duration)
end

if conf.abort
and conf.abort.http_status ~= nil
and sample_hit(conf.abort.percentage)
then
return conf.abort.http_status, conf.abort.body
if conf.abort and sample_hit(conf.abort.percentage) then
return conf.abort.http_status, core.utils.resolve_var(conf.abort.body, ctx.var)
end
end

Expand Down
6 changes: 3 additions & 3 deletions doc/plugins/fault-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ Fault injection plugin, this plugin can be used with other plugins and will be e

| Name | Type | Requirement | Default | Valid | Description |
| ----------------- | ------- | ----------- | ------- | ---------- | ------------------------------------------------ |
| abort.http_status | integer | optional | | [200, ...] | user-specified http code returned to the client. |
| abort.body | string | optional | | | response data returned to the client. |
| abort.http_status | integer | required | | [200, ...] | user-specified http code returned to the client. |
| abort.body | string | optional | | | response data returned to the client. Nginx varialbe can be used inside, like `client addr: $remote_addr\n` |
| abort.percentage | integer | optional | | [0, 100] | percentage of requests to be aborted. |
| delay.duration | number | optional | | | delay time (can be decimal). |
| delay.duration | number | required | | | delay time (can be decimal). |
| delay.percentage | integer | optional | | [0, 100] | percentage of requests to be delayed. |

Note: One of `abort` and `delay` must be specified.
Expand Down
6 changes: 3 additions & 3 deletions doc/zh-cn/plugins/fault-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@

| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------------- | ------- | ------ | ------ | ---------- | -------------------------- |
| abort.http_status | integer | 可选 | | [200, ...] | 返回给客户端的 http 状态码 |
| abort.body | string | 可选 | | | 返回给客户端的响应数据 |
| abort.http_status | integer | 必需 | | [200, ...] | 返回给客户端的 http 状态码 |
| abort.body | string | 可选 | | | 返回给客户端的响应数据。支持使用 Nginx 变量,如 `client addr: $remote_addr\n`|
| abort.percentage | integer | 可选 | | [0, 100] | 将被中断的请求占比 |
| delay.duration | number | 可选 | | | 延迟时间,可以指定小数 |
| delay.duration | number | 必需 | | | 延迟时间,可以指定小数 |
| delay.percentage | integer | 可选 | | [0, 100] | 将被延迟的请求占比 |

注:参数 abort 和 delay 至少要存在一个。
Expand Down
40 changes: 40 additions & 0 deletions t/core/utils.t
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,43 @@ received: \nreceived: hello world
close: 1 nil}
--- no_error_log
[error]



=== TEST 6: resolve_var
--- config
location /t {
content_by_lua_block {
local resolve_var = require("apisix.core.utils").resolve_var
local cases = {
"",
"xx",
"$me",
"$me run",
"talk with $me",
"tell $me to",
"$you and $me",
"$eva and $me",
"$you and \\$me",
}
local ctx = {
you = "John",
me = "David",
}
for _, case in ipairs(cases) do
ngx.say("res:", resolve_var(case, ctx))
end
}
}
--- request
GET /t
--- response_body
res:
res:xx
res:David
res:David run
res:talk with David
res:tell David to
res:John and David
res: and David
res:John and \$me
106 changes: 106 additions & 0 deletions t/plugin/fault-injection.t
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,109 @@ GET /hello HTTP/1.1
hello1 world
--- no_error_log
[error]



=== TEST 20: set route(body with var)
--- 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,
[[{
"plugins": {
"fault-injection": {
"abort": {
"http_status": 200,
"body": "client addr: $remote_addr\n"
}
},
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 21: hit route(body with var)
--- request
GET /hello
--- response_body
client addr: 127.0.0.1
--- no_error_log
[error]



=== TEST 22: set route(abort without body)
--- 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,
[[{
"plugins": {
"fault-injection": {
"abort": {
"http_status": 200
}
},
"proxy-rewrite": {
"uri": "/hello"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 23: hit route(abort without body)
--- request
GET /hello
--- response_body
--- no_error_log
[error]