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
}