Skip to content

Commit

Permalink
feat(conf_loader): load all WASM filters from conf path (#10353)
Browse files Browse the repository at this point in the history
  • Loading branch information
locao authored and flrgh committed Apr 12, 2023
1 parent d76e802 commit d8900ef
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 38 deletions.
5 changes: 5 additions & 0 deletions kong.conf.default
Original file line number Diff line number Diff line change
Expand Up @@ -1904,3 +1904,8 @@
# in a Kong cluster must have a unique and
# valid UUID. When empty, node ID is
# automatically generated.
#wasm = off # Use this setting to enable WasmX, this allows running
# Wasm filters to process request data.

#wasm_filters_path = # Path to the directory containing Wasm filters
# that Kong must load on startup.
76 changes: 54 additions & 22 deletions kong/conf_loader/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ local concat = table.concat
local getenv = os.getenv
local exists = pl_path.exists
local abspath = pl_path.abspath
local isdir = pl_path.isdir
local tostring = tostring
local tonumber = tonumber
local setmetatable = setmetatable
Expand Down Expand Up @@ -585,10 +586,9 @@ local CONF_PARSERS = {
proxy_server = { typ = "string" },
proxy_server_ssl_verify = { typ = "boolean" },

max_queued_batches = { typ = "number" },

wasm = { typ = "boolean" },
wasm_modules = { typ = "array" },
wasm_filters_path = { typ = "string" },

error_template_html = { typ = "string" },
error_template_json = { typ = "string" },
error_template_xml = { typ = "string" },
Expand Down Expand Up @@ -670,6 +670,18 @@ local function parse_value(value, typ)
end


-- Validate Wasm properties
local function validate_wasm(wasm_enabled, filters_path)
if wasm_enabled and filters_path then
if not exists(filters_path) or not isdir(filters_path) then
return nil, fmt("wasm_filters_path '%s' is not a valid directory", filters_path)
end
end

return true
end


-- Validate properties (type/enum/custom) and infer their type.
-- @param[type=table] conf The configuration table to treat.
local function check_and_parse(conf, opts)
Expand Down Expand Up @@ -1297,6 +1309,14 @@ local function check_and_parse(conf, opts)
end
end

do
local ok, err = validate_wasm(conf.wasm, conf.wasm_filters_path)

if not ok then
errors[#errors + 1] = err
end
end

return #errors == 0, errors[1], errors
end

Expand Down Expand Up @@ -1478,6 +1498,34 @@ local function load_config_file(path)
return load_config(f)
end

--- Get available Wasm filters list
-- @param[type=string] Path where Wasm filters are stored.
local function get_wasm_filters(filters_path)
local wasm_filters = {}

if filters_path then
local filter_files = {}
for entry in pl_path.dir(filters_path) do
local pathname = pl_path.join(filters_path, entry)
if not filter_files[pathname] and pl_path.isfile(pathname) then
filter_files[pathname] = pathname

local extension = pl_path.extension(entry)
if string.lower(extension) == ".wasm" then
insert(wasm_filters, {
name = entry:sub(0, -#extension - 1),
path = pathname,
})
else
log(DEBUG, "ignoring file ", entry, " in ", filters_path, ": does not contain wasm suffix")
end
end
end
end

return wasm_filters
end


--- Load Kong configuration
-- The loaded configuration will have all properties from the default config
Expand Down Expand Up @@ -2038,25 +2086,9 @@ local function load(path, custom_conf, opts)
assert(require("kong.tools.dns")(conf))

-- WebAssembly module support
if conf.wasm_modules then
local paths = {}
local wasm_modules = {}

for _, pathname in ipairs(conf.wasm_modules) do
if not paths[pathname] then
paths[pathname] = path

local basename = pl_path.basename(pathname)
local extension = pl_path.extension(basename)

insert(wasm_modules, {
name = basename:sub(0, -#extension - 1),
path = pathname,
})
end
end

conf.wasm_modules_parsed = setmetatable(wasm_modules, _nop_tostring_mt)
if conf.wasm then
local wasm_filters = get_wasm_filters(conf.wasm_filters_path)
conf.wasm_modules_parsed = setmetatable(wasm_filters, _nop_tostring_mt)
end

return setmetatable(conf, nil) -- remove Map mt
Expand Down
4 changes: 1 addition & 3 deletions kong/templates/kong_defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,6 @@ opentelemetry_tracing_sampling_rate = 1.0
tracing_instrumentations = off
tracing_sampling_rate = 1.0
max_queued_batches = 100
wasm = off
wasm_modules = NONE
wasm_filters_path = NONE
]]
4 changes: 2 additions & 2 deletions kong/templates/nginx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ events {
> end
}
> if wasm then
> if #wasm_modules_parsed > 0 then
wasm {
shm_kv kong_wasm_rate_limiting_counters 12m;
> for _, module in ipairs(wasm_modules_parsed) do
module $(module.name) $(module.path);
module $(module.name) $(module.path);
> end
}
Expand Down
38 changes: 33 additions & 5 deletions spec/01-unit/03-conf_loader_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1693,19 +1693,47 @@ describe("Configuration loader", function()
end)

describe("#wasm properties", function()
it("wasm_modules", function()
it("wasm disabled", function()
local conf, err = conf_loader(nil, {
wasm_modules = { "spec/fixtures/filter.wasm" },
wasm = "off",
wasm_filters_path = "spec/fixtures/wasm/unit-test",
})
assert.is_nil(err)
assert.is_nil(conf.wasm_modules_parsed)
end)

it("wasm default disabled", function()
local conf, err = conf_loader(nil, {
wasm_filters_path = "spec/fixtures/wasm/unit-test",
})
assert.is_nil(err)
assert.is_nil(conf.wasm_modules_parsed)
end)

it("wasm_filters_path", function()
local conf, err = conf_loader(nil, {
wasm = "on",
wasm_filters_path = "spec/fixtures/wasm/unit-test",
})
assert.is_nil(err)
assert.same({
{
name = "filter",
path = "spec/fixtures/filter.wasm",
name = "empty-filter",
path = "spec/fixtures/wasm/unit-test/empty-filter.wasm",
}
}, conf.wasm_modules_parsed)
assert.same({ "spec/fixtures/filter.wasm" }, conf.wasm_modules)
assert.same("spec/fixtures/wasm/unit-test", conf.wasm_filters_path)
end)

it("invalid wasm_filters_path", function()
local conf, err = conf_loader(nil, {
wasm = "on",
wasm_filters_path = "spec/fixtures/no-wasm-here/unit-test",
})
assert.same(err, "wasm_filters_path 'spec/fixtures/no-wasm-here/unit-test' is not a valid directory")
assert.is_nil(conf)
end)

end)

describe("errors", function()
Expand Down
7 changes: 4 additions & 3 deletions spec/01-unit/04-prefix_handler_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -773,13 +773,14 @@ describe("NGINX conf compiler", function()
describe("#wasm subsystem", function()
it("injects the wasm{} subsystem", function()
local conf = assert(conf_loader(nil, {
wasm_modules = { "spec/fixtures/filter.wasm" },
wasm = "on",
wasm_filters_path = "spec/fixtures/wasm/unit-test/",
}))
assert.is_true(conf.wasm)
assert.equal(conf.wasm_filters_path, "spec/fixtures/wasm/unit-test/")

local nginx_conf = prefix_handler.compile_nginx_conf(conf)
assert.matches("wasm {", nginx_conf)
assert.matches("module filter spec/fixtures/filter.wasm;", nginx_conf)
assert.matches("module empty%-filter spec/fixtures/wasm/unit%-test/empty%-filter.wasm;", nginx_conf)
end)
end)
end)
Expand Down
3 changes: 2 additions & 1 deletion spec/03-plugins/38-proxy-wasm/02-filters_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ describe("Plugin: proxy-wasm filters (#wasm)", function()
database = DATABASE,
plugins = "bundled, proxy-wasm",
nginx_conf = "spec/fixtures/custom_nginx.template",
wasm_modules = PROXY_WASM_PATH .. "/target/wasm32-wasi/debug/tests.wasm",
wasm = "on",
wasm_filters_path = PROXY_WASM_PATH .. "/target/wasm32-wasi/debug",
})
end)

Expand Down
7 changes: 5 additions & 2 deletions spec/fixtures/custom_nginx.template
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ events {
> end
}

> if wasm then
> if #wasm_modules_parsed > 0 then
wasm {
shm_kv kong_wasm_rate_limiting_counters 12m;

> for _, module in ipairs(wasm_modules_parsed) do
module $(module.name) $(module.path);
module $(module.name) $(module.path);
> end
}


env RUST_BACKTRACE=1;
env WASMTIME_BACKTRACE_DETAILS=1;
> end
Expand Down

0 comments on commit d8900ef

Please sign in to comment.