Skip to content

Commit

Permalink
fix(wasm): add a startup check for missing filters
Browse files Browse the repository at this point in the history
This adds a check during `init` that will prevent Kong from starting if
any filter chain entities are found in the database using a filter that
is not installed. Example:

> Error: ./kong/cmd/start.lua:99: nginx: [error] init_by_lua error: /path/to/kong/init.lua:750: [wasm]: found one or more filter chain entities with filters that are not enabled/installed:
> filter chain: 9e0b56d6-0e8c-469f-bf15-142debdd5d05, filter: #1 (response_transformer)
> filter chain: 9e0b56d6-0e8c-469f-bf15-142debdd5d05, filter: #3 (response_transformer)

Previously, this condition would not be caught until the Wasm state is
built during `init_worker`. This change brings Wasm more in line with the
behavior of the plugins iterator.
  • Loading branch information
flrgh committed Oct 23, 2024
1 parent b45aca4 commit 8f107b2
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 0 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/kong/fix-wasm-check-missing-filters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
message: |
**proxy-wasm:** Added a check that prevents Kong from starting when the
database contains invalid Wasm filters.
type: bugfix
scope: Core
5 changes: 5 additions & 0 deletions kong/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,11 @@ function Kong.init()
if not is_control_plane(config) then
assert(runloop.build_router("init"))

ok, err = wasm.check_enabled_filters()
if not ok then
error("[wasm]: " .. err)
end

ok, err = runloop.set_init_versions_in_cache()
if not ok then
error("error setting initial versions for router and plugins iterator in cache: " ..
Expand Down
32 changes: 32 additions & 0 deletions kong/runloop/wasm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1000,4 +1000,36 @@ function _M.status()
return true
end

function _M.check_enabled_filters()
if not ENABLED then
return true
end

local enabled_filters = _M.filters_by_name

local errs
for chain, err in kong.db.filter_chains:each() do
if err then
return nil, err
end

for i, filter in ipairs(chain.filters) do
if not enabled_filters[filter.name] then
errs = errs or {}

insert(errs, fmt("filter chain: %s, filter: #%s (%s)",
chain.id, i, filter.name))
end
end
end

if errs then
return nil, "found one or more filter chain entities with filters that are "
.. "not enabled/installed:\n" .. table.concat(errs, "\n")
end


return true
end

return _M
103 changes: 103 additions & 0 deletions spec/02-integration/20-wasm/11-missing-filters_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
local helpers = require "spec.helpers"

local FILTER_PATH = assert(helpers.test_conf.wasm_filters_path)

-- no cassandra support
for _, strategy in helpers.each_strategy({ "postgres", "off" }) do

describe("missing filters in the config [#" .. strategy .. "]", function()
local bp
local service, route

lazy_setup(function()
require("kong.runloop.wasm").enable({
{ name = "tests",
path = FILTER_PATH .. "/tests.wasm",
},
{ name = "response_transformer",
path = FILTER_PATH .. "/response_transformer.wasm",
},
})

bp = helpers.get_db_utils(strategy, {
"routes",
"services",
"filter_chains",
})

service = assert(bp.services:insert {
name = "wasm-test",
})

route = assert(bp.routes:insert {
service = service,
paths = { "/" },
})

assert(bp.filter_chains:insert {
name = "test",
route = route,
filters = {
{
name = "response_transformer",
config = require("cjson").encode {
append = {
headers = {
"x-wasm-test:my-value",
},
},
}
},
{
name = "tests",
config = nil,
},
{
name = "response_transformer",
config = require("cjson").encode {
append = {
headers = {
"x-wasm-test:my-value",
},
},
}
}
}
})
end)

lazy_teardown(function()
helpers.clean_prefix()
end)

it("causes Kong to fail to start", function()
local started, err = helpers.start_kong({
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
wasm_filters = "tests",
wasm = true,
})

-- clean up even if the test fails
if started then
helpers.stop_kong()
end

assert.falsy(started, "expected `kong start` to fail")
assert.string(err)

if strategy == "postgres" then
-- wasm.check_enabled_filters() code path
assert.matches("response_transformer", err)

elseif strategy == "off" then
-- dbless mode will fail the Lua schema check on `filter_chains[].filters[].name`
assert.matches("no such filter", err)

else
error("missing test coverage/assertion for strategy: " .. strategy)
end
end)
end)

end -- each strategy

0 comments on commit 8f107b2

Please sign in to comment.