Skip to content

Commit

Permalink
fix(wasm): validate filters in all persistence modes
Browse files Browse the repository at this point in the history
  • Loading branch information
flrgh committed Jul 28, 2023
1 parent 7f9ae5f commit eb0aff4
Show file tree
Hide file tree
Showing 15 changed files with 344 additions and 163 deletions.
1 change: 0 additions & 1 deletion kong-3.5.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ build = {
["kong.db.schema"] = "kong/db/schema/init.lua",
["kong.db.dao.keys"] = "kong/db/dao/keys.lua",
["kong.db.dao.key_sets"] = "kong/db/dao/key_sets.lua",
["kong.db.dao.filter_chains"] = "kong/db/dao/filter_chains.lua",
["kong.db.schema.entities.keys"] = "kong/db/schema/entities/keys.lua",
["kong.db.schema.entities.key_sets"] = "kong/db/schema/entities/key_sets.lua",
["kong.db.schema.entities.consumers"] = "kong/db/schema/entities/consumers.lua",
Expand Down
5 changes: 3 additions & 2 deletions kong/clustering/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local pl_tablex = require("pl.tablex")
local clustering_utils = require("kong.clustering.utils")
local events = require("kong.clustering.events")
local clustering_tls = require("kong.clustering.tls")
local wasm = require("kong.runloop.wasm")


local assert = assert
Expand Down Expand Up @@ -102,8 +103,8 @@ function _M:init_worker()
end, plugins_list)

local filters = {}
if kong.db.filter_chains.filters then
for _, filter in ipairs(kong.db.filter_chains.filters) do
if wasm.enabled() and wasm.filters then
for _, filter in ipairs(wasm.filters) do
filters[filter.name] = { name = filter.name }
end
end
Expand Down
108 changes: 0 additions & 108 deletions kong/db/dao/filter_chains.lua

This file was deleted.

24 changes: 22 additions & 2 deletions kong/db/schema/entities/filter_chains.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
local typedefs = require "kong.db.schema.typedefs"
local wasm = require "kong.runloop.wasm"


---@class kong.db.schema.entities.filter_chain : table
---
Expand All @@ -20,10 +22,12 @@ local typedefs = require "kong.db.schema.typedefs"
---@field enabled boolean
---@field config string|table|nil


local filter = {
type = "record",
fields = {
{ name = { type = "string", required = true, }, },
{ name = { type = "string", required = true, one_of = wasm.filter_names,
err = "no such filter", }, },
{ config = { type = "string", required = false, }, },
{ enabled = { type = "boolean", default = true, required = true, }, },
},
Expand All @@ -37,7 +41,6 @@ return {
admin_api_name = "filter-chains",
generate_admin_api = true,
workspaceable = true,
dao = "kong.db.dao.filter_chains",
cache_key = { "route", "service" },

fields = {
Expand Down Expand Up @@ -65,5 +68,22 @@ return {
"route",
}
},

-- This check is for user experience and is not strictly necessary to
-- validate filter chain input.
--
-- The `one_of` check on `filters[].name` already covers validation, but in
-- the case where wasm is disabled or no filters are installed, this check
-- adds an additional entity-level error (e.g. "wasm support is not enabled"
-- or "no wasm filters are available").
--
-- All of the wasm API routes are disabled when wasm is also disabled, so
-- this primarily serves the dbless `/config` endpoint.
{ custom_entity_check = {
field_sources = { "filters" },
run_with_invalid_fields = true,
fn = wasm.status,
},
},
},
}
5 changes: 4 additions & 1 deletion kong/db/schema/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,10 @@ local function run_entity_check(self, name, input, arg, full_check, errors)
end

-- Don't run check if any of its fields has errors
if not all_ok and not checker.run_with_invalid_fields then
if not all_ok
and not checker.run_with_invalid_fields
and not arg.run_with_invalid_fields
then
return
end

Expand Down
1 change: 1 addition & 0 deletions kong/db/schema/metaschema.lua
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ local entity_checkers = {
{ field_sources = { type = "array", elements = { type = "string" } } },
{ fn = { type = "function" } },
{ run_with_missing_fields = { type = "boolean" } },
{ run_with_invalid_fields = { type = "boolean" } },
}
}
},
Expand Down
2 changes: 0 additions & 2 deletions kong/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,6 @@ function Kong.init()
-- Load plugins as late as possible so that everything is set up
assert(db.plugins:load_plugin_schemas(config.loaded_plugins))

