feat(apisix): add Cloudron package
- 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>
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
--
|
||||
-- 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 core = require("apisix.core")
|
||||
local timers = require("apisix.timers")
|
||||
local plugin = require("apisix.plugin")
|
||||
|
||||
local ngx_time = ngx.time
|
||||
local ngx_timer_at = ngx.timer.at
|
||||
local ngx_worker_id = ngx.worker.id
|
||||
local type = type
|
||||
|
||||
local load_time = os.time()
|
||||
local plugin_name = "server-info"
|
||||
local default_report_ttl = 60
|
||||
local lease_id
|
||||
|
||||
local schema = {
|
||||
type = "object",
|
||||
}
|
||||
local attr_schema = {
|
||||
type = "object",
|
||||
properties = {
|
||||
report_ttl = {
|
||||
type = "integer",
|
||||
description = "live time for server info in etcd",
|
||||
default = default_report_ttl,
|
||||
minimum = 3,
|
||||
maximum = 86400,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local internal_status = ngx.shared["internal-status"]
|
||||
if not internal_status then
|
||||
error("lua_shared_dict \"internal-status\" not configured")
|
||||
end
|
||||
|
||||
|
||||
local _M = {
|
||||
version = 0.1,
|
||||
priority = 990,
|
||||
name = plugin_name,
|
||||
schema = schema,
|
||||
scope = "global",
|
||||
}
|
||||
|
||||
|
||||
local function get_boot_time()
|
||||
local time, err = internal_status:get("server_info:boot_time")
|
||||
if err ~= nil then
|
||||
core.log.error("failed to get boot_time from shdict: ", err)
|
||||
return load_time
|
||||
end
|
||||
|
||||
if time ~= nil then
|
||||
return time
|
||||
end
|
||||
|
||||
local _, err = internal_status:set("server_info:boot_time", load_time)
|
||||
if err ~= nil then
|
||||
core.log.error("failed to save boot_time to shdict: ", err)
|
||||
end
|
||||
|
||||
return load_time
|
||||
end
|
||||
|
||||
|
||||
local function uninitialized_server_info()
|
||||
local boot_time = get_boot_time()
|
||||
return {
|
||||
etcd_version = "unknown",
|
||||
hostname = core.utils.gethostname(),
|
||||
id = core.id.get(),
|
||||
version = core.version.VERSION,
|
||||
boot_time = boot_time,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
local function get()
|
||||
local data, err = internal_status:get("server_info")
|
||||
if err ~= nil then
|
||||
core.log.error("get error: ", err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if not data then
|
||||
return uninitialized_server_info()
|
||||
end
|
||||
|
||||
local server_info, err = core.json.decode(data)
|
||||
if not server_info then
|
||||
core.log.error("failed to decode server_info: ", err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return server_info
|
||||
end
|
||||
|
||||
|
||||
local function get_server_info()
|
||||
local info, err = get()
|
||||
if not info then
|
||||
core.log.error("failed to get server_info: ", err)
|
||||
return 500
|
||||
end
|
||||
|
||||
return 200, info
|
||||
end
|
||||
|
||||
|
||||
local function set(key, value, ttl)
|
||||
local res_new, err = core.etcd.set(key, value, ttl)
|
||||
if not res_new then
|
||||
core.log.error("failed to set server_info: ", err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
if not res_new.body.lease_id then
|
||||
core.log.error("failed to get lease_id: ", err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
lease_id = res_new.body.lease_id
|
||||
|
||||
-- set or update lease_id
|
||||
local ok, err = internal_status:set("lease_id", lease_id)
|
||||
if not ok then
|
||||
core.log.error("failed to set lease_id to shdict: ", err)
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local function report(premature, report_ttl)
|
||||
if premature then
|
||||
return
|
||||
end
|
||||
|
||||
-- get apisix node info
|
||||
local server_info, err = get()
|
||||
if not server_info then
|
||||
core.log.error("failed to get server_info: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
if server_info.etcd_version == "unknown" then
|
||||
local res, err = core.etcd.server_version()
|
||||
if not res then
|
||||
core.log.error("failed to fetch etcd version: ", err)
|
||||
return
|
||||
|
||||
elseif type(res.body) ~= "table" then
|
||||
core.log.error("failed to fetch etcd version: bad version info")
|
||||
return
|
||||
|
||||
else
|
||||
if res.body.etcdcluster == "" then
|
||||
server_info.etcd_version = res.body.etcdserver
|
||||
else
|
||||
server_info.etcd_version = res.body.etcdcluster
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- get inside etcd data, if not exist, create it
|
||||
local key = "/data_plane/server_info/" .. server_info.id
|
||||
local res, err = core.etcd.get(key)
|
||||
if not res or (res.status ~= 200 and res.status ~= 404) then
|
||||
core.log.error("failed to get server_info from etcd: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
if not res.body.node then
|
||||
local ok, err = set(key, server_info, report_ttl)
|
||||
if not ok then
|
||||
core.log.error("failed to set server_info to etcd: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local ok = core.table.deep_eq(server_info, res.body.node.value)
|
||||
-- not equal, update it
|
||||
if not ok then
|
||||
local ok, err = set(key, server_info, report_ttl)
|
||||
if not ok then
|
||||
core.log.error("failed to set server_info to etcd: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- get lease_id from ngx dict
|
||||
lease_id, err = internal_status:get("lease_id")
|
||||
if not lease_id then
|
||||
core.log.error("failed to get lease_id from shdict: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
-- call keepalive
|
||||
local res, err = core.etcd.keepalive(lease_id)
|
||||
if not res then
|
||||
core.log.error("send heartbeat failed: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local data, err = core.json.encode(server_info)
|
||||
if not data then
|
||||
core.log.error("failed to encode server_info: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local ok, err = internal_status:set("server_info", data)
|
||||
if not ok then
|
||||
core.log.error("failed to encode and save server info: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function _M.check_schema(conf)
|
||||
local ok, err = core.schema.check(schema, conf)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function _M.control_api()
|
||||
return {
|
||||
{
|
||||
methods = {"GET"},
|
||||
uris ={"/v1/server_info"},
|
||||
handler = get_server_info,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
function _M.init()
|
||||
core.log.warn("The server-info plugin is deprecated and will be removed in a future release.")
|
||||
if core.config ~= require("apisix.core.config_etcd") then
|
||||
-- we don't need to report server info if etcd is not in use.
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local local_conf = core.config.local_conf()
|
||||
local deployment_role = core.table.try_read_attr(
|
||||
local_conf, "deployment", "role")
|
||||
if deployment_role == "data_plane" then
|
||||
-- data_plane should not write to etcd
|
||||
return
|
||||
end
|
||||
|
||||
local attr = plugin.plugin_attr(plugin_name)
|
||||
local ok, err = core.schema.check(attr_schema, attr)
|
||||
if not ok then
|
||||
core.log.error("failed to check plugin_attr: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local report_ttl = attr and attr.report_ttl or default_report_ttl
|
||||
local start_at = ngx_time()
|
||||
|
||||
local fn = function()
|
||||
local now = ngx_time()
|
||||
-- If ttl remaining time is less than half, then flush the ttl
|
||||
if now - start_at >= (report_ttl / 2) then
|
||||
start_at = now
|
||||
report(nil, report_ttl)
|
||||
end
|
||||
end
|
||||
|
||||
if ngx_worker_id() == 0 then
|
||||
local ok, err = ngx_timer_at(0, report, report_ttl)
|
||||
if not ok then
|
||||
core.log.error("failed to create initial timer to report server info: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
timers.register_timer("plugin#server-info", fn, true)
|
||||
|
||||
core.log.info("timer update the server info ttl, current ttl: ", report_ttl)
|
||||
end
|
||||
|
||||
|
||||
function _M.destroy()
|
||||
timers.unregister_timer("plugin#server-info", true)
|
||||
end
|
||||
|
||||
|
||||
return _M
|
Reference in New Issue
Block a user