Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(runloop): plugin:configure(configs) handler #11703

Merged
merged 1 commit into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/kong/plugin-configure-phase.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
message: >
Plugins can now implement `Plugin:configure(configs)` function that is called whenever
there is a change in plugin entities. An array of current plugin configurations is
passed to the function, or `nil` in case there is no active configurations for the plugin.
type: feature
scope: Core
8 changes: 5 additions & 3 deletions kong/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ local function execute_collected_plugins_iterator(plugins_iterator, phase, ctx)
span:finish()
end
end

if is_timing_enabled then
req_dyn_hook_run_hooks(ctx, "timing", "after:plugin_iterator")
end
Expand Down Expand Up @@ -946,8 +946,8 @@ function Kong.init_worker()
local errors = execute_init_worker_plugins_iterator(plugins_iterator, ctx)
if errors then
for _, e in ipairs(errors) do
local err = "failed to execute the \"init_worker\" " ..
"handler for plugin \"" .. e.plugin .."\": " .. e.err
local err = 'failed to execute the "init_worker" ' ..
'handler for plugin "' .. e.plugin ..'": ' .. e.err
stash_init_worker_error(err)
end
end
Expand All @@ -966,6 +966,8 @@ function Kong.init_worker()
stash_init_worker_error(err)
return
end

plugins_iterator:configure(ctx)
end


Expand Down
18 changes: 3 additions & 15 deletions kong/plugins/acme/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -508,21 +508,9 @@ local function renew_certificate_storage(conf)

end

local function renew_certificate(premature)
if premature then
return
end

for plugin, err in kong.db.plugins:each(1000) do
if err then
kong.log.warn("error fetching plugin: ", err)
end

if plugin.name == "acme" then
kong.log.info("renew storage configured in acme plugin: ", plugin.id)
renew_certificate_storage(plugin.config)
end
end
local function renew_certificate(config)
kong.log.info("renew storage configured in acme plugin: ", config.__plugin_id)
renew_certificate_storage(config)
end

local function load_renew_hosts(conf)
Expand Down
35 changes: 20 additions & 15 deletions kong/plugins/acme/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,28 +70,33 @@ local domains_matcher
-- expose it for use in api.lua
ACMEHandler.build_domain_matcher = build_domain_matcher

function ACMEHandler:init_worker()
local worker_id = ngx.worker.id()
kong.log.info("acme renew timer started on worker ", worker_id)
ngx.timer.every(86400, client.renew_certificate)

-- handle cache updating of domains_matcher
kong.worker_events.register(function(data)
if data.entity.name ~= "acme" then
return
end
local CONFIG

local operation = data.operation

if operation == "create" or operation == "update" then
local conf = data.entity.config
domains_matcher = build_domain_matcher(conf.domains)
end
local function renew(premature)
if premature or not CONFIG then
return
end
client.renew_certificate(CONFIG)
end


end, "crud", "plugins")
function ACMEHandler:init_worker()
local worker_id = ngx.worker.id()
kong.log.info("acme renew timer started on worker ", worker_id)
ngx.timer.every(86400, renew)
end


function ACMEHandler:configure(configs)
CONFIG = configs and configs[1] or nil
jschmid1 marked this conversation as resolved.
Show resolved Hide resolved
if CONFIG then
domains_matcher = build_domain_matcher(CONFIG.domains)
end
end


local function check_domains(conf, host)
if not conf.enable_ipv4_common_name and string_find(host, "^(%d+)%.(%d+)%.(%d+)%.(%d+)$") then
return false
Expand Down
69 changes: 12 additions & 57 deletions kong/plugins/prometheus/exporter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ local role = kong.configuration.role

local KONG_LATENCY_BUCKETS = { 1, 2, 5, 7, 10, 15, 20, 30, 50, 75, 100, 200, 500, 750, 1000}
local UPSTREAM_LATENCY_BUCKETS = {25, 50, 80, 100, 250, 400, 700, 1000, 2000, 5000, 10000, 30000, 60000 }
local IS_PROMETHEUS_ENABLED


local metrics = {}
-- prometheus.lua instance
Expand All @@ -33,60 +35,6 @@ local kong_subsystem = ngx.config.subsystem
local http_subsystem = kong_subsystem == "http"


-- should we introduce a way to know if a plugin is configured or not?
local is_prometheus_enabled, register_events_handler do
local PLUGIN_NAME = "prometheus"
local CACHE_KEY = "prometheus:enabled"

