mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-03 09:20:10 +00:00
366 lines
13 KiB
Lua
366 lines
13 KiB
Lua
-- ##############################################
|
|
|
|
-- @brief Get the default configuration for the given user script
|
|
-- and granularity.
|
|
-- @param user_script a user_script returned by user_scripts.load
|
|
-- @param granularity_str the target granularity
|
|
-- @return a table with the default configuration
|
|
function user_scripts.getDefaultConfig(user_script, granularity_str)
|
|
local conf = {script_conf = {}, enabled = user_script.default_enabled}
|
|
|
|
if((user_script.default_values ~= nil) and (user_script.default_values[granularity_str] ~= nil)) then
|
|
-- granularity specific default
|
|
conf.script_conf = user_script.default_values[granularity_str] or {}
|
|
else
|
|
conf.script_conf = user_script.default_value or {}
|
|
end
|
|
|
|
return(conf)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
local function getConfigurationKey(subdir)
|
|
-- NOTE: strings needed by user_scripts.deleteConfigurations
|
|
-- NOTE: The configuration must not be saved under a specific ifid, since we
|
|
-- allow global interfaces configurations
|
|
return(string.format("ntopng.prefs.user_scripts.conf.%s", subdir))
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Get the user scripts configuration
|
|
-- @param subdir: the subdir
|
|
-- @return a table
|
|
-- {[hook] = {entity_value -> {enabled=true, script_conf = {a = 1}, }, ..., default -> {enabled=false, script_conf = {}, }}, ...}
|
|
-- @note debug with: redis-cli get ntopng.prefs.user_scripts.conf.interface | python -m json.tool
|
|
local function loadConfiguration(subdir)
|
|
local key = getConfigurationKey(subdir)
|
|
local value = ntop.getPref(key)
|
|
|
|
if(not isEmptyString(value)) then
|
|
value = json.decode(value) or {}
|
|
else
|
|
value = {}
|
|
end
|
|
|
|
return(value)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Save the user scripts configuration.
|
|
-- @param subdir: the subdir
|
|
-- @param config: the configuration to save
|
|
local function saveConfiguration(subdir, config)
|
|
local key = getConfigurationKey(subdir)
|
|
|
|
if(table.empty(config)) then
|
|
ntop.delCache(key)
|
|
else
|
|
local value = json.encode(config)
|
|
ntop.setPref(key, value)
|
|
end
|
|
|
|
-- Reload the periodic scripts as the configuration has changed
|
|
ntop.reloadPeriodicScripts()
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
function user_scripts.deleteConfigurations()
|
|
deleteCachePattern(getConfigurationKey("*"))
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- This needs to be called whenever the available_modules.conf changes
|
|
-- It updates the single scripts config
|
|
local function reload_scripts_config(available_modules)
|
|
local scripts_conf = available_modules.conf
|
|
|
|
for _, script in pairs(available_modules.modules) do
|
|
script.conf = scripts_conf[script.key] or {}
|
|
end
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
local function delete_script_conf(scripts_conf, key, hook, conf_key)
|
|
if(scripts_conf[key] and scripts_conf[key][hook]) then
|
|
scripts_conf[key][hook][conf_key] = nil
|
|
|
|
-- Cleanup empty tables
|
|
if table.empty(scripts_conf[key][hook]) then
|
|
scripts_conf[key][hook] = nil
|
|
|
|
if table.empty(scripts_conf[key]) then
|
|
scripts_conf[key] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- ##############################################
|
|
|
|
function user_scripts.handlePOST(subdir, available_modules, hook, entity_value, remote_host)
|
|
if(table.empty(_POST)) then
|
|
return
|
|
end
|
|
|
|
hook = hook or NON_TRAFFIC_ELEMENT_CONF_KEY
|
|
entity_value = entity_value or NON_TRAFFIC_ELEMENT_ENTITY
|
|
|
|
local scripts_conf = available_modules.conf
|
|
|
|
for _, user_script in pairs(available_modules.modules) do
|
|
-- There are 3 different configurations:
|
|
-- - specific_config: the configuration specific of an host/interface/network
|
|
-- - global_config: the configuration specific for all the (local/remote) hosts, interfaces, networks
|
|
-- - default_config: the default configuration, specified by the user script
|
|
-- They follow the follwing priorities:
|
|
-- [lower] specific_config > global_config > default [upper]
|
|
--
|
|
-- Moreover:
|
|
-- - specific_config is only set if it differs from the global_config
|
|
-- - global_config is only set if it differs from the default_config
|
|
--
|
|
|
|
-- This is used to represent the previous config in order of priority in order
|
|
-- to determine if the current config differs from its default.
|
|
local upper_config = user_scripts.getDefaultConfig(user_script, hook)
|
|
|
|
-- NOTE: we must process the global_config before the specific_config
|
|
for _, prefix in ipairs({"global_", ""}) do
|
|
local k = prefix .. user_script.key
|
|
local is_global = (prefix == "global_")
|
|
local enabled_k = "enabled_" .. k
|
|
local is_enabled = _POST[enabled_k]
|
|
local conf_key = ternary(is_global, get_global_conf_key(remote_host), entity_value)
|
|
local script_conf = nil
|
|
|
|
if(user_script.gui and (user_script.gui.post_handler ~= nil)) then
|
|
script_conf = user_script.gui.post_handler(k)
|
|
end
|
|
|
|
if(is_enabled == nil) then
|
|
-- TODO remove this after changing the gui to support a separate on/off field
|
|
-- For backward compatibility, an empty configuration means that the script is disabled
|
|
|
|
if(user_script.gui and (user_script.gui.post_handler ~= nil) and (subdir ~= "flow")) then
|
|
is_enabled = not table.empty(script_conf)
|
|
else
|
|
is_enabled = user_script.default_enabled
|
|
end
|
|
else
|
|
is_enabled = (is_enabled == "on")
|
|
end
|
|
|
|
local cur_config = {
|
|
enabled = is_enabled,
|
|
script_conf = script_conf,
|
|
}
|
|
|
|
if(not table.compare(upper_config, cur_config)) then
|
|
-- Configuration differs
|
|
scripts_conf[user_script.key] = scripts_conf[user_script.key] or {}
|
|
scripts_conf[user_script.key][hook] = scripts_conf[user_script.key][hook] or {}
|
|
scripts_conf[user_script.key][hook][conf_key] = cur_config
|
|
else
|
|
-- Use the default
|
|
delete_script_conf(scripts_conf, user_script.key, hook, conf_key)
|
|
end
|
|
|
|
-- Needed for specific_config vs global_config comparison
|
|
upper_config = cur_config
|
|
end
|
|
end
|
|
|
|
reload_scripts_config(available_modules)
|
|
saveConfiguration(subdir, scripts_conf)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Get the configuration to use for a specific entity
|
|
-- @param user_script the user script, loaded with user_scripts.load
|
|
-- @param (optional) hook the hook function
|
|
-- @param (optional) entity_value the entity value
|
|
-- @param (optional) is_remote_host, for hosts only, indicates if the entity is a remote host
|
|
-- @return the script configuration as a table
|
|
function user_scripts.getConfiguration(user_script, hook, entity_value, is_remote_host)
|
|
local rv = nil
|
|
hook = hook or NON_TRAFFIC_ELEMENT_CONF_KEY
|
|
entity_value = entity_value or NON_TRAFFIC_ELEMENT_ENTITY
|
|
local conf = user_script.conf[hook]
|
|
|
|
-- A configuration may not exist for the given hook
|
|
if(conf ~= nil) then
|
|
-- Search for this specific entity config
|
|
rv = conf[entity_value]
|
|
end
|
|
|
|
if(rv == nil) then
|
|
-- Search for a global/default configuration
|
|
rv = user_scripts.getGlobalConfiguration(user_script, hook, is_remote_host)
|
|
end
|
|
|
|
if(rv.script_conf == nil) then
|
|
-- Use the default
|
|
rv.script_conf = user_script.default_value or {}
|
|
end
|
|
|
|
return(rv)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
local function get_global_conf_key(is_remote_host)
|
|
return(ternary(is_remote_host, "global_remote", "global"))
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Get the global configuration to use for a all the entities of this user_script
|
|
-- @param user_script the user script, loaded with user_scripts.load
|
|
-- @param hook the hook function
|
|
-- @param is_remote_host, for hosts only, indicates if the entity is a remote host
|
|
-- @return the script configuration as a table
|
|
function user_scripts.getGlobalConfiguration(user_script, hook, is_remote_host)
|
|
local conf = user_script.conf[hook]
|
|
local rv = nil
|
|
|
|
if(conf ~= nil) then
|
|
rv = conf[get_global_conf_key(is_remote_host)]
|
|
end
|
|
|
|
if(rv == nil) then
|
|
-- No Specific/Global configuration found, try defaults
|
|
rv = user_scripts.getDefaultConfig(user_script, hook)
|
|
end
|
|
|
|
return(rv)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Delete the configuration of a specific element (e.g. a specific host)
|
|
function user_scripts.deleteSpecificConfiguration(subdir, available_modules, hook, entity_value)
|
|
hook = hook or NON_TRAFFIC_ELEMENT_CONF_KEY
|
|
entity_value = entity_value or NON_TRAFFIC_ELEMENT_ENTITY
|
|
|
|
local scripts_conf = available_modules.conf
|
|
|
|
for _, script in pairs(available_modules.modules) do
|
|
delete_script_conf(scripts_conf, script.key, hook, entity_value)
|
|
end
|
|
|
|
reload_scripts_config(available_modules)
|
|
saveConfiguration(subdir, scripts_conf)
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- Delete the configuration for all the elements in subdir (e.g. all the hosts)
|
|
function user_scripts.deleteGlobalConfiguration(subdir, available_modules, hook, remote_host)
|
|
return(user_scripts.deleteSpecificConfiguration(subdir, available_modules, hook, get_global_conf_key(remote_host)))
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
-- For built-in input_builders, return the _POST handler to use
|
|
local input_builder_to_post_handler = {
|
|
[user_scripts.threshold_cross_input_builder] = user_scripts.threshold_cross_post_handler,
|
|
}
|
|
|
|
function user_scripts.getDefaultPostHandler(input_builder)
|
|
return(input_builder_to_post_handler[input_builder])
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
function user_scripts.checkbox_input_builder(gui_conf, submit_field, active)
|
|
local on_value = "on"
|
|
local off_value = "off"
|
|
local value
|
|
local on_color = "success"
|
|
local off_color = "danger"
|
|
submit_field = "enabled_" .. submit_field
|
|
|
|
local on_active
|
|
local off_active
|
|
|
|
if active then
|
|
|
|
value = on_value
|
|
on_active = "btn-"..on_color.." active"
|
|
off_active = "btn-secondary"
|
|
else
|
|
value = off_value
|
|
on_active = "btn-secondary"
|
|
off_active = "btn-"..off_color.." active"
|
|
end
|
|
|
|
return [[
|
|
<div class="btn-group btn-toggle">
|
|
<button type="button" onclick="]]..submit_field..[[_on_fn()" id="]]..submit_field..[[_on_id" class="btn btn-sm ]]..on_active..[[">On</button>
|
|
<button type="button" onclick="]]..submit_field..[[_off_fn()" id="]]..submit_field..[[_off_id" class="btn btn-sm ]]..off_active..[[">Off</button>
|
|
</div>
|
|
<input type=hidden id="]]..submit_field..[[_input" name="]]..submit_field..[[" value="]]..value..[["/>
|
|
<script>
|
|
|
|
|
|
function ]]..submit_field..[[_on_fn() {
|
|
var class_on = document.getElementById("]]..submit_field..[[_on_id");
|
|
var class_off = document.getElementById("]]..submit_field..[[_off_id");
|
|
class_on.removeAttribute("class");
|
|
class_off.removeAttribute("class");
|
|
class_on.setAttribute("class", "btn btn-sm btn-]]..on_color..[[ active");
|
|
class_off.setAttribute("class", "btn btn-sm btn-secondary");
|
|
$("#]]..submit_field..[[_input").val("]]..on_value..[[").trigger('change');
|
|
}
|
|
|
|
function ]]..submit_field..[[_off_fn() {
|
|
var class_on = document.getElementById("]]..submit_field..[[_on_id");
|
|
var class_off = document.getElementById("]]..submit_field..[[_off_id");
|
|
class_on.removeAttribute("class");
|
|
class_off.removeAttribute("class");
|
|
class_on.setAttribute("class", "btn btn-sm btn-secondary");
|
|
class_off.setAttribute("class", "btn btn-sm btn-]]..off_color..[[ active");
|
|
$("#]]..submit_field..[[_input").val("]]..off_value..[[").trigger('change');
|
|
}
|
|
</script>
|
|
]]
|
|
end
|
|
|
|
-- ##############################################
|
|
|
|
function user_scripts.threshold_cross_input_builder(gui_conf, input_id, value)
|
|
value = value or {}
|
|
local gt_selected = ternary((value.operator or gui_conf.field_operator) == "gt", ' selected="selected"', '')
|
|
local lt_selected = ternary((value.operator or gui_conf.field_operator) == "lt", ' selected="selected"', '')
|
|
local input_op = "op_" .. input_id
|
|
local input_val = "value_" .. input_id
|
|
|
|
return(string.format([[<select name="%s">
|
|
<option value="gt"%s ]] .. (ternary(gui_conf.field_operator == "lt", "hidden", "")) .. [[>></option>
|
|
<option value="lt"%s ]] .. (ternary(gui_conf.field_operator == "gt", "hidden", "")) .. [[><</option>
|
|
</select> <input type="number" class="text-right form-control" min="%s" max="%s" step="%s" style="display:inline; width:12em;" name="%s" value="%s"/> <span>%s</span>]],
|
|
input_op, gt_selected, lt_selected,
|
|
gui_conf.field_min or "0", gui_conf.field_max or "", gui_conf.field_step or "1",
|
|
input_val, value.threshold, i18n(gui_conf.i18n_field_unit))
|
|
)
|
|
end
|
|
|
|
function user_scripts.threshold_cross_post_handler(input_id)
|
|
local input_op = _POST["op_" .. input_id]
|
|
local input_val = tonumber(_POST["value_" .. input_id])
|
|
|
|
if(input_val ~= nil) then
|
|
return {
|
|
operator = input_op,
|
|
threshold = input_val,
|
|
}
|
|
end
|
|
end
|