From 5f864d53a8a694f6eb22e92f106e88926e3d054e Mon Sep 17 00:00:00 2001 From: miguel angel rasteu Date: Mon, 3 Jul 2023 09:18:30 +0200 Subject: [PATCH 01/48] #11051 Add action to mark all notification as read --- pandora_console/general/header.php | 27 +++++++++++++++++++ .../godmode/setup/setup_notifications.php | 21 +++++++++++++++ .../include/class/ConsoleSupervisor.php | 7 +++-- pandora_console/include/functions_html.php | 3 +++ .../include/functions_notifications.php | 15 ++++++++++- pandora_console/include/styles/pandora.css | 5 ++++ 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index 6129fcebb4..ba6922e03c 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -539,6 +539,33 @@ echo sprintf('
', $menuTypeClass); element.style.display = "none" } + function notifications_clean_all() { + let wrapper_inner = document.getElementById('notification-wrapper-inner'); + while (wrapper_inner.firstChild) { + wrapper_inner.removeChild(wrapper_inner.firstChild); + } + } + + function mark_all_notification_as_read() { + jQuery.post ("ajax.php", + { + "page" : "godmode/setup/setup_notifications", + "mark_all_notification_as_read" : 1 + }, + function (data, status) { + notifications_clean_all(); + location.reload(); + }, + "json" + ) + .fail(function(xhr, textStatus, errorThrown){ + console.error( + "Failed to mark al notification as read. Error: ", + xhr.responseText + ); + }); + } + function click_on_notification_toast(event) { var match = /notification-(.*)-id-([0-9]+)/.exec(event.target.id); if (!match) { diff --git a/pandora_console/godmode/setup/setup_notifications.php b/pandora_console/godmode/setup/setup_notifications.php index 6aaaabf032..f2289a7cc3 100644 --- a/pandora_console/godmode/setup/setup_notifications.php +++ b/pandora_console/godmode/setup/setup_notifications.php @@ -187,6 +187,27 @@ if (get_parameter('mark_notification_as_read', 0)) { return; } +if (get_parameter('mark_all_notification_as_read', 0)) { + $unread_messages = db_get_all_rows_sql('SELECT id_mensaje FROM tnotification_user WHERE utimestamp_read is NULL'); + + if ($unread_messages !== false) { + foreach ($unread_messages as $messages) { + messages_process_read($messages['id_mensaje']); + } + + $result = true; + } else { + $result = false; + } + + // If there is new messages, get the info. + echo json_encode( + ['result' => $result] + ); + + return; +} + if (get_parameter('get_notifications_dropdown', 0)) { echo notifications_print_dropdown(); return; diff --git a/pandora_console/include/class/ConsoleSupervisor.php b/pandora_console/include/class/ConsoleSupervisor.php index 7ef169aec1..99299a21ac 100644 --- a/pandora_console/include/class/ConsoleSupervisor.php +++ b/pandora_console/include/class/ConsoleSupervisor.php @@ -169,6 +169,7 @@ class ConsoleSupervisor * NOTIF.PHP.DISABLE_FUNCTIONS * NOTIF.PHP.CHROMIUM * NOTIF.PHP.VERSION + * NOTIF.PHP.VERSION.SUPPORT */ $this->checkPHPSettings(); @@ -377,6 +378,7 @@ class ConsoleSupervisor * NOTIF.PHP.DISABLE_FUNCTIONS * NOTIF.PHP.CHROMIUM * NOTIF.PHP.VERSION + * NOTIF.PHP.VERSION.SUPPORT */ $this->checkPHPSettings(); @@ -853,6 +855,7 @@ class ConsoleSupervisor case 'NOTIF.PHP.DISABLE_FUNCTIONS': case 'NOTIF.PHP.CHROMIUM': case 'NOTIF.PHP.VERSION': + case 'NOTIF.PHP.VERSION.SUPPORT': case 'NOTIF.HISTORYDB': case 'NOTIF.PANDORADB': case 'NOTIF.PANDORADB.HISTORICAL': @@ -1807,14 +1810,14 @@ class ConsoleSupervisor $url = 'https://www.php.net/supported-versions.php'; $this->notify( [ - 'type' => 'NOTIF.PHP.VERSION', + 'type' => 'NOTIF.PHP.VERSION.SUPPORT', 'title' => __('PHP UPDATE REQUIRED'), 'message' => __('You should update your PHP version because it will be out of official support').'
'.__('Current PHP version: ').PHP_VERSION, 'url' => $url, ] ); } else { - $this->cleanNotifications('NOTIF.PHP.VERSION'); + $this->cleanNotifications('NOTIF.PHP.VERSION.SUPPORT'); } } diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 076a81e7f3..652e878e82 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -2849,6 +2849,8 @@ function html_print_anchor( $output .= '>'; + $output .= (isset($options['text']) === true) ? $options['text'] : ''; + $output .= (isset($options['content']) === true) ? io_safe_input_html($options['content']) : ''; $output .= ''; @@ -6882,6 +6884,7 @@ function html_print_menu_button(array $options, bool $return=false) 'class' => ($options['class'] ?? ''), 'style' => ($options['style'] ?? ''), 'onClick' => ($options['onClick'] ?? ''), + 'text' => ($options['text'] ?? ''), 'content' => $content, ], $return diff --git a/pandora_console/include/functions_notifications.php b/pandora_console/include/functions_notifications.php index ee23d122a4..dce8fa3502 100644 --- a/pandora_console/include/functions_notifications.php +++ b/pandora_console/include/functions_notifications.php @@ -136,6 +136,7 @@ function notifications_get_subtypes(?string $source=null) 'NOTIF.PHP.DISABLE_FUNCTIONS', 'NOTIF.PHP.CHROMIUM', 'NOTIF.PHP.VERSION', + 'NOTIF.PHP.VERSION.SUPPORT', 'NOTIF.HISTORYDB', 'NOTIF.PANDORADB', 'NOTIF.PANDORADB.HISTORICAL', @@ -1025,9 +1026,20 @@ function notifications_print_dropdown() $mess = []; } + $notification_menu = html_print_menu_button( + [ + 'href' => 'javascript:', + 'class' => 'notification_menu_actions', + 'text' => __('Mark all as read'), + 'onClick' => 'mark_all_notification_as_read()', + ], + true + ); + return sprintf( "
+ %s
@@ -1037,6 +1049,7 @@ function notifications_print_dropdown() >
", + $notification_menu, array_reduce( $mess, function ($carry, $message) { @@ -1114,7 +1127,7 @@ function notifications_print_dropdown_element($message_info)

