EVOLUTION-MANAGER
Edit File: script_manager.lua
-- -- (C) 2019-24 - ntop.org -- -- Includes local dirs = ntop.getDirs() package.path = dirs.installdir .. "/scripts/lua/modules/notifications/?.lua;" .. package.path local os_utils = require("os_utils") local template_utils = require("template_utils") local lua_path_utils = require("lua_path_utils") require "lua_trace" require "lua_utils_generic" require "check_redis_prefs" -- ############################################## --[[ IMPORTANT NOTE. scripts include: - alert_definitions: 'old' alerts definition, developed in Lua (like Interface and Network alerts) - check_definitions: 'new' alerts definition, developed in C++ - locales: languages - ts_schemas: timeseries schemas - web_gui: html templates of some scripts (not all of them) - menu_items: navigation menu used in the web gui - alert_endpoints: endpoints/recipients list - http_lint: clear the data received by the web gui to avoid Scripts Injection Attacks - templates: containing web gui html templates - modules: lua modules, containing functions, variables, ecc. - callbacks: periodic callbacks executed, like checks, timeseries, ecc. - httpdocs: client side files (JS, HTML, CSS). ]] local script_manager = {} -- ############################################## local cached_runtime_dir = nil -- @brief Return the path of the scripts function script_manager.getRuntimePath() if (not cached_runtime_dir) then cached_runtime_dir = ntop.getCurrentScriptsDir() end return (cached_runtime_dir) end -- ############################################## -- Local variables local runtime_path = script_manager.getRuntimePath() local MENU_ITEMS_PATH = "menu_items" local RUNTIME_PATHS = { -- Definitions alert_definitions = os_utils.fixPath(runtime_path .. "/alert_definitions"), check_definitions = os_utils.fixPath(runtime_path .. "/check_definitions"), -- Locales locales = os_utils.fixPath(runtime_path .. "/locales"), -- Timeseries ts_schemas = os_utils.fixPath(runtime_path .. "/ts_schemas"), -- Web Gui web_gui = os_utils.fixPath(runtime_path) .. "/scripts", menu_items = os_utils.fixPath(runtime_path .. "/" .. MENU_ITEMS_PATH), -- Alert endpoints alert_endpoints = os_utils.fixPath(runtime_path) .. "/alert_endpoints", -- HTTP lint http_lint = os_utils.fixPath(runtime_path) .. "/http_lint", -- TODO: rename scripts_data -- Scripts Data Directories scripts_data = os_utils.fixPath(runtime_path) .. "/scripts_data", -- Templates templates = os_utils.fixPath(runtime_path) .. "/templates", -- Lua Modules modules = os_utils.fixPath(runtime_path) .. "/modules", -- Client Side Files httpdocs = os_utils.fixPath(runtime_path) .. "/httpdocs", -- Callbacks interface_scripts = os_utils.fixPath(runtime_path .. "/callbacks/interface/interface"), host_scripts = os_utils.fixPath(runtime_path .. "/callbacks/interface/host"), network_scripts = os_utils.fixPath(runtime_path .. "/callbacks/interface/network"), flow_scripts = os_utils.fixPath(runtime_path .. "/callbacks/interface/flow"), syslog = os_utils.fixPath(runtime_path .. "/callbacks/system/syslog"), snmp_scripts = os_utils.fixPath(runtime_path .. "/callbacks/system/snmp_device"), system_scripts = os_utils.fixPath(runtime_path .. "/callbacks/system/system"), active_monitoring_scripts = os_utils.fixPath(runtime_path .. "/callbacks/system/active_monitoring") } -- ############################################## -- @brief Loads the timeseries schemas. function script_manager.loadSchemas(granularity) lua_path_utils.package_path_prepend(RUNTIME_PATHS.ts_schemas) for ts_name in pairs(ntop.readdir(RUNTIME_PATHS.ts_schemas)) do local ts_dir = os_utils.fixPath(RUNTIME_PATHS.ts_schemas .. "/" .. ts_name) local files_to_load = {} if (granularity ~= nil) then -- Only load schemas for the specified granularity local ts_granularity_file = granularity .. ".lua" local ts_granularity_path = os_utils.fixPath(ts_dir .. "/" .. ts_granularity_file) if ntop.exists(ts_granularity_path) then files_to_load = {ts_granularity_file} end else -- Load all granularities files_to_load = ntop.readdir(ts_dir) end for _, fname in pairs(files_to_load) do if fname:ends(".lua") then local fgran = string.sub(fname, 1, string.len(fname) - 4) -- Ts schemas are required using the dot notation in the -- require string name. Dots are used to navigate the base directory, RUNTIME_PATHS.ts_schemas, -- which has been prepended to the path. -- Examples: -- require(active_monitoring.hour) -- require(active_monitoring.5mins) -- require(active_monitoring.min) -- require(score.min) -- require(influxdb_monitor.5mins) local req_name = string.format("%s.%s", ts_name, fgran) require(req_name) end end end end -- ############################################## -- @brief Return the menu entries function script_manager.getMenuEntries() local menu = {} local entries_data = {} lua_path_utils.package_path_prepend(script_manager.getRuntimePath()) for fname in pairs(ntop.readdir(RUNTIME_PATHS.menu_items)) do local req_name = string.format("%s.%s", MENU_ITEMS_PATH, fname) local menu_entry = require(req_name) if (menu_entry and ((not menu_entry.is_shown) or menu_entry.is_shown())) then -- Don't add any getHttpPrefix to the url here, it's the caller that -- can potentially add it menu_entry.url = "/scripts/" .. menu_entry.script menu[fname] = menu_entry if menu_entry.menu_entry then entries_data[menu_entry.menu_entry.key] = menu_entry.menu_entry end end end return menu, entries_data end -- ############################################## -- @brief Return monitor pages URL (e.g. /lua/monitor/redis_monitor.lua) function script_manager.getMonitorUrl(script) return (ntop.getHttpPrefix() .. "/lua/monitor/" .. script) end -- ############################################## -- @brief Checks if the system timeseries are enabled function script_manager.systemTimeseriesEnabled() return areSystemTimeseriesEnabled() end -- ############################################## -- @brief Retrieve the runtime templates directory of the script -- @param script_name the script name -- @return the runtime directory path function script_manager.getScriptTemplatesDir(script_name) local path = dirs.installdir .. "/httpdocs/templates/pages/" .. (script_name or '') return os_utils.fixPath(path) end -- ############################################## -- @brief Return the list of available endpoint/recipients, -- named even 'notification' local function get_available_notification(path, rv) -- Get Endpoints files, like discord.lua, slack.lua ecc. local base_path = os_utils.fixPath(dirs.installdir .. path) lua_path_utils.package_path_prepend(base_path) for fname in pairs(ntop.readdir(base_path)) do if fname:ends(".lua") then local full_path = os_utils.fixPath(base_path .. "/" .. fname) local key = string.sub(fname, 1, string.len(fname) - 4) -- Check if the endpoint has a valid function to handle the notification local endpoint = require(key) if (endpoint) then if ((type(endpoint.isAvailable) ~= "function") or endpoint.isAvailable()) then endpoint.full_path = full_path endpoint.key = key rv[#rv + 1] = endpoint end else traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Could not load alert endpoint '%s'", full_path)) end end end return rv end -- ############################################## -- @brief Sorter used to sort endpoints by priority local function endpoint_sorter(a, b) if ((a.prio ~= nil) and (b.prio == nil)) then return (true) elseif ((a.prio == nil) and (b.prio ~= nil)) then return (false) elseif (a.prio ~= b.prio) then return (a.prio > b.prio) end -- Use the endpoint key to fix a defined sort order return (a.key > b.key) end -- ############################################## -- @brief Get the available alert endpoints -- @return a sorted table, in order of priority, for the alert endpoints function script_manager.getLoadedAlertEndpoints() local rv = {} -- Community endpoints rv = get_available_notification("/scripts/lua/modules/notifications/endpoints/", rv) -- Pro, Enterprise M and Enterprise L endpoints if ntop.isPro() then rv = get_available_notification("/pro/scripts/lua/notifications/endpoints/", rv) end -- Sort by priority (higher priority first) table.sort(rv, endpoint_sorter) return (rv) end -- ############################################## -- @brief Extends the http_lint using all the lint available function script_manager.extendLintParams(http_lint, params) lua_path_utils.package_path_prepend(RUNTIME_PATHS.http_lint) for fname in pairs(ntop.readdir(RUNTIME_PATHS.http_lint)) do local key = string.sub(fname, 1, string.len(fname) - 4) local lint = require(key) if (lint == nil) then traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Could not load lint for '%s'", key)) goto continue end if (lint.getAdditionalParameters == nil) then traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("Missing mandatory function 'getAdditionalParameters' in '%s'", key)) goto continue end local rv = lint.getAdditionalParameters(http_lint) if (type(rv) ~= "table") then traceError(TRACE_ERROR, TRACE_CONSOLE, string.format("function 'getAdditionalParameters' in '%s' returned a non-table value", key)) goto continue end for k, v in pairs(rv) do params[k] = v end ::continue:: end end -- ############################################## -- @brief Render an html template located into the templates directory function script_manager.renderNotificationTemplate(script_name, template_file, context) -- Locate the template file into the script directory, e.g. httpdocs/templates/pages/notifications/webhook_endpoint.template local full_path = script_manager.getScriptTemplatesDir("notifications/" .. script_name .. "/" .. template_file) -- If no template is found attempt to locate the template under the modules if not ntop.exists(full_path) then full_path = os_utils.fixPath(dirs.installdir .. "/scripts/lua/modules/check_templates/" .. template_file) end return template_utils.gen(full_path, context, true --[[ using full path ]] ) end -- ############################################## -- @brief Load an alert template function script_manager.loadTemplate(script_name, template_file) -- Checking the standard templates path, '/httpdocs/templates/pages/' local script_template_path = script_manager.getScriptTemplatesDir(script_name) local template_path = os_utils.fixPath(script_template_path .. "/" .. template_file .. ".lua") local req = nil -- Templates not found if ntop.exists(template_path) then -- Do the necessary require lua_path_utils.package_path_prepend(RUNTIME_PATHS.templates) local req_name = string.format("%s.%s", script_name, template_file) req = require(req_name) end return req end -- ############################################## function script_manager.getAllRuntimePaths() return RUNTIME_PATHS end -- ############################################## return (script_manager)