- Implements Apache APISIX packaging for Cloudron platform. - Includes Dockerfile, CloudronManifest.json, and start.sh. - Configured to use Cloudron's etcd addon. 🤖 Generated with Gemini CLI Co-Authored-By: Gemini <noreply@google.com>
213 lines
6.2 KiB
Lua
213 lines
6.2 KiB
Lua
--
|
|
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
|
-- contributor license agreements. See the NOTICE file distributed with
|
|
-- this work for additional information regarding copyright ownership.
|
|
-- The ASF licenses this file to You under the Apache License, Version 2.0
|
|
-- (the "License"); you may not use this file except in compliance with
|
|
-- the License. You may obtain a copy of the License at
|
|
--
|
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
|
--
|
|
-- Unless required by applicable law or agreed to in writing, software
|
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
-- See the License for the specific language governing permissions and
|
|
-- limitations under the License.
|
|
--
|
|
local require = require
|
|
local router = require("apisix.utils.router")
|
|
local radixtree = require("resty.radixtree")
|
|
local builtin_v1_routes = require("apisix.control.v1")
|
|
local plugin_mod = require("apisix.plugin")
|
|
local core = require("apisix.core")
|
|
|
|
local str_sub = string.sub
|
|
local ipairs = ipairs
|
|
local pairs = pairs
|
|
local type = type
|
|
local ngx = ngx
|
|
local get_method = ngx.req.get_method
|
|
local events = require("apisix.events")
|
|
|
|
local _M = {}
|
|
|
|
|
|
local function format_dismod_uri(mod_name, uri)
|
|
if core.string.has_prefix(uri, "/v1/") then
|
|
return uri
|
|
end
|
|
|
|
local tmp = {"/v1/discovery/", mod_name}
|
|
if not core.string.has_prefix(uri, "/") then
|
|
core.table.insert(tmp, "/")
|
|
end
|
|
core.table.insert(tmp, uri)
|
|
|
|
return core.table.concat(tmp, "")
|
|
end
|
|
|
|
-- we do not hardcode the discovery module's control api uri
|
|
local function format_dismod_control_api_uris(mod_name, api_route)
|
|
if not api_route or #api_route == 0 then
|
|
return api_route
|
|
end
|
|
|
|
local clone_route = core.table.clone(api_route)
|
|
for _, v in ipairs(clone_route) do
|
|
local uris = v.uris
|
|
local target_uris = core.table.new(#uris, 0)
|
|
for _, uri in ipairs(uris) do
|
|
local target_uri = format_dismod_uri(mod_name, uri)
|
|
core.table.insert(target_uris, target_uri)
|
|
end
|
|
v.uris = target_uris
|
|
end
|
|
|
|
return clone_route
|
|
end
|
|
|
|
|
|
local fetch_control_api_router
|
|
do
|
|
local function register_api_routes(routes, api_routes)
|
|
for _, route in ipairs(api_routes) do
|
|
core.table.insert(routes, {
|
|
methods = route.methods,
|
|
-- note that it is 'uris' for control API, which is an array of strings
|
|
paths = route.uris,
|
|
handler = function (api_ctx)
|
|
local code, body = route.handler(api_ctx)
|
|
if code or body then
|
|
if type(body) == "table" and ngx.header["Content-Type"] == nil then
|
|
core.response.set_header("Content-Type", "application/json")
|
|
end
|
|
|
|
core.response.exit(code, body)
|
|
end
|
|
end
|
|
})
|
|
end
|
|
end
|
|
|
|
local routes = {}
|
|
local v1_routes = {}
|
|
local function empty_func() end
|
|
|
|
function fetch_control_api_router()
|
|
core.table.clear(routes)
|
|
|
|
for _, plugin in ipairs(plugin_mod.plugins) do
|
|
local api_fun = plugin.control_api
|
|
if api_fun then
|
|
local api_route = api_fun()
|
|
register_api_routes(routes, api_route)
|
|
end
|
|
end
|
|
|
|
local discovery_type = require("apisix.core.config_local").local_conf().discovery
|
|
if discovery_type then
|
|
local discovery = require("apisix.discovery.init").discovery
|
|
local dump_apis = {}
|
|
for key, _ in pairs(discovery_type) do
|
|
local dis_mod = discovery[key]
|
|
-- if discovery module has control_api method, support it
|
|
local api_fun = dis_mod.control_api
|
|
if api_fun then
|
|
local api_route = api_fun()
|
|
local format_route = format_dismod_control_api_uris(key, api_route)
|
|
register_api_routes(routes, format_route)
|
|
end
|
|
|
|
local dump_data = dis_mod.dump_data
|
|
if dump_data then
|
|
local target_uri = format_dismod_uri(key, "/dump")
|
|
local item = {
|
|
methods = {"GET"},
|
|
uris = {target_uri},
|
|
handler = function()
|
|
return 200, dump_data()
|
|
end
|
|
}
|
|
core.table.insert(dump_apis, item)
|
|
end
|
|
end
|
|
|
|
if #dump_apis > 0 then
|
|
core.log.notice("dump_apis: ", core.json.encode(dump_apis, true))
|
|
register_api_routes(routes, dump_apis)
|
|
end
|
|
end
|
|
|
|
core.table.clear(v1_routes)
|
|
register_api_routes(v1_routes, builtin_v1_routes)
|
|
|
|
local v1_router, err = router.new(v1_routes)
|
|
if not v1_router then
|
|
return nil, err
|
|
end
|
|
|
|
core.table.insert(routes, {
|
|
paths = {"/v1/*"},
|
|
filter_fun = function(vars, opts, ...)
|
|
local uri = str_sub(vars.uri, #"/v1" + 1)
|
|
return v1_router:dispatch(uri, opts, ...)
|
|
end,
|
|
handler = empty_func,
|
|
})
|
|
|
|
local with_parameter = false
|
|
local conf = core.config.local_conf()
|
|
if conf.apisix.enable_control and conf.apisix.control then
|
|
if conf.apisix.control.router == "radixtree_uri_with_parameter" then
|
|
with_parameter = true
|
|
end
|
|
end
|
|
|
|
if with_parameter then
|
|
return radixtree.new(routes)
|
|
else
|
|
return router.new(routes)
|
|
end
|
|
end
|
|
|
|
end -- do
|
|
|
|
|
|
do
|
|
local match_opts = {}
|
|
local cached_version
|
|
local router
|
|
|
|
function _M.match(uri)
|
|
if cached_version ~= plugin_mod.load_times then
|
|
local err
|
|
router, err = fetch_control_api_router()
|
|
if router == nil then
|
|
core.log.error("failed to fetch valid api router: ", err)
|
|
return false
|
|
end
|
|
|
|
cached_version = plugin_mod.load_times
|
|
end
|
|
|
|
core.table.clear(match_opts)
|
|
match_opts.method = get_method()
|
|
|
|
return router:dispatch(uri, match_opts)
|
|
end
|
|
|
|
end -- do
|
|
|
|
local function reload_plugins()
|
|
core.log.info("start to hot reload plugins")
|
|
plugin_mod.load()
|
|
end
|
|
|
|
|
|
function _M.init_worker()
|
|
-- register reload plugin handler
|
|
events:register(reload_plugins, builtin_v1_routes.reload_event, "PUT")
|
|
end
|
|
|
|
return _M
|