assert(db.filter_chains:load_filters(config.wasm_modules_parsed))

if is_stream_module then
stream_api.load_handlers()
end
Expand Down
114 changes: 98 additions & 16 deletions kong/runloop/wasm.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
local _M = {}
local _M = {
-- these filter lookup tables are created once and then reset/re-used when
-- `wasm.init()` is called. This means other modules are permitted to stash
-- a reference to them, which helps to avoid several chicken/egg dependency
-- ordering issues.

---@type kong.configuration.wasm_filter[]
filters = {},

---@type table<string, kong.configuration.wasm_filter>
filters_by_name = {},

---@type string[]
filter_names = {},
}


--- This represents a wasm module discovered by the conf_loader in
--- `kong.configuration.wasm_filters_path`
---
---@class kong.configuration.wasm_filter
---
---@field name string
---@field path string


local utils = require "kong.tools.utils"
local dns = require "kong.tools.dns"
Expand Down Expand Up @@ -48,6 +72,8 @@ local TYPE_COMBINED = 2


local ENABLED = false
local STATUS = "wasm support is not enabled"


local hash_chain
do
Expand Down Expand Up @@ -513,33 +539,79 @@ local function get_filter_chain_for_request(route, service)
end


---@param filters kong.configuration.wasm_filter[]|nil
local function set_available_filters(filters)
clear_tab(_M.filters)
clear_tab(_M.filters_by_name)
clear_tab(_M.filter_names)

if filters then
for i, filter in ipairs(filters) do
_M.filters[i] = filter
_M.filters_by_name[filter.name] = filter
_M.filter_names[i] = filter.name
end
end
end


---@param reason string
local function disable(reason)
set_available_filters(nil)

_G.dns_client = nil

ENABLED = false
STATUS = reason or "wasm support is not enabled"
end


local function enable(kong_config)
set_available_filters(kong_config.wasm_modules_parsed)

-- setup a DNS client for ngx_wasm_module
_G.dns_client = _G.dns_client or dns(kong_config)

proxy_wasm = proxy_wasm or require "resty.wasmx.proxy_wasm"
ATTACH_OPTS.isolation = proxy_wasm.isolations.FILTER

ENABLED = true
STATUS = "wasm support is enabled"
end


_M.get_version = get_version

_M.update_in_place = update_in_place

_M.set_state = set_state

function _M.enable(filters)
enable({
wasm = true,
wasm_modules_parsed = filters,
})
end

---@param kong_config table
function _M.init(kong_config)
if not kong_config.wasm then
return
end
_M.disable = disable

local modules = kong_config.wasm_modules_parsed
if not modules or #modules == 0 then
return
end

reports.add_immutable_value("wasm_cnt", #modules)
---@param kong_config table
function _M.init(kong_config)
if kong_config.wasm then
local filters = kong_config.wasm_modules_parsed

-- setup a DNS client for ngx_wasm_module
_G.dns_client = dns(kong_config)
if filters and #filters > 0 then
reports.add_immutable_value("wasm_cnt", #filters)
enable(kong_config)

proxy_wasm = require "resty.wasmx.proxy_wasm"
ENABLED = true
else
disable("no wasm filters are available")
end

ATTACH_OPTS.isolation = proxy_wasm.isolations.FILTER
else
disable("wasm support is not enabled")
end
end


Expand Down Expand Up @@ -653,4 +725,14 @@ function _M.enabled()
end


---@return boolean? ok
---@return string? error
function _M.status()
if not ENABLED then
return nil, STATUS
end

return true
end

return _M
12 changes: 6 additions & 6 deletions spec/02-integration/20-wasm/01-admin-api_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ describe("wasm admin API [#" .. strategy .. "]", function()
local service, route

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

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

db.filter_chains:load_filters({
{ name = "tests" },
{ name = "response_transformer" },
})

service = assert(db.services:insert {
name = "wasm-test",
url = "http://wasm.test",
Expand Down Expand Up @@ -111,7 +111,7 @@ describe("wasm admin API [#" .. strategy .. "]", function()
local body = assert.response(res).has.jsonbody()
assert.same({ data = {}, next = ngx.null }, body)

local chain = assert(bp.filter_chains:insert({
local chain = assert(bp.filter_chains:insert({
filters = { { name = "tests" } },
service = { id = service.id },
tags = { "a" },
Expand Down
Loading

0 comments on commit eb0aff4

Please sign in to comment.