Generalize periodic and flows callbacks

Now periodic callbacks are properly called even when alerts are disabled
The granularity filter and check_function has been replaced with a more generic hooks list
This commit is contained in:
emanuele-f 2019-10-07 19:00:51 +02:00
parent 6bcb8b18a2
commit ede9a7940a
47 changed files with 566 additions and 438 deletions

View file

@ -15,7 +15,6 @@ local alerts_api = {}
-- NOTE: sqlite can handle about 10-50 alerts/sec
local MAX_NUM_ENQUEUED_ALERT_PER_INTERFACE = 256
local ALERT_CHECKS_MODULES_BASEDIR = dirs.installdir .. "/scripts/callbacks/interface"
-- Just helpers
local str_2_periodicity = {
@ -929,215 +928,10 @@ end
-- ##############################################
function alerts_api.load_check_modules(subdir, str_granularity)
local checks_dir = os_utils.fixPath(ALERT_CHECKS_MODULES_BASEDIR .. "/" .. subdir)
local is_nedge = ntop.isnEdge()
local available_modules = {}
package.path = checks_dir .. "/?.lua;" .. package.path
for fname in pairs(ntop.readdir(checks_dir)) do
if ends(fname, ".lua") then
local modname = string.sub(fname, 1, string.len(fname) - 4)
local check_module = require(modname)
if check_module.check_function and check_module.key then
if check_module.nedge_exclude and is_nedge then
goto continue
end
if check_module.granularity and str_granularity then
-- When the module specify one or more granularities
-- at which checks have to be run, the module is only
-- loaded after checking the granularity
for _, gran in pairs(check_module.granularity) do
if gran == str_granularity then
available_modules[modname] = check_module
break
end
end
else
-- When no granularity is explicitly specified
-- in the module, then the check it is assumed to
-- be run for every granularity and the module is
-- always loaded
available_modules[modname] = check_module
end
end
end
::continue::
end
return available_modules
end
-- ##############################################
local function get_flow_check_module_enabled_key(check_module_key)
return string.format("ntopng.prefs.flow_check_modules.ifid_%d.%s", interface.getId(), check_module_key)
end
-- ##############################################
local function refresh_flow_check_module_conf(flow_check_module)
if table.len(_POST) > 0 then
local conf_hash = get_flow_check_module_enabled_key(flow_check_module.key)
for k, v in pairs(_POST) do
if k:ends(flow_check_module.key) then
if k == "enabled_"..flow_check_module.key then
if v == "off" then
ntop.setHashCache(conf_hash, "enabled", "false")
elseif v == "on" then
ntop.delHashCache(conf_hash, "enabled")
end
end
end
end
end
end
-- ##############################################
local function load_flow_check_module_conf(flow_check_module)
if not flow_check_module["conf"] then
flow_check_module["conf"] = {}
end
-- if there's a _POST we try and refresh the module conf with possibly new
-- submitted values
refresh_flow_check_module_conf(flow_check_module)
local k = get_flow_check_module_enabled_key(flow_check_module.key)
local enabled = ntop.getHashCache(k, "enabled")
if enabled ~= "false" then
flow_check_module["conf"]["enabled"] = true
else
flow_check_module["conf"]["enabled"] = false
end
end
-- ##############################################
local function flow_check_modules_benchmarks_key(mod_k)
local ifid = interface.getId()
return string.format("ntopng.cache.ifid_%d.flow_check_modules_benchmarks.mod_%s", ifid, mod_k)
end
-- ##############################################
function alerts_api.store_flow_check_modules_benchmarks(benchmarks)
for mod_k, modules in pairs(benchmarks or {}) do
local k = flow_check_modules_benchmarks_key(mod_k)
for mod_fn, mod_benchmark in pairs(modules) do
ntop.setHashCache(k, mod_fn, json.encode(mod_benchmark))
end
end
end
-- ##############################################
function alerts_api.get_flow_check_module_benchmarks(mod_k)
local k = flow_check_modules_benchmarks_key(mod_k)
-- ntop.delCache(k)
local res = ntop.getHashAllCache(k)
for mod_fn, benchmark in pairs(res or {}) do
res[mod_fn] = json.decode(benchmark)
end
return res
end
-- ##############################################
--
-- Flow check modules are lua scripts located into the following locations:
-- - scripts/callbacks/interface/flow for community scripts
-- - pro/scripts/callbacks/interface/flow for pro/enterprise scripts
--
-- A script must return a lua table, with the following fields:
-- - setup(): a function to call once before processing any flow. It must return true
-- if the module is enabled, false otherwise.
-- - protocolDetected(info) (optional): a function which will be called once the flow protocol
-- has been detected or detection has been aborted. This should happen once per flow.
-- - statusChanged(info) (optional): a function which will be called *after* the protocolDetected()
-- if the flow status changes.
--
function alerts_api.load_flow_check_modules(enabled_only)
local available_modules = {protocolDetected = {}, statusChanged = {}, idle = {}, periodicUpdate = {}, all = {}}
local check_dirs = {
os_utils.fixPath(ALERT_CHECKS_MODULES_BASEDIR .. "/flow"),
}
if ntop.isPro() then
check_dirs[#check_dirs + 1] = os_utils.fixPath(dirs.installdir .. "/pro/scripts/callbacks/interface/flow")
end
for _, checks_dir in pairs(check_dirs) do
package.path = checks_dir .. "/?.lua;" .. package.path
for fname in pairs(ntop.readdir(checks_dir)) do
if ends(fname, ".lua") then
local modname = string.sub(fname, 1, string.len(fname) - 4)
local check_module = require(modname)
load_flow_check_module_conf(check_module)
check_module["benchmark"] = alerts_api.get_flow_check_module_benchmarks(modname)
if check_module.setup then
local is_enabled = check_module["conf"]["enabled"]
if is_enabled or not enabled_only then
local setup_ok = check_module.setup()
if setup_ok then
if check_module.protocolDetected then available_modules["protocolDetected"][modname] = check_module end
if check_module.statusChanged then available_modules["statusChanged"][modname] = check_module end
if check_module.idle then available_modules["idle"][modname] = check_module end
if check_module.periodicUpdate then available_modules["periodicUpdate"][modname] = check_module end
available_modules["all"][modname] = check_module
end
end
end
end
end
end
return available_modules
end
-- ##############################################
-- @brief Get the default alert configuration value for the given check module
-- and granularity.
-- @param check_module a check_module returned by alerts_api.load_check_modules
-- @param granularity_str the target granularity
-- @return nil if there is not default value, the given value otherwise
function alerts_api.getCheckModuleDefaultValue(check_module, granularity_str)
if((check_module.default_values ~= nil) and (check_module.default_values[granularity_str] ~= nil)) then
-- granularity specific default
return(check_module.default_values[granularity_str])
end
-- global default
return(check_module.default_value)
end
-- ##############################################
-- An alert check function which performs threshold checks of a value
-- against a configured threshold and generates a threshold_cross alert
-- if the value is above the threshold.
-- A check_module must implement:
-- A check_module (see check_modules.lua) must implement:
-- get_threshold_value(granularity, entity_info)
-- A function, which returns the current value to be compared agains the threshold
-- The check_module may implement an additional threshold_type_builder function which
@ -1332,7 +1126,7 @@ end
function alerts_api.flow_checkbox_input_builder(check_module)
local input_id = string.format("enabled_%s", check_module.key)
local built = build_on_off_toggle(input_id, check_module.conf.enabled)
local built = build_on_off_toggle(input_id, check_module.enabled)
return built
end