Skip to content

Commit

Permalink
feat: implement new plugin server-info (#2926)
Browse files Browse the repository at this point in the history
close #2821
  • Loading branch information
tokers authored Dec 9, 2020
1 parent 1e882e3 commit 7855d9e
Show file tree
Hide file tree
Showing 9 changed files with 605 additions and 1 deletion.
1 change: 1 addition & 0 deletions apisix/cli/ngx_tpl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ http {
.. [=[$prefix/deps/lib/lua/5.1/?.so;;]=]
.. [=[{*lua_cpath*};";
lua_shared_dict internal_status 10m;
lua_shared_dict plugin-limit-req 10m;
lua_shared_dict plugin-limit-count 10m;
lua_shared_dict prometheus-metrics 10m;
Expand Down
30 changes: 30 additions & 0 deletions apisix/core/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
--
local core_str = require("apisix.core.string")
local table = require("apisix.core.table")
local log = require("apisix.core.log")
local string = require("apisix.core.string")
local ngx_re = require("ngx.re")
local resolver = require("resty.dns.resolver")
local ipmatcher= require("resty.ipmatcher")
Expand All @@ -29,11 +31,14 @@ local tonumber = tonumber
local tostring = tostring
local re_gsub = ngx.re.gsub
local type = type
local io_popen = io.popen
local C = ffi.C
local ffi_string = ffi.string
local get_string_buf = base.get_string_buf
local exiting = ngx.worker.exiting
local ngx_sleep = ngx.sleep

local hostname
local max_sleep_interval = 1

ffi.cdef[[
Expand Down Expand Up @@ -206,6 +211,31 @@ function _M.validate_header_value(value)
end


-- only use this method in init/init_worker phase.
function _M.gethostname()
if hostname then
return hostname
end

local hd = io_popen("/bin/hostname")
local data, err = hd:read("*a")
if err == nil then
hostname = data
if string.has_suffix(hostname, "\r\n") then
hostname = sub_str(hostname, 1, -3)
elseif string.has_suffix(hostname, "\n") then
hostname = sub_str(hostname, 1, -2)
end

else
hostname = "unknown"
log.error("failed to read output of \"/bin/hostname\": ", err)
end

return hostname
end


local function sleep(sec)
if sec <= max_sleep_interval then
return ngx_sleep(sec)
Expand Down
210 changes: 210 additions & 0 deletions apisix/plugins/server-info.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
--
-- 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 ngx_time = ngx.time
local ngx_timer_at = ngx.timer.at
local ngx_worker_id = ngx.worker.id
local type = type

local boot_time = os.time()
local plugin_name = "server-info"
local default_report_interval = 60
local default_report_ttl = 7200

local schema = {
type = "object",
additionalProperties = false,
}
local attr_schema = {
type = "object",
properties = {
report_interval = {
type = "integer",
description = "server info reporting interval (unit: second)",
default = default_report_interval,
minimum = 60,
maximum = 3600,
},
report_ttl = {
type = "integer",
description = "live time for server info in etcd",
default = default_report_ttl,
minimum = 3600,
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,
}


local function uninitialized_server_info()
return {
etcd_version = "unknown",
hostname = core.utils.gethostname(),
id = core.id.get(),
version = core.version.VERSION,
up_time = ngx_time() - boot_time,
boot_time = boot_time,
last_report_time = -1,
}
end


local function get()
local data, err = internal_status:get("server_info")
if err ~= nil then
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
return nil, err
end

server_info.up_time = ngx_time() - server_info.boot_time
return server_info
end


local function report(premature, report_ttl)
if premature then
return
end

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
server_info.etcd_version = res.body.etcdcluster
end
end

server_info.last_report_time = ngx_time()

local data, err = core.json.encode(server_info)
if not data then
core.log.error("failed to encode server_info: ", err)
return
end

local key = "/data_plane/server_info/" .. server_info.id
local ok, err = core.etcd.set(key, data, report_ttl)
if not ok then
core.log.error("failed to report server info to etcd: ", 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.init()
core.log.info("server info: ", core.json.delay_encode(get()))

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 attr = core.table.try_read_attr(local_conf, "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 report_interval = attr and attr.report_interval or default_report_interval
local start_at = ngx_time()

local fn = function()
local now = ngx_time()
if now - start_at >= report_interval 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 created to report server info, interval: ",
report_interval)
end


function _M.destory()
timers.unregister_timer("plugin#server-info", true)
end


return _M
11 changes: 10 additions & 1 deletion apisix/timers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ local unpack = unpack
local thread_spawn = ngx.thread.spawn
local thread_wait = ngx.thread.wait

local check_interval = 0.5

local timers = {}

Expand Down Expand Up @@ -57,7 +58,10 @@ end


function _M.init_worker()
local timer, err = core.timer.new("background", background_timer, {check_interval = 0.5})
local opts = {
check_interval = check_interval,
}
local timer, err = core.timer.new("background", background_timer, opts)
if not timer then
core.log.error("failed to create background timer: ", err)
return
Expand Down Expand Up @@ -85,4 +89,9 @@ function _M.unregister_timer(name, privileged)
end


function _M.check_interval()
return check_interval
end


return _M
4 changes: 4 additions & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ plugins: # plugin list (sorted in alphabetical order)
- uri-blocker
- wolf-rbac
- zipkin
#- server-info

stream_plugins:
- mqtt-proxy
Expand All @@ -253,3 +254,6 @@ plugin_attr:
endpoint_addr: http://127.0.0.1:12800
prometheus:
export_uri: /apisix/prometheus/metrics
server-info:
report_interval: 60 # server info report interval (unit: second)
report_ttl: 3600 # live time for server info in etcd (unit: second)
Loading

0 comments on commit 7855d9e

Please sign in to comment.