diff --git a/pandora_console/extras/mr/66.sql b/pandora_console/extras/mr/66.sql index bd970d70c4..526602e24c 100644 --- a/pandora_console/extras/mr/66.sql +++ b/pandora_console/extras/mr/66.sql @@ -23,6 +23,12 @@ UPDATE tagente_modulo SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; UPDATE tpolicy_modules SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; UPDATE tnetwork_component SET `tcp_send` = '2c' WHERE `tcp_send` = '2'; +ALTER TABLE talert_templates +ADD COLUMN `time_window` ENUM ('thirty_days','this_month','seven_days','this_week','one_day','today'), +ADD COLUMN `math_function` ENUM ('avg', 'min', 'max', 'sum'), +ADD COLUMN `condition` ENUM ('lower', 'greater', 'equal'), +MODIFY COLUMN `type` ENUM ('regex', 'max_min', 'max', 'min', 'equal', 'not_equal', 'warning', 'critical', 'onchange', 'unknown', 'always', 'not_normal', 'complex'); + ALTER TABLE `tsesion_filter_log_viewer` CHANGE COLUMN `date_range` `custom_date` INT NULL DEFAULT NULL , CHANGE COLUMN `start_date_defined` `date` VARCHAR(45) NULL DEFAULT NULL , @@ -66,4 +72,5 @@ ALTER TABLE `treport_content` ADD COLUMN `cat_security_hardening` INT NOT NULL ALTER TABLE `treport_content` ADD COLUMN `ignore_skipped` INT NOT NULL DEFAULT 0; ALTER TABLE `treport_content` ADD COLUMN `status_of_check` TINYTEXT; + COMMIT; diff --git a/pandora_console/godmode/alerts/configure_alert_template.php b/pandora_console/godmode/alerts/configure_alert_template.php index edaa003ce6..56b2d40085 100644 --- a/pandora_console/godmode/alerts/configure_alert_template.php +++ b/pandora_console/godmode/alerts/configure_alert_template.php @@ -374,6 +374,9 @@ function update_template($step) $max = (float) get_parameter('max'); $min = (float) get_parameter('min'); $matches = (bool) get_parameter('matches_value'); + $math_function = (string) get_parameter('math_function'); + $condition = (string) get_parameter('condition'); + $time_window = (string) get_parameter('time_window'); $default_action = (int) get_parameter('default_action'); if (empty($default_action) === true) { @@ -394,6 +397,9 @@ function update_template($step) 'min_value' => $min, 'matches_value' => $matches, 'disable_event' => $disable_event, + 'math_function' => $math_function, + 'condition' => $condition, + 'time_window' => $time_window, ]; $result = alerts_update_alert_template($id, $values); @@ -607,6 +613,9 @@ if ($id && ! $create_template) { $max = $template['max_value']; $min = $template['min_value']; $matches = $template['matches_value']; + $math_function = $template['math_function']; + $condition = $template['condition']; + $time_window = $template['time_window']; $schedule = json_encode( $default_events_calendar @@ -856,6 +865,58 @@ if ($step == 2) { ).'' ); + + $table->data["math_function"][0] = html_print_label_input_block( + __('Math function'), + html_print_select( + alerts_get_alert_templates_functions(), + 'math_function', + $math_function, + '', + __('None'), + 0, + true, + false, + false, + 'w100p', + (!$is_management_allowed | $disabled) + ) + ); + + $table->data["time_window"][0] = html_print_label_input_block( + __('Time window').ui_print_help_tip(__('Limits to data in the following time window.'), true), + html_print_select( + alerts_get_alert_templates_windows(), + 'time_window', + $time_window, + '', + __('None'), + 0, + true, + false, + false, + 'w100p', + (!$is_management_allowed | $disabled) + ) + ); + + $table->data["condition"][0] = html_print_label_input_block( + __('Alert condition'), + html_print_select( + alerts_get_alert_templates_conditions(), + 'condition', + $condition, + '', + __('None'), + 0, + true, + false, + false, + 'w100p', + (!$is_management_allowed | $disabled) + ) + ); + $table->data['value'][1] = html_print_label_input_block( __('Value'), html_print_input_text( @@ -1088,6 +1149,12 @@ if ($step == 2) { $table->rowstyle['min'] = ''; break; + case 'complex': + $table->rowstyle['math_function'] = ''; + $table->rowstyle['condition'] = ''; + $table->rowstyle['time_window'] = ''; + break; + case 'onchange': $show_matches = true; break; @@ -1299,6 +1366,7 @@ var onchange_not = ; var error_message_min_max_zero = ; var not_normal = ; +var complex = within ')."'"; ?>; function check_fields_step2() { var correct = true; @@ -1361,6 +1429,68 @@ function render_example () { else { $("span#value").empty ().append (vvalue); } + + /* Set math function */ + var vfunction = $("select#math_function").val(); + var functionMessage = ""; + + if (vfunction == "0") { + functionMessage = ""; + } else { + if (vfunction == "avg"){ + $("span#value").empty (); + } + functionMessage = vfunction; + } + $("span#math_function").empty ().append (functionMessage); + + /* Set complex value */ + if($("select#type").val() == "complex"){ + var valueMessage = ""; + + if(vfunction == "avg"){ + valueMessage = ""; + }else if (vvalue == "") { + valueMessage = "" ; + } else { + valueMessage = vvalue; + } + + $("span#value").empty ().append (valueMessage); + } + + /* Set condition */ + var vCondition = $("select#condition").val(); + var conditionMessage = "" ; + switch (vCondition){ + case "greater": + conditionMessage = (vfunction == "avg") ? "increases" : "is more than"; + break + case "lower": + conditionMessage = (vfunction == "avg") ? "decreases" : "is less than"; + break + case "equal": + conditionMessage = (vfunction == "avg") ? "remains the same" : "is equal to"; + break + } + + $("span#condition").empty ().append (conditionMessage); + + var vWindow = $("select#time_window").val(); + + /* Set time window */ + var timeWindowMessages = { + "thirty_days": "the last 30 days", + "month": "the last month", + "seven_days": "the last 7 days", + "week": "the last week", + "one_day": "the last 24 hours", + "today": "today" + }; + var windowMessage = timeWindowMessages[vWindow] || ""; + + $("span#time_window").empty().append(windowMessage); + } // Fix for metaconsole toggle @@ -1388,6 +1518,18 @@ if ($step == 2) { $("input#text-value").keyup (render_example); $("input#text-max").keyup (render_example); $("input#text-min").keyup (render_example); + $("#condition").change (render_example); + $("#time_window").change (render_example); + + $("#math_function").change (function () { + if (["0", 'avg'].includes(this.value)) { + $("#template-value").hide(); + } else { + $("#template-value").show (); + } + + render_example (); + }) $("#type").change (function () { switch (this.value) { @@ -1395,6 +1537,7 @@ if ($step == 2) { case "not_equal": $("img#regex_good, img#regex_bad, span#matches_value").hide (); $("#template-max, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-value, #template-example").show (); /* Show example */ @@ -1405,6 +1548,7 @@ if ($step == 2) { break; case "regex": $("#template-max, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-value, #template-example, span#matches_value").show (); check_regex (); @@ -1416,6 +1560,7 @@ if ($step == 2) { break; case "max_min": $("#template-value").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-max, #template-min, #template-example, span#matches_value").show (); /* Show example */ @@ -1424,9 +1569,25 @@ if ($step == 2) { else $("span#example").empty ().append (between_not); + break; + case "complex": + $("pan#matches_value, #template-example, #template-value, #template-max, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").show (); + $("#template-example").show (); + + if (["0", 'avg'].includes($("#math_function").val())) { + $("#template-value").hide(); + }else { + $("#template-value").show(); + } + + /* Show example */ + $("span#example").empty ().append (complex); + break; case "max": $("#template-value, #template-min, span#matches_value").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-max, #template-example").show (); /* Show example */ @@ -1434,6 +1595,7 @@ if ($step == 2) { break; case "min": $("#template-value, #template-max, span#matches_value").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-min, #template-example").show (); /* Show example */ @@ -1441,6 +1603,7 @@ if ($step == 2) { break; case "warning": $("#template-value, #template-max, span#matches_value, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-example").show (); /* Show example */ @@ -1448,6 +1611,7 @@ if ($step == 2) { break; case "critical": $("#template-value, #template-max, span#matches_value, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-example").show (); /* Show example */ @@ -1455,6 +1619,7 @@ if ($step == 2) { break; case "not_normal": $("#template-value, #template-max, span#matches_value, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-example").show (); /* Show example */ @@ -1462,6 +1627,7 @@ if ($step == 2) { break; case "onchange": $("#template-value, #template-max, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-example, span#matches_value").show (); /* Show example */ @@ -1472,6 +1638,7 @@ if ($step == 2) { break; case "unknown": $("#template-value, #template-max, span#matches_value, #template-min").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); $("#template-example").show (); if ($("#text-min_alerts").val() > 0 ) { @@ -1483,6 +1650,7 @@ if ($step == 2) { break; default: $("#template-value, #template-max, #template-min, #template-example, span#matches_value").hide (); + $("#template-math_function, #template-condition, #template-time_window").hide (); break; } diff --git a/pandora_console/include/functions_alerts.php b/pandora_console/include/functions_alerts.php index 8d51a3b536..fc28b59b6d 100644 --- a/pandora_console/include/functions_alerts.php +++ b/pandora_console/include/functions_alerts.php @@ -688,11 +688,67 @@ function alerts_get_alert_templates_types() $types['onchange'] = __('On Change'); $types['always'] = __('Always'); $types['not_normal'] = __('Not normal status'); + $types['complex'] = __('Complex alert'); return $types; } +/** + * Get matemathical functions for complex alert templates. + * + * @return array Mathematical function for complex templates. + */ +function alerts_get_alert_templates_functions() +{ + $functions = []; + + $functions['avg'] = __('Avg.'); + $functions['sum'] = __('Sum.'); + $functions['max'] = __('Max.'); + $functions['min'] = __('Min.'); + + return $functions; +} + + +/** + * Get conditions for complex alert templates. + * + * @return array Conditions for complex templates. + */ +function alerts_get_alert_templates_conditions() +{ + $conditions = []; + + $conditions['lower'] = __('<'); + $conditions['greater'] = __('>'); + $conditions['equal'] = __('='); + + return $conditions; +} + + +/** + * Get time windows for complex alert templates. + * + * @return array Windows for complex templates. + */ +function alerts_get_alert_templates_windows() +{ + $windows = []; + + $windows['thirty_days'] = __('Last 30 days'); + $windows['month'] = __('This month'); + $windows['seven_days'] = __('Last 7 days'); + $windows['week'] = __('This week'); + $windows['one_day'] = __('Last 24 hours'); + $windows['today'] = __('Today'); + + return $windows; +} + + /** * Get type name of an alert template. * diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 147ff1bb24..b8efa4b701 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -484,11 +484,14 @@ CREATE TABLE IF NOT EXISTS `talert_templates` ( `field18` TEXT, `field19` TEXT, `field20` TEXT, - `type` ENUM ('regex', 'max_min', 'max', 'min', 'equal', 'not_equal', 'warning', 'critical', 'onchange', 'unknown', 'always', 'not_normal'), + `type` ENUM ('regex', 'max_min', 'max', 'min', 'equal', 'not_equal', 'warning', 'critical', 'onchange', 'unknown', 'always', 'not_normal', 'complex'), `value` VARCHAR(255) DEFAULT '', `matches_value` TINYINT DEFAULT 0, `max_value` DOUBLE DEFAULT NULL, `min_value` DOUBLE DEFAULT NULL, + `time_window` ENUM ('thirty_days','this_month','seven_days','this_week','one_day','today'), + `math_function` ENUM ('avg', 'min', 'max', 'sum'), + `condition` ENUM ('lower', 'greater', 'equal'), `time_threshold` INT NOT NULL DEFAULT 0, `max_alerts` INT UNSIGNED NOT NULL DEFAULT 1, `min_alerts` INT UNSIGNED NOT NULL DEFAULT 0, diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm index f2c7d46143..e7ac485a1d 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -704,6 +704,49 @@ sub pandora_evaluate_alert ($$$$$$$;$$$$) { return $status if (valid_regex ($alert->{'value'}) == 1 && $data =~ m/$alert->{'value'}/i); } } + + if($alert-> {'type'} eq "complex") { + + my @allowed_functions = ("sum", "min", "max", "avg"); + my %condition_map = ( + lower => '<', + greater => '>', + equal => '==', + ); + my %time_windows_map = ( + thirty_days => sub { return time - 30 * 24 * 60 * 60 }, + this_month => sub { return timelocal(0, 0, 0, 1, (localtime)[4, 5]) }, + seven_days => sub { return time - 7 * 24 * 60 * 60 }, + this_week => sub { return time - ((localtime)[6] % 7) * 24 * 60 * 60 }, + one_day => sub { return time - 1 * 24 * 60 * 60 }, + today => sub { return timelocal(0, 0, 0, (localtime)[3, 4, 5]) }, + ); + + my $function = $alert-> {'math_function'}; + my $condition = $condition_map{$alert->{'condition'}}; + my $window = $time_windows_map{$alert->{'time_window'}}; + my $value = defined $alert->{'value'} && $alert->{'value'} ne "" ? $alert->{'value'} : 0; + + if((grep { $_ eq $function } @allowed_functions) == 1 && defined($condition) && defined($window)){ + + my $query = "SELECT IFNULL($function(datos), 0) AS $function + FROM tagente_datos + WHERE id_agente_modulo = ? AND utimestamp > ?"; + + my $historical_value = get_db_value($dbh, $query, $alert->{"id_agent_module"}, $window->()); + + my $activate_alert = 0; + if($function eq "avg"){ + # Check if the received value meets the condition compared to the avg. + $activate_alert = eval("$data $condition $historical_value"); + }else{ + # Check if the hiscorical value meets the condition compared to the val. + $activate_alert = eval("$historical_value $condition $value"); + } + # Return $status if the alert is not activated + return $status if !$activate_alert; + } + } return $status if ($last_status != 1 && $alert->{'type'} eq 'critical'); return $status if ($last_status != 2 && $alert->{'type'} eq 'warning'); @@ -736,7 +779,7 @@ sub pandora_evaluate_alert ($$$$$$$;$$$$) { if(defined ($agent)) { pandora_mark_agent_for_alert_update ($dbh, $agent->{'id_agente'}); } - + return 0; #Launch the alert }