local function is_prometheus_enabled_fetch()
for plugin, err in kong.db.plugins:each() do
if err then
kong.log.crit("could not obtain list of plugins: ", err)
return nil, err
end

if plugin.name == PLUGIN_NAME and plugin.enabled then
return true
end
end

return false
end


-- Returns `true` if Prometheus is enabled anywhere inside Kong.
-- The results are then cached and purged as necessary.
function is_prometheus_enabled()
local enabled, err = kong.cache:get(CACHE_KEY, nil, is_prometheus_enabled_fetch)

if err then
error("error when checking if prometheus enabled: " .. err)
end

return enabled
end


-- invalidate cache when a plugin is added/removed/updated
function register_events_handler()
local worker_events = kong.worker_events

if kong.configuration.database == "off" then
worker_events.register(function()
kong.cache:invalidate(CACHE_KEY)
end, "declarative", "reconfigure")

else
worker_events.register(function(data)
if data.entity.name == PLUGIN_NAME then
kong.cache:invalidate(CACHE_KEY)
end
end, "crud", "plugins")
end
end
end


local function init()
local shm = "prometheus_metrics"
if not ngx.shared[shm] then
Expand Down Expand Up @@ -230,11 +178,17 @@ local function init()
end
end


local function init_worker()
prometheus:init_worker()
register_events_handler()
end


local function configure(configs)
IS_PROMETHEUS_ENABLED = configs ~= nil
end


-- Convert the MD5 hex string to its numeric representation
-- Note the following will be represented as a float instead of int64 since luajit
-- don't like int64. Good news is prometheus uses float instead of int64 as well
Expand Down Expand Up @@ -412,7 +366,7 @@ local function metric_data(write_fn)
-- upstream targets accessible?
local upstreams_dict = get_all_upstreams()
for key, upstream_id in pairs(upstreams_dict) do
-- long loop maybe spike proxy request latency, so we
-- long loop maybe spike proxy request latency, so we
-- need yield to avoid blocking other requests
-- kong.tools.utils.yield(true)
yield(true, phase)
Expand Down Expand Up @@ -489,7 +443,7 @@ local function metric_data(write_fn)

-- notify the function if prometheus plugin is enabled,
-- so that it can avoid exporting unnecessary metrics if not
prometheus:metric_data(write_fn, not is_prometheus_enabled())
prometheus:metric_data(write_fn, not IS_PROMETHEUS_ENABLED)
jschmid1 marked this conversation as resolved.
Show resolved Hide resolved
end

local function collect()
Expand Down Expand Up @@ -525,6 +479,7 @@ end
return {
init = init,
init_worker = init_worker,
configure = configure,
log = log,
metric_data = metric_data,
collect = collect,
Expand Down
10 changes: 8 additions & 2 deletions kong/plugins/prometheus/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ local PrometheusHandler = {
VERSION = kong_meta.version,
}

function PrometheusHandler.init_worker()
function PrometheusHandler:init_worker()
exporter.init_worker()
end


function PrometheusHandler:configure(configs)
exporter.configure(configs)
end


local http_subsystem = ngx.config.subsystem == "http"


function PrometheusHandler.log(self, conf)
function PrometheusHandler:log(conf)
local message = kong.log.serialize()

local serialized = {}
Expand Down
14 changes: 14 additions & 0 deletions kong/runloop/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ local exec = ngx.exec
local header = ngx.header
local set_header = ngx.req.set_header
local timer_at = ngx.timer.at
local get_phase = ngx.get_phase
local subsystem = ngx.config.subsystem
local clear_header = ngx.req.clear_header
local http_version = ngx.req.http_version
Expand Down Expand Up @@ -519,6 +520,14 @@ local function build_plugins_iterator(version)
if not plugins_iterator then
return nil, err
end

local phase = get_phase()
-- skip calling plugins_iterator:configure on init/init_worker
-- as it is explicitly called on init_worker
if phase ~= "init" and phase ~= "init_worker" then
plugins_iterator:configure()
end

PLUGINS_ITERATOR = plugins_iterator
return true
end
Expand Down Expand Up @@ -719,6 +728,11 @@ do
end

if plugins_iterator then
-- Before we replace plugin iterator we need to call configure handler
-- of each plugin. There is a slight chance that plugin configure handler
-- would yield, and that should be considered a bad practice.
plugins_iterator:configure()
bungle marked this conversation as resolved.
Show resolved Hide resolved

PLUGINS_ITERATOR = plugins_iterator
CURRENT_PLUGINS_HASH = plugins_hash or 0
end
Expand Down
Loading