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: support _meta.pre_function to execute custom logic before execution of each phase #11793

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ uwsgi_temp
proxy_temp
fastcgi_temp
client_body_temp
utils/lj-releng
utils/reindex
*.etcd/
t/lib/dubbo*/**/target/
Expand Down
40 changes: 36 additions & 4 deletions apisix/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ local type = type
local local_plugins = core.table.new(32, 0)
local tostring = tostring
local error = error
-- make linter happy to avoid error: getting the Lua global "load"
-- luacheck: globals load, ignore lua_load
local lua_load = load
local is_http = ngx.config.subsystem == "http"
local local_plugins_hash = core.table.new(0, 32)
local stream_local_plugins = core.table.new(32, 0)
Expand All @@ -49,6 +52,9 @@ local merged_stream_route = core.lrucache.new({
local expr_lrucache = core.lrucache.new({
ttl = 300, count = 512
})
local meta_pre_func_load_lrucache = core.lrucache.new({
ttl = 300, count = 512
})
local local_conf
local check_plugin_metadata

Expand Down Expand Up @@ -901,10 +907,23 @@ local function check_single_plugin_schema(name, plugin_conf, schema_type, skip_d
.. name .. " err: " .. err
end

if plugin_conf._meta and plugin_conf._meta.filter then
ok, err = expr.new(plugin_conf._meta.filter)
if not ok then
return nil, "failed to validate the 'vars' expression: " .. err
if plugin_conf._meta then
if plugin_conf._meta.filter then
ok, err = expr.new(plugin_conf._meta.filter)
if not ok then
return nil, "failed to validate the 'vars' expression: " .. err
end
end

if plugin_conf._meta.pre_function then
local pre_function, err = meta_pre_func_load_lrucache(plugin_conf._meta.pre_function
, "",
lua_load,
plugin_conf._meta.pre_function, "meta pre_function")
if not pre_function then
return nil, "failed to load _meta.pre_function in plugin " .. name .. ": "
.. err
end
end
end
end
Expand Down Expand Up @@ -1125,6 +1144,17 @@ function _M.stream_plugin_checker(item, in_cp)
return true
end

local function run_meta_pre_function(conf, api_ctx, name)
if conf._meta and conf._meta.pre_function then
local _, pre_function = pcall(meta_pre_func_load_lrucache(conf._meta.pre_function, "",
lua_load,
conf._meta.pre_function, "meta pre_function"))
local ok, err = pcall(pre_function, conf, api_ctx)
if not ok then
core.log.error("pre_function execution for plugin ", name, " failed: ", err)
end
end
end

function _M.run_plugin(phase, plugins, api_ctx)
local plugin_run = false
Expand Down Expand Up @@ -1164,6 +1194,7 @@ function _M.run_plugin(phase, plugins, api_ctx)
goto CONTINUE
end

run_meta_pre_function(conf, api_ctx, plugins[i]["name"])
plugin_run = true
api_ctx._plugin_name = plugins[i]["name"]
local code, body = phase_func(conf, api_ctx)
Expand Down Expand Up @@ -1202,6 +1233,7 @@ function _M.run_plugin(phase, plugins, api_ctx)
local conf = plugins[i + 1]
if phase_func and meta_filter(api_ctx, plugins[i]["name"], conf) then
plugin_run = true
run_meta_pre_function(conf, api_ctx, plugins[i]["name"])
api_ctx._plugin_name = plugins[i]["name"]
phase_func(conf, api_ctx)
api_ctx._plugin_name = nil
Expand Down
8 changes: 8 additions & 0 deletions apisix/plugins/example-plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ function _M.access(conf, ctx)
return
end

function _M.header_filter(conf, ctx)
core.log.warn("plugin header_filter phase, conf: ", core.json.encode(conf))
end


function _M.body_filter(conf, ctx)
core.log.warn("plugin body_filter phase, eof: ", ngx.arg[2],
Expand All @@ -119,6 +123,10 @@ function _M.delayed_body_filter(conf, ctx)
", conf: ", core.json.encode(conf))
end

function _M.log(conf, ctx)
core.log.warn("plugin log phase, conf: ", core.json.encode(conf))
end


local function hello()
local args = ngx.req.get_uri_args()
Expand Down
11 changes: 9 additions & 2 deletions apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1027,8 +1027,15 @@ _M.plugin_injected_schema = {
description = "filter determines whether the plugin "..
"needs to be executed at runtime",
type = "array",
}
}
},
pre_function = {
description = "function to be executed in each phase " ..
"before execution of plugins. The pre_function will have access " ..
"to two arguments: `conf` and `ctx`.",
type = "string",
},
},
additionalProperties = false,
}
}