", - $action.';click_on_notification_toast(event)', + $action.'; click_on_notification_toast(event)', $message_info['id_mensaje'], messages_get_url($message_info['id_mensaje']), $target, diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 06a3640c7c..11580027bf 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -12289,3 +12289,8 @@ tr[id^="network_component-plugin-wmi-fields-dynamicMacroRow-"] input, tr[id^="network_component-plugin-snmp-fields-dynamicMacroRow-"] input { width: 100% !important; } + +.notification_menu { + padding-top: 10px; + padding-left: 15px; +} From 0bd6125841171f25cafd2673a6a1cd020469ed92 Mon Sep 17 00:00:00 2001 From: miguel angel rasteu Date: Tue, 4 Jul 2023 13:33:29 +0200 Subject: [PATCH 02/48] #11051 Add notifications filter --- pandora_console/general/header.php | 21 ++++ .../include/functions_notifications.php | 105 +++++++++++++++++- pandora_console/include/styles/pandora.css | 50 ++++++++- 3 files changed, 174 insertions(+), 2 deletions(-) diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index ba6922e03c..778f394446 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -566,6 +566,27 @@ echo sprintf('
', $menuTypeClass); }); } + function filter_notification() { + let notification_type = ''; + $('.notification-item').hide(); + $(".checkbox_filter_notifications:checkbox:checked").each(function() { + notification_type = $(this).val(); + console.log(notification_type); + $('.notification-item[value='+notification_type+']').show(); + if (notification_type == 'All'){ + $('.notification-item').show(); + } + }); + + if (notification_type == 'All'){ + $('.notification-item').show(); + } + + if (notification_type == ''){ + $('.notification-item').hide(); + } + } + function click_on_notification_toast(event) { var match = /notification-(.*)-id-([0-9]+)/.exec(event.target.id); if (!match) { diff --git a/pandora_console/include/functions_notifications.php b/pandora_console/include/functions_notifications.php index dce8fa3502..2e038c1c64 100644 --- a/pandora_console/include/functions_notifications.php +++ b/pandora_console/include/functions_notifications.php @@ -1014,6 +1014,101 @@ function notifications_print_user_switch($source, $user, $label) } +/** + * Generates an HTML of notification filter types. + * + * @return string HTML filter notification. + */ +function notification_filter() +{ + $types_list[] = 'All'; + $notification_types = db_get_all_rows_sql('SELECT DISTINCT subtype FROM tmensajes'); + if ($notification_types !== false) { + foreach ($notification_types as $notification_type) { + $type = explode('.', $notification_type['subtype'])[1]; + $types_list[] = $type; + } + } + + $notification_filter = "'; + return $notification_filter; +} + + /** * Generates the dropdown notifications menu. * @@ -1035,11 +1130,15 @@ function notifications_print_dropdown() ], true ); + $notification_filter = notification_filter(); return sprintf( "
- +
+ + +
%s
@@ -1049,6 +1148,7 @@ function notifications_print_dropdown() >
", + $notification_filter, $notification_menu, array_reduce( $mess, @@ -1109,11 +1209,13 @@ function notifications_print_dropdown_element($message_info) $message_info['subject'] = io_safe_input($img); } + $type = explode('.', $message_info['subtype'])[1]; return sprintf( " @@ -1129,6 +1231,7 @@ function notifications_print_dropdown_element($message_info) ", $action.'; click_on_notification_toast(event)', $message_info['id_mensaje'], + $type, messages_get_url($message_info['id_mensaje']), $target, html_print_image('images/info.svg', true, ['style' => 'height: 40px;margin-left: -20px;margin-top: -40px;']), diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 11580027bf..c5ca2d0b19 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -12290,7 +12290,55 @@ tr[id^="network_component-plugin-snmp-fields-dynamicMacroRow-"] input { width: 100% !important; } -.notification_menu { +.notificaion_menu_container { + display: flex; padding-top: 10px; padding-left: 15px; } +.notification_menu { + width: 100px; +} + +.filter_notification { + width: auto; + min-width: 50px; +} + +#menu-filter_notification * { + list-style: none; +} +#menu-filter_notification li { + line-height: 180%; +} +#menu-filter_notification input[name="filter_menu"] { + position: absolute; + left: -1000em; +} +#menu-filter_notification label[id="filter_menu_label"]:before { + content: "\025b8"; + margin-right: 4px; +} +#menu-filter_notification + input[name="filter_menu"]:checked + ~ label[id="filter_menu_label"]:before { + content: "\025be"; +} +#menu-filter_notification .sublevel-filter_notification { + display: none; +} +#menu-filter_notification input[name="filter_menu"]:checked ~ ul { + display: block; +} + +.item-filter > label { + display: inline-block; + width: auto; + vertical-align: middle; +} + +.item-filter > input[type="checkbox"] { + display: inline-block; + width: 40px; + height: 100%; + vertical-align: middle; +} From 3c345ed1f901ad0ec10b7c70545638b6e8762f76 Mon Sep 17 00:00:00 2001 From: miguel angel rasteu Date: Thu, 13 Jul 2023 13:12:43 +0200 Subject: [PATCH 03/48] #8285 Add CSV export on agents modules view --- pandora_console/extensions/agents_modules.php | 26 +++- .../extensions/agents_modules_csv.php | 117 ++++++++++++++++++ pandora_console/include/functions_modules.php | 72 +++++++++++ 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 pandora_console/extensions/agents_modules_csv.php diff --git a/pandora_console/extensions/agents_modules.php b/pandora_console/extensions/agents_modules.php index 215e478319..d33341f25f 100644 --- a/pandora_console/extensions/agents_modules.php +++ b/pandora_console/extensions/agents_modules.php @@ -267,6 +267,23 @@ function agents_modules_load_js() // } // }); } + /* e.value).get(); + let module_id = $('#module option:selected').map((_, e) => e.value).get(); + + let filters_array = {group_id: group_id, module_group_id:module_group_id, agent_id:agent_id, module_id:module_id} + let jsonFilters = JSON.stringify(filters_array) + let filters = window.btoa(jsonFilters) + var f = document.forms.filter_form; + + blockResubmit($(this)); + f.action = "extensions/agents_modules_csv.php?get_agents_module_csv=1&filters="+filters; + $("#filter_form").submit(); + } + /* ]]> */ '; + $show_filters = '
'; $show_filters .= ''; $show_filters .= ''; $show_filters .= ''; @@ -679,6 +696,13 @@ function mainAgentsModules() 'onclick' => 'select_selected()', ], true + ).html_print_button( + __('Export to CSV'), + 'srcbutton', + false, + 'export_csv()', + ['class' => 'secondary mini'], + true, ), ], true diff --git a/pandora_console/extensions/agents_modules_csv.php b/pandora_console/extensions/agents_modules_csv.php new file mode 100644 index 0000000000..53225f8e4d --- /dev/null +++ b/pandora_console/extensions/agents_modules_csv.php @@ -0,0 +1,117 @@ + $value) { + $out_csv .= $value.$divider; + } + + $out_csv .= "\n"; + + foreach ($results as $result) { + foreach ($result as $key => $value) { + $out_csv .= io_safe_output($value).$divider; + } + + $out_csv .= "\n"; + } + + echo io_safe_output($out_csv); + + exit; +} diff --git a/pandora_console/include/functions_modules.php b/pandora_console/include/functions_modules.php index b670088f85..940880c3e7 100755 --- a/pandora_console/include/functions_modules.php +++ b/pandora_console/include/functions_modules.php @@ -4682,3 +4682,75 @@ function get_agent_module_childs( } } } + + +/** + * Function for export a csv file from Agents/Module view + * + * @param array $filters Data from agents/module filter. + * + * @return array Returns the data that will be saved in the csv file + */ +function export_agents_module_csv($filters) +{ + $query_filter = ''; + foreach ($filters as $key => $filter) { + switch ($key) { + case 'group_id': + if ($filter != 0) { + $query_filter .= ' AND ta.id_grupo = '.$filter.' '; + } + break; + + case 'module_group_id': + if ($filter != 0) { + $query_filter .= ' AND tam.id_module_group = '.$filter.' '; + ; + } + break; + + case 'agent_id': + if (count($filter) > 0) { + $agent_filter = '('.implode(', ', $filter).')'; + $query_filter .= ' AND ta.id_agente IN '.$agent_filter.' '; + } + break; + + case 'module_id': + if (count($filter) > 0) { + if (is_numeric($filter[0]) === false) { + foreach ($filter as $key => $module) { + $filter[$key] = io_safe_input($module); + } + + $module_filter = '(\''.implode("', '", $filter).'\')'; + $query_filter .= ' AND tam.nombre IN '.$module_filter.' '; + } else { + $module_filter = '('.implode(', ', $filter).')'; + $query_filter .= ' AND tam.id_tipo_modulo IN '.$module_filter.' '; + } + } + break; + + default: + // Nothing to do + break; + } + } + + // Query fields result. + $query = sprintf( + 'SELECT ta.alias as agent, tam.nombre as module, tae.datos as data + FROM tagente_modulo as tam + INNER JOIN tagente as ta ON tam.id_agente = ta.id_agente + INNER JOIN tagente_estado as tae ON tam.id_agente_modulo = tae.id_agente_modulo + WHERE ta.disabled = 0 + %s + ', + $query_filter + ); + + $result = db_get_all_rows_sql($query); + + return $result; +} From 18927561029b4fd670bc919db3821a92c95aeb0a Mon Sep 17 00:00:00 2001 From: alejandro Date: Tue, 25 Jul 2023 15:21:38 +0200 Subject: [PATCH 04/48] added files modules,agents,transfer,http,general,discovery --- .../extras/pandoraPlugintools/agents.py | 107 ++++++++++++ .../extras/pandoraPlugintools/discover.py | 124 ++++++++++++++ .../extras/pandoraPlugintools/general.py | 156 ++++++++++++++++++ .../extras/pandoraPlugintools/http.py | 60 +++++++ .../extras/pandoraPlugintools/modules.py | 151 +++++++++++++++++ .../extras/pandoraPlugintools/transfer.py | 121 ++++++++++++++ 6 files changed, 719 insertions(+) create mode 100644 pandora_server/extras/pandoraPlugintools/agents.py create mode 100644 pandora_server/extras/pandoraPlugintools/discover.py create mode 100644 pandora_server/extras/pandoraPlugintools/general.py create mode 100644 pandora_server/extras/pandoraPlugintools/http.py create mode 100644 pandora_server/extras/pandoraPlugintools/modules.py create mode 100644 pandora_server/extras/pandoraPlugintools/transfer.py diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py new file mode 100644 index 0000000000..cadaa764d5 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -0,0 +1,107 @@ +from datetime import datetime +from subprocess import * +import hashlib +import sys + +global_variables = { + 'temporal' : '/tmp', + 'agents_group_name': '', + 'interval' : 300 +} + +#### +# Set a global variable with the specified name and assigns a value to it. +########################################### +def set_global_variable( + variable_name, + value + ): + + global_variables[variable_name] = value + +#### +# Prints agent XML. Requires agent conf +# (dict) and modules (list) as arguments. +########################################### +def print_agent( + agent, + modules, + temp_dir=global_variables['temporal'], + log_modules= None, + print_flag = None + ): + """Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. + - Use print_flag to show modules' XML in STDOUT. + - Returns a tuple (xml, data_file). + """ + data_file=None + + header = "\n" + header += " str: + """Expects a macro dictionary key:value (macro_name:macro_value) + and a string to replace macro. \n + It will replace the macro_name for the macro_value in any string. + """ + for macro_name, macro_value in macro_dic.items(): + data = data.replace(macro_name, macro_value) + + return data + + +######################################################################################### +# Configuration file parser +######################################################################################### + +def parse_configuration( + file="/etc/pandora/pandora_server.conf", + separator=" " + ): + """ + Parse configuration. Reads configuration file and stores its data as dict. + + Args: + - file (str): configuration file path. Defaults to "/etc/pandora/pandora_server.conf". \n + - separator (str, optional): Separator for option and value. Defaults to " ". + + Returns: + - dict: containing all keys and values from file. + """ + config = {} + try: + with open (file, "r") as conf: + lines = conf.read().splitlines() + for line in lines: + if line.startswith("#") or len(line) < 1 : + pass + else: + option, value = line.strip().split(separator) + config[option.strip()] = value.strip() + + return config + except Exception as e: + print (f"{type(e).__name__}: {e}") + +######################################################################################### +# csv file parser +######################################################################################### +def parse_csv_file( + file, separator=';', + count_parameters=None, + debug=False + ) -> list: + """ + Parse csv configuration. Reads configuration file and stores its data in an array. + + Args: + - file (str): configuration csv file path. \n + - separator (str, optional): Separator for option and value. Defaults to ";". + - coun_parameters (int): min number of parameters each line shold have. Default None + - debug: print errors on lines + + Returns: + - List: containing a list for of values for each csv line. + """ + csv_arr = [] + try: + with open (file, "r") as conf: + lines = conf.read().splitlines() + for line in lines: + if line.startswith("#") or len(line) < 1 : + continue + else: + value = line.strip().split(separator) + if count_parameters is None or len(value) >= count_parameters: + csv_arr.append(value) + elif debug==True: + print(f'Csv line: {line} doesnt match minimun parameter defined: {count_parameters}',file=sys.stderr) + + return csv_arr + except Exception as e: + print (f"{type(e).__name__}: {e}") + return 1 diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py new file mode 100644 index 0000000000..bca0eedb30 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -0,0 +1,60 @@ +from requests_ntlm import HttpNtlmAuth +from requests.auth import HTTPBasicAuth +from requests.auth import HTTPDigestAuth +from requests.sessions import Session + +######################################################################################### +# URL calls +######################################################################################### + +def auth_call( + session, + authtype, + user, + passw + ): + """Authentication for url request. Requires request.sessions.Session() object. + + Args: + - session (object): request Session() object. + - authtype (str): 'ntlm', 'basic' or 'digest'. + - user (str): auth user. + - passw (str): auth password. + """ + if authtype == 'ntlm': + session.auth = HttpNtlmAuth(user, passw) + elif authtype == 'basic': + session.auth = HTTPBasicAuth(user, passw) + elif authtype == 'digest': + session.auth = HTTPDigestAuth(user, passw) + +def call_url( + url, + authtype, + user, + passw, + time_out + ): + """Call URL. Uses request module to get url contents. + + Args: + - url (str): URL + - authtype (str): ntlm', 'basic', 'digest'. Optional. + - user (str): auth user. Optional. + - passw (str): auth password. Optional. + + Returns: + - str: call output + """ + # using with so we make sure the session is closed even when exceptions are encountered + with Session() as session: + if authtype != None: + auth_call(session, authtype, user, passw) + try: + output = session.get(url, timeout=time_out, verify=False) + except ValueError: + exit("Error: URL format not valid (example http://myserver/page.php)") + except Exception as e: + exit(f"{type(e).__name__}:\t{str(e)}") + else: + return output diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py new file mode 100644 index 0000000000..4e3e66f3d6 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -0,0 +1,151 @@ +#### +# Returns module in XML format. +# Accepts only {dict} +########################################### +def print_module( + module, + print_flag=None + ): + """Returns module in XML format. Accepts only {dict}.\n + - Only works with one module at a time: otherwise iteration is needed. + - Module "value" field accepts str type or [list] for datalists. + - Use print_flag to show modules' XML in STDOUT. + """ + data = dict(module) + module_xml = ("\n" + "\t\n" + "\t" + str(data["type"]) + "\n" + ) + + if type(data["type"]) is not str and "string" not in data["type"]: #### Strip spaces if module not generic_data_string + data["value"] = data["value"].strip() + if isinstance(data["value"], list): # Checks if value is a list + module_xml += "\t\n" + for value in data["value"]: + if type(value) is dict and "value" in value: + module_xml += "\t\n" + module_xml += "\t\t\n" + if "timestamp" in value: + module_xml += "\t\t\n" + module_xml += "\t\n" + module_xml += "\t\n" + else: + module_xml += "\t\n" + if "desc" in data: + module_xml += "\t\n" + if "unit" in data: + module_xml += "\t\n" + if "interval" in data: + module_xml += "\t\n" + if "tags" in data: + module_xml += "\t" + str(data["tags"]) + "\n" + if "module_group" in data: + module_xml += "\t" + str(data["module_group"]) + "\n" + if "module_parent" in data: + module_xml += "\t" + str(data["module_parent"]) + "\n" + if "min_warning" in data: + module_xml += "\t\n" + if "min_warning_forced" in data: + module_xml += "\t\n" + if "max_warning" in data: + module_xml += "\t\n" + if "max_warning_forced" in data: + module_xml += "\t\n" + if "min_critical" in data: + module_xml += "\t\n" + if "min_critical_forced" in data: + module_xml += "\t\n" + if "max_critical" in data: + module_xml += "\t\n" + if "max_critical_forced" in data: + module_xml += "\t\n" + if "str_warning" in data: + module_xml += "\t\n" + if "str_warning_forced" in data: + module_xml += "\t\n" + if "str_critical" in data: + module_xml += "\t\n" + if "str_critical_forced" in data: + module_xml += "\t\n" + if "critical_inverse" in data: + module_xml += "\t\n" + if "warning_inverse" in data: + module_xml += "\t\n" + if "max" in data: + module_xml += "\t\n" + if "min" in data: + module_xml += "\t\n" + if "post_process" in data: + module_xml += "\t\n" + if "disabled" in data: + module_xml += "\t\n" + if "min_ff_event" in data: + module_xml += "\t\n" + if "status" in data: + module_xml += "\t\n" + if "timestamp" in data: + module_xml += "\t\n" + if "custom_id" in data: + module_xml += "\t\n" + if "critical_instructions" in data: + module_xml += "\t\n" + if "warning_instructions" in data: + module_xml += "\t\n" + if "unknown_instructions" in data: + module_xml += "\t\n" + if "quiet" in data: + module_xml += "\t\n" + if "module_ff_interval" in data: + module_xml += "\t\n" + if "crontab" in data: + module_xml += "\t\n" + if "min_ff_event_normal" in data: + module_xml += "\t\n" + if "min_ff_event_warning" in data: + module_xml += "\t\n" + if "min_ff_event_critical" in data: + module_xml += "\t\n" + if "ff_type" in data: + module_xml += "\t\n" + if "ff_timeout" in data: + module_xml += "\t\n" + if "each_ff" in data: + module_xml += "\t\n" + if "module_parent_unlink" in data: + module_xml += "\t\n" + if "global_alerts" in data: + for alert in data["alert"]: + module_xml += "\t\n" + module_xml += "\n" + + if print_flag: + print (module_xml) + + return (module_xml) + + +######################################################################################### +# print_module +######################################################################################### + +def print_log_module( + module, + print_flag = None + ): + """Returns log module in XML format. Accepts only {dict}.\n + - Only works with one module at a time: otherwise iteration is needed. + - Module "value" field accepts str type. + - Use not_print_flag to avoid printing the XML (only populates variables). + """ + data = dict(module) + module_xml = ("\n" + "\t\n" + "\t\"" + str(data["value"]) + "\"\n" + ) + + module_xml += "\n" + + if print_flag: + print (module_xml) + + return (module_xml) diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py new file mode 100644 index 0000000000..43a97886d5 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -0,0 +1,121 @@ +from datetime import datetime +from subprocess import * +import shutil +import subprocess +import os +import sys + +global_variables = { + 'transfer_mode' : 'tentacle', + 'temporal' : '/tmp', + 'data_dir' : '/var/spool/pandora/data_in/', + 'tentacle_client' : 'tentacle_client', + 'tentacle_ip' : '127.0.0.1', + 'tentacle_port' : 41121 +} + +#### +# Set a global variable with the specified name and assigns a value to it. +########################################### +def set_global_variable( + variable_name, + value + ): + + global_variables[variable_name] = value + +#### +# Sends file using tentacle protocol +########################################### +def tentacle_xml( + file, + tentacle_ops, + tentacle_path='', + debug=0 + ): + """Sends file using tentacle protocol\n + - Only works with one file at time. + - file variable needs full file path. + - tentacle_opts should be a dict with tentacle options (address [password] [port]). + - tentacle_path allows to define a custom path for tentacle client in case is not in sys path). + - if debug is enabled, the data file will not be removed after being sent. + + Returns 0 for OK and 1 for errors. + """ + + if file is None : + msg="Tentacle error: file path is required." + print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg, file=sys.stderr) + else : + data_file = file + + if tentacle_ops['address'] is None : + msg="Tentacle error: No address defined" + print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg, file=sys.stderr) + return 1 + + try : + with open(data_file, 'r') as data: + data.read() + data.close() + except Exception as e : + msg=f"Tentacle error: {type(e).__name__} {e}" + print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) + return 1 + + tentacle_cmd = f"{tentacle_path}{global_variables['tentacle_client']} -v -a {tentacle_ops['address']} {global_variables['tentacle_opts']}" + if "port" in tentacle_ops: + tentacle_cmd += f"-p {tentacle_ops['port']} " + if "password" in tentacle_ops: + tentacle_cmd += f"-x {tentacle_ops['password']} " + tentacle_cmd += f"{data_file.strip()} " + + tentacle_exe=Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() + + if rc != 0 : + stderr = tentacle_exe.stderr.read().decode() + msg="Tentacle error:" + str(stderr) + print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) + next + return 1 + elif debug == 0 : + os.remove(file) + + return 0 + +#### +# Detect transfer mode and execute +########################################### +def agentplugin( + modules, + agent, + temp_dir=global_variables['temporal'], + tentacle=False, + tentacle_conf=None + ): + agent_file=print_agent(agent,modules,temp_dir) + + if agent_file[1] is not None: + if tentacle == True and tentacle_conf is not None: + tentacle_xml(agent_file[1],tentacle_conf) + else: + shutil.move(agent_file[1], global_variables['data_dir']) + +#### +# Detect transfer mode and execute (call agentplugin()) +########################################### +def transfer_xml( + agent, + modules, + transfer_mode=global_variables['transfer_mode'], + tentacle_ip=global_variables['tentacle_ip'], + tentacle_port=global_variables['tentacle_port'], + temporal=global_variables['temporal'] + ): + + if transfer_mode != "local" and tentacle_ip is not None: + tentacle_conf={"address":tentacle_ip,"port":tentacle_port} + agentplugin(modules,agent,temporal,True,tentacle_conf) + else: + agentplugin(modules,agent,temporal) From 1aa245352898878c24178a4d64391cf618042ee8 Mon Sep 17 00:00:00 2001 From: alejandro Date: Wed, 26 Jul 2023 11:03:55 +0200 Subject: [PATCH 05/48] added __init__.py and modificate transfer.py and agents.py --- pandora_server/extras/pandoraPlugintools/__init__.py | 6 ++++++ pandora_server/extras/pandoraPlugintools/agents.py | 2 +- pandora_server/extras/pandoraPlugintools/transfer.py | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 pandora_server/extras/pandoraPlugintools/__init__.py diff --git a/pandora_server/extras/pandoraPlugintools/__init__.py b/pandora_server/extras/pandoraPlugintools/__init__.py new file mode 100644 index 0000000000..3b6bec543e --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/__init__.py @@ -0,0 +1,6 @@ +from .agents import * +from .modules import * +from .transfer import * +from .discovery import * +from .http import * +from .general import * diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index cadaa764d5..f81a407086 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -2,6 +2,7 @@ from datetime import datetime from subprocess import * import hashlib import sys +from .modules import print_module,print_log_module global_variables = { 'temporal' : '/tmp', @@ -104,4 +105,3 @@ def init_agent() : "agent_mode" : "1", } return agent - diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 43a97886d5..5dbce337b2 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -4,6 +4,7 @@ import shutil import subprocess import os import sys +from .agents import print_agent global_variables = { 'transfer_mode' : 'tentacle', From b70be8b4e6ee715d0726208c01580cfa2a5ed317 Mon Sep 17 00:00:00 2001 From: alejandro Date: Wed, 26 Jul 2023 11:21:15 +0200 Subject: [PATCH 06/48] describe functions --- .../extras/pandoraPlugintools/agents.py | 13 ++++ .../extras/pandoraPlugintools/discover.py | 70 +++++++++++++++++++ .../extras/pandoraPlugintools/transfer.py | 29 ++++++++ 3 files changed, 112 insertions(+) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index f81a407086..e3310f5d72 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -17,6 +17,13 @@ def set_global_variable( variable_name, value ): + """ + Sets the value of a global variable in the 'global_variables' dictionary. + + Args: + variable_name (str): Name of the variable to set. + value (any): Value to assign to the variable. + """ global_variables[variable_name] = value @@ -90,6 +97,12 @@ def write_xml( # Init agent template ########################################### def init_agent() : + """ + Initializes an agent template with default values. + + Returns: + dict: Dictionary representing the agent template with default values. + """ agent = { "agent_name" : "", "agent_alias" : "", diff --git a/pandora_server/extras/pandoraPlugintools/discover.py b/pandora_server/extras/pandoraPlugintools/discover.py index 8d872a3588..2171ef4dae 100644 --- a/pandora_server/extras/pandoraPlugintools/discover.py +++ b/pandora_server/extras/pandoraPlugintools/discover.py @@ -8,6 +8,13 @@ def set_summary_value( key="", value="" ): + """ + Sets a fixed value for a key in the 'summary' dictionary. + + Args: + key (str): Key to set the value for. + value (any): Value to assign to the key. + """ global summary summary[key] = value @@ -19,6 +26,15 @@ def add_summary_value( key="", value="" ): + """ + Adds a value to a key in the 'summary' dictionary. + + If the key already exists, the value will be incremented. Otherwise, a new key will be created. + + Args: + key (str): Key to add the value to. + value (any): Value to add to the key. + """ global summary if key in summary: @@ -32,6 +48,12 @@ def add_summary_value( def set_error_level( value=0 ): + """ + Sets the error level to the specified value. + + Args: + value (int, optional): The error level value. Default is 0. + """ global error_level error_level = value @@ -42,6 +64,12 @@ def set_error_level( def add_info_value( data="" ): + """ + Adds data to the 'info' variable. + + Args: + data (str, optional): The data to add to the 'info' variable. Default is an empty string. + """ global info info += data @@ -52,6 +80,12 @@ def add_info_value( def set_info_value( data="" ): + """ + Sets a fixed value to the 'info' variable. + + Args: + data (str, optional): The value to set in the 'info' variable. Default is an empty string. + """ global info info = data @@ -64,6 +98,17 @@ def parse_parameter( default="", key="" ): + """ + Parses a parameter from the configuration file. + + Args: + config (ConfigParser, optional): The ConfigParser object representing the configuration file. Default is None. + default (any, optional): The default value to return if the parameter is not found. Default is an empty string. + key (str): The key of the parameter to parse. + + Returns: + any: The parsed value of the parameter, or the default value if the parameter is not found. + """ try: return config.get("CONF", key) @@ -76,6 +121,15 @@ def parse_parameter( def parse_conf_entities( entities="" ): + """ + Parses the configuration file credentials. + + Args: + entities (str): A JSON string representing the entities. + + Returns: + list: A list of entities parsed from the JSON string. If parsing fails, an empty list is returned. + """ entities_list = [] try: @@ -96,6 +150,15 @@ def parse_conf_entities( def param_int( param="" ): + """ + Parses a parameter as an integer. + + Args: + param (any): The parameter to be parsed as an integer. + + Returns: + int: The parsed integer value. If parsing fails, returns 0. + """ try: return int(param) except: @@ -105,6 +168,13 @@ def param_int( # Print JSON output and exit script ########################################### def print_output(): + """ + Prints the JSON output and exits the script. + + The function uses the global variables 'output', 'error_level', 'summary', and 'info' + to create the JSON output. It then prints the JSON string and exits the script with + the 'error_level' as the exit code. + """ global output global error_level diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 5dbce337b2..eab9c10616 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -22,6 +22,13 @@ def set_global_variable( variable_name, value ): + """ + Sets the value of a global variable in the 'global_variables' dictionary. + + Args: + variable_name (str): Name of the variable to set. + value (any): Value to assign to the variable. + """ global_variables[variable_name] = value @@ -95,6 +102,16 @@ def agentplugin( tentacle=False, tentacle_conf=None ): + """ + Detects the transfer mode and executes the corresponding action. + + Args: + modules (list): List of modules. + agent (dict): Dictionary with agent configuration. + temp_dir (str, optional): Temporary directory. Default is global_variables['temporal']. + tentacle (bool, optional): Indicates whether to use the Tentacle protocol. Default is False. + tentacle_conf (dict, optional): Dictionary with Tentacle protocol configuration. Default is None. + """ agent_file=print_agent(agent,modules,temp_dir) if agent_file[1] is not None: @@ -114,6 +131,18 @@ def transfer_xml( tentacle_port=global_variables['tentacle_port'], temporal=global_variables['temporal'] ): + + """ + Detects the transfer mode and calls the agentplugin() function to perform the transfer. + + Args: + agent (dict): Dictionary with agent configuration. + modules (list): List of modules. + transfer_mode (str, optional): Transfer mode. Default is global_variables['transfer_mode']. + tentacle_ip (str, optional): IP address for Tentacle. Default is global_variables['tentacle_ip']. + tentacle_port (str, optional): Port for Tentacle. Default is global_variables['tentacle_port']. + temporal (str, optional): Temporary directory. Default is global_variables['temporal']. + """ if transfer_mode != "local" and tentacle_ip is not None: tentacle_conf={"address":tentacle_ip,"port":tentacle_port} From b526b102007ae490727949fbeeebfbc45b410eed Mon Sep 17 00:00:00 2001 From: alejandro Date: Wed, 26 Jul 2023 15:28:44 +0200 Subject: [PATCH 07/48] add readme.md and minor changes --- .../extras/pandoraPlugintools/README.md | 88 +++++++++++++++++++ .../extras/pandoraPlugintools/agents.py | 32 +++++++ .../extras/pandoraPlugintools/general.py | 48 ++++------ 3 files changed, 138 insertions(+), 30 deletions(-) create mode 100644 pandora_server/extras/pandoraPlugintools/README.md diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md new file mode 100644 index 0000000000..e7ff22756c --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -0,0 +1,88 @@ +# Python: module plugintools for PandoraFMS Developers + +pandoraPluginTools is a library that aims to help the creation of scripts and their integration in PandoraFMS. + +[PluginTools Reference Documentation](https://pandorafms.com/guides/public/books/plugintools) + +The package includes the following modules: agents, modules, transfer, general, discovery and http. Each one has different requirements and functions that facilitate and automate the data integration in PandoraFMS. They have the following dependencies : + +**agents** +Module that contains functions oriented to the creation of agents. +- datetime.datetime +- subprocess.Popen +- Hashlib +- sys +- os +- print_module +- print_log_module + +**modules** +Module that contains functions oriented to the creation of modules. + +**transfer** +Module containing functions oriented to file transfer and data sending. +- datetime.datetime +- subprocess.Popen +- shutil +- sys +- os +- print_agent + +**general** +Module containing general purpose functions, useful in the creation of plugins for PandoraFMS. +- datetime.datetime +- hashlib +- json +- sys + +**discovery** +Module that contains general purpose functions, useful in the creation of plugins for PandoraFMS discovery. +- json +- sys + +**http** +Module that contains general purpose functions, useful in the creation of plugins for PandoraFMS discovery. +- requests_ntlm.HttpNtlmAuth +- requests.auth.HTTPBasicAuth +- requests.auth.HTTPDigestAuth +- requests.sessions.Session + + +## Example + +``` python +import pandoraPluginTools as ppt + +## Define agent +server_name = "WIN-SERV" + +agent=ppt.agents.init_agent() +agent.update( + agent_name = ppt.generate_md5(server_name), + agent_alias = server_name, + description = "Default Windows server", +) + +## Define modules +modules=[] + +data = 10 +modules.append({ + "name" : "CPU usage", + "type" : "generic_data", + "value": data, + "desc" : "percentage of cpu utilization", + "unit" : "%" +}) + +## Transfer XML +ppt.transfer_xml( + agent, + modules, + transfer_mode="tentacle", + tentacle_address="192.168.1.20", + tentacle_port="41121", + temporal="/tmp" +) +``` + diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index e3310f5d72..acbb08d1ad 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -2,6 +2,7 @@ from datetime import datetime from subprocess import * import hashlib import sys +import os from .modules import print_module,print_log_module global_variables = { @@ -9,6 +10,21 @@ global_variables = { 'agents_group_name': '', 'interval' : 300 } +######################################################################################### +# OS check +######################################################################################### + +POSIX = os.name == "posix" +WINDOWS = os.name == "nt" +LINUX = sys.platform.startswith("linux") +MACOS = sys.platform.startswith("darwin") +OSX = MACOS # deprecated alias +FREEBSD = sys.platform.startswith("freebsd") +OPENBSD = sys.platform.startswith("openbsd") +NETBSD = sys.platform.startswith("netbsd") +BSD = FREEBSD or OPENBSD or NETBSD +SUNOS = sys.platform.startswith(("sunos", "solaris")) +AIX = sys.platform.startswith("aix") #### # Set a global variable with the specified name and assigns a value to it. @@ -118,3 +134,19 @@ def init_agent() : "agent_mode" : "1", } return agent + + +######################################################################################### +# Agent class +######################################################################################### + +class Agent: + """Basic agent class. Requires agent parameters (config {dictionary}) + and module definition (modules_def [list of dictionaries]) """ + def __init__( + self, + config, + modules_def + ): + self.config = config + self.modules_def = modules_def diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 6e9f577e11..afc46286e5 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -2,37 +2,8 @@ import sys import os import json from datetime import datetime +import hashlib -######################################################################################### -# OS check -######################################################################################### - -POSIX = os.name == "posix" -WINDOWS = os.name == "nt" -LINUX = sys.platform.startswith("linux") -MACOS = sys.platform.startswith("darwin") -OSX = MACOS # deprecated alias -FREEBSD = sys.platform.startswith("freebsd") -OPENBSD = sys.platform.startswith("openbsd") -NETBSD = sys.platform.startswith("netbsd") -BSD = FREEBSD or OPENBSD or NETBSD -SUNOS = sys.platform.startswith(("sunos", "solaris")) -AIX = sys.platform.startswith("aix") - -######################################################################################### -# Agent class -######################################################################################### - -class Agent: - """Basic agent class. Requires agent parameters (config {dictionary}) - and module definition (modules_def [list of dictionaries]) """ - def __init__( - self, - config, - modules_def - ): - self.config = config - self.modules_def = modules_def ######################################################################################### # Debug_dict: prints dictionary in formatted json string. @@ -154,3 +125,20 @@ def parse_csv_file( except Exception as e: print (f"{type(e).__name__}: {e}") return 1 + + +######################################################################################### +# md5 generator +######################################################################################### +def generate_md5(input_string): + """ + Generates an MD5 hash for the given input string. + + Args: + input_string (str): The string for which the MD5 hash will be generated. + + Returns: + str: The MD5 hash of the input string as a hexadecimal string. + """ + md5_hash = hashlib.md5(input_string.encode()).hexdigest() + return md5_hash \ No newline at end of file From 909d05b30097928214fb2f8f957aa8475ef6a0f3 Mon Sep 17 00:00:00 2001 From: alejandro Date: Thu, 27 Jul 2023 12:07:24 +0200 Subject: [PATCH 08/48] fix readme.md --- pandora_server/extras/pandoraPlugintools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index e7ff22756c..9992a13a08 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -41,7 +41,7 @@ Module that contains general purpose functions, useful in the creation of plugin - sys **http** -Module that contains general purpose functions, useful in the creation of plugins for PandoraFMS discovery. +Module that contains useful functions for making http requests. - requests_ntlm.HttpNtlmAuth - requests.auth.HTTPBasicAuth - requests.auth.HTTPDigestAuth From 2ca114f8443b68c8f045debda202b472820e3b97 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Thu, 27 Jul 2023 15:53:10 +0200 Subject: [PATCH 09/48] Organization and new functions for pandoraPluginTools --- .../extras/pandoraPlugintools/README.md | 75 +++-- .../extras/pandoraPlugintools/__init__.py | 3 +- .../extras/pandoraPlugintools/agents.py | 180 ++++++------ .../extras/pandoraPlugintools/discover.py | 194 ------------- .../extras/pandoraPlugintools/discovery.py | 130 +++++++++ .../extras/pandoraPlugintools/general.py | 259 ++++++++++++----- .../extras/pandoraPlugintools/http.py | 61 ++-- .../extras/pandoraPlugintools/modules.py | 269 +++++++++--------- .../extras/pandoraPlugintools/threads.py | 87 ++++++ .../extras/pandoraPlugintools/transfer.py | 215 +++++++------- 10 files changed, 822 insertions(+), 651 deletions(-) delete mode 100644 pandora_server/extras/pandoraPlugintools/discover.py create mode 100644 pandora_server/extras/pandoraPlugintools/discovery.py create mode 100644 pandora_server/extras/pandoraPlugintools/threads.py diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index e7ff22756c..dd18794c6c 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -1,52 +1,31 @@ # Python: module plugintools for PandoraFMS Developers -pandoraPluginTools is a library that aims to help the creation of scripts and their integration in PandoraFMS. +pandoraPluginTools is a library that aims to help the creation of scripts and their integration in Pandora FMS. [PluginTools Reference Documentation](https://pandorafms.com/guides/public/books/plugintools) -The package includes the following modules: agents, modules, transfer, general, discovery and http. Each one has different requirements and functions that facilitate and automate the data integration in PandoraFMS. They have the following dependencies : - -**agents** -Module that contains functions oriented to the creation of agents. -- datetime.datetime -- subprocess.Popen -- Hashlib -- sys -- os -- print_module -- print_log_module - -**modules** -Module that contains functions oriented to the creation of modules. - -**transfer** -Module containing functions oriented to file transfer and data sending. -- datetime.datetime -- subprocess.Popen -- shutil -- sys -- os -- print_agent +The package includes the following modules. Each one has different functions that facilitate and automate the data integration in Pandora FMS: **general** -Module containing general purpose functions, useful in the creation of plugins for PandoraFMS. -- datetime.datetime -- hashlib -- json -- sys +Module containing general purpose functions, useful in the creation of plugins for PandoraFMS + +**threads** +Module containing threading purpose functions, useful to run parallel functions. + +**agents** +Module that contains functions oriented to the creation of Pandora FMS agents + +**modules** +Module that contains functions oriented to the creation of Pandora FMS modules. + +**transfer** +Module containing functions oriented to file transfer and data sending to Pandora FMS server **discovery** -Module that contains general purpose functions, useful in the creation of plugins for PandoraFMS discovery. -- json -- sys +Module containing functions oriented to the creation of Pandora FMS discovery plugins **http** -Module that contains general purpose functions, useful in the creation of plugins for PandoraFMS discovery. -- requests_ntlm.HttpNtlmAuth -- requests.auth.HTTPBasicAuth -- requests.auth.HTTPDigestAuth -- requests.sessions.Session - +Module containing functions oriented to HTTP API calls ## Example @@ -56,7 +35,7 @@ import pandoraPluginTools as ppt ## Define agent server_name = "WIN-SERV" -agent=ppt.agents.init_agent() +agent=ppt.init_agent() agent.update( agent_name = ppt.generate_md5(server_name), agent_alias = server_name, @@ -86,3 +65,21 @@ ppt.transfer_xml( ) ``` +The package has the following dependencies: +- Hashlib +- datetime.datetime +- hashlib +- json +- os +- print_agent +- print_log_module +- print_module +- queue.Queue +- requests.auth.HTTPBasicAuth +- requests.auth.HTTPDigestAuth +- requests.sessions.Session +- requests_ntlm.HttpNtlmAuth +- shutil +- subprocess.Popen +- sys +- threading.Thread diff --git a/pandora_server/extras/pandoraPlugintools/__init__.py b/pandora_server/extras/pandoraPlugintools/__init__.py index 3b6bec543e..e71d801c6a 100644 --- a/pandora_server/extras/pandoraPlugintools/__init__.py +++ b/pandora_server/extras/pandoraPlugintools/__init__.py @@ -1,6 +1,7 @@ +from .general import * +from .threads import * from .agents import * from .modules import * from .transfer import * from .discovery import * from .http import * -from .general import * diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index acbb08d1ad..29b972b0c0 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -3,15 +3,22 @@ from subprocess import * import hashlib import sys import os +from .general import now,set_dict_key_value from .modules import print_module,print_log_module +from .transfer import write_xml + +#### +# Define global variables dict, used in functions as default values. +# Its values can be changed. +######################################################################################### global_variables = { - 'temporal' : '/tmp', - 'agents_group_name': '', - 'interval' : 300 + 'agents_group_name' : '', + 'interval' : 300 } -######################################################################################### -# OS check + +#### +# Define some global variables ######################################################################################### POSIX = os.name == "posix" @@ -28,9 +35,9 @@ AIX = sys.platform.startswith("aix") #### # Set a global variable with the specified name and assigns a value to it. -########################################### +######################################################################################### def set_global_variable( - variable_name, + variable_name: str = "", value ): """ @@ -40,79 +47,33 @@ def set_global_variable( variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ - - global_variables[variable_name] = value + set_dict_key_value(global_variables, variable_name, value) #### -# Prints agent XML. Requires agent conf -# (dict) and modules (list) as arguments. -########################################### -def print_agent( - agent, - modules, - temp_dir=global_variables['temporal'], - log_modules= None, - print_flag = None - ): - """Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. - - Use print_flag to show modules' XML in STDOUT. - - Returns a tuple (xml, data_file). +# Agent class +######################################################################################### + +class Agent: """ - data_file=None + Basic agent class. Requires agent parameters (config {dictionary}) + and module definition (modules_def [list of dictionaries]) + """ + def __init__( + self, + config: dict = None, + modules_def: list = [] + ): - header = "\n" - header += " dict: """ Initializes an agent template with default values. @@ -120,33 +81,58 @@ def init_agent() : dict: Dictionary representing the agent template with default values. """ agent = { - "agent_name" : "", - "agent_alias" : "", + "agent_name" : "", + "agent_alias" : "", "parent_agent_name" : "", - "description" : "", - "version" : "", - "os_name" : "", - "os_version" : "", - "timestamp" : datetime.today().strftime('%Y/%m/%d %H:%M:%S'), - "address" : "", - "group" : global_variables['agents_group_name'], - "interval" : global_variables['interval'], - "agent_mode" : "1", - } + "description" : "", + "version" : "", + "os_name" : "", + "os_version" : "", + "timestamp" : now(), + "address" : "", + "group" : global_variables['agents_group_name'], + "interval" : global_variables['interval'], + "agent_mode" : "1", + } + return agent - -######################################################################################### -# Agent class +#### +# Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. ######################################################################################### +def print_agent( + agent: dict = None, + modules: list = [], + log_modules: list = [], + print_flag: bool = False + ) -> str: + """ + Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. + - Use print_flag to show modules' XML in STDOUT. + - Returns xml (str). + """ + xml = "" + data_file = None -class Agent: - """Basic agent class. Requires agent parameters (config {dictionary}) - and module definition (modules_def [list of dictionaries]) """ - def __init__( - self, - config, - modules_def - ): - self.config = config - self.modules_def = modules_def + if agent is not None: + header = "\n" + header += " 0: + input_dict[key] = input_value + +#### +# Return MD5 hash string. +######################################################################################### + +def generate_md5( + input_string: str = "" + ) -> str: + """ + Generates an MD5 hash for the given input string. + + Args: + input_string (str): The string for which the MD5 hash will be generated. + + Returns: + str: The MD5 hash of the input string as a hexadecimal string. + """ + try: + md5_hash = hashlib.md5(input_string.encode()).hexdigest() + except: + md5_hash = "" + + return md5_hash + +#### +# Returns or print current time in date format or utimestamp. +######################################################################################### + +def now( + print_flag: int = 0, + utimestamp: int = 0 + ) -> str: + """ + Returns time in yyyy/mm/dd HH:MM:SS format by default. Use 1 as an argument + to get epoch time (utimestamp) + """ + today = datetime.today() + + if utimestamp: + time = datetime.timestamp(today) + else: + time = today.strftime('%Y/%m/%d %H:%M:%S') + + if print_flag: + print(time) + + return time + +#### +# Translate macros in string from a dict. ######################################################################################### def translate_macros( - macro_dic: dict, - data: str - ) -> str: - """Expects a macro dictionary key:value (macro_name:macro_value) - and a string to replace macro. \n + macro_dic: dict = {}, + data: str = "" + ) -> str: + """ + Expects a macro dictionary key:value (macro_name:macro_value) + and a string to replace macro. + It will replace the macro_name for the macro_value in any string. """ for macro_name, macro_value in macro_dic.items(): @@ -54,14 +106,15 @@ def translate_macros( return data -######################################################################################### -# Configuration file parser +#### +# Parse configuration file line by line based on separator and return dict. ######################################################################################### def parse_configuration( - file="/etc/pandora/pandora_server.conf", - separator=" " - ): + file: str = "/etc/pandora/pandora_server.conf", + separator: str = " ", + default_values: dict = {} + ) -> dict: """ Parse configuration. Reads configuration file and stores its data as dict. @@ -73,72 +126,148 @@ def parse_configuration( - dict: containing all keys and values from file. """ config = {} + try: with open (file, "r") as conf: lines = conf.read().splitlines() for line in lines: - if line.startswith("#") or len(line) < 1 : - pass + if line.strip().startswith("#") or len(line.strip()) < 1 : + continue else: - option, value = line.strip().split(separator) + option, value = line.strip().split(separator, maxsplit=1) config[option.strip()] = value.strip() - return config except Exception as e: print (f"{type(e).__name__}: {e}") + + for option, value in default_values.items(): + if option.strip() not in config: + config[option.strip()] = value.strip() + return config + +#### +# Parse csv file line by line and return list. ######################################################################################### -# csv file parser -######################################################################################### + def parse_csv_file( - file, separator=';', - count_parameters=None, - debug=False + file: str = "", + separator: str = ';', + count_parameters: int = 0, + debug: bool = False ) -> list: """ - Parse csv configuration. Reads configuration file and stores its data in an array. + Parse csv configuration. Reads configuration file and stores its data in a list. Args: - file (str): configuration csv file path. \n - separator (str, optional): Separator for option and value. Defaults to ";". - coun_parameters (int): min number of parameters each line shold have. Default None - - debug: print errors on lines + - debug (bool): print errors on lines Returns: - List: containing a list for of values for each csv line. """ csv_arr = [] + try: - with open (file, "r") as conf: - lines = conf.read().splitlines() + with open (file, "r") as csv: + lines = csv.read().splitlines() for line in lines: - if line.startswith("#") or len(line) < 1 : + if line.strip().startswith("#") or len(line.strip()) < 1 : continue else: value = line.strip().split(separator) - if count_parameters is None or len(value) >= count_parameters: + if len(value) >= count_parameters: csv_arr.append(value) elif debug==True: - print(f'Csv line: {line} doesnt match minimun parameter defined: {count_parameters}',file=sys.stderr) + print(f'Csv line: {line} does not match minimun parameter defined: {count_parameters}',file=sys.stderr) - return csv_arr except Exception as e: print (f"{type(e).__name__}: {e}") - return 1 + return csv_arr +#### +# Parse given variable to integer. ######################################################################################### -# md5 generator -######################################################################################### -def generate_md5(input_string): + +def parse_int( + var="" + ) -> int: """ - Generates an MD5 hash for the given input string. + Parse given variable to integer. Args: - input_string (str): The string for which the MD5 hash will be generated. + var (any): The variable to be parsed as an integer. Returns: - str: The MD5 hash of the input string as a hexadecimal string. + int: The parsed integer value. If parsing fails, returns 0. """ - md5_hash = hashlib.md5(input_string.encode()).hexdigest() - return md5_hash \ No newline at end of file + try: + return int(var) + except: + return 0 + +#### +# Parse given variable to float. +######################################################################################### + +def parse_float( + var="" + ) -> float: + """ + Parse given variable to float. + + Args: + var (any): The variable to be parsed as an float. + + Returns: + float: The parsed float value. If parsing fails, returns 0. + """ + try: + return float(var) + except: + return 0 + +#### +# Parse given variable to string. +######################################################################################### + +def parse_str( + var="" + ) -> str: + """ + Parse given variable to string. + + Args: + var (any): The variable to be parsed as an string. + + Returns: + str: The parsed string value. If parsing fails, returns "". + """ + try: + return str(var) + except: + return "" + +#### +# Parse given variable to bool. +######################################################################################### + +def parse_bool( + var="" + ) -> bool: + """ + Parse given variable to bool. + + Args: + var (any): The variable to be parsed as an bool. + + Returns: + bool: The parsed bool value. If parsing fails, returns False. + """ + try: + return bool(var) + except: + return False \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index bca0eedb30..913655ecb6 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -3,17 +3,18 @@ from requests.auth import HTTPBasicAuth from requests.auth import HTTPDigestAuth from requests.sessions import Session -######################################################################################### -# URL calls +#### +# Auth URL session ######################################################################################### def auth_call( - session, - authtype, - user, - passw + session = None, + authtype: str = "basic", + user: str = "", + passw: str = "" ): - """Authentication for url request. Requires request.sessions.Session() object. + """ + Authentication for url request. Requires request.sessions.Session() object. Args: - session (object): request Session() object. @@ -21,27 +22,34 @@ def auth_call( - user (str): auth user. - passw (str): auth password. """ - if authtype == 'ntlm': - session.auth = HttpNtlmAuth(user, passw) - elif authtype == 'basic': - session.auth = HTTPBasicAuth(user, passw) - elif authtype == 'digest': - session.auth = HTTPDigestAuth(user, passw) + if session is not None: + if authtype == 'ntlm': + session.auth = HttpNtlmAuth(user, passw) + elif authtype == 'basic': + session.auth = HTTPBasicAuth(user, passw) + elif authtype == 'digest': + session.auth = HTTPDigestAuth(user, passw) + +#### +# Call URL and return output +######################################################################################### def call_url( - url, - authtype, - user, - passw, - time_out - ): - """Call URL. Uses request module to get url contents. + url: str = "", + authtype: str = "basic", + user: str = "", + passw: str = "", + timeout: int = 1 + ) -> str: + """ + Call URL. Uses request module to get url contents. Args: - url (str): URL - authtype (str): ntlm', 'basic', 'digest'. Optional. - user (str): auth user. Optional. - passw (str): auth password. Optional. + - timeout (int): session timeout seconds. Optional. Returns: - str: call output @@ -50,11 +58,14 @@ def call_url( with Session() as session: if authtype != None: auth_call(session, authtype, user, passw) + + output = "" + try: - output = session.get(url, timeout=time_out, verify=False) + output = session.get(url, timeout=timeout, verify=False) except ValueError: - exit("Error: URL format not valid (example http://myserver/page.php)") + output = "Error: URL format not valid (example http://myserver/page.php)" except Exception as e: - exit(f"{type(e).__name__}:\t{str(e)}") - else: - return output + output = f"{type(e).__name__}:\t{str(e)}" + + return output diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 4e3e66f3d6..2e9c7449a6 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -1,151 +1,160 @@ #### -# Returns module in XML format. -# Accepts only {dict} -########################################### +# Returns module in XML format. Accepts only {dict} +######################################################################################### def print_module( - module, - print_flag=None - ): - """Returns module in XML format. Accepts only {dict}.\n + module: dict = None, + print_flag: bool = False + ) -> str: + """ + Returns module in XML format. Accepts only {dict}. - Only works with one module at a time: otherwise iteration is needed. - Module "value" field accepts str type or [list] for datalists. - Use print_flag to show modules' XML in STDOUT. """ - data = dict(module) - module_xml = ("\n" - "\t\n" - "\t" + str(data["type"]) + "\n" - ) - - if type(data["type"]) is not str and "string" not in data["type"]: #### Strip spaces if module not generic_data_string - data["value"] = data["value"].strip() - if isinstance(data["value"], list): # Checks if value is a list - module_xml += "\t\n" - for value in data["value"]: - if type(value) is dict and "value" in value: - module_xml += "\t\n" - module_xml += "\t\t\n" - if "timestamp" in value: - module_xml += "\t\t\n" - module_xml += "\t\n" - module_xml += "\t\n" - else: - module_xml += "\t\n" - if "desc" in data: - module_xml += "\t\n" - if "unit" in data: - module_xml += "\t\n" - if "interval" in data: - module_xml += "\t\n" - if "tags" in data: - module_xml += "\t" + str(data["tags"]) + "\n" - if "module_group" in data: - module_xml += "\t" + str(data["module_group"]) + "\n" - if "module_parent" in data: - module_xml += "\t" + str(data["module_parent"]) + "\n" - if "min_warning" in data: - module_xml += "\t\n" - if "min_warning_forced" in data: - module_xml += "\t\n" - if "max_warning" in data: - module_xml += "\t\n" - if "max_warning_forced" in data: - module_xml += "\t\n" - if "min_critical" in data: - module_xml += "\t\n" - if "min_critical_forced" in data: - module_xml += "\t\n" - if "max_critical" in data: - module_xml += "\t\n" - if "max_critical_forced" in data: - module_xml += "\t\n" - if "str_warning" in data: - module_xml += "\t\n" - if "str_warning_forced" in data: - module_xml += "\t\n" - if "str_critical" in data: - module_xml += "\t\n" - if "str_critical_forced" in data: - module_xml += "\t\n" - if "critical_inverse" in data: - module_xml += "\t\n" - if "warning_inverse" in data: - module_xml += "\t\n" - if "max" in data: - module_xml += "\t\n" - if "min" in data: - module_xml += "\t\n" - if "post_process" in data: - module_xml += "\t\n" - if "disabled" in data: - module_xml += "\t\n" - if "min_ff_event" in data: - module_xml += "\t\n" - if "status" in data: - module_xml += "\t\n" - if "timestamp" in data: - module_xml += "\t\n" - if "custom_id" in data: - module_xml += "\t\n" - if "critical_instructions" in data: - module_xml += "\t\n" - if "warning_instructions" in data: - module_xml += "\t\n" - if "unknown_instructions" in data: - module_xml += "\t\n" - if "quiet" in data: - module_xml += "\t\n" - if "module_ff_interval" in data: - module_xml += "\t\n" - if "crontab" in data: - module_xml += "\t\n" - if "min_ff_event_normal" in data: - module_xml += "\t\n" - if "min_ff_event_warning" in data: - module_xml += "\t\n" - if "min_ff_event_critical" in data: - module_xml += "\t\n" - if "ff_type" in data: - module_xml += "\t\n" - if "ff_timeout" in data: - module_xml += "\t\n" - if "each_ff" in data: - module_xml += "\t\n" - if "module_parent_unlink" in data: - module_xml += "\t\n" - if "global_alerts" in data: - for alert in data["alert"]: - module_xml += "\t\n" - module_xml += "\n" + module_xml = "" + + if module is not None: + data = dict(module) + module_xml = ("\n" + "\t\n" + "\t" + str(data["type"]) + "\n" + ) + + if type(data["type"]) is not str and "string" not in data["type"]: #### Strip spaces if module not generic_data_string + data["value"] = data["value"].strip() + + if isinstance(data["value"], list): # Checks if value is a list + module_xml += "\t\n" + for value in data["value"]: + if type(value) is dict and "value" in value: + module_xml += "\t\n" + module_xml += "\t\t\n" + if "timestamp" in value: + module_xml += "\t\t\n" + module_xml += "\t\n" + module_xml += "\t\n" + else: + module_xml += "\t\n" + + if "desc" in data: + module_xml += "\t\n" + if "unit" in data: + module_xml += "\t\n" + if "interval" in data: + module_xml += "\t\n" + if "tags" in data: + module_xml += "\t" + str(data["tags"]) + "\n" + if "module_group" in data: + module_xml += "\t" + str(data["module_group"]) + "\n" + if "module_parent" in data: + module_xml += "\t" + str(data["module_parent"]) + "\n" + if "min_warning" in data: + module_xml += "\t\n" + if "min_warning_forced" in data: + module_xml += "\t\n" + if "max_warning" in data: + module_xml += "\t\n" + if "max_warning_forced" in data: + module_xml += "\t\n" + if "min_critical" in data: + module_xml += "\t\n" + if "min_critical_forced" in data: + module_xml += "\t\n" + if "max_critical" in data: + module_xml += "\t\n" + if "max_critical_forced" in data: + module_xml += "\t\n" + if "str_warning" in data: + module_xml += "\t\n" + if "str_warning_forced" in data: + module_xml += "\t\n" + if "str_critical" in data: + module_xml += "\t\n" + if "str_critical_forced" in data: + module_xml += "\t\n" + if "critical_inverse" in data: + module_xml += "\t\n" + if "warning_inverse" in data: + module_xml += "\t\n" + if "max" in data: + module_xml += "\t\n" + if "min" in data: + module_xml += "\t\n" + if "post_process" in data: + module_xml += "\t\n" + if "disabled" in data: + module_xml += "\t\n" + if "min_ff_event" in data: + module_xml += "\t\n" + if "status" in data: + module_xml += "\t\n" + if "timestamp" in data: + module_xml += "\t\n" + if "custom_id" in data: + module_xml += "\t\n" + if "critical_instructions" in data: + module_xml += "\t\n" + if "warning_instructions" in data: + module_xml += "\t\n" + if "unknown_instructions" in data: + module_xml += "\t\n" + if "quiet" in data: + module_xml += "\t\n" + if "module_ff_interval" in data: + module_xml += "\t\n" + if "crontab" in data: + module_xml += "\t\n" + if "min_ff_event_normal" in data: + module_xml += "\t\n" + if "min_ff_event_warning" in data: + module_xml += "\t\n" + if "min_ff_event_critical" in data: + module_xml += "\t\n" + if "ff_type" in data: + module_xml += "\t\n" + if "ff_timeout" in data: + module_xml += "\t\n" + if "each_ff" in data: + module_xml += "\t\n" + if "module_parent_unlink" in data: + module_xml += "\t\n" + if "alert" in data: + for alert in data["alert"]: + module_xml += "\t\n" + module_xml += "\n" if print_flag: - print (module_xml) + print(module_xml) - return (module_xml) + return module_xml -######################################################################################### -# print_module +#### +# Returns log module in XML format. Accepts only {dict} ######################################################################################### def print_log_module( - module, - print_flag = None - ): - """Returns log module in XML format. Accepts only {dict}.\n + module: dict = None, + print_flag: bool = False + ) -> str: + """ + Returns log module in XML format. Accepts only {dict}. - Only works with one module at a time: otherwise iteration is needed. - Module "value" field accepts str type. - Use not_print_flag to avoid printing the XML (only populates variables). """ - data = dict(module) - module_xml = ("\n" - "\t\n" - "\t\"" + str(data["value"]) + "\"\n" - ) - - module_xml += "\n" + module_xml = "" + + if module is not None: + data = dict(module) + module_xml = ("\n" + "\t\n" + "\t\"" + str(data["value"]) + "\"\n" + ) + + module_xml += "\n" if print_flag: - print (module_xml) + print(module_xml) - return (module_xml) + return module_xml diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py new file mode 100644 index 0000000000..83f967b4b3 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -0,0 +1,87 @@ +import sys +from queue import Queue +from threading import Thread + +#### +# Internal use only: Run a given function in a thread +######################################################################################### +def _single_thread( + q = None, + function: callable = None, + errors: list = [] + ): + """ + Internal use only: Run a given function in a thread + """ + params=q.get() + q.task_done() + try: + function(params) + except Exception as e: + errors.append("Error while runing single thread: "+str(e)) + +#### +# Run a given function for given items list in a given number of threads +######################################################################################### +def run_threads( + max_threads: int = 1, + function: callable = None, + items: list = [] + ) -> bool: + """ + Run a given function for given items list in a given number of threads + """ + + # Assign threads + threads = max_threads + + if threads > len(items): + threads = len(items) + + if threads < 1: + threads = 1 + + # Distribute items per thread + items_per_thread = [] + thread = 0 + for item in items: + if not 0 <= thread < len(items_per_thread): + items_per_thread.append([]) + + items_per_thread[thread].append(item) + + thread += 1 + if thread >= threads: + thread=0 + + # Run threads + try: + q=Queue() + for n_thread in range(threads) : + q.put(items_per_thread[n_thread]) + + run_threads = [] + errors = [] + + for n_thread in range(threads): + t = Thread(target=_single_thread, args=(q, function, errors)) + t.daemon=True + t.start() + run_threads.append(t) + + for t in run_threads: + t.join() + + q.join() + + for error in errors: + print(error,file=sys.stderr) + + if len(errors) > 0: + return False + else: + return True + + except Exception as e: + print("Error while running threads: "+str(e)+"\n",file=sys.stderr) + return False \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index eab9c10616..e06b6a8765 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -4,22 +4,29 @@ import shutil import subprocess import os import sys +from .general import generate_md5,set_dict_key_value from .agents import print_agent +#### +# Define global variables dict, used in functions as default values. +# Its values can be changed. +######################################################################################### + global_variables = { - 'transfer_mode' : 'tentacle', - 'temporal' : '/tmp', - 'data_dir' : '/var/spool/pandora/data_in/', - 'tentacle_client' : 'tentacle_client', - 'tentacle_ip' : '127.0.0.1', - 'tentacle_port' : 41121 + 'transfer_mode' : 'tentacle', + 'temporal' : '/tmp', + 'data_dir' : '/var/spool/pandora/data_in/', + 'tentacle_client' : 'tentacle_client', + 'tentacle_ip' : '127.0.0.1', + 'tentacle_port' : 41121, + 'tentacle_extra_opts' : '' } #### # Set a global variable with the specified name and assigns a value to it. -########################################### +######################################################################################### def set_global_variable( - variable_name, + variable_name: str = "", value ): """ @@ -29,123 +36,131 @@ def set_global_variable( variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ - - global_variables[variable_name] = value + set_dict_key_value(global_variables, variable_name, value) #### # Sends file using tentacle protocol -########################################### +######################################################################################### def tentacle_xml( - file, - tentacle_ops, - tentacle_path='', - debug=0 - ): - """Sends file using tentacle protocol\n + data_file: str = "", + tentacle_ops: dict = {}, + tentacle_path: str = global_variables['tentacle_client'], + debug: int = 0, + print_errors: bool = True + ) -> bool: + """ + Sends file using tentacle protocol - Only works with one file at time. - file variable needs full file path. - tentacle_opts should be a dict with tentacle options (address [password] [port]). - tentacle_path allows to define a custom path for tentacle client in case is not in sys path). - if debug is enabled, the data file will not be removed after being sent. + - if print_errors is enabled, function will print all error messages - Returns 0 for OK and 1 for errors. + Returns True for OK and False for errors. """ - if file is None : - msg="Tentacle error: file path is required." - print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg, file=sys.stderr) - else : - data_file = file + if data_file is not None : - if tentacle_ops['address'] is None : - msg="Tentacle error: No address defined" - print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg, file=sys.stderr) - return 1 + if not 'address' in tentacle_ops: + tentacle_ops['address'] = global_variables['tentacle_ip'] + if not 'port' in tentacle_ops: + tentacle_ops['port'] = global_variables['tentacle_port'] + if not 'extra_opts' in tentacle_ops: + tentacle_ops['extra_opts'] = global_variables['tentacle_extra_opts'] + + if tentacle_ops['address'] is None : + if print_errors: + sys.stderr.write("Tentacle error: No address defined") + return False + + try : + with open(data_file.strip(), 'r') as data: + data.read() + data.close() + except Exception as e : + if print_errors: + sys.stderr.write(f"Tentacle error: {type(e).__name__} {e}") + return False + + tentacle_cmd = f"{tentacle_path} -v -a {tentacle_ops['address']} -p {tentacle_ops['port']} {tentacle_ops['extra_opts']} {data_file.strip()}" + + tentacle_exe=Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() + + if debug == 0 : + os.remove(data_file.strip()) + + if rc != 0 : + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg="Tentacle error:" + str(stderr) + print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) + return False - try : - with open(data_file, 'r') as data: - data.read() - data.close() - except Exception as e : - msg=f"Tentacle error: {type(e).__name__} {e}" - print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) - return 1 - - tentacle_cmd = f"{tentacle_path}{global_variables['tentacle_client']} -v -a {tentacle_ops['address']} {global_variables['tentacle_opts']}" - if "port" in tentacle_ops: - tentacle_cmd += f"-p {tentacle_ops['port']} " - if "password" in tentacle_ops: - tentacle_cmd += f"-x {tentacle_ops['password']} " - tentacle_cmd += f"{data_file.strip()} " - - tentacle_exe=Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) - rc=tentacle_exe.wait() - - if rc != 0 : - stderr = tentacle_exe.stderr.read().decode() - msg="Tentacle error:" + str(stderr) - print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) - next - return 1 - elif debug == 0 : - os.remove(file) - - return 0 + else: + if print_errors: + sys.stderr.write("Tentacle error: file path is required.") + return False #### -# Detect transfer mode and execute -########################################### -def agentplugin( - modules, - agent, - temp_dir=global_variables['temporal'], - tentacle=False, - tentacle_conf=None - ): - """ - Detects the transfer mode and executes the corresponding action. - - Args: - modules (list): List of modules. - agent (dict): Dictionary with agent configuration. - temp_dir (str, optional): Temporary directory. Default is global_variables['temporal']. - tentacle (bool, optional): Indicates whether to use the Tentacle protocol. Default is False. - tentacle_conf (dict, optional): Dictionary with Tentacle protocol configuration. Default is None. - """ - agent_file=print_agent(agent,modules,temp_dir) - - if agent_file[1] is not None: - if tentacle == True and tentacle_conf is not None: - tentacle_xml(agent_file[1],tentacle_conf) - else: - shutil.move(agent_file[1], global_variables['data_dir']) - -#### -# Detect transfer mode and execute (call agentplugin()) -########################################### +# Detect transfer mode and send XML. +######################################################################################### def transfer_xml( - agent, - modules, - transfer_mode=global_variables['transfer_mode'], - tentacle_ip=global_variables['tentacle_ip'], - tentacle_port=global_variables['tentacle_port'], - temporal=global_variables['temporal'] + file: str = "", + transfer_mode: str = global_variables['transfer_mode'], + tentacle_ip: str = global_variables['tentacle_ip'], + tentacle_port: int = global_variables['tentacle_port'], + tentacle_extra_opts: str = global_variables['tentacle_extra_opts'], + data_dir: str = global_variables['data_dir'] ): """ Detects the transfer mode and calls the agentplugin() function to perform the transfer. Args: - agent (dict): Dictionary with agent configuration. - modules (list): List of modules. + file (str): Path to file to send. transfer_mode (str, optional): Transfer mode. Default is global_variables['transfer_mode']. tentacle_ip (str, optional): IP address for Tentacle. Default is global_variables['tentacle_ip']. tentacle_port (str, optional): Port for Tentacle. Default is global_variables['tentacle_port']. - temporal (str, optional): Temporary directory. Default is global_variables['temporal']. + data_dir (str, optional): Path to data dir with local transfer mode. Default is global_variables['data_dir']. """ + if file is not None: + if transfer_mode != "local": + tentacle_conf = { + 'address' : tentacle_ip, + 'port' : tentacle_port, + 'extra_opts' : tentacle_extra_opts + } + tentacle_xml(file, tentacle_conf) + else: + shutil.move(file, data_dir) + +#### +# Creates a agent .data file in the specified data_dir folder +######################################################################################### +def write_xml( + xml: str = "", + agent_name: str = "", + data_dir: str = global_variables['temporal'] + ) -> str: + """ + Creates a agent .data file in the specified data_dir folder + Args: + - xml (str): XML string to be written in the file. + - agent_name (str): agent name for the xml and file name. + - data_dir (str): folder in which the file will be created. + """ + Utime = datetime.now().strftime('%s') + agent_name_md5 = generate_md5(agent_name) + data_file = "%s/%s.%s.data" %(str(data_dir),agent_name_md5,str(Utime)) - if transfer_mode != "local" and tentacle_ip is not None: - tentacle_conf={"address":tentacle_ip,"port":tentacle_port} - agentplugin(modules,agent,temporal,True,tentacle_conf) - else: - agentplugin(modules,agent,temporal) + try: + with open(data_file, 'x') as data: + data.write(xml) + except OSError as o: + print(f"ERROR - Could not write file: {o}, please check directory permissions", file=sys.stderr) + except Exception as e: + print(f"{type(e).__name__}: {e}", file=sys.stderr) + + return data_file From 2098daa9093371387181b6eed7d25c751501c15b Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Thu, 27 Jul 2023 16:04:27 +0200 Subject: [PATCH 10/48] Added param default_values for init_agent --- pandora_server/extras/pandoraPlugintools/agents.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 29b972b0c0..f560677588 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -73,7 +73,9 @@ class Agent: #### # Init agent template ######################################################################################### -def init_agent() -> dict: +def init_agent( + default_values: dict = {} + ) -> dict: """ Initializes an agent template with default values. @@ -95,6 +97,10 @@ def init_agent() -> dict: "agent_mode" : "1", } + for key, value in default_values.items(): + if key in agent: + agent[key] = value + return agent #### From 64917608d516a8476703b17d10ae54f6a9d0f247 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 28 Jul 2023 09:52:16 +0200 Subject: [PATCH 11/48] Updated README example --- pandora_server/extras/pandoraPlugintools/README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index dd18794c6c..afebb28c2d 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -35,12 +35,11 @@ import pandoraPluginTools as ppt ## Define agent server_name = "WIN-SERV" -agent=ppt.init_agent() -agent.update( - agent_name = ppt.generate_md5(server_name), - agent_alias = server_name, - description = "Default Windows server", -) +agent=ppt.init_agent({ + "agent_name" : ppt.generate_md5(server_name), + "agent_alias" : server_name, + "description" : "Default Windows server" +}) ## Define modules modules=[] From 1b2312ce9ad56e1f3465f3e7ea35cc375d8a2760 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 28 Jul 2023 09:59:28 +0200 Subject: [PATCH 12/48] Updated README example --- pandora_server/extras/pandoraPlugintools/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index afebb28c2d..668b27ccf8 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -53,10 +53,11 @@ modules.append({ "unit" : "%" }) -## Transfer XML +## Generate and transfer XML +xml_content = ppt.print_agent(agent, modules) +xml_file = ppt.write_xml(xml_content, agent["agent_name"]) ppt.transfer_xml( - agent, - modules, + xml_file, transfer_mode="tentacle", tentacle_address="192.168.1.20", tentacle_port="41121", From f1938cdb76fd997948e88bf7f6b357406766d372 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 28 Jul 2023 10:00:40 +0200 Subject: [PATCH 13/48] Updated README example --- pandora_server/extras/pandoraPlugintools/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index 668b27ccf8..22bca247ca 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -49,7 +49,7 @@ modules.append({ "name" : "CPU usage", "type" : "generic_data", "value": data, - "desc" : "percentage of cpu utilization", + "desc" : "Percentage of CPU utilization", "unit" : "%" }) From df36ea608a88244895745fbe17c5a55d21f4d697 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 28 Jul 2023 11:22:02 +0200 Subject: [PATCH 14/48] Updated README --- pandora_server/extras/pandoraPlugintools/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index 22bca247ca..df7503d021 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -7,7 +7,7 @@ pandoraPluginTools is a library that aims to help the creation of scripts and th The package includes the following modules. Each one has different functions that facilitate and automate the data integration in Pandora FMS: **general** -Module containing general purpose functions, useful in the creation of plugins for PandoraFMS +Module containing general purpose functions, useful in the creation of plugins for PandoraFMS. **threads** Module containing threading purpose functions, useful to run parallel functions. @@ -19,13 +19,13 @@ Module that contains functions oriented to the creation of Pandora FMS agents Module that contains functions oriented to the creation of Pandora FMS modules. **transfer** -Module containing functions oriented to file transfer and data sending to Pandora FMS server +Module containing functions oriented to file transfer and data sending to Pandora FMS server. **discovery** -Module containing functions oriented to the creation of Pandora FMS discovery plugins +Module containing functions oriented to the creation of Pandora FMS discovery plugins. **http** -Module containing functions oriented to HTTP API calls +Module containing functions oriented to HTTP API calls. ## Example From 27bab031c3f5441d10f3f61e251378b769b966cc Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 28 Jul 2023 12:02:34 +0200 Subject: [PATCH 15/48] Added add_monitoring_data function --- .../extras/pandoraPlugintools/discovery.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 7e8e254033..589c07bf42 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -100,6 +100,19 @@ def set_info_value( info = data +#### +# Set fixed value to info +######################################################################################### +def add_monitoring_data( + data: dict = {} + ): + """ + TODO: Add comments + """ + global monitoring_data + + monitoring_data.append(data) + #### # Print JSON output and exit script ######################################################################################### @@ -116,6 +129,7 @@ def print_output(): global error_level global summary global info + global monitoring_data output={} if summary: @@ -123,6 +137,9 @@ def print_output(): if info: output["info"] = info + + if monitoring_data: + output["monitoring_data"] = monitoring_data json_string = json.dumps(output) From 3c5ee4e03b96e0ba2139d978c3833cba5005d0da Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 10:31:52 +0200 Subject: [PATCH 16/48] Added multiprocessing functions --- .../extras/pandoraPlugintools/threads.py | 115 +++++++++++++++++- 1 file changed, 110 insertions(+), 5 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 83f967b4b3..93c36b1cf5 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -1,6 +1,15 @@ import sys from queue import Queue from threading import Thread +from multiprocessing import Pool, Manager + +#### +# Define multi-processing internal global variables. +######################################################################################### + +_manager = Manager() +_shared_dict = _manager.dict() +_shared_dict_lock = _manager.Lock() #### # Internal use only: Run a given function in a thread @@ -26,7 +35,8 @@ def _single_thread( def run_threads( max_threads: int = 1, function: callable = None, - items: list = [] + items: list = [], + print_errors: bool = False ) -> bool: """ Run a given function for given items list in a given number of threads @@ -74,8 +84,9 @@ def run_threads( q.join() - for error in errors: - print(error,file=sys.stderr) + if print_errors: + for error in errors: + print(error,file=sys.stderr) if len(errors) > 0: return False @@ -83,5 +94,99 @@ def run_threads( return True except Exception as e: - print("Error while running threads: "+str(e)+"\n",file=sys.stderr) - return False \ No newline at end of file + if print_errors: + print("Error while running threads: "+str(e)+"\n",file=sys.stderr) + return False + +#### +# Set a given value to a key in the internal shared dict. +# Used by all parallel processes. +######################################################################################### +def set_shared_dict_value( + key: str = None, + value = None + ): + """ + Set a given value to a key in the internal shared dict. + Used by all parallel processes. + """ + global _shared_dict + + if key is not None: + with _shared_dict_lock: + _shared_dict[key] = value + +#### +# Add a given value to a key in the internal shared dict. +# Used by all parallel processes. +######################################################################################### +def add_shared_dict_value( + key: str = None, + value = None + ): + """ + Add a given value to a key in the internal shared dict. + Used by all parallel processes. + """ + global _shared_dict + + if key is not None: + with _shared_dict_lock: + if key in _shared_dict: + _shared_dict[key] += value + else: + set_shared_dict_value(key, value) + +#### +# Get the value of a key in the internal shared dict. +# Used by all parallel processes. +######################################################################################### +def get_shared_dict_value( + key: str = None + ): + """ + Get the value of a key in the internal shared dict. + Used by all parallel processes. + """ + global _shared_dict + + with _shared_dict_lock: + if key in _shared_dict and key is not None: + return _shared_dict[key] + else: + return None + +#### +# Run a given function for given items list in a given number of processes +# Given function receives each item as first parameter +######################################################################################### +def run_processes( + max_processes: int = 1, + function: callable = None, + items: list = [], + print_errors: bool = False + ) -> bool: + """ + Run a given function for given items list in a given number of processes + """ + + # Assign processes + processes = max_processes + + if processes > len(items): + processes = len(items) + + if processes < 1: + processes = 1 + + # Run processes + with Pool(processes) as pool: + try: + pool.map(function, items) + result = True + except Exception as error: + if print_errors: + print(error,file=sys.stderr) + result = False + + return result \ No newline at end of file From 3a5949ac5e353b18bf23408c2caee0bee99493b6 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 11:32:34 +0200 Subject: [PATCH 17/48] Changed global variables names and minor changes --- .../extras/pandoraPlugintools/agents.py | 10 +- .../extras/pandoraPlugintools/discovery.py | 169 ++++++++++-------- .../extras/pandoraPlugintools/threads.py | 28 +-- .../extras/pandoraPlugintools/transfer.py | 34 ++-- 4 files changed, 126 insertions(+), 115 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index f560677588..658c1a0bb4 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -12,7 +12,7 @@ from .transfer import write_xml # Its values can be changed. ######################################################################################### -global_variables = { +GLOBAL_VARIABLES = { 'agents_group_name' : '', 'interval' : 300 } @@ -41,13 +41,13 @@ def set_global_variable( value ): """ - Sets the value of a global variable in the 'global_variables' dictionary. + Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ - set_dict_key_value(global_variables, variable_name, value) + set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) #### # Agent class @@ -92,8 +92,8 @@ def init_agent( "os_version" : "", "timestamp" : now(), "address" : "", - "group" : global_variables['agents_group_name'], - "interval" : global_variables['interval'], + "group" : GLOBAL_VARIABLES['agents_group_name'], + "interval" : GLOBAL_VARIABLES['interval'], "agent_mode" : "1", } diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 589c07bf42..22dfb9d3f4 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -5,52 +5,10 @@ import json # Define some global variables ######################################################################################### -output = {} -error_level = 0 -summary = {} -info = "" -monitoring_data = [] - -#### -# Set fixed value to summary key -######################################################################################### -def set_summary_value( - key: str = "", - value = "" - ): - """ - Sets a fixed value for a key in the 'summary' dictionary. - - Args: - key (str): Key to set the value for. - value (any): Value to assign to the key. - """ - global summary - - summary[key] = value - -#### -# Add value to summary key -######################################################################################### -def add_summary_value( - key: str = "", - value = "" - ): - """ - Adds a value to a key in the 'summary' dictionary. - - If the key already exists, the value will be incremented. Otherwise, a new key will be created. - - Args: - key (str): Key to add the value to. - value (any): Value to add to the key. - """ - global summary - - if key in summary: - summary[key] += value - else: - set_summary_value(key, value) +ERROR_LEVEL = 0 +SUMMARY = {} +INFO = "" +MONITORING_DATA = [] #### # Set error level to value @@ -64,44 +22,98 @@ def set_error_level( Args: value (int, optional): The error level value. Default is 0. """ - global error_level + global ERROR_LEVEL - error_level = value + ERROR_LEVEL = value #### -# Add data to info +# Set fixed value to summary key ######################################################################################### -def add_info_value( - data: str = "" +def set_summary_value( + key: str = "", + value = "" ): """ - Adds data to the 'info' variable. + Sets a fixed value for a key in the 'SUMMARY' dictionary. Args: - data (str, optional): The data to add to the 'info' variable. Default is an empty string. + key (str): Key to set the value for. + value (any): Value to assign to the key. """ - global info + global SUMMARY - info += data + SUMMARY[key] = value + +#### +# Add value to summary key +######################################################################################### +def add_summary_value( + key: str = "", + value = "" + ): + """ + Adds a value to a key in the 'SUMMARY' dictionary. + + If the key already exists, the value will be incremented. Otherwise, a new key will be created. + + Args: + key (str): Key to add the value to. + value (any): Value to add to the key. + """ + global SUMMARY + + if key in SUMMARY: + SUMMARY[key] += value + else: + set_summary_value(key, value) #### # Set fixed value to info ######################################################################################### def set_info_value( - data: str = "" + value: str = "" ): """ - Sets a fixed value to the 'info' variable. + Sets a fixed value to the 'INFO' variable. Args: - data (str, optional): The value to set in the 'info' variable. Default is an empty string. + data (str, optional): The value to set in the 'INFO' variable. Default is an empty string. """ - global info + global INFO - info = data + INFO = value #### -# Set fixed value to info +# Add data to info +######################################################################################### +def add_info_value( + value: str = "" + ): + """ + Adds data to the 'INFO' variable. + + Args: + data (str, optional): The data to add to the 'INFO' variable. Default is an empty string. + """ + global INFO + + INFO += value + +#### +# Set fixed value to monitoring data +######################################################################################### +def set_monitoring_data( + data: list = [] + ): + """ + TODO: Add comments + """ + global MONITORING_DATA + + MONITORING_DATA = data + +#### +# Add value to monitoring data ######################################################################################### def add_monitoring_data( data: dict = {} @@ -109,9 +121,9 @@ def add_monitoring_data( """ TODO: Add comments """ - global monitoring_data + global MONITORING_DATA - monitoring_data.append(data) + MONITORING_DATA.append(data) #### # Print JSON output and exit script @@ -120,28 +132,27 @@ def print_output(): """ Prints the JSON output and exits the script. - The function uses the global variables 'output', 'error_level', 'summary', and 'info' + The function uses the global variables 'ERROR_LEVEL', 'SUMMARY', and 'info' to create the JSON output. It then prints the JSON string and exits the script with - the 'error_level' as the exit code. + the 'ERROR_LEVEL' as the exit code. """ - global output - global error_level - global summary - global info - global monitoring_data + global ERROR_LEVEL + global SUMMARY + global INFO + global MONITORING_DATA - output={} - if summary: - output["summary"] = summary + OUTPUT={} + if SUMMARY: + OUTPUT["summary"] = SUMMARY - if info: - output["info"] = info + if INFO: + OUTPUT["info"] = INFO - if monitoring_data: - output["monitoring_data"] = monitoring_data + if MONITORING_DATA: + OUTPUT["monitoring_data"] = MONITORING_DATA - json_string = json.dumps(output) + json_string = json.dumps(OUTPUT) print(json_string) - sys.exit(error_level) + sys.exit(ERROR_LEVEL) diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 93c36b1cf5..8e3a5dfa09 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -7,9 +7,9 @@ from multiprocessing import Pool, Manager # Define multi-processing internal global variables. ######################################################################################### -_manager = Manager() -_shared_dict = _manager.dict() -_shared_dict_lock = _manager.Lock() +_MANAGER = Manager() +_SHARED_DICT = _MANAGER.dict() +_SHARED_DICT_LOCK = _MANAGER.Lock() #### # Internal use only: Run a given function in a thread @@ -110,11 +110,11 @@ def set_shared_dict_value( Set a given value to a key in the internal shared dict. Used by all parallel processes. """ - global _shared_dict + global _SHARED_DICT if key is not None: - with _shared_dict_lock: - _shared_dict[key] = value + with _SHARED_DICT_LOCK: + _SHARED_DICT[key] = value #### # Add a given value to a key in the internal shared dict. @@ -128,12 +128,12 @@ def add_shared_dict_value( Add a given value to a key in the internal shared dict. Used by all parallel processes. """ - global _shared_dict + global _SHARED_DICT if key is not None: - with _shared_dict_lock: - if key in _shared_dict: - _shared_dict[key] += value + with _SHARED_DICT_LOCK: + if key in _SHARED_DICT: + _SHARED_DICT[key] += value else: set_shared_dict_value(key, value) @@ -148,11 +148,11 @@ def get_shared_dict_value( Get the value of a key in the internal shared dict. Used by all parallel processes. """ - global _shared_dict + global _SHARED_DICT - with _shared_dict_lock: - if key in _shared_dict and key is not None: - return _shared_dict[key] + with _SHARED_DICT_LOCK: + if key in _SHARED_DICT and key is not None: + return _SHARED_DICT[key] else: return None diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index e06b6a8765..ebe35daf0f 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -12,7 +12,7 @@ from .agents import print_agent # Its values can be changed. ######################################################################################### -global_variables = { +GLOBAL_VARIABLES = { 'transfer_mode' : 'tentacle', 'temporal' : '/tmp', 'data_dir' : '/var/spool/pandora/data_in/', @@ -30,13 +30,13 @@ def set_global_variable( value ): """ - Sets the value of a global variable in the 'global_variables' dictionary. + Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ - set_dict_key_value(global_variables, variable_name, value) + set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) #### # Sends file using tentacle protocol @@ -44,7 +44,7 @@ def set_global_variable( def tentacle_xml( data_file: str = "", tentacle_ops: dict = {}, - tentacle_path: str = global_variables['tentacle_client'], + tentacle_path: str = GLOBAL_VARIABLES['tentacle_client'], debug: int = 0, print_errors: bool = True ) -> bool: @@ -63,11 +63,11 @@ def tentacle_xml( if data_file is not None : if not 'address' in tentacle_ops: - tentacle_ops['address'] = global_variables['tentacle_ip'] + tentacle_ops['address'] = GLOBAL_VARIABLES['tentacle_ip'] if not 'port' in tentacle_ops: - tentacle_ops['port'] = global_variables['tentacle_port'] + tentacle_ops['port'] = GLOBAL_VARIABLES['tentacle_port'] if not 'extra_opts' in tentacle_ops: - tentacle_ops['extra_opts'] = global_variables['tentacle_extra_opts'] + tentacle_ops['extra_opts'] = GLOBAL_VARIABLES['tentacle_extra_opts'] if tentacle_ops['address'] is None : if print_errors: @@ -108,11 +108,11 @@ def tentacle_xml( ######################################################################################### def transfer_xml( file: str = "", - transfer_mode: str = global_variables['transfer_mode'], - tentacle_ip: str = global_variables['tentacle_ip'], - tentacle_port: int = global_variables['tentacle_port'], - tentacle_extra_opts: str = global_variables['tentacle_extra_opts'], - data_dir: str = global_variables['data_dir'] + transfer_mode: str = GLOBAL_VARIABLES['transfer_mode'], + tentacle_ip: str = GLOBAL_VARIABLES['tentacle_ip'], + tentacle_port: int = GLOBAL_VARIABLES['tentacle_port'], + tentacle_extra_opts: str = GLOBAL_VARIABLES['tentacle_extra_opts'], + data_dir: str = GLOBAL_VARIABLES['data_dir'] ): """ @@ -120,10 +120,10 @@ def transfer_xml( Args: file (str): Path to file to send. - transfer_mode (str, optional): Transfer mode. Default is global_variables['transfer_mode']. - tentacle_ip (str, optional): IP address for Tentacle. Default is global_variables['tentacle_ip']. - tentacle_port (str, optional): Port for Tentacle. Default is global_variables['tentacle_port']. - data_dir (str, optional): Path to data dir with local transfer mode. Default is global_variables['data_dir']. + transfer_mode (str, optional): Transfer mode. Default is GLOBAL_VARIABLES['transfer_mode']. + tentacle_ip (str, optional): IP address for Tentacle. Default is GLOBAL_VARIABLES['tentacle_ip']. + tentacle_port (str, optional): Port for Tentacle. Default is GLOBAL_VARIABLES['tentacle_port']. + data_dir (str, optional): Path to data dir with local transfer mode. Default is GLOBAL_VARIABLES['data_dir']. """ if file is not None: if transfer_mode != "local": @@ -142,7 +142,7 @@ def transfer_xml( def write_xml( xml: str = "", agent_name: str = "", - data_dir: str = global_variables['temporal'] + data_dir: str = GLOBAL_VARIABLES['temporal'] ) -> str: """ Creates a agent .data file in the specified data_dir folder From 8f72e9b6e79b17b5057ccb9954a568c70b23a27c Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 11:38:49 +0200 Subject: [PATCH 18/48] Changed definition format --- pandora_server/extras/pandoraPlugintools/general.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 477d1e8fe5..d57e3febf2 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -193,7 +193,7 @@ def parse_csv_file( ######################################################################################### def parse_int( - var="" + var = None ) -> int: """ Parse given variable to integer. @@ -214,7 +214,7 @@ def parse_int( ######################################################################################### def parse_float( - var="" + var = None ) -> float: """ Parse given variable to float. @@ -235,7 +235,7 @@ def parse_float( ######################################################################################### def parse_str( - var="" + var = None ) -> str: """ Parse given variable to string. @@ -256,7 +256,7 @@ def parse_str( ######################################################################################### def parse_bool( - var="" + var = None ) -> bool: """ Parse given variable to bool. From 54dc1df12daf7082b807e2b7dcb7a2544d235bd9 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 11:42:20 +0200 Subject: [PATCH 19/48] Set some default values to None --- pandora_server/extras/pandoraPlugintools/agents.py | 2 +- pandora_server/extras/pandoraPlugintools/discovery.py | 4 ++-- pandora_server/extras/pandoraPlugintools/general.py | 2 +- pandora_server/extras/pandoraPlugintools/transfer.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 658c1a0bb4..322781c43c 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -38,7 +38,7 @@ AIX = sys.platform.startswith("aix") ######################################################################################### def set_global_variable( variable_name: str = "", - value + value = None ): """ Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 22dfb9d3f4..d2a4bad632 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -31,7 +31,7 @@ def set_error_level( ######################################################################################### def set_summary_value( key: str = "", - value = "" + value = None ): """ Sets a fixed value for a key in the 'SUMMARY' dictionary. @@ -49,7 +49,7 @@ def set_summary_value( ######################################################################################### def add_summary_value( key: str = "", - value = "" + value = None ): """ Adds a value to a key in the 'SUMMARY' dictionary. diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index d57e3febf2..aa3a7e65ff 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -30,7 +30,7 @@ def debug_dict( def set_dict_key_value( input_dict: dict = {}, input_key: str = "", - input_value + input_value = None ): """ Assign to a key in a dict a given value diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index ebe35daf0f..8395fb75cd 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -27,7 +27,7 @@ GLOBAL_VARIABLES = { ######################################################################################### def set_global_variable( variable_name: str = "", - value + value = None ): """ Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. From bde41cac3d8ba7a3a4122d06842d2bba4e24c537 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 11:52:24 +0200 Subject: [PATCH 20/48] Removed loop imports --- pandora_server/extras/pandoraPlugintools/agents.py | 1 - pandora_server/extras/pandoraPlugintools/transfer.py | 1 - 2 files changed, 2 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 322781c43c..0f95c615cc 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -5,7 +5,6 @@ import sys import os from .general import now,set_dict_key_value from .modules import print_module,print_log_module -from .transfer import write_xml #### # Define global variables dict, used in functions as default values. diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 8395fb75cd..bce60935c8 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -5,7 +5,6 @@ import subprocess import os import sys from .general import generate_md5,set_dict_key_value -from .agents import print_agent #### # Define global variables dict, used in functions as default values. From a21486495751ffbcfd1edadd023a3afdf89762d7 Mon Sep 17 00:00:00 2001 From: alejandro Date: Tue, 1 Aug 2023 10:40:11 +0200 Subject: [PATCH 21/48] edit readme --- pandora_server/extras/pandoraPlugintools/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/README.md b/pandora_server/extras/pandoraPlugintools/README.md index df7503d021..735fcc78fd 100644 --- a/pandora_server/extras/pandoraPlugintools/README.md +++ b/pandora_server/extras/pandoraPlugintools/README.md @@ -59,9 +59,8 @@ xml_file = ppt.write_xml(xml_content, agent["agent_name"]) ppt.transfer_xml( xml_file, transfer_mode="tentacle", - tentacle_address="192.168.1.20", + tentacle_ip="192.168.1.20", tentacle_port="41121", - temporal="/tmp" ) ``` From 538a25d2d5ade2628e564ae4be9d0c298dada15b Mon Sep 17 00:00:00 2001 From: alejandro Date: Wed, 2 Aug 2023 12:05:51 +0200 Subject: [PATCH 22/48] clean imports --- pandora_server/extras/pandoraPlugintools/agents.py | 3 --- pandora_server/extras/pandoraPlugintools/general.py | 1 - 2 files changed, 4 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 0f95c615cc..147f453192 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -1,6 +1,3 @@ -from datetime import datetime -from subprocess import * -import hashlib import sys import os from .general import now,set_dict_key_value diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index aa3a7e65ff..8c4354b908 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -1,5 +1,4 @@ import sys -import os import json from datetime import datetime import hashlib From f5df8eb24c48985aac8563f6d89362ac66d3897b Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 2 Aug 2023 13:13:43 +0200 Subject: [PATCH 23/48] Added Agent class functions --- .../extras/pandoraPlugintools/agents.py | 140 +++++++++++++- .../extras/pandoraPlugintools/discovery.py | 1 + .../extras/pandoraPlugintools/http.py | 1 + .../extras/pandoraPlugintools/modules.py | 177 +++++++++++++----- .../extras/pandoraPlugintools/threads.py | 1 + .../extras/pandoraPlugintools/transfer.py | 2 +- 6 files changed, 274 insertions(+), 48 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 0f95c615cc..610b3f6587 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -3,8 +3,8 @@ from subprocess import * import hashlib import sys import os -from .general import now,set_dict_key_value -from .modules import print_module,print_log_module +from .general import debug_dict,now,set_dict_key_value,generate_md5 +from .modules import init_module,init_log_module,print_module,print_log_module #### # Define global variables dict, used in functions as default values. @@ -60,7 +60,8 @@ class Agent: def __init__( self, config: dict = None, - modules_def: list = [] + modules_def: list = [], + log_modules_def: list = [] ): if config is None: @@ -68,6 +69,137 @@ class Agent: self.config = config self.modules_def = modules_def + self.log_modules_def = log_modules_def + self.added_modules = [] + + ''' + TODO: Add commnets + ''' + def update_config( + self, + config: dict = {} + ): + + for key, value in config.items(): + if key in self.config: + self.config[key] = value + + ''' + TODO: Add commnets + ''' + def get_config( + self + ) -> dict: + + return self.config + + ''' + TODO: Add commnets + ''' + def add_module( + self, + module: dict = {} + ): + + if "name" in module and type(module["name"]) == str and len(module["name"].strip()) > 0: + self.modules_def.append(init_module(module)) + self.added_modules.append(generate_md5(module["name"])) + + ''' + TODO: Add commnets + ''' + def del_module( + self, + module_name: str = "" + ): + + if len(module_name.strip()) > 0: + try: + module_id = self.added_modules.index(generate_md5(module_name)) + except: + module_id = None + + if module_id is not None: + self.added_modules.pop(module_id) + self.modules_def.pop(module_id) + + ''' + TODO: Add commnets + ''' + def update_module( + self, + module_name: str = "", + module: dict = {} + ): + + module_def = self.get_module(module_name) + + if module_def: + if "name" not in module: + module["name"] = module_name + + module_def.update(module) + + self.del_module(module_name) + self.add_module(module_def) + + ''' + TODO: Add commnets + ''' + def get_module( + self, + module_name: str = "" + ) -> dict: + + if len(module_name.strip()) > 0: + try: + module_id = self.added_modules.index(generate_md5(module_name)) + except: + module_id = None + + if module_id is not None: + return self.modules_def[module_id] + else: + return {} + + ''' + TODO: Add commnets + ''' + def get_modules_def( + self + ) -> dict: + + return self.modules_def + + ''' + TODO: Add commnets + ''' + def add_log_module( + self, + log_module: dict = {} + ): + + if "source" in module and type(module["source"]) == str and len(module["source"].strip()) > 0: + self.log_modules_def.append(init_log_module(log_module)) + + ''' + TODO: Add commnets + ''' + def get_log_modules_def( + self + ) -> dict: + + return self.log_modules_def + + ''' + TODO: Add commnets + ''' + def print_xml( + self, + print_flag: bool = False + ) -> str: + + return print_agent(self.get_config(), self.get_modules_def(), self.get_log_modules_def(), print_flag) #### # Init agent template @@ -93,7 +225,7 @@ def init_agent( "address" : "", "group" : GLOBAL_VARIABLES['agents_group_name'], "interval" : GLOBAL_VARIABLES['interval'], - "agent_mode" : "1", + "agent_mode" : "1" } for key, value in default_values.items(): diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index d2a4bad632..4954100353 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -1,5 +1,6 @@ import sys import json +from .general import debug_dict #### # Define some global variables diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index 913655ecb6..c7f8cb253f 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -2,6 +2,7 @@ from requests_ntlm import HttpNtlmAuth from requests.auth import HTTPBasicAuth from requests.auth import HTTPDigestAuth from requests.sessions import Session +from .general import debug_dict #### # Auth URL session diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 2e9c7449a6..830795afc9 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -1,3 +1,71 @@ +from .general import debug_dict + +#### +# Init module template +######################################################################################### +def init_module( + default_values: dict = {} + ) -> dict: + """ + Initializes a module template with default values. + + Returns: + dict: Dictionary representing the module template with default values. + """ + module = { + "name" : None, + "type" : "generic_data_string", + "value" : "0", + "desc" : "", + "unit" : "", + "interval" : "", + "tags" : "", + "module_group" : "", + "module_parent" : "", + "min_warning" : "", + "min_warning_forced" : "", + "max_warning" : "", + "max_warning_forced" : "", + "min_critical" : "", + "min_critical_forced" : "", + "max_critical" : "", + "max_critical_forced" : "", + "str_warning" : "", + "str_warning_forced" : "", + "str_critical" : "", + "str_critical_forced" : "", + "critical_inverse" : "", + "warning_inverse" : "", + "max" : "", + "min" : "", + "post_process" : "", + "disabled" : "", + "min_ff_event" : "", + "status" : "", + "timestamp" : "", + "custom_id" : "", + "critical_instructions" : "", + "warning_instructions" : "", + "unknown_instructions" : "", + "quiet" : "", + "module_ff_interval" : "", + "crontab" : "", + "min_ff_event_normal" : "", + "min_ff_event_warning" : "", + "min_ff_event_critical" : "", + "ff_type" : "", + "ff_timeout" : "", + "each_ff" : "", + "module_parent_unlink" : "", + "alert" : [] + } + + for key, value in default_values.items(): + if key in module: + module[key] = value + + return module + #### # Returns module in XML format. Accepts only {dict} ######################################################################################### @@ -36,91 +104,92 @@ def print_module( else: module_xml += "\t\n" - if "desc" in data: + if "desc" in data and len(str(data["desc"]).strip()) > 0: module_xml += "\t\n" - if "unit" in data: + if "unit" in data and len(str(data["unit"]).strip()) > 0: module_xml += "\t\n" - if "interval" in data: + if "interval" in data and len(str(data["interval"]).strip()) > 0: module_xml += "\t\n" - if "tags" in data: + if "tags" in data and len(str(data["tags"]).strip()) > 0: module_xml += "\t" + str(data["tags"]) + "\n" - if "module_group" in data: + if "module_group" in data and len(str(data["module_group"]).strip()) > 0: module_xml += "\t" + str(data["module_group"]) + "\n" - if "module_parent" in data: + if "module_parent" in data and len(str(data["module_parent"]).strip()) > 0: module_xml += "\t" + str(data["module_parent"]) + "\n" - if "min_warning" in data: + if "min_warning" in data and len(str(data["min_warning"]).strip()) > 0: module_xml += "\t\n" - if "min_warning_forced" in data: + if "min_warning_forced" in data and len(str(data["min_warning_forced"]).strip()) > 0: module_xml += "\t\n" - if "max_warning" in data: + if "max_warning" in data and len(str(data["max_warning"]).strip()) > 0: module_xml += "\t\n" - if "max_warning_forced" in data: + if "max_warning_forced" in data and len(str(data["max_warning_forced"]).strip()) > 0: module_xml += "\t\n" - if "min_critical" in data: + if "min_critical" in data and len(str(data["min_critical"]).strip()) > 0: module_xml += "\t\n" - if "min_critical_forced" in data: + if "min_critical_forced" in data and len(str(data["min_critical_forced"]).strip()) > 0: module_xml += "\t\n" - if "max_critical" in data: + if "max_critical" in data and len(str(data["max_critical"]).strip()) > 0: module_xml += "\t\n" - if "max_critical_forced" in data: + if "max_critical_forced" in data and len(str(data["max_critical_forced"]).strip()) > 0: module_xml += "\t\n" - if "str_warning" in data: + if "str_warning" in data and len(str(data["str_warning"]).strip()) > 0: module_xml += "\t\n" - if "str_warning_forced" in data: + if "str_warning_forced" in data and len(str(data["str_warning_forced"]).strip()) > 0: module_xml += "\t\n" - if "str_critical" in data: + if "str_critical" in data and len(str(data["str_critical"]).strip()) > 0: module_xml += "\t\n" - if "str_critical_forced" in data: + if "str_critical_forced" in data and len(str(data["str_critical_forced"]).strip()) > 0: module_xml += "\t\n" - if "critical_inverse" in data: + if "critical_inverse" in data and len(str(data["critical_inverse"]).strip()) > 0: module_xml += "\t\n" - if "warning_inverse" in data: + if "warning_inverse" in data and len(str(data["warning_inverse"]).strip()) > 0: module_xml += "\t\n" - if "max" in data: + if "max" in data and len(str(data["max"]).strip()) > 0: module_xml += "\t\n" - if "min" in data: + if "min" in data and len(str(data["min"]).strip()) > 0: module_xml += "\t\n" - if "post_process" in data: + if "post_process" in data and len(str(data["post_process"]).strip()) > 0: module_xml += "\t\n" - if "disabled" in data: + if "disabled" in data and len(str(data["disabled"]).strip()) > 0: module_xml += "\t\n" - if "min_ff_event" in data: + if "min_ff_event" in data and len(str(data["min_ff_event"]).strip()) > 0: module_xml += "\t\n" - if "status" in data: + if "status" in data and len(str(data["status"]).strip()) > 0: module_xml += "\t\n" - if "timestamp" in data: + if "timestamp" in data and len(str(data["timestamp"]).strip()) > 0: module_xml += "\t\n" - if "custom_id" in data: + if "custom_id" in data and len(str(data["custom_id"]).strip()) > 0: module_xml += "\t\n" - if "critical_instructions" in data: + if "critical_instructions" in data and len(str(data["critical_instructions"]).strip()) > 0: module_xml += "\t\n" - if "warning_instructions" in data: + if "warning_instructions" in data and len(str(data["warning_instructions"]).strip()) > 0: module_xml += "\t\n" - if "unknown_instructions" in data: + if "unknown_instructions" in data and len(str(data["unknown_instructions"]).strip()) > 0: module_xml += "\t\n" - if "quiet" in data: + if "quiet" in data and len(str(data["quiet"]).strip()) > 0: module_xml += "\t\n" - if "module_ff_interval" in data: + if "module_ff_interval" in data and len(str(data["module_ff_interval"]).strip()) > 0: module_xml += "\t\n" - if "crontab" in data: + if "crontab" in data and len(str(data["crontab"]).strip()) > 0: module_xml += "\t\n" - if "min_ff_event_normal" in data: + if "min_ff_event_normal" in data and len(str(data["min_ff_event_normal"]).strip()) > 0: module_xml += "\t\n" - if "min_ff_event_warning" in data: + if "min_ff_event_warning" in data and len(str(data["min_ff_event_warning"]).strip()) > 0: module_xml += "\t\n" - if "min_ff_event_critical" in data: + if "min_ff_event_critical" in data and len(str(data["min_ff_event_critical"]).strip()) > 0: module_xml += "\t\n" - if "ff_type" in data: + if "ff_type" in data and len(str(data["ff_type"]).strip()) > 0: module_xml += "\t\n" - if "ff_timeout" in data: + if "ff_timeout" in data and len(str(data["ff_timeout"]).strip()) > 0: module_xml += "\t\n" - if "each_ff" in data: + if "each_ff" in data and len(str(data["each_ff"]).strip()) > 0: module_xml += "\t\n" - if "module_parent_unlink" in data: - module_xml += "\t\n" + if "module_parent_unlink" in data and len(str(data["module_parent_unlink"]).strip()) > 0: + module_xml += "\t\n" if "alert" in data: for alert in data["alert"]: - module_xml += "\t\n" + if len(str(alert).strip()) > 0: + module_xml += "\t\n" module_xml += "\n" if print_flag: @@ -128,6 +197,28 @@ def print_module( return module_xml +#### +# Init log module template +######################################################################################### +def init_log_module( + default_values: dict = {} + ) -> dict: + """ + Initializes a log module template with default values. + + Returns: + dict: Dictionary representing the log module template with default values. + """ + module = { + "source" : None, + "value" : "" + } + + for key, value in default_values.items(): + if key in module: + module[key] = value + + return module #### # Returns log module in XML format. Accepts only {dict} diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 8e3a5dfa09..0a77a3bd63 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -2,6 +2,7 @@ import sys from queue import Queue from threading import Thread from multiprocessing import Pool, Manager +from .general import debug_dict #### # Define multi-processing internal global variables. diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index bce60935c8..a32d95aad8 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -4,7 +4,7 @@ import shutil import subprocess import os import sys -from .general import generate_md5,set_dict_key_value +from .general import debug_dict,generate_md5,set_dict_key_value #### # Define global variables dict, used in functions as default values. From 40421fadbb1088d8a85b24626b9145a531d8c801 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Fri, 4 Aug 2023 14:51:39 +0200 Subject: [PATCH 24/48] Added safe_input and safe_output --- .../extras/pandoraPlugintools/general.py | 319 ++++++++++++++++++ 1 file changed, 319 insertions(+) diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 8c4354b908..ce94ba7976 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -3,6 +3,325 @@ import json from datetime import datetime import hashlib +#### +# Define some global variables +######################################################################################### + +# Entity to character mapping. Contains a few tweaks to make it backward compatible with the previous safe_input implementation. +_ENT2CHR = { + '#x00': chr(0), + '#x01': chr(1), + '#x02': chr(2), + '#x03': chr(3), + '#x04': chr(4), + '#x05': chr(5), + '#x06': chr(6), + '#x07': chr(7), + '#x08': chr(8), + '#x09': chr(9), + '#x0a': chr(10), + '#x0b': chr(11), + '#x0c': chr(12), + '#x0d': chr(13), + '#x0e': chr(14), + '#x0f': chr(15), + '#x10': chr(16), + '#x11': chr(17), + '#x12': chr(18), + '#x13': chr(19), + '#x14': chr(20), + '#x15': chr(21), + '#x16': chr(22), + '#x17': chr(23), + '#x18': chr(24), + '#x19': chr(25), + '#x1a': chr(26), + '#x1b': chr(27), + '#x1c': chr(28), + '#x1d': chr(29), + '#x1e': chr(30), + '#x1f': chr(31), + '#x20': chr(32), + 'quot': chr(34), + 'amp': chr(38), + '#039': chr(39), + '#40': chr(40), + '#41': chr(41), + 'lt': chr(60), + 'gt': chr(62), + '#92': chr(92), + '#x80': chr(128), + '#x81': chr(129), + '#x82': chr(130), + '#x83': chr(131), + '#x84': chr(132), + '#x85': chr(133), + '#x86': chr(134), + '#x87': chr(135), + '#x88': chr(136), + '#x89': chr(137), + '#x8a': chr(138), + '#x8b': chr(139), + '#x8c': chr(140), + '#x8d': chr(141), + '#x8e': chr(142), + '#x8f': chr(143), + '#x90': chr(144), + '#x91': chr(145), + '#x92': chr(146), + '#x93': chr(147), + '#x94': chr(148), + '#x95': chr(149), + '#x96': chr(150), + '#x97': chr(151), + '#x98': chr(152), + '#x99': chr(153), + '#x9a': chr(154), + '#x9b': chr(155), + '#x9c': chr(156), + '#x9d': chr(157), + '#x9e': chr(158), + '#x9f': chr(159), + '#xa0': chr(160), + '#xa1': chr(161), + '#xa2': chr(162), + '#xa3': chr(163), + '#xa4': chr(164), + '#xa5': chr(165), + '#xa6': chr(166), + '#xa7': chr(167), + '#xa8': chr(168), + '#xa9': chr(169), + '#xaa': chr(170), + '#xab': chr(171), + '#xac': chr(172), + '#xad': chr(173), + '#xae': chr(174), + '#xaf': chr(175), + '#xb0': chr(176), + '#xb1': chr(177), + '#xb2': chr(178), + '#xb3': chr(179), + '#xb4': chr(180), + '#xb5': chr(181), + '#xb6': chr(182), + '#xb7': chr(183), + '#xb8': chr(184), + '#xb9': chr(185), + '#xba': chr(186), + '#xbb': chr(187), + '#xbc': chr(188), + '#xbd': chr(189), + '#xbe': chr(190), + 'Aacute': chr(193), + 'Auml': chr(196), + 'Eacute': chr(201), + 'Euml': chr(203), + 'Iacute': chr(205), + 'Iuml': chr(207), + 'Ntilde': chr(209), + 'Oacute': chr(211), + 'Ouml': chr(214), + 'Uacute': chr(218), + 'Uuml': chr(220), + 'aacute': chr(225), + 'auml': chr(228), + 'eacute': chr(233), + 'euml': chr(235), + 'iacute': chr(237), + 'iuml': chr(239), + 'ntilde': chr(241), + 'oacute': chr(243), + 'ouml': chr(246), + 'uacute': chr(250), + 'uuml': chr(252), + 'OElig': chr(338), + 'oelig': chr(339), + 'Scaron': chr(352), + 'scaron': chr(353), + 'Yuml': chr(376), + 'fnof': chr(402), + 'circ': chr(710), + 'tilde': chr(732), + 'Alpha': chr(913), + 'Beta': chr(914), + 'Gamma': chr(915), + 'Delta': chr(916), + 'Epsilon': chr(917), + 'Zeta': chr(918), + 'Eta': chr(919), + 'Theta': chr(920), + 'Iota': chr(921), + 'Kappa': chr(922), + 'Lambda': chr(923), + 'Mu': chr(924), + 'Nu': chr(925), + 'Xi': chr(926), + 'Omicron': chr(927), + 'Pi': chr(928), + 'Rho': chr(929), + 'Sigma': chr(931), + 'Tau': chr(932), + 'Upsilon': chr(933), + 'Phi': chr(934), + 'Chi': chr(935), + 'Psi': chr(936), + 'Omega': chr(937), + 'alpha': chr(945), + 'beta': chr(946), + 'gamma': chr(947), + 'delta': chr(948), + 'epsilon': chr(949), + 'zeta': chr(950), + 'eta': chr(951), + 'theta': chr(952), + 'iota': chr(953), + 'kappa': chr(954), + 'lambda': chr(955), + 'mu': chr(956), + 'nu': chr(957), + 'xi': chr(958), + 'omicron': chr(959), + 'pi': chr(960), + 'rho': chr(961), + 'sigmaf': chr(962), + 'sigma': chr(963), + 'tau': chr(964), + 'upsilon': chr(965), + 'phi': chr(966), + 'chi': chr(967), + 'psi': chr(968), + 'omega': chr(969), + 'thetasym': chr(977), + 'upsih': chr(978), + 'piv': chr(982), + 'ensp': chr(8194), + 'emsp': chr(8195), + 'thinsp': chr(8201), + 'zwnj': chr(8204), + 'zwj': chr(8205), + 'lrm': chr(8206), + 'rlm': chr(8207), + 'ndash': chr(8211), + 'mdash': chr(8212), + 'lsquo': chr(8216), + 'rsquo': chr(8217), + 'sbquo': chr(8218), + 'ldquo': chr(8220), + 'rdquo': chr(8221), + 'bdquo': chr(8222), + 'dagger': chr(8224), + 'Dagger': chr(8225), + 'bull': chr(8226), + 'hellip': chr(8230), + 'permil': chr(8240), + 'prime': chr(8242), + 'Prime': chr(8243), + 'lsaquo': chr(8249), + 'rsaquo': chr(8250), + 'oline': chr(8254), + 'frasl': chr(8260), + 'euro': chr(8364), + 'image': chr(8465), + 'weierp': chr(8472), + 'real': chr(8476), + 'trade': chr(8482), + 'alefsym': chr(8501), + 'larr': chr(8592), + 'uarr': chr(8593), + 'rarr': chr(8594), + 'darr': chr(8595), + 'harr': chr(8596), + 'crarr': chr(8629), + 'lArr': chr(8656), + 'uArr': chr(8657), + 'rArr': chr(8658), + 'dArr': chr(8659), + 'hArr': chr(8660), + 'forall': chr(8704), + 'part': chr(8706), + 'exist': chr(8707), + 'empty': chr(8709), + 'nabla': chr(8711), + 'isin': chr(8712), + 'notin': chr(8713), + 'ni': chr(8715), + 'prod': chr(8719), + 'sum': chr(8721), + 'minus': chr(8722), + 'lowast': chr(8727), + 'radic': chr(8730), + 'prop': chr(8733), + 'infin': chr(8734), + 'ang': chr(8736), + 'and': chr(8743), + 'or': chr(8744), + 'cap': chr(8745), + 'cup': chr(8746), + 'int': chr(8747), + 'there4': chr(8756), + 'sim': chr(8764), + 'cong': chr(8773), + 'asymp': chr(8776), + 'ne': chr(8800), + 'equiv': chr(8801), + 'le': chr(8804), + 'ge': chr(8805), + 'sub': chr(8834), + 'sup': chr(8835), + 'nsub': chr(8836), + 'sube': chr(8838), + 'supe': chr(8839), + 'oplus': chr(8853), + 'otimes': chr(8855), + 'perp': chr(8869), + 'sdot': chr(8901), + 'lceil': chr(8968), + 'rceil': chr(8969), + 'lfloor': chr(8970), + 'rfloor': chr(8971), + 'lang': chr(9001), + 'rang': chr(9002), + 'loz': chr(9674), + 'spades': chr(9824), + 'clubs': chr(9827), + 'hearts': chr(9829), + 'diams': chr(9830), +} + +# Construct the character to entity mapping. +_CHR2ENT = {v: "&" + k + ";" for k, v in _ENT2CHR.items()} + +#### +# Convert the input_string encoded in html entity to clear char string. +######################################################################################### +def safe_input( + input_string: str = "" + ) -> str: + ''' + Convert the input_string encoded in html entity to clear char string. + ''' + if not input_string: + return "" + + return "".join(_CHR2ENT.get(char, char) for char in input_string) + +#### +# Convert the html entities to input_string encoded to rebuild char string. +######################################################################################### +def safe_output( + input_string: str = "" + ) -> str: + ''' + Convert the html entities to input_string encoded to rebuild char string. + ''' + if not input_string: + return "" + + for char, entity in _CHR2ENT.items(): + input_string = input_string.replace(entity, char) + + return input_string #### # Prints dictionary in formatted json string. From 6d62c38ee10c42f44a9ddd6c79b8a2227bc53b04 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 9 Aug 2023 13:46:09 +0200 Subject: [PATCH 25/48] New function and standarized methods --- .../extras/pandoraPlugintools/__init__.py | 4 +- .../extras/pandoraPlugintools/agents.py | 82 +++++++++-------- .../extras/pandoraPlugintools/discovery.py | 4 +- .../extras/pandoraPlugintools/encryption.py | 78 ++++++++++++++++ .../extras/pandoraPlugintools/general.py | 43 +++------ .../extras/pandoraPlugintools/http.py | 12 ++- .../extras/pandoraPlugintools/modules.py | 10 +- .../extras/pandoraPlugintools/output.py | 91 +++++++++++++++++++ .../extras/pandoraPlugintools/threads.py | 9 +- .../extras/pandoraPlugintools/transfer.py | 26 ++++-- 10 files changed, 268 insertions(+), 91 deletions(-) create mode 100644 pandora_server/extras/pandoraPlugintools/encryption.py create mode 100644 pandora_server/extras/pandoraPlugintools/output.py diff --git a/pandora_server/extras/pandoraPlugintools/__init__.py b/pandora_server/extras/pandoraPlugintools/__init__.py index e71d801c6a..f9360683ba 100644 --- a/pandora_server/extras/pandoraPlugintools/__init__.py +++ b/pandora_server/extras/pandoraPlugintools/__init__.py @@ -1,7 +1,9 @@ from .general import * +from .output import * +from .encryption import * from .threads import * from .agents import * from .modules import * from .transfer import * from .discovery import * -from .http import * +from .http import * \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index a50db3754a..e97fde4628 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -1,7 +1,5 @@ import sys import os -from .general import debug_dict,now,set_dict_key_value,generate_md5 -from .modules import init_module,init_log_module,print_module,print_log_module #### # Define global variables dict, used in functions as default values. @@ -43,6 +41,8 @@ def set_global_variable( variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ + from .general import set_dict_key_value + set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) #### @@ -69,46 +69,47 @@ class Agent: self.log_modules_def = log_modules_def self.added_modules = [] - ''' - TODO: Add commnets - ''' def update_config( self, config: dict = {} ): - + ''' + TODO: Add commnets + ''' for key, value in config.items(): if key in self.config: self.config[key] = value - ''' - TODO: Add commnets - ''' def get_config( self ) -> dict: - + ''' + TODO: Add commnets + ''' return self.config - ''' - TODO: Add commnets - ''' def add_module( self, module: dict = {} ): + ''' + TODO: Add commnets + ''' + from .general import generate_md5 + from .modules import init_module if "name" in module and type(module["name"]) == str and len(module["name"].strip()) > 0: self.modules_def.append(init_module(module)) self.added_modules.append(generate_md5(module["name"])) - ''' - TODO: Add commnets - ''' def del_module( self, module_name: str = "" ): + ''' + TODO: Add commnets + ''' + from .general import generate_md5 if len(module_name.strip()) > 0: try: @@ -120,15 +121,14 @@ class Agent: self.added_modules.pop(module_id) self.modules_def.pop(module_id) - ''' - TODO: Add commnets - ''' def update_module( self, module_name: str = "", module: dict = {} ): - + ''' + TODO: Add commnets + ''' module_def = self.get_module(module_name) if module_def: @@ -140,13 +140,14 @@ class Agent: self.del_module(module_name) self.add_module(module_def) - ''' - TODO: Add commnets - ''' def get_module( self, module_name: str = "" ) -> dict: + ''' + TODO: Add commnets + ''' + from .general import generate_md5 if len(module_name.strip()) > 0: try: @@ -159,43 +160,41 @@ class Agent: else: return {} - ''' - TODO: Add commnets - ''' def get_modules_def( self ) -> dict: - + ''' + TODO: Add commnets + ''' return self.modules_def - ''' - TODO: Add commnets - ''' def add_log_module( self, log_module: dict = {} ): + ''' + TODO: Add commnets + ''' + from .modules import init_log_module if "source" in module and type(module["source"]) == str and len(module["source"].strip()) > 0: self.log_modules_def.append(init_log_module(log_module)) - ''' - TODO: Add commnets - ''' def get_log_modules_def( self ) -> dict: - + ''' + TODO: Add commnets + ''' return self.log_modules_def - ''' - TODO: Add commnets - ''' def print_xml( self, print_flag: bool = False ) -> str: - + ''' + TODO: Add commnets + ''' return print_agent(self.get_config(), self.get_modules_def(), self.get_log_modules_def(), print_flag) #### @@ -210,6 +209,8 @@ def init_agent( Returns: dict: Dictionary representing the agent template with default values. """ + from .general import now + agent = { "agent_name" : "", "agent_alias" : "", @@ -245,6 +246,9 @@ def print_agent( - Use print_flag to show modules' XML in STDOUT. - Returns xml (str). """ + from .output import print_stdout + from .modules import print_module,print_log_module + xml = "" data_file = None @@ -267,6 +271,6 @@ def print_agent( xml += "" if print_flag: - print(xml) + print_stdout(xml) return xml diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 4954100353..f83251c2d0 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -1,6 +1,5 @@ import sys import json -from .general import debug_dict #### # Define some global variables @@ -137,6 +136,7 @@ def print_output(): to create the JSON output. It then prints the JSON string and exits the script with the 'ERROR_LEVEL' as the exit code. """ + from .output import print_stdout global ERROR_LEVEL global SUMMARY @@ -155,5 +155,5 @@ def print_output(): json_string = json.dumps(OUTPUT) - print(json_string) + print_stdout(json_string) sys.exit(ERROR_LEVEL) diff --git a/pandora_server/extras/pandoraPlugintools/encryption.py b/pandora_server/extras/pandoraPlugintools/encryption.py new file mode 100644 index 0000000000..af43b2aca3 --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/encryption.py @@ -0,0 +1,78 @@ +try: + from Crypto.Cipher import AES + from Crypto.Util.Padding import pad, unpad +except ImportError as e: + import sys + from .output import print_stderr + print_stderr("ModuleNotFoundError: No module named 'pycryptodome'") + sys.exit(1) + +import hashlib +import base64 +import hmac +from binascii import unhexlify + +#### +# Define encription internal global variables. +######################################################################################### + +_PASSWORD = "default_salt" + +#### +# Internal use only: Get AES cipher +######################################################################################### +def _get_cipher( + password: str = _PASSWORD + ) -> AES: + ''' + Internal use only: Get AES cipher + ''' + key = b'' + msg = password.encode('utf-8') + hash_obj = hmac.new(key, msg, hashlib.sha256) + hash_result = hash_obj.digest() + hash_base64 = base64.b64encode(hash_result)[:16].decode() + + iv = b'0000000000000000' + + return AES.new(hash_base64.encode(), AES.MODE_CBC, iv) + +#### +# Return encrypted string +######################################################################################### +def encrypt( + str_to_encrypt: str = "", + password: str = _PASSWORD + ) -> str: + ''' + Return encrypted string + ''' + cipher = _get_cipher(password) + + try: + msg_padded = pad(str_to_encrypt.encode(), AES.block_size, style='pkcs7') + cipher_text = cipher.encrypt(msg_padded) + b64str = base64.b64encode(cipher_text).decode() + except: + b64str = '' + + return b64str + +#### +# Return decrypted string +######################################################################################### +def decrypt( + str_to_decrypt: str = "", + password: str = _PASSWORD + ) -> str: + ''' + Return decrypted string + ''' + cipher = _get_cipher(password) + + try: + decrypted_str = unpad(cipher.decrypt(base64.b64decode(str_to_decrypt)), AES.block_size, style='pkcs7').decode().strip() + except: + decrypted_str = '' + + return decrypted_str \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index ce94ba7976..8a097f462a 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -1,5 +1,4 @@ import sys -import json from datetime import datetime import hashlib @@ -323,24 +322,6 @@ def safe_output( return input_string -#### -# Prints dictionary in formatted json string. -######################################################################################### - -def debug_dict( - jsontxt = "" - ): - """ - Prints any list, dict, string, float or integer as a json - """ - try: - debug_json = json.dumps(jsontxt, indent=4) - print (debug_json) - except json.JSONDecodeError as e: - print(f"debug_dict: Failed to dump. Error: {e}") - except Exception as e: - print(f"debug_dict: Unexpected error: {e}") - #### # Assign to a key in a dict a given value. ######################################################################################### @@ -386,13 +367,15 @@ def generate_md5( ######################################################################################### def now( - print_flag: int = 0, - utimestamp: int = 0 + print_flag: bool = False, + utimestamp: bool = False ) -> str: """ Returns time in yyyy/mm/dd HH:MM:SS format by default. Use 1 as an argument to get epoch time (utimestamp) """ + from .output import print_stdout + today = datetime.today() if utimestamp: @@ -401,7 +384,7 @@ def now( time = today.strftime('%Y/%m/%d %H:%M:%S') if print_flag: - print(time) + print_stdout(time) return time @@ -443,6 +426,8 @@ def parse_configuration( Returns: - dict: containing all keys and values from file. """ + from .output import print_stderr + config = {} try: @@ -456,7 +441,7 @@ def parse_configuration( config[option.strip()] = value.strip() except Exception as e: - print (f"{type(e).__name__}: {e}") + print_stderr(f"{type(e).__name__}: {e}") for option, value in default_values.items(): if option.strip() not in config: @@ -472,7 +457,7 @@ def parse_csv_file( file: str = "", separator: str = ';', count_parameters: int = 0, - debug: bool = False + print_errors: bool = False ) -> list: """ Parse csv configuration. Reads configuration file and stores its data in a list. @@ -481,11 +466,13 @@ def parse_csv_file( - file (str): configuration csv file path. \n - separator (str, optional): Separator for option and value. Defaults to ";". - coun_parameters (int): min number of parameters each line shold have. Default None - - debug (bool): print errors on lines + - print_errors (bool): print errors on lines Returns: - List: containing a list for of values for each csv line. """ + from .output import print_stderr + csv_arr = [] try: @@ -498,11 +485,11 @@ def parse_csv_file( value = line.strip().split(separator) if len(value) >= count_parameters: csv_arr.append(value) - elif debug==True: - print(f'Csv line: {line} does not match minimun parameter defined: {count_parameters}',file=sys.stderr) + elif print_errors==True: + print_stderr(f'Csv line: {line} does not match minimun parameter defined: {count_parameters}') except Exception as e: - print (f"{type(e).__name__}: {e}") + print_stderr(f"{type(e).__name__}: {e}") return csv_arr diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index c7f8cb253f..a4d0e38efe 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -2,7 +2,6 @@ from requests_ntlm import HttpNtlmAuth from requests.auth import HTTPBasicAuth from requests.auth import HTTPDigestAuth from requests.sessions import Session -from .general import debug_dict #### # Auth URL session @@ -40,7 +39,8 @@ def call_url( authtype: str = "basic", user: str = "", passw: str = "", - timeout: int = 1 + timeout: int = 1, + print_errors: bool = False ) -> str: """ Call URL. Uses request module to get url contents. @@ -55,6 +55,8 @@ def call_url( Returns: - str: call output """ + from .output import print_stderr + # using with so we make sure the session is closed even when exceptions are encountered with Session() as session: if authtype != None: @@ -65,8 +67,10 @@ def call_url( try: output = session.get(url, timeout=timeout, verify=False) except ValueError: - output = "Error: URL format not valid (example http://myserver/page.php)" + if print_errors: + print_stderr("Error: URL format not valid (example http://myserver/page.php)") except Exception as e: - output = f"{type(e).__name__}:\t{str(e)}" + if print_errors: + print_stderr(f"{type(e).__name__}:\t{str(e)}") return output diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 830795afc9..8a5be45812 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -1,5 +1,3 @@ -from .general import debug_dict - #### # Init module template ######################################################################################### @@ -79,6 +77,8 @@ def print_module( - Module "value" field accepts str type or [list] for datalists. - Use print_flag to show modules' XML in STDOUT. """ + from .output import print_stdout + module_xml = "" if module is not None: @@ -193,7 +193,7 @@ def print_module( module_xml += "\n" if print_flag: - print(module_xml) + print_stdout(module_xml) return module_xml @@ -234,6 +234,8 @@ def print_log_module( - Module "value" field accepts str type. - Use not_print_flag to avoid printing the XML (only populates variables). """ + from .output import print_stdout + module_xml = "" if module is not None: @@ -246,6 +248,6 @@ def print_log_module( module_xml += "\n" if print_flag: - print(module_xml) + print_stdout(module_xml) return module_xml diff --git a/pandora_server/extras/pandoraPlugintools/output.py b/pandora_server/extras/pandoraPlugintools/output.py new file mode 100644 index 0000000000..d4c9bd5edc --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/output.py @@ -0,0 +1,91 @@ +import sys +import os +import json + +#### +# Prints message in stdout +######################################################################################### + +def print_stdout( + message: str = "" + ): + """ + Prints message in stdout + """ + print(message) + +#### +# Prints message in stderr +######################################################################################### + +def print_stderr( + message: str = "" + ): + """ + Prints message in stderr + """ + print(message, file=sys.stderr) + +#### +# Prints dictionary in formatted json string. +######################################################################################### + +def print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + try: + debug_json = json.dumps(var, indent=4) + print_stdout(debug_json) + except json.JSONDecodeError as e: + if print_errors: + print_stderr(f"debug_dict: Failed to dump. Error: {e}") + except Exception as e: + if print_errors: + print_stderr(f"debug_dict: Unexpected error: {e}") + +#### +# Add new line to log file +######################################################################################### +def logger( + log_file: str = "", + message: str = "", + log_level: str = "", + add_date: bool = True, + print_errors: bool = False + ) -> bool: + ''' + Add new line to log file + ''' + from .general import now + + try: + if not os.path.exists(log_file): + with open(log_file, 'w') as file: + pass # Creates an empty file + elif not os.access(log_file, os.W_OK): + if print_errors: + print_stderr(f"Log file '{log_file}' is not writable.") + return False + + with open(log_file, 'a') as file: + final_message = "" + + if add_date: + final_message += now() + " " + if log_level != "": + final_message += "[" + log_level + "] " + + final_message += message + "\n" + + file.write(final_message) + + return True + + except Exception as e: + if print_errors: + print_stderr(f"An error occurred while appending to the log: {e}") + return False \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 0a77a3bd63..0dcaf7d72a 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -2,7 +2,6 @@ import sys from queue import Queue from threading import Thread from multiprocessing import Pool, Manager -from .general import debug_dict #### # Define multi-processing internal global variables. @@ -42,6 +41,7 @@ def run_threads( """ Run a given function for given items list in a given number of threads """ + from .output import print_stderr # Assign threads threads = max_threads @@ -87,7 +87,7 @@ def run_threads( if print_errors: for error in errors: - print(error,file=sys.stderr) + print_stderr(str(error)) if len(errors) > 0: return False @@ -96,7 +96,7 @@ def run_threads( except Exception as e: if print_errors: - print("Error while running threads: "+str(e)+"\n",file=sys.stderr) + print_stderr("Error while running threads: "+str(e)) return False #### @@ -170,6 +170,7 @@ def run_processes( """ Run a given function for given items list in a given number of processes """ + from .output import print_stderr # Assign processes processes = max_processes @@ -187,7 +188,7 @@ def run_processes( result = True except Exception as error: if print_errors: - print(error,file=sys.stderr) + print_stderr(str(error)) result = False return result \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index a32d95aad8..9e9a121da4 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -4,7 +4,6 @@ import shutil import subprocess import os import sys -from .general import debug_dict,generate_md5,set_dict_key_value #### # Define global variables dict, used in functions as default values. @@ -35,6 +34,8 @@ def set_global_variable( variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. """ + from .general import set_dict_key_value + set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) #### @@ -58,6 +59,7 @@ def tentacle_xml( Returns True for OK and False for errors. """ + from .output import print_stderr if data_file is not None : @@ -70,7 +72,7 @@ def tentacle_xml( if tentacle_ops['address'] is None : if print_errors: - sys.stderr.write("Tentacle error: No address defined") + print_stderr("Tentacle error: No address defined") return False try : @@ -79,12 +81,12 @@ def tentacle_xml( data.close() except Exception as e : if print_errors: - sys.stderr.write(f"Tentacle error: {type(e).__name__} {e}") + print_stderr(f"Tentacle error: {type(e).__name__} {e}") return False tentacle_cmd = f"{tentacle_path} -v -a {tentacle_ops['address']} -p {tentacle_ops['port']} {tentacle_ops['extra_opts']} {data_file.strip()}" - tentacle_exe=Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) rc=tentacle_exe.wait() if debug == 0 : @@ -94,12 +96,12 @@ def tentacle_xml( if print_errors: stderr = tentacle_exe.stderr.read().decode() msg="Tentacle error:" + str(stderr) - print(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg , file=sys.stderr) + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) return False else: if print_errors: - sys.stderr.write("Tentacle error: file path is required.") + print_stderr("Tentacle error: file path is required.") return False #### @@ -141,7 +143,8 @@ def transfer_xml( def write_xml( xml: str = "", agent_name: str = "", - data_dir: str = GLOBAL_VARIABLES['temporal'] + data_dir: str = GLOBAL_VARIABLES['temporal'], + print_errors: bool = False ) -> str: """ Creates a agent .data file in the specified data_dir folder @@ -150,6 +153,9 @@ def write_xml( - agent_name (str): agent name for the xml and file name. - data_dir (str): folder in which the file will be created. """ + from .general import generate_md5 + from .output import print_stderr + Utime = datetime.now().strftime('%s') agent_name_md5 = generate_md5(agent_name) data_file = "%s/%s.%s.data" %(str(data_dir),agent_name_md5,str(Utime)) @@ -158,8 +164,10 @@ def write_xml( with open(data_file, 'x') as data: data.write(xml) except OSError as o: - print(f"ERROR - Could not write file: {o}, please check directory permissions", file=sys.stderr) + if print_errors: + print_stderr(f"ERROR - Could not write file: {o}, please check directory permissions") except Exception as e: - print(f"{type(e).__name__}: {e}", file=sys.stderr) + if print_errors: + print_stderr(f"{type(e).__name__}: {e}") return data_file From 0fed9f8749fa92904316a3e7293267971927869b Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Thu, 10 Aug 2023 14:07:57 +0200 Subject: [PATCH 26/48] Changed some functions names and added _print_debug for all modules --- .../extras/pandoraPlugintools/agents.py | 14 +++++++++ .../extras/pandoraPlugintools/discovery.py | 30 ++++++++++++++----- .../extras/pandoraPlugintools/encryption.py | 14 +++++++++ .../extras/pandoraPlugintools/general.py | 18 +++++++++-- .../extras/pandoraPlugintools/http.py | 14 +++++++++ .../extras/pandoraPlugintools/modules.py | 14 +++++++++ .../extras/pandoraPlugintools/output.py | 13 ++++++++ .../extras/pandoraPlugintools/threads.py | 14 +++++++++ .../extras/pandoraPlugintools/transfer.py | 14 +++++++++ 9 files changed, 135 insertions(+), 10 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index e97fde4628..85cfdd5ed9 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -27,6 +27,20 @@ BSD = FREEBSD or OPENBSD or NETBSD SUNOS = sys.platform.startswith(("sunos", "solaris")) AIX = sys.platform.startswith("aix") +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Set a global variable with the specified name and assigns a value to it. ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index f83251c2d0..60473ed13e 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -10,10 +10,24 @@ SUMMARY = {} INFO = "" MONITORING_DATA = [] +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Set error level to value ######################################################################################### -def set_error_level( +def set_disco_error_level( value: int = 0 ): """ @@ -29,7 +43,7 @@ def set_error_level( #### # Set fixed value to summary key ######################################################################################### -def set_summary_value( +def set_disco_summary_value( key: str = "", value = None ): @@ -47,7 +61,7 @@ def set_summary_value( #### # Add value to summary key ######################################################################################### -def add_summary_value( +def add_disco_summary_value( key: str = "", value = None ): @@ -70,7 +84,7 @@ def add_summary_value( #### # Set fixed value to info ######################################################################################### -def set_info_value( +def set_disco_info_value( value: str = "" ): """ @@ -86,7 +100,7 @@ def set_info_value( #### # Add data to info ######################################################################################### -def add_info_value( +def add_disco_info_value( value: str = "" ): """ @@ -102,7 +116,7 @@ def add_info_value( #### # Set fixed value to monitoring data ######################################################################################### -def set_monitoring_data( +def set_disco_monitoring_data( data: list = [] ): """ @@ -115,7 +129,7 @@ def set_monitoring_data( #### # Add value to monitoring data ######################################################################################### -def add_monitoring_data( +def add_disco_monitoring_data( data: dict = {} ): """ @@ -128,7 +142,7 @@ def add_monitoring_data( #### # Print JSON output and exit script ######################################################################################### -def print_output(): +def disco_output(): """ Prints the JSON output and exits the script. diff --git a/pandora_server/extras/pandoraPlugintools/encryption.py b/pandora_server/extras/pandoraPlugintools/encryption.py index af43b2aca3..4b6408c120 100644 --- a/pandora_server/extras/pandoraPlugintools/encryption.py +++ b/pandora_server/extras/pandoraPlugintools/encryption.py @@ -18,6 +18,20 @@ from binascii import unhexlify _PASSWORD = "default_salt" +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Internal use only: Get AES cipher ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 8a097f462a..8c85cd4bc7 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -291,6 +291,20 @@ _ENT2CHR = { # Construct the character to entity mapping. _CHR2ENT = {v: "&" + k + ";" for k, v in _ENT2CHR.items()} +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Convert the input_string encoded in html entity to clear char string. ######################################################################################### @@ -367,8 +381,8 @@ def generate_md5( ######################################################################################### def now( - print_flag: bool = False, - utimestamp: bool = False + utimestamp: bool = False, + print_flag: bool = False ) -> str: """ Returns time in yyyy/mm/dd HH:MM:SS format by default. Use 1 as an argument diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index a4d0e38efe..1ababef7f5 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -3,6 +3,20 @@ from requests.auth import HTTPBasicAuth from requests.auth import HTTPDigestAuth from requests.sessions import Session +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Auth URL session ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 8a5be45812..091c6d136c 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -1,3 +1,17 @@ +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Init module template ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/output.py b/pandora_server/extras/pandoraPlugintools/output.py index d4c9bd5edc..1488d548f6 100644 --- a/pandora_server/extras/pandoraPlugintools/output.py +++ b/pandora_server/extras/pandoraPlugintools/output.py @@ -2,6 +2,19 @@ import sys import os import json +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + print_debug(var, print_errors) + #### # Prints message in stdout ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 0dcaf7d72a..2b83879b85 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -11,6 +11,20 @@ _MANAGER = Manager() _SHARED_DICT = _MANAGER.dict() _SHARED_DICT_LOCK = _MANAGER.Lock() +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Internal use only: Run a given function in a thread ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 9e9a121da4..66d177f55e 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -20,6 +20,20 @@ GLOBAL_VARIABLES = { 'tentacle_extra_opts' : '' } +#### +# Internal: Alias for output.print_debug function +######################################################################################### + +def _print_debug( + var = "", + print_errors: bool = False + ): + """ + Prints any list, dict, string, float or integer as a json + """ + from .output import print_debug + print_debug(var, print_errors) + #### # Set a global variable with the specified name and assigns a value to it. ######################################################################################### From 9c97fc2aa6e144e0ce15062ea17ce3b9b4bcad9c Mon Sep 17 00:00:00 2001 From: alejandro Date: Mon, 14 Aug 2023 14:57:02 +0200 Subject: [PATCH 27/48] added comments in all functions, fix miss type in add_log_module --- .../extras/pandoraPlugintools/agents.py | 79 +++++++++++++++---- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 85cfdd5ed9..9b4a59d2a3 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -88,7 +88,10 @@ class Agent: config: dict = {} ): ''' - TODO: Add commnets + Update the configuration settings with new values. + + Args: + config (dict): A dictionary containing configuration keys and their new values. ''' for key, value in config.items(): if key in self.config: @@ -98,7 +101,10 @@ class Agent: self ) -> dict: ''' - TODO: Add commnets + Retrieve the current configuration settings. + + Returns: + dict: A dictionary containing the current configuration settings. ''' return self.config @@ -107,7 +113,10 @@ class Agent: module: dict = {} ): ''' - TODO: Add commnets + Add a new module to the list of modules. + + Args: + module (dict): A dictionary containing module information. ''' from .general import generate_md5 from .modules import init_module @@ -121,7 +130,10 @@ class Agent: module_name: str = "" ): ''' - TODO: Add commnets + Delete a module based on its name. + + Args: + module_name (str): The name of the module to be deleted. ''' from .general import generate_md5 @@ -141,7 +153,11 @@ class Agent: module: dict = {} ): ''' - TODO: Add commnets + Update a module based on its name. + + Args: + module_name (str): The name of the module to be updated. + module (dict): A dictionary containing updated module information. ''' module_def = self.get_module(module_name) @@ -159,7 +175,13 @@ class Agent: module_name: str = "" ) -> dict: ''' - TODO: Add commnets + Retrieve module information based on its name. + + Args: + module_name (str): The name of the module to retrieve. + + Returns: + dict: A dictionary containing module information if found, otherwise an empty dictionary. ''' from .general import generate_md5 @@ -178,7 +200,10 @@ class Agent: self ) -> dict: ''' - TODO: Add commnets + Retrieve the definitions of all added modules. + + Returns: + dict: A dictionary containing the definitions of all added modules. ''' return self.modules_def @@ -187,18 +212,24 @@ class Agent: log_module: dict = {} ): ''' - TODO: Add commnets + Add a new log module to the list of log modules. + + Args: + log_module (dict): A dictionary containing log module information. ''' from .modules import init_log_module - if "source" in module and type(module["source"]) == str and len(module["source"].strip()) > 0: + if "source" in log_module and type(log_module["source"]) == str and len(log_module["source"].strip()) > 0: self.log_modules_def.append(init_log_module(log_module)) def get_log_modules_def( self ) -> dict: ''' - TODO: Add commnets + Retrieve the definitions of all added log modules. + + Returns: + dict: A dictionary containing the definitions of all added log modules. ''' return self.log_modules_def @@ -207,7 +238,13 @@ class Agent: print_flag: bool = False ) -> str: ''' - TODO: Add commnets + Generate and optionally print the XML representation of the agent. + + Args: + print_flag (bool): A flag indicating whether to print the XML representation. + + Returns: + str: The XML representation of the agent. ''' return print_agent(self.get_config(), self.get_modules_def(), self.get_log_modules_def(), print_flag) @@ -218,10 +255,13 @@ def init_agent( default_values: dict = {} ) -> dict: """ - Initializes an agent template with default values. + Initialize an agent template with default values. + + Args: + default_values (dict): A dictionary containing custom default values for the agent template. Returns: - dict: Dictionary representing the agent template with default values. + dict: A dictionary representing the agent template with default and custom values. """ from .general import now @@ -256,9 +296,16 @@ def print_agent( print_flag: bool = False ) -> str: """ - Prints agent XML. Requires agent conf (dict) and modules (list) as arguments. - - Use print_flag to show modules' XML in STDOUT. - - Returns xml (str). + Print the XML representation of an agent. + + Args: + agent (dict): A dictionary containing agent configuration. + modules (list): A list of dictionaries representing modules. + log_modules (list): A list of dictionaries representing log modules. + print_flag (bool): A flag indicating whether to print the XML representation. + + Returns: + str: The XML representation of the agent. """ from .output import print_stdout from .modules import print_module,print_log_module From 7cf65b005979276835452290baea70adf7a80d9e Mon Sep 17 00:00:00 2001 From: alejandro Date: Mon, 14 Aug 2023 15:08:57 +0200 Subject: [PATCH 28/48] fix miss type in add_disco_summary_value, added comments --- .../extras/pandoraPlugintools/discovery.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 60473ed13e..789e1a13a4 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -19,7 +19,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Print the variable as a JSON-like representation for debugging purposes. + + Args: + var (any): The variable to be printed. + print_errors (bool): A flag indicating whether to print errors during debugging. """ from .output import print_debug print_debug(var, print_errors) @@ -79,7 +83,7 @@ def add_disco_summary_value( if key in SUMMARY: SUMMARY[key] += value else: - set_summary_value(key, value) + set_disco_summary_value(key, value) #### # Set fixed value to info @@ -120,7 +124,10 @@ def set_disco_monitoring_data( data: list = [] ): """ - TODO: Add comments + Set the monitoring data for disk usage. + + Args: + data (list): A list containing disk monitoring data. """ global MONITORING_DATA @@ -133,7 +140,10 @@ def add_disco_monitoring_data( data: dict = {} ): """ - TODO: Add comments + Add disk monitoring data to the global monitoring dataset. + + Args: + data (dict): A dictionary containing disk monitoring data. """ global MONITORING_DATA From 5ae20fdf21f33257ed7c0c3f3d98c6dc1accc5d1 Mon Sep 17 00:00:00 2001 From: alejandro Date: Mon, 14 Aug 2023 15:44:56 +0200 Subject: [PATCH 29/48] added comments --- .../extras/pandoraPlugintools/encryption.py | 32 +++++++-- .../extras/pandoraPlugintools/general.py | 72 +++++++++++++------ .../extras/pandoraPlugintools/http.py | 31 ++++---- .../extras/pandoraPlugintools/modules.py | 30 ++++++-- .../extras/pandoraPlugintools/output.py | 24 +++++++ .../extras/pandoraPlugintools/threads.py | 59 ++++++++++++--- .../extras/pandoraPlugintools/transfer.py | 33 ++++++--- 7 files changed, 220 insertions(+), 61 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/encryption.py b/pandora_server/extras/pandoraPlugintools/encryption.py index 4b6408c120..89d1959adb 100644 --- a/pandora_server/extras/pandoraPlugintools/encryption.py +++ b/pandora_server/extras/pandoraPlugintools/encryption.py @@ -27,7 +27,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Print the variable as a JSON-like representation for debugging purposes. + + Args: + var (any): The variable to be printed. + print_errors (bool): A flag indicating whether to print errors during debugging. """ from .output import print_debug print_debug(var, print_errors) @@ -39,7 +43,13 @@ def _get_cipher( password: str = _PASSWORD ) -> AES: ''' - Internal use only: Get AES cipher + Internal use only: Get AES cipher for encryption and decryption. + + Args: + password (str): The password used to derive the encryption key. + + Returns: + AES: An AES cipher instance for encryption and decryption. ''' key = b'' msg = password.encode('utf-8') @@ -59,7 +69,14 @@ def encrypt( password: str = _PASSWORD ) -> str: ''' - Return encrypted string + Encrypt a string using AES encryption. + + Args: + str_to_encrypt (str): The string to be encrypted. + password (str): The password used to derive the encryption key. + + Returns: + str: The encrypted string in base64 encoding. ''' cipher = _get_cipher(password) @@ -80,7 +97,14 @@ def decrypt( password: str = _PASSWORD ) -> str: ''' - Return decrypted string + Decrypt an encrypted string using AES decryption. + + Args: + str_to_decrypt (str): The encrypted string to be decrypted. + password (str): The password used to derive the encryption key. + + Returns: + str: The decrypted string. ''' cipher = _get_cipher(password) diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 8c85cd4bc7..49c131fe5e 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -300,7 +300,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Print the variable as a JSON-like representation for debugging purposes. + + Args: + var (any): The variable to be printed. + print_errors (bool): A flag indicating whether to print errors during debugging. """ from .output import print_debug print_debug(var, print_errors) @@ -312,7 +316,13 @@ def safe_input( input_string: str = "" ) -> str: ''' - Convert the input_string encoded in html entity to clear char string. + Convert an input string encoded in HTML entities to a clear character string. + + Args: + input_string (str): The input string encoded in HTML entities. + + Returns: + str: The decoded clear character string. ''' if not input_string: return "" @@ -326,7 +336,13 @@ def safe_output( input_string: str = "" ) -> str: ''' - Convert the html entities to input_string encoded to rebuild char string. + Convert HTML entities back to their corresponding characters in the input string. + + Args: + input_string (str): The input string containing HTML entities. + + Returns: + str: The decoded clear character string. ''' if not input_string: return "" @@ -346,7 +362,12 @@ def set_dict_key_value( input_value = None ): """ - Assign to a key in a dict a given value + Assign a given value to a specified key in a dictionary. + + Args: + input_dict (dict): The dictionary to which the value will be assigned. + input_key (str): The key in the dictionary to which the value will be assigned. + input_value (any): The value to be assigned to the specified key. """ key = input_key.strip() @@ -385,8 +406,14 @@ def now( print_flag: bool = False ) -> str: """ - Returns time in yyyy/mm/dd HH:MM:SS format by default. Use 1 as an argument - to get epoch time (utimestamp) + Get the current time in the specified format or as a Unix timestamp. + + Args: + utimestamp (bool): Set to True to get the Unix timestamp (epoch time). + print_flag (bool): Set to True to print the time to standard output. + + Returns: + str: The current time in the desired format or as a Unix timestamp. """ from .output import print_stdout @@ -410,10 +437,14 @@ def translate_macros( data: str = "" ) -> str: """ - Expects a macro dictionary key:value (macro_name:macro_value) - and a string to replace macro. - - It will replace the macro_name for the macro_value in any string. + Replace macros in the input string with their corresponding values. + + Args: + macro_dic (dict): A dictionary containing macro names and their corresponding values. + data (str): The input string in which macros should be replaced. + + Returns: + str: The input string with macros replaced by their values. """ for macro_name, macro_value in macro_dic.items(): data = data.replace(macro_name, macro_value) @@ -431,14 +462,15 @@ def parse_configuration( default_values: dict = {} ) -> dict: """ - Parse configuration. Reads configuration file and stores its data as dict. + Parse a configuration file and return its data as a dictionary. Args: - - file (str): configuration file path. Defaults to "/etc/pandora/pandora_server.conf". \n - - separator (str, optional): Separator for option and value. Defaults to " ". + file (str): The path to the configuration file. Defaults to "/etc/pandora/pandora_server.conf". + separator (str, optional): The separator between option and value. Defaults to " ". + default_values (dict, optional): A dictionary of default values. Defaults to an empty dictionary. Returns: - - dict: containing all keys and values from file. + dict: A dictionary containing all keys and values from the configuration file. """ from .output import print_stderr @@ -474,16 +506,16 @@ def parse_csv_file( print_errors: bool = False ) -> list: """ - Parse csv configuration. Reads configuration file and stores its data in a list. + Parse a CSV configuration file and return its data in a list. Args: - - file (str): configuration csv file path. \n - - separator (str, optional): Separator for option and value. Defaults to ";". - - coun_parameters (int): min number of parameters each line shold have. Default None - - print_errors (bool): print errors on lines + file (str): The path to the CSV configuration file. + separator (str, optional): The separator between values in the CSV. Defaults to ";". + count_parameters (int, optional): The minimum number of parameters each line should have. Defaults to 0. + print_errors (bool, optional): Set to True to print errors for lines with insufficient parameters. Defaults to False. Returns: - - List: containing a list for of values for each csv line. + list: A list containing lists of values for each line in the CSV. """ from .output import print_stderr diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index 1ababef7f5..30d7722598 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -12,7 +12,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Print the provided variable as JSON, supporting various data types. + + Args: + var (any): The variable to be printed as JSON. + print_errors (bool): Set to True to print errors encountered during printing. """ from .output import print_debug print_debug(var, print_errors) @@ -28,13 +32,13 @@ def auth_call( passw: str = "" ): """ - Authentication for url request. Requires request.sessions.Session() object. + Perform authentication for URL requests using various authentication types. Args: - - session (object): request Session() object. - - authtype (str): 'ntlm', 'basic' or 'digest'. - - user (str): auth user. - - passw (str): auth password. + session (object, optional): The request Session() object. Defaults to None. + authtype (str, optional): The authentication type. Supported values: 'ntlm', 'basic', or 'digest'. Defaults to 'basic'. + user (str, optional): The authentication user. Defaults to an empty string. + passw (str, optional): The authentication password. Defaults to an empty string. """ if session is not None: if authtype == 'ntlm': @@ -57,17 +61,18 @@ def call_url( print_errors: bool = False ) -> str: """ - Call URL. Uses request module to get url contents. + Call a URL and return its contents. Args: - - url (str): URL - - authtype (str): ntlm', 'basic', 'digest'. Optional. - - user (str): auth user. Optional. - - passw (str): auth password. Optional. - - timeout (int): session timeout seconds. Optional. + url (str): The URL to call. + authtype (str, optional): The authentication type. Supported values: 'ntlm', 'basic', 'digest'. Defaults to 'basic'. + user (str, optional): The authentication user. Defaults to an empty string. + passw (str, optional): The authentication password. Defaults to an empty string. + timeout (int, optional): The session timeout in seconds. Defaults to 1. + print_errors (bool, optional): Set to True to print errors encountered during the call. Defaults to False. Returns: - - str: call output + str: The output from the URL call. """ from .output import print_stderr diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 091c6d136c..623f379482 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -7,7 +7,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Print the provided variable as JSON format, supporting various data types. + + Args: + var (any, optional): The variable to be printed as JSON. Defaults to an empty string. + print_errors (bool, optional): Set to True to print errors encountered during printing. Defaults to False. """ from .output import print_debug print_debug(var, print_errors) @@ -21,6 +25,9 @@ def init_module( """ Initializes a module template with default values. + Args: + default_values (dict, optional): Dictionary containing default values to override template values. Defaults to an empty dictionary. + Returns: dict: Dictionary representing the module template with default values. """ @@ -87,9 +94,13 @@ def print_module( ) -> str: """ Returns module in XML format. Accepts only {dict}. - - Only works with one module at a time: otherwise iteration is needed. - - Module "value" field accepts str type or [list] for datalists. - - Use print_flag to show modules' XML in STDOUT. + + Args: + module (dict, optional): Dictionary containing module data. Defaults to None. + print_flag (bool, optional): Flag to print the module XML to STDOUT. Defaults to False. + + Returns: + str: Module data in XML format. """ from .output import print_stdout @@ -220,6 +231,9 @@ def init_log_module( """ Initializes a log module template with default values. + Args: + default_values (dict, optional): Default values to initialize the log module with. Defaults to an empty dictionary. + Returns: dict: Dictionary representing the log module template with default values. """ @@ -247,7 +261,15 @@ def print_log_module( - Only works with one module at a time: otherwise iteration is needed. - Module "value" field accepts str type. - Use not_print_flag to avoid printing the XML (only populates variables). + + Args: + module (dict, optional): Dictionary representing the log module. Defaults to None. + print_flag (bool, optional): Flag to indicate whether to print the XML. Defaults to False. + + Returns: + str: XML representation of the log module. """ + from .output import print_stdout module_xml = "" diff --git a/pandora_server/extras/pandoraPlugintools/output.py b/pandora_server/extras/pandoraPlugintools/output.py index 1488d548f6..f9064c2abf 100644 --- a/pandora_server/extras/pandoraPlugintools/output.py +++ b/pandora_server/extras/pandoraPlugintools/output.py @@ -12,6 +12,10 @@ def _print_debug( ): """ Prints any list, dict, string, float or integer as a json + + Args: + var (any, optional): Variable to be printed. Defaults to "". + print_errors (bool, optional): Flag to indicate whether to print errors. Defaults to False. """ print_debug(var, print_errors) @@ -24,6 +28,9 @@ def print_stdout( ): """ Prints message in stdout + + Args: + message (str, optional): Message to be printed. Defaults to "". """ print(message) @@ -36,6 +43,9 @@ def print_stderr( ): """ Prints message in stderr + + Args: + message (str, optional): Message to be printed. Defaults to "". """ print(message, file=sys.stderr) @@ -49,6 +59,10 @@ def print_debug( ): """ Prints any list, dict, string, float or integer as a json + + Args: + var: Variable to be printed. + print_errors (bool, optional): Whether to print errors. Defaults to False. """ try: debug_json = json.dumps(var, indent=4) @@ -72,6 +86,16 @@ def logger( ) -> bool: ''' Add new line to log file + + Args: + log_file (str): Path to the log file. + message (str): Message to be added to the log. + log_level (str): Log level, if applicable. Defaults to an empty string. + add_date (bool): Whether to add the current date and time to the log entry. Defaults to True. + print_errors (bool): Whether to print errors. Defaults to False. + + Returns: + bool: True if the log entry was successfully added, False otherwise. ''' from .general import now diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index 2b83879b85..f38c479eab 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -20,7 +20,11 @@ def _print_debug( print_errors: bool = False ): """ - Prints any list, dict, string, float or integer as a json + Prints the provided variable in a JSON-like format. + + Args: + var: The variable (list, dict, string, float, integer) to be printed. + print_errors (bool): If True, prints any errors that occur during formatting. """ from .output import print_debug print_debug(var, print_errors) @@ -34,7 +38,12 @@ def _single_thread( errors: list = [] ): """ - Internal use only: Run a given function in a thread + Internal use only: Runs a given function in a thread. + + Args: + q: A queue from which to get parameters for the function. + function (callable): The function to be executed in the thread. + errors (list): A list to store any errors encountered during execution. """ params=q.get() q.task_done() @@ -53,7 +62,16 @@ def run_threads( print_errors: bool = False ) -> bool: """ - Run a given function for given items list in a given number of threads + Run a given function for a list of items in multiple threads. + + Args: + max_threads (int): Maximum number of threads to use. + function (callable): The function to be executed in each thread. + items (list): List of items to process. + print_errors (bool): Whether to print errors encountered during execution. + + Returns: + bool: True if all threads executed successfully, False otherwise. """ from .output import print_stderr @@ -122,8 +140,12 @@ def set_shared_dict_value( value = None ): """ - Set a given value to a key in the internal shared dict. - Used by all parallel processes. + Set a value for a key in the internal shared dictionary. + This function is used by all parallel processes. + + Args: + key (str): The key in the shared dictionary. + value: The value to be assigned to the key. """ global _SHARED_DICT @@ -140,8 +162,12 @@ def add_shared_dict_value( value = None ): """ - Add a given value to a key in the internal shared dict. - Used by all parallel processes. + Add a value to a key in the internal shared dictionary. + This function is used by all parallel processes. + + Args: + key (str): The key in the shared dictionary. + value: The value to be added to the key. """ global _SHARED_DICT @@ -160,8 +186,14 @@ def get_shared_dict_value( key: str = None ): """ - Get the value of a key in the internal shared dict. - Used by all parallel processes. + Get the value of a key in the internal shared dictionary. + This function is used by all parallel processes. + + Args: + key (str): The key in the shared dictionary. + + Returns: + The value associated with the key, or None if the key does not exist. """ global _SHARED_DICT @@ -183,6 +215,15 @@ def run_processes( ) -> bool: """ Run a given function for given items list in a given number of processes + + Args: + max_processes (int): The maximum number of processes to run in parallel. + function (callable): The function to be executed for each item. + items (list): List of items to be processed. + print_errors (bool): Whether to print errors. + + Returns: + bool: True if all processes completed successfully, False otherwise. """ from .output import print_stderr diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 66d177f55e..e299307b11 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -30,6 +30,10 @@ def _print_debug( ): """ Prints any list, dict, string, float or integer as a json + + Args: + var: The variable to be printed. + print_errors (bool): Whether to print errors. """ from .output import print_debug print_debug(var, print_errors) @@ -64,14 +68,16 @@ def tentacle_xml( ) -> bool: """ Sends file using tentacle protocol - - Only works with one file at time. - - file variable needs full file path. - - tentacle_opts should be a dict with tentacle options (address [password] [port]). - - tentacle_path allows to define a custom path for tentacle client in case is not in sys path). - - if debug is enabled, the data file will not be removed after being sent. - - if print_errors is enabled, function will print all error messages + + Args: + data_file (str): Path to the data file to be sent. + tentacle_ops (dict): Tentacle options as a dictionary (address [password] [port]). + tentacle_path (str): Custom path for the tentacle client executable. + debug (int): Debug mode flag. If enabled (1), the data file will not be removed after sending. + print_errors (bool): Whether to print error messages. - Returns True for OK and False for errors. + Returns: + bool: True for success, False for errors. """ from .output import print_stderr @@ -161,11 +167,16 @@ def write_xml( print_errors: bool = False ) -> str: """ - Creates a agent .data file in the specified data_dir folder + Creates an agent .data file in the specified data_dir folder + Args: - - xml (str): XML string to be written in the file. - - agent_name (str): agent name for the xml and file name. - - data_dir (str): folder in which the file will be created. + xml (str): XML string to be written in the file. + agent_name (str): Agent name for the XML and file name. + data_dir (str): Folder in which the file will be created. + print_errors (bool): Whether to print error messages. + + Returns: + str: Path to the created .data file. """ from .general import generate_md5 from .output import print_stderr From 6159f285fda9b5a060ea6cdfc4e034625c61bcc6 Mon Sep 17 00:00:00 2001 From: Enrique Martin Date: Wed, 16 Aug 2023 08:12:14 +0200 Subject: [PATCH 30/48] Standarized globals and functions --- .../extras/pandoraPlugintools/agents.py | 97 ++++++++++++++----- .../extras/pandoraPlugintools/discovery.py | 91 +++++++++-------- .../extras/pandoraPlugintools/encryption.py | 4 +- .../extras/pandoraPlugintools/general.py | 18 ++++ .../extras/pandoraPlugintools/http.py | 53 ++++++---- .../extras/pandoraPlugintools/modules.py | 41 ++++++++ .../extras/pandoraPlugintools/transfer.py | 50 ++++++---- 7 files changed, 254 insertions(+), 100 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 85cfdd5ed9..9455fdda50 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -6,7 +6,7 @@ import os # Its values can be changed. ######################################################################################### -GLOBAL_VARIABLES = { +_GLOBAL_VARIABLES = { 'agents_group_name' : '', 'interval' : 300 } @@ -15,17 +15,16 @@ GLOBAL_VARIABLES = { # Define some global variables ######################################################################################### -POSIX = os.name == "posix" -WINDOWS = os.name == "nt" -LINUX = sys.platform.startswith("linux") -MACOS = sys.platform.startswith("darwin") -OSX = MACOS # deprecated alias -FREEBSD = sys.platform.startswith("freebsd") -OPENBSD = sys.platform.startswith("openbsd") -NETBSD = sys.platform.startswith("netbsd") -BSD = FREEBSD or OPENBSD or NETBSD -SUNOS = sys.platform.startswith(("sunos", "solaris")) -AIX = sys.platform.startswith("aix") +_WINDOWS = os.name == "nt" or os.name == "ce" +_LINUX = sys.platform.startswith("linux") +_MACOS = sys.platform.startswith("darwin") +_OSX = _MACOS # deprecated alias +_FREEBSD = sys.platform.startswith("freebsd") +_OPENBSD = sys.platform.startswith("openbsd") +_NETBSD = sys.platform.startswith("netbsd") +_BSD = _FREEBSD or _OPENBSD or _NETBSD +_SUNOS = sys.platform.startswith(("sunos", "solaris")) +_AIX = sys.platform.startswith("aix") #### # Internal: Alias for output.print_debug function @@ -49,7 +48,7 @@ def set_global_variable( value = None ): """ - Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. + Sets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. @@ -57,7 +56,23 @@ def set_global_variable( """ from .general import set_dict_key_value - set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) + set_dict_key_value(_GLOBAL_VARIABLES, variable_name, value) + +#### +# Get a global variable with the specified name. +######################################################################################### +def get_global_variable( + variable_name: str = "" + ): + """ + Gets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. + + Args: + variable_name (str): Name of the variable to set. + """ + from .general import get_dict_key_value + + get_dict_key_value(_GLOBAL_VARIABLES, variable_name) #### # Agent class @@ -70,18 +85,22 @@ class Agent: """ def __init__( self, - config: dict = None, + config: dict = {}, modules_def: list = [], log_modules_def: list = [] ): - if config is None: - config = init_agent() - - self.config = config - self.modules_def = modules_def - self.log_modules_def = log_modules_def + self.modules_def = [] self.added_modules = [] + self.log_modules_def = [] + + self.config = init_agent(config) + + for module in modules_def: + self.add_module(module) + + for log_module in log_modules_def: + self.add_log_module(log_module) def update_config( self, @@ -211,6 +230,38 @@ class Agent: ''' return print_agent(self.get_config(), self.get_modules_def(), self.get_log_modules_def(), print_flag) +#### +# Gets system OS name +######################################################################################### +def get_os() -> str: + """ + Gets system OS name + + Returns: + str: OS name. + """ + os = "Other" + + if _WINDOWS: + os = "Windows" + + if _LINUX: + os = "Linux" + + if _MACOS or _OSX: + os = "MacOS" + + if _FREEBSD or _OPENBSD or _NETBSD or _BSD: + os = "BSD" + + if _SUNOS: + os = "Solaris" + + if _AIX: + os = "AIX" + + return os + #### # Init agent template ######################################################################################### @@ -235,8 +286,8 @@ def init_agent( "os_version" : "", "timestamp" : now(), "address" : "", - "group" : GLOBAL_VARIABLES['agents_group_name'], - "interval" : GLOBAL_VARIABLES['interval'], + "group" : _GLOBAL_VARIABLES['agents_group_name'], + "interval" : _GLOBAL_VARIABLES['interval'], "agent_mode" : "1" } diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 60473ed13e..46bb5697c4 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -5,10 +5,10 @@ import json # Define some global variables ######################################################################################### -ERROR_LEVEL = 0 -SUMMARY = {} -INFO = "" -MONITORING_DATA = [] +_ERROR_LEVEL = 0 +_SUMMARY = {} +_INFO = "" +_MONITORING_DATA = [] #### # Internal: Alias for output.print_debug function @@ -36,9 +36,22 @@ def set_disco_error_level( Args: value (int, optional): The error level value. Default is 0. """ - global ERROR_LEVEL + global _ERROR_LEVEL - ERROR_LEVEL = value + _ERROR_LEVEL = value + +#### +# Set fixed value to summary dict +######################################################################################### +def set_disco_summary( + data: dict = {} + ): + """ + TODO: Add comments + """ + global _SUMMARY + + _SUMMARY = {} #### # Set fixed value to summary key @@ -48,15 +61,15 @@ def set_disco_summary_value( value = None ): """ - Sets a fixed value for a key in the 'SUMMARY' dictionary. + Sets a fixed value for a key in the '_SUMMARY' dictionary. Args: key (str): Key to set the value for. value (any): Value to assign to the key. """ - global SUMMARY + global _SUMMARY - SUMMARY[key] = value + _SUMMARY[key] = value #### # Add value to summary key @@ -74,10 +87,10 @@ def add_disco_summary_value( key (str): Key to add the value to. value (any): Value to add to the key. """ - global SUMMARY + global _SUMMARY - if key in SUMMARY: - SUMMARY[key] += value + if key in _SUMMARY: + _SUMMARY[key] += value else: set_summary_value(key, value) @@ -88,14 +101,14 @@ def set_disco_info_value( value: str = "" ): """ - Sets a fixed value to the 'INFO' variable. + Sets a fixed value to the '_INFO' variable. Args: - data (str, optional): The value to set in the 'INFO' variable. Default is an empty string. + data (str, optional): The value to set in the '_INFO' variable. Default is an empty string. """ - global INFO + global _INFO - INFO = value + _INFO = value #### # Add data to info @@ -104,14 +117,14 @@ def add_disco_info_value( value: str = "" ): """ - Adds data to the 'INFO' variable. + Adds data to the '_INFO' variable. Args: - data (str, optional): The data to add to the 'INFO' variable. Default is an empty string. + data (str, optional): The data to add to the '_INFO' variable. Default is an empty string. """ - global INFO + global _INFO - INFO += value + _INFO += value #### # Set fixed value to monitoring data @@ -122,9 +135,9 @@ def set_disco_monitoring_data( """ TODO: Add comments """ - global MONITORING_DATA + global _MONITORING_DATA - MONITORING_DATA = data + _MONITORING_DATA = data #### # Add value to monitoring data @@ -135,9 +148,9 @@ def add_disco_monitoring_data( """ TODO: Add comments """ - global MONITORING_DATA + global _MONITORING_DATA - MONITORING_DATA.append(data) + _MONITORING_DATA.append(data) #### # Print JSON output and exit script @@ -146,28 +159,28 @@ def disco_output(): """ Prints the JSON output and exits the script. - The function uses the global variables 'ERROR_LEVEL', 'SUMMARY', and 'info' + The function uses the global variables '_ERROR_LEVEL', '_SUMMARY', '_INFO' and '_MONITORING_DATA' to create the JSON output. It then prints the JSON string and exits the script with - the 'ERROR_LEVEL' as the exit code. + the '_ERROR_LEVEL' as the exit code. """ from .output import print_stdout - global ERROR_LEVEL - global SUMMARY - global INFO - global MONITORING_DATA + global _ERROR_LEVEL + global _SUMMARY + global _INFO + global _MONITORING_DATA - OUTPUT={} - if SUMMARY: - OUTPUT["summary"] = SUMMARY + output={} + if _SUMMARY: + output["summary"] = _SUMMARY - if INFO: - OUTPUT["info"] = INFO + if _INFO: + output["info"] = _INFO - if MONITORING_DATA: - OUTPUT["monitoring_data"] = MONITORING_DATA + if _MONITORING_DATA: + output["monitoring_data"] = _MONITORING_DATA - json_string = json.dumps(OUTPUT) + json_string = json.dumps(output) print_stdout(json_string) - sys.exit(ERROR_LEVEL) + sys.exit(_ERROR_LEVEL) diff --git a/pandora_server/extras/pandoraPlugintools/encryption.py b/pandora_server/extras/pandoraPlugintools/encryption.py index 4b6408c120..9ed9e60c7e 100644 --- a/pandora_server/extras/pandoraPlugintools/encryption.py +++ b/pandora_server/extras/pandoraPlugintools/encryption.py @@ -54,7 +54,7 @@ def _get_cipher( #### # Return encrypted string ######################################################################################### -def encrypt( +def encrypt_AES( str_to_encrypt: str = "", password: str = _PASSWORD ) -> str: @@ -75,7 +75,7 @@ def encrypt( #### # Return decrypted string ######################################################################################### -def decrypt( +def decrypt_AES( str_to_decrypt: str = "", password: str = _PASSWORD ) -> str: diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index 8c85cd4bc7..769071b1ca 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -353,6 +353,24 @@ def set_dict_key_value( if len(key) > 0: input_dict[key] = input_value +#### +# Return the value of a key in a given dict. +######################################################################################### + +def get_dict_key_value( + input_dict: dict = {}, + input_key: str = "" + ): + """ + Return the value of a key in a given dict. + """ + key = input_key.strip() + + if key in input_dict: + return input_dict[key] + else: + return None + #### # Return MD5 hash string. ######################################################################################### diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index 1ababef7f5..a659aa6aa0 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -1,7 +1,9 @@ +import urllib3 +import warnings +from requests.sessions import Session from requests_ntlm import HttpNtlmAuth from requests.auth import HTTPBasicAuth from requests.auth import HTTPDigestAuth -from requests.sessions import Session #### # Internal: Alias for output.print_debug function @@ -18,10 +20,10 @@ def _print_debug( print_debug(var, print_errors) #### -# Auth URL session +# Internal: Auth URL session ######################################################################################### -def auth_call( +def _auth_call( session = None, authtype: str = "basic", user: str = "", @@ -54,6 +56,7 @@ def call_url( user: str = "", passw: str = "", timeout: int = 1, + verify: bool = True, print_errors: bool = False ) -> str: """ @@ -71,20 +74,32 @@ def call_url( """ from .output import print_stderr - # using with so we make sure the session is closed even when exceptions are encountered - with Session() as session: - if authtype != None: - auth_call(session, authtype, user, passw) - - output = "" + if url == "": + if print_errors: + print_stderr("Error: URL not provided") + return None + else: + # using with so we make sure the session is closed even when exceptions are encountered + with Session() as session: + if authtype is not None: + _auth_call(session, authtype, user, passw) + + output = "" - try: - output = session.get(url, timeout=timeout, verify=False) - except ValueError: - if print_errors: - print_stderr("Error: URL format not valid (example http://myserver/page.php)") - except Exception as e: - if print_errors: - print_stderr(f"{type(e).__name__}:\t{str(e)}") - - return output + try: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=urllib3.exceptions.InsecureRequestWarning) + response = session.get(url, timeout=timeout, verify=verify) + response.raise_for_status() # Raise an exception for non-2xx responses + return response.content + except requests.exceptions.Timeout: + if print_errors: + print_stderr("Error: Request timed out") + except requests.exceptions.RequestException as e: + if print_errors: + print_stderr(f"RequestException:\t{e}") + except ValueError: + if print_errors: + print_stderr("Error: URL format not valid (example http://myserver/page.php)") + + return None diff --git a/pandora_server/extras/pandoraPlugintools/modules.py b/pandora_server/extras/pandoraPlugintools/modules.py index 091c6d136c..6a459b8b77 100644 --- a/pandora_server/extras/pandoraPlugintools/modules.py +++ b/pandora_server/extras/pandoraPlugintools/modules.py @@ -120,86 +120,127 @@ def print_module( if "desc" in data and len(str(data["desc"]).strip()) > 0: module_xml += "\t\n" + if "unit" in data and len(str(data["unit"]).strip()) > 0: module_xml += "\t\n" + if "interval" in data and len(str(data["interval"]).strip()) > 0: module_xml += "\t\n" + if "tags" in data and len(str(data["tags"]).strip()) > 0: module_xml += "\t" + str(data["tags"]) + "\n" + if "module_group" in data and len(str(data["module_group"]).strip()) > 0: module_xml += "\t" + str(data["module_group"]) + "\n" + if "module_parent" in data and len(str(data["module_parent"]).strip()) > 0: module_xml += "\t" + str(data["module_parent"]) + "\n" + if "min_warning" in data and len(str(data["min_warning"]).strip()) > 0: module_xml += "\t\n" + if "min_warning_forced" in data and len(str(data["min_warning_forced"]).strip()) > 0: module_xml += "\t\n" + if "max_warning" in data and len(str(data["max_warning"]).strip()) > 0: module_xml += "\t\n" + if "max_warning_forced" in data and len(str(data["max_warning_forced"]).strip()) > 0: module_xml += "\t\n" + if "min_critical" in data and len(str(data["min_critical"]).strip()) > 0: module_xml += "\t\n" + if "min_critical_forced" in data and len(str(data["min_critical_forced"]).strip()) > 0: module_xml += "\t\n" + if "max_critical" in data and len(str(data["max_critical"]).strip()) > 0: module_xml += "\t\n" + if "max_critical_forced" in data and len(str(data["max_critical_forced"]).strip()) > 0: module_xml += "\t\n" + if "str_warning" in data and len(str(data["str_warning"]).strip()) > 0: module_xml += "\t\n" + if "str_warning_forced" in data and len(str(data["str_warning_forced"]).strip()) > 0: module_xml += "\t\n" + if "str_critical" in data and len(str(data["str_critical"]).strip()) > 0: module_xml += "\t\n" + if "str_critical_forced" in data and len(str(data["str_critical_forced"]).strip()) > 0: module_xml += "\t\n" + if "critical_inverse" in data and len(str(data["critical_inverse"]).strip()) > 0: module_xml += "\t\n" + if "warning_inverse" in data and len(str(data["warning_inverse"]).strip()) > 0: module_xml += "\t\n" + if "max" in data and len(str(data["max"]).strip()) > 0: module_xml += "\t\n" + if "min" in data and len(str(data["min"]).strip()) > 0: module_xml += "\t\n" + if "post_process" in data and len(str(data["post_process"]).strip()) > 0: module_xml += "\t\n" + if "disabled" in data and len(str(data["disabled"]).strip()) > 0: module_xml += "\t\n" + if "min_ff_event" in data and len(str(data["min_ff_event"]).strip()) > 0: module_xml += "\t\n" + if "status" in data and len(str(data["status"]).strip()) > 0: module_xml += "\t\n" + if "timestamp" in data and len(str(data["timestamp"]).strip()) > 0: module_xml += "\t\n" + if "custom_id" in data and len(str(data["custom_id"]).strip()) > 0: module_xml += "\t\n" + if "critical_instructions" in data and len(str(data["critical_instructions"]).strip()) > 0: module_xml += "\t\n" + if "warning_instructions" in data and len(str(data["warning_instructions"]).strip()) > 0: module_xml += "\t\n" + if "unknown_instructions" in data and len(str(data["unknown_instructions"]).strip()) > 0: module_xml += "\t\n" + if "quiet" in data and len(str(data["quiet"]).strip()) > 0: module_xml += "\t\n" + if "module_ff_interval" in data and len(str(data["module_ff_interval"]).strip()) > 0: module_xml += "\t\n" + if "crontab" in data and len(str(data["crontab"]).strip()) > 0: module_xml += "\t\n" + if "min_ff_event_normal" in data and len(str(data["min_ff_event_normal"]).strip()) > 0: module_xml += "\t\n" + if "min_ff_event_warning" in data and len(str(data["min_ff_event_warning"]).strip()) > 0: module_xml += "\t\n" + if "min_ff_event_critical" in data and len(str(data["min_ff_event_critical"]).strip()) > 0: module_xml += "\t\n" + if "ff_type" in data and len(str(data["ff_type"]).strip()) > 0: module_xml += "\t\n" + if "ff_timeout" in data and len(str(data["ff_timeout"]).strip()) > 0: module_xml += "\t\n" + if "each_ff" in data and len(str(data["each_ff"]).strip()) > 0: module_xml += "\t\n" + if "module_parent_unlink" in data and len(str(data["module_parent_unlink"]).strip()) > 0: module_xml += "\t\n" + if "alert" in data: for alert in data["alert"]: if len(str(alert).strip()) > 0: diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 66d177f55e..8fef11032f 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -10,7 +10,7 @@ import sys # Its values can be changed. ######################################################################################### -GLOBAL_VARIABLES = { +_GLOBAL_VARIABLES = { 'transfer_mode' : 'tentacle', 'temporal' : '/tmp', 'data_dir' : '/var/spool/pandora/data_in/', @@ -42,7 +42,7 @@ def set_global_variable( value = None ): """ - Sets the value of a global variable in the 'GLOBAL_VARIABLES' dictionary. + Sets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. @@ -50,7 +50,23 @@ def set_global_variable( """ from .general import set_dict_key_value - set_dict_key_value(GLOBAL_VARIABLES, variable_name, value) + set_dict_key_value(_GLOBAL_VARIABLES, variable_name, value) + +#### +# Get a global variable with the specified name. +######################################################################################### +def get_global_variable( + variable_name: str = "" + ): + """ + Gets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. + + Args: + variable_name (str): Name of the variable to set. + """ + from .general import get_dict_key_value + + get_dict_key_value(_GLOBAL_VARIABLES, variable_name) #### # Sends file using tentacle protocol @@ -58,7 +74,7 @@ def set_global_variable( def tentacle_xml( data_file: str = "", tentacle_ops: dict = {}, - tentacle_path: str = GLOBAL_VARIABLES['tentacle_client'], + tentacle_path: str = _GLOBAL_VARIABLES['tentacle_client'], debug: int = 0, print_errors: bool = True ) -> bool: @@ -78,11 +94,11 @@ def tentacle_xml( if data_file is not None : if not 'address' in tentacle_ops: - tentacle_ops['address'] = GLOBAL_VARIABLES['tentacle_ip'] + tentacle_ops['address'] = _GLOBAL_VARIABLES['tentacle_ip'] if not 'port' in tentacle_ops: - tentacle_ops['port'] = GLOBAL_VARIABLES['tentacle_port'] + tentacle_ops['port'] = _GLOBAL_VARIABLES['tentacle_port'] if not 'extra_opts' in tentacle_ops: - tentacle_ops['extra_opts'] = GLOBAL_VARIABLES['tentacle_extra_opts'] + tentacle_ops['extra_opts'] = _GLOBAL_VARIABLES['tentacle_extra_opts'] if tentacle_ops['address'] is None : if print_errors: @@ -123,11 +139,11 @@ def tentacle_xml( ######################################################################################### def transfer_xml( file: str = "", - transfer_mode: str = GLOBAL_VARIABLES['transfer_mode'], - tentacle_ip: str = GLOBAL_VARIABLES['tentacle_ip'], - tentacle_port: int = GLOBAL_VARIABLES['tentacle_port'], - tentacle_extra_opts: str = GLOBAL_VARIABLES['tentacle_extra_opts'], - data_dir: str = GLOBAL_VARIABLES['data_dir'] + transfer_mode: str = _GLOBAL_VARIABLES['transfer_mode'], + tentacle_ip: str = _GLOBAL_VARIABLES['tentacle_ip'], + tentacle_port: int = _GLOBAL_VARIABLES['tentacle_port'], + tentacle_extra_opts: str = _GLOBAL_VARIABLES['tentacle_extra_opts'], + data_dir: str = _GLOBAL_VARIABLES['data_dir'] ): """ @@ -135,10 +151,10 @@ def transfer_xml( Args: file (str): Path to file to send. - transfer_mode (str, optional): Transfer mode. Default is GLOBAL_VARIABLES['transfer_mode']. - tentacle_ip (str, optional): IP address for Tentacle. Default is GLOBAL_VARIABLES['tentacle_ip']. - tentacle_port (str, optional): Port for Tentacle. Default is GLOBAL_VARIABLES['tentacle_port']. - data_dir (str, optional): Path to data dir with local transfer mode. Default is GLOBAL_VARIABLES['data_dir']. + transfer_mode (str, optional): Transfer mode. Default is _GLOBAL_VARIABLES['transfer_mode']. + tentacle_ip (str, optional): IP address for Tentacle. Default is _GLOBAL_VARIABLES['tentacle_ip']. + tentacle_port (str, optional): Port for Tentacle. Default is _GLOBAL_VARIABLES['tentacle_port']. + data_dir (str, optional): Path to data dir with local transfer mode. Default is _GLOBAL_VARIABLES['data_dir']. """ if file is not None: if transfer_mode != "local": @@ -157,7 +173,7 @@ def transfer_xml( def write_xml( xml: str = "", agent_name: str = "", - data_dir: str = GLOBAL_VARIABLES['temporal'], + data_dir: str = _GLOBAL_VARIABLES['temporal'], print_errors: bool = False ) -> str: """ From 98670ea3498be1ad42e5548eecb70b966c39e8a2 Mon Sep 17 00:00:00 2001 From: alejandro Date: Thu, 17 Aug 2023 10:35:28 +0200 Subject: [PATCH 31/48] added retry option in the tranfer module --- .../extras/pandoraPlugintools/transfer.py | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 5b1b67ef11..c607ca8d79 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -17,7 +17,8 @@ _GLOBAL_VARIABLES = { 'tentacle_client' : 'tentacle_client', 'tentacle_ip' : '127.0.0.1', 'tentacle_port' : 41121, - 'tentacle_extra_opts' : '' + 'tentacle_extra_opts' : '', + 'tentacle_retries' : 1 } #### @@ -79,6 +80,7 @@ def tentacle_xml( data_file: str = "", tentacle_ops: dict = {}, tentacle_path: str = _GLOBAL_VARIABLES['tentacle_client'], + retry: bool = False, debug: int = 0, print_errors: bool = True ) -> bool: @@ -89,6 +91,7 @@ def tentacle_xml( data_file (str): Path to the data file to be sent. tentacle_ops (dict): Tentacle options as a dictionary (address [password] [port]). tentacle_path (str): Custom path for the tentacle client executable. + retry (bool): Whether to retry sending the file if it fails. debug (int): Debug mode flag. If enabled (1), the data file will not be removed after sending. print_errors (bool): Whether to print error messages. @@ -122,18 +125,49 @@ def tentacle_xml( tentacle_cmd = f"{tentacle_path} -v -a {tentacle_ops['address']} -p {tentacle_ops['port']} {tentacle_ops['extra_opts']} {data_file.strip()}" - tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) - rc=tentacle_exe.wait() - - if debug == 0 : - os.remove(data_file.strip()) + if retry: - if rc != 0 : - if print_errors: - stderr = tentacle_exe.stderr.read().decode() - msg="Tentacle error:" + str(stderr) - print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) - return False + retry_count = 0 + + while retry_count < _GLOBAL_VARIABLES['tentacle_retries'] : + + tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() + + if debug == 0 : + os.remove(data_file.strip()) + + if rc == 0: + break + + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg = f"Tentacle error (Retry {retry_count + 1}/{_GLOBAL_VARIABLES['tentacle_retries']}): {stderr}" + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) + + retry_count += 1 + + if retry_count >= _GLOBAL_VARIABLES['tentacle_retries']: + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg = f"Tentacle error (Final Retry): {stderr}" + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) + return False + + else: + + tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() + + if debug == 0 : + os.remove(data_file.strip()) + + if rc != 0 : + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg="Tentacle error:" + str(stderr) + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) + return False else: if print_errors: From 1c0497289e54284d1fe3934fb389322ef96e727b Mon Sep 17 00:00:00 2001 From: alejandro Date: Thu, 17 Aug 2023 11:23:36 +0200 Subject: [PATCH 32/48] edit retry option --- .../extras/pandoraPlugintools/transfer.py | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index c607ca8d79..6a574355c1 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -124,50 +124,54 @@ def tentacle_xml( return False tentacle_cmd = f"{tentacle_path} -v -a {tentacle_ops['address']} -p {tentacle_ops['port']} {tentacle_ops['extra_opts']} {data_file.strip()}" - - if retry: - - retry_count = 0 - - while retry_count < _GLOBAL_VARIABLES['tentacle_retries'] : - - tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) - rc=tentacle_exe.wait() - - if debug == 0 : - os.remove(data_file.strip()) - - if rc == 0: - break - - if print_errors: - stderr = tentacle_exe.stderr.read().decode() - msg = f"Tentacle error (Retry {retry_count + 1}/{_GLOBAL_VARIABLES['tentacle_retries']}): {stderr}" - print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) - - retry_count += 1 - - if retry_count >= _GLOBAL_VARIABLES['tentacle_retries']: - if print_errors: - stderr = tentacle_exe.stderr.read().decode() - msg = f"Tentacle error (Final Retry): {stderr}" - print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) - return False - - else: - - tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) - rc=tentacle_exe.wait() + tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() - if debug == 0 : - os.remove(data_file.strip()) + if debug == 0 : + os.remove(data_file.strip()) - if rc != 0 : + if rc != 0 : + + if retry: + + if _GLOBAL_VARIABLES['tentacle_retries'] > 1: + _GLOBAL_VARIABLES['tentacle_retries'] = 1 + + retry_count = 0 + + while retry_count < _GLOBAL_VARIABLES['tentacle_retries'] : + + tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) + rc=tentacle_exe.wait() + + if debug == 0 : + os.remove(data_file.strip()) + + if rc == 0: + break + + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg = f"Tentacle error (Retry {retry_count + 1}/{_GLOBAL_VARIABLES['tentacle_retries']}): {stderr}" + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) + + retry_count += 1 + + if retry_count >= _GLOBAL_VARIABLES['tentacle_retries']: + if print_errors: + stderr = tentacle_exe.stderr.read().decode() + msg = f"Tentacle error (Final Retry): {stderr}" + print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) + return False + else: + if print_errors: stderr = tentacle_exe.stderr.read().decode() msg="Tentacle error:" + str(stderr) print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) return False + + else: if print_errors: From f55efbee7f9c61a7a08ba361cdbb64d73816c6c1 Mon Sep 17 00:00:00 2001 From: alejandro Date: Thu, 17 Aug 2023 12:45:09 +0200 Subject: [PATCH 33/48] minor changes in transfer (retry) --- .../extras/pandoraPlugintools/transfer.py | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 6a574355c1..9c8316c6c5 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -126,52 +126,49 @@ def tentacle_xml( tentacle_cmd = f"{tentacle_path} -v -a {tentacle_ops['address']} -p {tentacle_ops['port']} {tentacle_ops['extra_opts']} {data_file.strip()}" tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) rc=tentacle_exe.wait() - - if debug == 0 : - os.remove(data_file.strip()) + result = True + if rc != 0 : if retry: - if _GLOBAL_VARIABLES['tentacle_retries'] > 1: - _GLOBAL_VARIABLES['tentacle_retries'] = 1 + tentacle_retries = _GLOBAL_VARIABLES['tentacle_retries'] + + if tentacle_retries < 1: + tentacle_retries = 1 retry_count = 0 - while retry_count < _GLOBAL_VARIABLES['tentacle_retries'] : + while retry_count < tentacle_retries : tentacle_exe=subprocess.Popen(tentacle_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True) rc=tentacle_exe.wait() - if debug == 0 : - os.remove(data_file.strip()) - if rc == 0: break if print_errors: stderr = tentacle_exe.stderr.read().decode() - msg = f"Tentacle error (Retry {retry_count + 1}/{_GLOBAL_VARIABLES['tentacle_retries']}): {stderr}" + msg = f"Tentacle error (Retry {retry_count + 1}/{tentacle_retries}): {stderr}" print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) retry_count += 1 - if retry_count >= _GLOBAL_VARIABLES['tentacle_retries']: - if print_errors: - stderr = tentacle_exe.stderr.read().decode() - msg = f"Tentacle error (Final Retry): {stderr}" - print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) - return False + if retry_count >= tentacle_retries: + result = False else: if print_errors: stderr = tentacle_exe.stderr.read().decode() msg="Tentacle error:" + str(stderr) print_stderr(str(datetime.today().strftime('%Y-%m-%d %H:%M')) + msg) - return False + result = False - + if debug == 0 : + os.remove(data_file.strip()) + + return result else: if print_errors: From 177ae606491dd15c907b73f2d41cdb4f4c868e1f Mon Sep 17 00:00:00 2001 From: alejandro Date: Thu, 17 Aug 2023 15:55:32 +0200 Subject: [PATCH 34/48] added snmp module, Session, get and walk --- .../extras/pandoraPlugintools/snmp.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 pandora_server/extras/pandoraPlugintools/snmp.py diff --git a/pandora_server/extras/pandoraPlugintools/snmp.py b/pandora_server/extras/pandoraPlugintools/snmp.py new file mode 100644 index 0000000000..38b359e0fd --- /dev/null +++ b/pandora_server/extras/pandoraPlugintools/snmp.py @@ -0,0 +1,74 @@ +from easysnmp import Session + +#### +# Define global variables dict, used in functions as default values. +# Its values can be changed. +######################################################################################### + +_GLOBAL_VARIABLES = { + 'hostname' : '', + 'version' : 3, + 'community' : 'public', + 'user' : '', + 'auth_protocol' : "", + 'auth_password' : "", + 'privacy_protocol' : "", + 'privacy_password' : "", + 'security_level' : "authPriv", + 'timeout' : 2, + 'retries' : 1, + 'remote_port' : 161, +} + +def create_snmp_session(): + host = _GLOBAL_VARIABLES['hostname'] + version = _GLOBAL_VARIABLES['version'] + community = _GLOBAL_VARIABLES['community'] + user = _GLOBAL_VARIABLES['user'] + auth_protocol = _GLOBAL_VARIABLES['auth_protocol'] + auth_password = _GLOBAL_VARIABLES['auth_password'] + privacy_protocol = _GLOBAL_VARIABLES['privacy_protocol'] + privacy_password = _GLOBAL_VARIABLES['privacy_password'] + security_level = _GLOBAL_VARIABLES['security_level'] + timeout = _GLOBAL_VARIABLES['timeout'] + retries = _GLOBAL_VARIABLES['retries'] + remote_port = _GLOBAL_VARIABLES['remote_port'] + + session_kwargs = { + "hostname": host, + "version": version, + "use_numeric": True, + "timeout": timeout, + "retries": retries, + "remote_port": remote_port + } + + if version == 1 or version == 2: + session_kwargs["community"] = community + elif version == 3: + session_kwargs["security_username"] = user + + if security_level == "authPriv": + session_kwargs.update({ + "auth_protocol": auth_protocol, + "auth_password": auth_password, + "privacy_protocol": privacy_protocol, + "privacy_password": privacy_password, + "security_level": "auth_with_privacy" + }) + elif security_level == "authNoPriv": + session_kwargs.update({ + "auth_protocol": auth_protocol, + "auth_password": auth_password, + "security_level": "auth_without_privacy" + }) + elif security_level == "noAuthNoPriv": + session_kwargs["security_level"] = "no_auth_or_privacy" + + return Session(**session_kwargs) + +def snmp_get(session, oid): + return session.get(oid) + +def snmp_walk(session, oid): + return session.walk(oid) From 932e171813d67cef2e4db60951ca8908445df13e Mon Sep 17 00:00:00 2001 From: alejandro Date: Fri, 18 Aug 2023 10:14:53 +0200 Subject: [PATCH 35/48] added function to send traps --- pandora_server/extras/pandoraPlugintools/snmp.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pandora_server/extras/pandoraPlugintools/snmp.py b/pandora_server/extras/pandoraPlugintools/snmp.py index 38b359e0fd..2fead7b8c3 100644 --- a/pandora_server/extras/pandoraPlugintools/snmp.py +++ b/pandora_server/extras/pandoraPlugintools/snmp.py @@ -1,4 +1,4 @@ -from easysnmp import Session +from easysnmp import Session, TrapSender #### # Define global variables dict, used in functions as default values. @@ -72,3 +72,13 @@ def snmp_get(session, oid): def snmp_walk(session, oid): return session.walk(oid) + +def send_trap(trap_oid, trap_value, destination_ip, community): + trap = TrapSender() + + trap.trap_oid = trap_oid + trap.trap_value = trap_value + trap.destination_ip = destination_ip + trap.community = community + + trap.send_trap() \ No newline at end of file From 66394f8ec4e275fe779e8b0d0c3bb2c652496693 Mon Sep 17 00:00:00 2001 From: alejandro Date: Fri, 18 Aug 2023 10:35:59 +0200 Subject: [PATCH 36/48] minor changes --- .../extras/pandoraPlugintools/snmp.py | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/snmp.py b/pandora_server/extras/pandoraPlugintools/snmp.py index 2fead7b8c3..5730c8ded7 100644 --- a/pandora_server/extras/pandoraPlugintools/snmp.py +++ b/pandora_server/extras/pandoraPlugintools/snmp.py @@ -67,13 +67,56 @@ def create_snmp_session(): return Session(**session_kwargs) -def snmp_get(session, oid): +def snmp_get( + session: Session, + oid: str + ) -> str: + """ + Performs an SNMP GET operation to retrieve the value of a specified OID. + + Args: + session (Session): The SNMP session to use for the operation. + oid (str): The OID (Object Identifier) for the SNMP GET operation. + + Returns: + str: The value retrieved from the specified OID. + """ return session.get(oid) -def snmp_walk(session, oid): +def snmp_walk( + session: Session, + oid: str + ) -> list: + """ + Performs an SNMP WALK operation to retrieve a list of values from a subtree of the MIB. + + Args: + session (Session): The SNMP session to use for the operation. + oid (str): The OID (Object Identifier) representing the root of the subtree. + + Returns: + list: A list of values retrieved from the specified subtree. + """ return session.walk(oid) -def send_trap(trap_oid, trap_value, destination_ip, community): +def send_trap( + trap_oid: str, + trap_value: str, + destination_ip: str, + community: str + ) -> None: + """ + Sends an SNMP trap to the specified destination IP using the given OID, value, and community. + + Args: + trap_oid (str): The OID (Object Identifier) for the SNMP trap. + trap_value (str): The value associated with the trap. + destination_ip (str): The IP address of the trap's destination. + community (str): The SNMP community string for authentication. + + Returns: + None + """ trap = TrapSender() trap.trap_oid = trap_oid From a42a87dffea0e5bdd19e5a4c9d5796114779f5d7 Mon Sep 17 00:00:00 2001 From: alejandro Date: Fri, 18 Aug 2023 10:41:39 +0200 Subject: [PATCH 37/48] added snmp in __init__.py --- .../extras/pandoraPlugintools/__init__.py | 3 ++- .../extras/pandoraPlugintools/snmp.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pandora_server/extras/pandoraPlugintools/__init__.py b/pandora_server/extras/pandoraPlugintools/__init__.py index f9360683ba..e52f6cc12d 100644 --- a/pandora_server/extras/pandoraPlugintools/__init__.py +++ b/pandora_server/extras/pandoraPlugintools/__init__.py @@ -6,4 +6,5 @@ from .agents import * from .modules import * from .transfer import * from .discovery import * -from .http import * \ No newline at end of file +from .http import * +from .snmp import * \ No newline at end of file diff --git a/pandora_server/extras/pandoraPlugintools/snmp.py b/pandora_server/extras/pandoraPlugintools/snmp.py index 5730c8ded7..45bd487f74 100644 --- a/pandora_server/extras/pandoraPlugintools/snmp.py +++ b/pandora_server/extras/pandoraPlugintools/snmp.py @@ -20,7 +20,16 @@ _GLOBAL_VARIABLES = { 'remote_port' : 161, } +#### +# Creates an SNMP session based on the global configuration variables. +######################################################################################### def create_snmp_session(): + """ + Creates an SNMP session based on the global configuration variables. + + Returns: + Session: An SNMP session configured based on the global variables. + """ host = _GLOBAL_VARIABLES['hostname'] version = _GLOBAL_VARIABLES['version'] community = _GLOBAL_VARIABLES['community'] @@ -67,6 +76,10 @@ def create_snmp_session(): return Session(**session_kwargs) + +#### +# Performs an SNMP GET operation to retrieve the value of a specified OID. +######################################################################################### def snmp_get( session: Session, oid: str @@ -83,6 +96,9 @@ def snmp_get( """ return session.get(oid) +#### +# Performs an SNMP WALK operation to retrieve a list of values from a subtree of the MIB. +######################################################################################### def snmp_walk( session: Session, oid: str @@ -99,6 +115,9 @@ def snmp_walk( """ return session.walk(oid) +#### +# Sends an SNMP trap to the specified destination IP using the given OID, value, and community. +######################################################################################### def send_trap( trap_oid: str, trap_value: str, From 1a8c2f2a233bcc5af1411384de869928a66b9ad7 Mon Sep 17 00:00:00 2001 From: alejandro Date: Fri, 18 Aug 2023 12:53:03 +0200 Subject: [PATCH 38/48] Minor changes --- .../extras/pandoraPlugintools/agents.py | 35 ++++++++++--- .../extras/pandoraPlugintools/discovery.py | 49 +++++++++++++++---- .../extras/pandoraPlugintools/general.py | 16 ++++-- .../extras/pandoraPlugintools/http.py | 5 +- .../extras/pandoraPlugintools/output.py | 15 ++++-- .../extras/pandoraPlugintools/threads.py | 4 +- .../extras/pandoraPlugintools/transfer.py | 15 ++++-- 7 files changed, 110 insertions(+), 29 deletions(-) diff --git a/pandora_server/extras/pandoraPlugintools/agents.py b/pandora_server/extras/pandoraPlugintools/agents.py index 18674bd012..dfd5eea788 100644 --- a/pandora_server/extras/pandoraPlugintools/agents.py +++ b/pandora_server/extras/pandoraPlugintools/agents.py @@ -46,13 +46,16 @@ def _print_debug( def set_global_variable( variable_name: str = "", value = None - ): + )-> None: """ Sets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. + + Returns: + None """ from .general import set_dict_key_value @@ -63,12 +66,15 @@ def set_global_variable( ######################################################################################### def get_global_variable( variable_name: str = "" - ): + )-> None: """ Gets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. + + Returns: + None """ from .general import get_dict_key_value @@ -105,12 +111,15 @@ class Agent: def update_config( self, config: dict = {} - ): + )-> None: ''' Update the configuration settings with new values. Args: config (dict): A dictionary containing configuration keys and their new values. + + Returns: + None ''' for key, value in config.items(): if key in self.config: @@ -130,12 +139,15 @@ class Agent: def add_module( self, module: dict = {} - ): + )-> None: ''' Add a new module to the list of modules. Args: module (dict): A dictionary containing module information. + + Returns: + None ''' from .general import generate_md5 from .modules import init_module @@ -147,12 +159,15 @@ class Agent: def del_module( self, module_name: str = "" - ): + )-> None: ''' Delete a module based on its name. Args: module_name (str): The name of the module to be deleted. + + Returns: + None ''' from .general import generate_md5 @@ -170,13 +185,16 @@ class Agent: self, module_name: str = "", module: dict = {} - ): + )-> None: ''' Update a module based on its name. Args: module_name (str): The name of the module to be updated. module (dict): A dictionary containing updated module information. + + Returns: + None ''' module_def = self.get_module(module_name) @@ -229,12 +247,15 @@ class Agent: def add_log_module( self, log_module: dict = {} - ): + )-> None: ''' Add a new log module to the list of log modules. Args: log_module (dict): A dictionary containing log module information. + + Returns: + None ''' from .modules import init_log_module diff --git a/pandora_server/extras/pandoraPlugintools/discovery.py b/pandora_server/extras/pandoraPlugintools/discovery.py index 229e963a8d..fc74144d35 100644 --- a/pandora_server/extras/pandoraPlugintools/discovery.py +++ b/pandora_server/extras/pandoraPlugintools/discovery.py @@ -33,7 +33,7 @@ def _print_debug( ######################################################################################### def set_disco_error_level( value: int = 0 - ): + )-> None: """ Sets the error level to the specified value. @@ -49,9 +49,17 @@ def set_disco_error_level( ######################################################################################### def set_disco_summary( data: dict = {} - ): + )-> None: """ - TODO: Add comments + Sets the disk summary data in the internal summary dictionary. + + This function updates the summary dictionary with the provided disk summary data. + + Args: + data (dict): A dictionary containing disk summary data. + + Returns: + None """ global _SUMMARY @@ -63,13 +71,16 @@ def set_disco_summary( def set_disco_summary_value( key: str = "", value = None - ): + )-> None: """ Sets a fixed value for a key in the '_SUMMARY' dictionary. Args: key (str): Key to set the value for. value (any): Value to assign to the key. + + Returns: + None """ global _SUMMARY @@ -81,7 +92,7 @@ def set_disco_summary_value( def add_disco_summary_value( key: str = "", value = None - ): + )-> None: """ Adds a value to a key in the 'SUMMARY' dictionary. @@ -90,6 +101,9 @@ def add_disco_summary_value( Args: key (str): Key to add the value to. value (any): Value to add to the key. + + Returns: + None """ global _SUMMARY @@ -103,12 +117,15 @@ def add_disco_summary_value( ######################################################################################### def set_disco_info_value( value: str = "" - ): + )-> None: """ Sets a fixed value to the '_INFO' variable. Args: data (str, optional): The value to set in the '_INFO' variable. Default is an empty string. + + Returns: + None """ global _INFO @@ -119,12 +136,15 @@ def set_disco_info_value( ######################################################################################### def add_disco_info_value( value: str = "" - ): + )-> None: """ Adds data to the '_INFO' variable. Args: data (str, optional): The data to add to the '_INFO' variable. Default is an empty string. + + Returns: + None """ global _INFO @@ -135,12 +155,15 @@ def add_disco_info_value( ######################################################################################### def set_disco_monitoring_data( data: list = [] - ): + )-> None: """ Set the monitoring data for disk usage. Args: data (list): A list containing disk monitoring data. + + Returns: + None """ global _MONITORING_DATA @@ -151,12 +174,15 @@ def set_disco_monitoring_data( ######################################################################################### def add_disco_monitoring_data( data: dict = {} - ): + )-> None: """ Add disk monitoring data to the global monitoring dataset. Args: data (dict): A dictionary containing disk monitoring data. + + Returns: + None """ global _MONITORING_DATA @@ -165,13 +191,16 @@ def add_disco_monitoring_data( #### # Print JSON output and exit script ######################################################################################### -def disco_output(): +def disco_output()-> None: """ Prints the JSON output and exits the script. The function uses the global variables '_ERROR_LEVEL', '_SUMMARY', '_INFO' and '_MONITORING_DATA' to create the JSON output. It then prints the JSON string and exits the script with the '_ERROR_LEVEL' as the exit code. + + Returns: + None """ from .output import print_stdout diff --git a/pandora_server/extras/pandoraPlugintools/general.py b/pandora_server/extras/pandoraPlugintools/general.py index a6c4c9a5ac..abf07221a2 100644 --- a/pandora_server/extras/pandoraPlugintools/general.py +++ b/pandora_server/extras/pandoraPlugintools/general.py @@ -360,7 +360,7 @@ def set_dict_key_value( input_dict: dict = {}, input_key: str = "", input_value = None - ): + )-> None: """ Assign a given value to a specified key in a dictionary. @@ -368,6 +368,9 @@ def set_dict_key_value( input_dict (dict): The dictionary to which the value will be assigned. input_key (str): The key in the dictionary to which the value will be assigned. input_value (any): The value to be assigned to the specified key. + + Returns: + None """ key = input_key.strip() @@ -381,9 +384,16 @@ def set_dict_key_value( def get_dict_key_value( input_dict: dict = {}, input_key: str = "" - ): + )-> None: """ - Return the value of a key in a given dict. + Return the value associated with a given key in a provided dictionary. + + Args: + input_dict (dict): The dictionary to search for the key-value pair. + input_key (str): The key to look up in the dictionary. + + Returns: + The value associated with the specified key, or None if the key is not found. """ key = input_key.strip() diff --git a/pandora_server/extras/pandoraPlugintools/http.py b/pandora_server/extras/pandoraPlugintools/http.py index e5bc1b1768..20e082537c 100644 --- a/pandora_server/extras/pandoraPlugintools/http.py +++ b/pandora_server/extras/pandoraPlugintools/http.py @@ -32,7 +32,7 @@ def _auth_call( authtype: str = "basic", user: str = "", passw: str = "" - ): + )-> None: """ Perform authentication for URL requests using various authentication types. @@ -41,6 +41,9 @@ def _auth_call( authtype (str, optional): The authentication type. Supported values: 'ntlm', 'basic', or 'digest'. Defaults to 'basic'. user (str, optional): The authentication user. Defaults to an empty string. passw (str, optional): The authentication password. Defaults to an empty string. + + Returns: + None """ if session is not None: if authtype == 'ntlm': diff --git a/pandora_server/extras/pandoraPlugintools/output.py b/pandora_server/extras/pandoraPlugintools/output.py index f9064c2abf..89b87dcdd6 100644 --- a/pandora_server/extras/pandoraPlugintools/output.py +++ b/pandora_server/extras/pandoraPlugintools/output.py @@ -25,12 +25,15 @@ def _print_debug( def print_stdout( message: str = "" - ): + )-> None: """ Prints message in stdout Args: message (str, optional): Message to be printed. Defaults to "". + + Returns: + None """ print(message) @@ -40,12 +43,15 @@ def print_stdout( def print_stderr( message: str = "" - ): + )-> None: """ Prints message in stderr Args: message (str, optional): Message to be printed. Defaults to "". + + Returns: + None """ print(message, file=sys.stderr) @@ -56,13 +62,16 @@ def print_stderr( def print_debug( var = "", print_errors: bool = False - ): + )-> None: """ Prints any list, dict, string, float or integer as a json Args: var: Variable to be printed. print_errors (bool, optional): Whether to print errors. Defaults to False. + + Returns: + None """ try: debug_json = json.dumps(var, indent=4) diff --git a/pandora_server/extras/pandoraPlugintools/threads.py b/pandora_server/extras/pandoraPlugintools/threads.py index f38c479eab..fe8e844df1 100644 --- a/pandora_server/extras/pandoraPlugintools/threads.py +++ b/pandora_server/extras/pandoraPlugintools/threads.py @@ -138,7 +138,7 @@ def run_threads( def set_shared_dict_value( key: str = None, value = None - ): + )-> None: """ Set a value for a key in the internal shared dictionary. This function is used by all parallel processes. @@ -160,7 +160,7 @@ def set_shared_dict_value( def add_shared_dict_value( key: str = None, value = None - ): + )-> None: """ Add a value to a key in the internal shared dictionary. This function is used by all parallel processes. diff --git a/pandora_server/extras/pandoraPlugintools/transfer.py b/pandora_server/extras/pandoraPlugintools/transfer.py index 9c8316c6c5..798b0511c4 100644 --- a/pandora_server/extras/pandoraPlugintools/transfer.py +++ b/pandora_server/extras/pandoraPlugintools/transfer.py @@ -45,13 +45,16 @@ def _print_debug( def set_global_variable( variable_name: str = "", value = None - ): + )-> None: """ Sets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. value (any): Value to assign to the variable. + + Returns: + None """ from .general import set_dict_key_value @@ -62,12 +65,15 @@ def set_global_variable( ######################################################################################### def get_global_variable( variable_name: str = "" - ): + )-> None: """ Gets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. Args: variable_name (str): Name of the variable to set. + + Returns: + None """ from .general import get_dict_key_value @@ -185,7 +191,7 @@ def transfer_xml( tentacle_port: int = _GLOBAL_VARIABLES['tentacle_port'], tentacle_extra_opts: str = _GLOBAL_VARIABLES['tentacle_extra_opts'], data_dir: str = _GLOBAL_VARIABLES['data_dir'] - ): + )-> None: """ Detects the transfer mode and calls the agentplugin() function to perform the transfer. @@ -196,6 +202,9 @@ def transfer_xml( tentacle_ip (str, optional): IP address for Tentacle. Default is _GLOBAL_VARIABLES['tentacle_ip']. tentacle_port (str, optional): Port for Tentacle. Default is _GLOBAL_VARIABLES['tentacle_port']. data_dir (str, optional): Path to data dir with local transfer mode. Default is _GLOBAL_VARIABLES['data_dir']. + + Returns: + None """ if file is not None: if transfer_mode != "local": From 2e0b9522505f4b839e98930415aeadcdbd910de2 Mon Sep 17 00:00:00 2001 From: alejandro Date: Fri, 18 Aug 2023 14:53:12 +0200 Subject: [PATCH 39/48] added set_global_variable and get_global_variable in snmp --- .../extras/pandoraPlugintools/snmp.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pandora_server/extras/pandoraPlugintools/snmp.py b/pandora_server/extras/pandoraPlugintools/snmp.py index 45bd487f74..19c8c04179 100644 --- a/pandora_server/extras/pandoraPlugintools/snmp.py +++ b/pandora_server/extras/pandoraPlugintools/snmp.py @@ -20,6 +20,46 @@ _GLOBAL_VARIABLES = { 'remote_port' : 161, } +#### +# Set a global variable with the specified name and assigns a value to it. +######################################################################################### +def set_global_variable( + variable_name: str = "", + value = None + )-> None: + """ + Sets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. + + Args: + variable_name (str): Name of the variable to set. + value (any): Value to assign to the variable. + + Returns: + None + """ + from .general import set_dict_key_value + + set_dict_key_value(_GLOBAL_VARIABLES, variable_name, value) + +#### +# Get a global variable with the specified name. +######################################################################################### +def get_global_variable( + variable_name: str = "" + )-> None: + """ + Gets the value of a global variable in the '_GLOBAL_VARIABLES' dictionary. + + Args: + variable_name (str): Name of the variable to set. + + Returns: + None + """ + from .general import get_dict_key_value + + get_dict_key_value(_GLOBAL_VARIABLES, variable_name) + #### # Creates an SNMP session based on the global configuration variables. ######################################################################################### From 4191a7037f93861c98d0896ac8f5fa6ea2e53dbe Mon Sep 17 00:00:00 2001 From: miguel angel rasteu Date: Mon, 21 Aug 2023 10:59:29 +0200 Subject: [PATCH 40/48] #11051 Fix checkbox --- pandora_console/include/functions_notifications.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandora_console/include/functions_notifications.php b/pandora_console/include/functions_notifications.php index b75e427129..c04d6ebfb4 100644 --- a/pandora_console/include/functions_notifications.php +++ b/pandora_console/include/functions_notifications.php @@ -1019,7 +1019,7 @@ function notifications_print_user_switch($source, $user, $label) function notification_filter() { $types_list[] = 'All'; - $notification_types = db_get_all_rows_sql('SELECT DISTINCT subtype FROM tmensajes'); + $notification_types = db_get_all_rows_sql('SELECT DISTINCT tm.subtype FROM tmensajes as tm INNER JOIN tnotification_user as tnu ON tm.id_mensaje = tnu.id_mensaje WHERE tnu.utimestamp_read IS NULL'); if ($notification_types !== false) { foreach ($notification_types as $notification_type) { $type = explode('.', $notification_type['subtype'])[1]; @@ -1027,6 +1027,7 @@ function notification_filter() } } + $types_list = array_unique($types_list); $notification_filter = "
'.$filter_type.'