项目文件夹

文件
2026-07-13 12:32:21 +08:00

193 行
5.0 KiB
Lua

local buffer = require("string.buffer")
local declarative = require("kong.db.declarative")
local reports = require("kong.reports")
local errors = require("kong.db.errors")
local kong = kong
local ngx = ngx
local type = type
local tostring = tostring
local _reports = {
decl_fmt_version = false,
}
local function reports_timer(premature)
if premature then
return
end
reports.send("dbless-reconfigure", _reports)
end
local function truthy(val)
if type(val) == "string" then
val = val:lower()
return val == "true"
or val == "1"
or val == "on"
or val == "yes"
end
return val == true
or val == 1
end
local function hydrate_config_from_request(params, dc)
if params._format_version then
return params
end
local config = params.config
if not config then
local body = kong.request.get_raw_body()
if type(body) == "string" and #body > 0 then
config = body
else
return kong.response.exit(400, {
message = "expected a declarative configuration"
})
end
end
local dc_table, _, err_t, new_hash = dc:unserialize(config)
if not dc_table then
return kong.response.exit(400, errors:declarative_config(err_t))
end
return dc_table, new_hash
end
local function parse_config_post_opts(params)
local flatten_errors = truthy(params.flatten_errors)
params.flatten_errors = nil
-- XXX: this code is much older than the `flatten_errors` flag and therefore
-- does not use the same `truthy()` helper, for backwards compatibility
local check_hash = tostring(params.check_hash) == "1"
params.check_hash = nil
return {
flatten_errors = flatten_errors,
check_hash = check_hash,
}
end
return {
["/config"] = {
GET = function(self, db)
if kong.db.strategy ~= "off" then
return kong.response.exit(400, {
message = "this endpoint is only available when Kong is " ..
"configured to not use a database"
})
end
local file = {
buf = buffer.new(),
write = function(self, str)
self.buf:put(str)
end,
}
local ok, err = declarative.export_from_db(file)
if not ok then
kong.log.err("failed exporting config from cache: ", err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end
return kong.response.exit(200, { config = file.buf:get() })
end,
POST = function(self, db)
if kong.db.strategy ~= "off" then
return kong.response.exit(400, {
message = "this endpoint is only available when Kong is " ..
"configured to not use a database"
})
end
local opts = parse_config_post_opts(self.params)
local old_hash = opts.check_hash and declarative.get_current_hash()
local dc = kong.db.declarative_config
if not dc then
kong.log.crit("received POST request to /config endpoint, but ",
"kong.db.declarative_config was not initialized")
return kong.response.exit(500, { message = "An unexpected error occurred" })
end
local dc_table, new_hash = hydrate_config_from_request(self.params, dc)
if opts.check_hash and new_hash and old_hash == new_hash then
return kong.response.exit(304)
end
local entities, _, err_t, meta
entities, _, err_t, meta, new_hash = dc:parse_table(dc_table, new_hash)
if not entities then
local res
if opts.flatten_errors and dc_table then
res = errors:declarative_config_flattened(err_t, dc_table)
else
res = errors:declarative_config(err_t)
end
return kong.response.exit(400, res)
end
local ok, err, ttl = declarative.load_into_cache_with_events(entities, meta, new_hash)
if not ok then
if err == "busy" or err == "locked" then
return kong.response.exit(429, {
message = "Currently loading previous configuration"
}, { ["Retry-After"] = ttl })
end
if err == "timeout" then
return kong.response.exit(504, {
message = "Timed out while loading configuration"
})
end
if err == "exiting" then
return kong.response.exit(503, {
message = "Kong currently exiting"
})
end
if err == "map full" then
kong.log.err("not enough space for declarative config")
return kong.response.exit(413, {
message = "Configuration does not fit in LMDB database, " ..
"consider raising the \"lmdb_map_size\" config for Kong"
})
end
kong.log.err("failed loading declarative config into cache: ", err)
return kong.response.exit(500, { message = "An unexpected error occurred" })
end
_reports.decl_fmt_version = meta._format_version
ngx.timer.at(0, reports_timer)
declarative.sanitize_output(entities)
return kong.response.exit(201, entities)
end,
},
}