Expand Down
4 changes: 2 additions & 2 deletions t/admin/plugins.t
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ plugins:
}
}
--- response_body eval
qr/\{"metadata_schema":\{"properties":\{"ikey":\{"minimum":0,"type":"number"\},"skey":\{"type":"string"\}\},"required":\["ikey","skey"\],"type":"object"\},"priority":0,"schema":\{"\$comment":"this is a mark for our injected plugin schema","properties":\{"_meta":\{"properties":\{"disable":\{"type":"boolean"\},"error_response":\{"oneOf":\[\{"type":"string"\},\{"type":"object"\}\]\},"filter":\{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"\},"priority":\{"description":"priority of plugins by customized order","type":"integer"\}\},"type":"object"\},"i":\{"minimum":0,"type":"number"\},"ip":\{"type":"string"\},"port":\{"type":"integer"\},"s":\{"type":"string"\},"t":\{"minItems":1,"type":"array"\}\},"required":\["i"\],"type":"object"\},"version":0.1\}/
qr/\{"metadata_schema":\{"properties":\{"ikey":\{"minimum":0,"type":"number"\},"skey":\{"type":"string"\}\},"required":\["ikey","skey"\],"type":"object"\},"priority":0,"schema":\{"\$comment":"this is a mark for our injected plugin schema","properties":\{"_meta":\{"additionalProperties":false,"properties":\{"disable":\{"type":"boolean"\},"error_response":\{"oneOf":\[\{"type":"string"\},\{"type":"object"\}\]\},"filter":\{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"\},"pre_function":\{"description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`.","type":"string"\},"priority":\{"description":"priority of plugins by customized order","type":"integer"\}\},"type":"object"\},"i":\{"minimum":0,"type":"number"\},"ip":\{"type":"string"\},"port":\{"type":"integer"\},"s":\{"type":"string"\},"t":\{"minItems":1,"type":"array"\}\},"required":\["i"\],"type":"object"\},"version":0.1\}/



Expand Down Expand Up @@ -382,7 +382,7 @@ qr/\{"encrypt_fields":\["password"\],"properties":\{"password":\{"type":"string"
}
}
--- response_body
{"priority":1003,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"_meta":{"properties":{"disable":{"type":"boolean"},"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"filter":{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"},"priority":{"description":"priority of plugins by customized order","type":"integer"}},"type":"object"},"burst":{"minimum":0,"type":"integer"},"conn":{"exclusiveMinimum":0,"type":"integer"},"default_conn_delay":{"exclusiveMinimum":0,"type":"number"},"key":{"type":"string"},"key_type":{"default":"var","enum":["var","var_combination"],"type":"string"},"only_use_default_delay":{"default":false,"type":"boolean"}},"required":["conn","burst","default_conn_delay","key"],"type":"object"},"version":0.1}
{"priority":1003,"schema":{"$comment":"this is a mark for our injected plugin schema","properties":{"_meta":{"additionalProperties":false,"properties":{"disable":{"type":"boolean"},"error_response":{"oneOf":[{"type":"string"},{"type":"object"}]},"filter":{"description":"filter determines whether the plugin needs to be executed at runtime","type":"array"},"pre_function":{"description":"function to be executed in each phase before execution of plugins. The pre_function will have access to two arguments: `conf` and `ctx`.","type":"string"},"priority":{"description":"priority of plugins by customized order","type":"integer"}},"type":"object"},"burst":{"minimum":0,"type":"integer"},"conn":{"exclusiveMinimum":0,"type":"integer"},"default_conn_delay":{"exclusiveMinimum":0,"type":"number"},"key":{"type":"string"},"key_type":{"default":"var","enum":["var","var_combination"],"type":"string"},"only_use_default_delay":{"default":false,"type":"boolean"}},"required":["conn","burst","default_conn_delay","key"],"type":"object"},"version":0.1}



Expand Down
Loading
Loading