- 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>
317 lines
8.0 KiB
Lua
317 lines
8.0 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 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
|