Merge remote-tracking branch 'origin/develop' into ent-8130-ncm-fase-2

Conflicts:
	pandora_console/extras/mr/51.sql
This commit is contained in:
fbsanchez 2021-12-14 11:03:04 +01:00
commit f852df2f1c
53 changed files with 3325 additions and 651 deletions

View File

@ -1,5 +1,5 @@
package: pandorafms-agent-unix
Version: 7.0NG.758.1-211207
Version: 7.0NG.758.1-211214
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.758.1-211207"
pandora_version="7.0NG.758.1-211214"
echo "Test if you has the tools for to make the packages."
whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null

View File

@ -1015,7 +1015,7 @@ my $Sem = undef;
my $ThreadSem = undef;
use constant AGENT_VERSION => '7.0NG.758.1';
use constant AGENT_BUILD => '211207';
use constant AGENT_BUILD => '211214';
# Agent log default file size maximum and instances
use constant DEFAULT_MAX_LOG_SIZE => 600000;

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.758.1
%define release 211207
%define release 211214
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_agent_unix
%define version 7.0NG.758.1
%define release 211207
%define release 211214
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -10,7 +10,7 @@
# **********************************************************************
PI_VERSION="7.0NG.758.1"
PI_BUILD="211207"
PI_BUILD="211214"
OS_NAME=`uname -s`
FORCE=0

View File

@ -186,7 +186,7 @@ UpgradeApplicationID
{}
Version
{211207}
{211214}
ViewReadme
{Yes}

View File

@ -30,7 +30,7 @@ using namespace Pandora;
using namespace Pandora_Strutils;
#define PATH_SIZE _MAX_PATH+1
#define PANDORA_VERSION ("7.0NG.758.1 Build 211207")
#define PANDORA_VERSION ("7.0NG.758.1 Build 211214")
string pandora_path;
string pandora_dir;

View File

@ -11,7 +11,7 @@ BEGIN
VALUE "LegalCopyright", "Artica ST"
VALUE "OriginalFilename", "PandoraAgent.exe"
VALUE "ProductName", "Pandora FMS Windows Agent"
VALUE "ProductVersion", "(7.0NG.758.1(Build 211207))"
VALUE "ProductVersion", "(7.0NG.758.1(Build 211214))"
VALUE "FileVersion", "1.0.0.0"
END
END

View File

@ -1,5 +1,5 @@
package: pandorafms-console
Version: 7.0NG.758.1-211207
Version: 7.0NG.758.1-211214
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.758.1-211207"
pandora_version="7.0NG.758.1-211214"
package_pear=0
package_pandora=1

View File

@ -89,14 +89,13 @@ function agents_modules_load_js()
var controls = document.getElementById('vc-controls');
autoHideElement(controls, 1000);
$('select#refresh').change(function (event) {
refr = Number.parseInt(event.target.value, 10);
startCountDown(refr, false);
});
}
else {
var agentes_id = $("#id_agents2").val();
var id_agentes = getQueryParam("full_agents_id");
if (agentes_id === null && id_agentes !== null) {
@ -104,15 +103,15 @@ function agents_modules_load_js()
id_agentes.forEach(function(element) {
$("#id_agents2 option[value="+ element +"]").attr("selected",true);
});
selection_agent_module();
}
$('#refresh').change(function () {
$('#hidden-vc_refr').val($('#refresh option:selected').val());
});
}
$("#group_id").change (function () {
jQuery.post ("ajax.php",
{"page" : "operation/agentes/ver_agente",
@ -128,7 +127,6 @@ function agents_modules_load_js()
jQuery.each (data, function (id, value) {
// Remove keys_prefix from the index
id = id.substring(1);
option = $("<option></option>")
.attr ("value", value["id_agente"])
.html (value["alias"]);
@ -139,7 +137,7 @@ function agents_modules_load_js()
"json"
);
});
$("#checkbox-recursion").change (function () {
jQuery.post ("ajax.php",
{"page" : "operation/agentes/ver_agente",
@ -155,7 +153,6 @@ function agents_modules_load_js()
jQuery.each (data, function (id, value) {
// Remove keys_prefix from the index
id = id.substring(1);
option = $("<option></option>")
.attr ("value", value["id_agente"])
.html (value["alias"]);
@ -166,7 +163,7 @@ function agents_modules_load_js()
"json"
);
});
$("#modulegroup").change (function () {
jQuery.post ("ajax.php",
{"page" : "operation/agentes/ver_agente",
@ -180,8 +177,8 @@ function agents_modules_load_js()
if(data){
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
}
@ -207,8 +204,8 @@ function agents_modules_load_js()
if(data){
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
}
@ -231,11 +228,11 @@ function agents_modules_load_js()
if(data){
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
var id_modules = getQueryParam("full_modules_selected");
if(id_modules !== null) {
id_modules = id_modules.split(";");
@ -249,20 +246,19 @@ function agents_modules_load_js()
);
}
function getQueryParam (key) {
key = key.replace(/[[]/, '[');
key = key.replace(/[]]/, ']');
var pattern = "[?&]" + key + "=([^&#]*)";
function getQueryParam (key) {
key = key.replace(/[[]/, '[');
key = key.replace(/[]]/, ']');
var pattern = "[?&]" + key + "=([^&#]*)";
var regex = new RegExp(pattern);
var url = unescape(window.location.href);
var results = regex.exec(url);
if (results === null) {
return null;
} else {
return results[1];
}
if (results === null) {
return null;
} else {
return results[1];
}
}
</script>
<?php
}

View File

@ -8,7 +8,7 @@ ALTER TABLE `tlocal_component` ADD COLUMN `percentage_critical` tinyint(1) UNSIG
ALTER TABLE `tlocal_component` ADD COLUMN `percentage_warning` tinyint(1) UNSIGNED DEFAULT 0;
ALTER TABLE `tpolicy_modules` ADD COLUMN `percentage_warning` tinyint(1) UNSIGNED DEFAULT 0;
ALTER TABLE `tpolicy_modules` ADD COLUMN `percentage_critical` tinyint(1) UNSIGNED DEFAULT 0;
ALTER TABLE `tsync_queue` ADD COLUMN `result` TEXT;
ALTER TABLE tagente_modulo MODIFY debug_content TEXT;
CREATE TABLE IF NOT EXISTS `tncm_queue` (
@ -39,23 +39,30 @@ CREATE TABLE IF NOT EXISTS `tncm_firmware` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `talert_calendar` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL default '',
`id_group` INT(10) NOT NULL DEFAULT 0,
`description` text,
PRIMARY KEY (`id`),
UNIQUE (`name`)
`id_group` INT(10) NOT NULL DEFAULT 0,
`description` text,
PRIMARY KEY (`id`),
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tipam_network_location` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE (`name`)
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tipam_sites` (
`id` serial,
`name` varchar(100) UNIQUE NOT NULL default '',
`description` text,
`parent` bigint unsigned null,
PRIMARY KEY (`id`),
FOREIGN KEY (`parent`) REFERENCES `tipam_sites`(`id`) ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `tncm_agent` ADD COLUMN `cron_interval` varchar(100) default '' AFTER `execute`;
ALTER TABLE `tncm_agent` ADD COLUMN `event_on_change` int unsigned default null AFTER `cron_interval`;
ALTER TABLE `tipam_network` MODIFY `location` int(10) unsigned NULL;
ALTER TABLE `tipam_network` ADD FOREIGN KEY (`location`) REFERENCES `tipam_network_location`(`id`) ON DELETE CASCADE;
ALTER TABLE `tagent_repository` ADD COLUMN `deployment_timeout` INT UNSIGNED DEFAULT 600 AFTER `path`;
@ -63,6 +70,15 @@ ALTER TABLE `talert_special_days` ADD COLUMN `id_calendar` int(10) unsigned NOT
ALTER TABLE `talert_special_days` ADD COLUMN `day_code` tinyint(2) unsigned NOT NULL DEFAULT 0;
ALTER TABLE `talert_special_days` DROP COLUMN `same_day`;
ALTER TABLE `talert_special_days` ADD FOREIGN KEY (`id_calendar`) REFERENCES `talert_calendar`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `tipam_network` ADD COLUMN `id_site` bigint unsigned;
ALTER TABLE `tipam_network` ADD CONSTRAINT FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `tipam_supernet` ADD COLUMN `id_site` bigint unsigned;
ALTER TABLE `tipam_supernet` ADD CONSTRAINT FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `tipam_network` ADD COLUMN `vrf` int(10) unsigned;
ALTER TABLE `tipam_network` ADD CONSTRAINT FOREIGN KEY (`vrf`) REFERENCES `tagente`(`id_agente`) ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE `tncm_agent` ADD COLUMN `cron_interval` varchar(100) default '' AFTER `execute`;
ALTER TABLE `tncm_agent` ADD COLUMN `event_on_change` int unsigned default null AFTER `cron_interval`;
ALTER TABLE `tncm_vendor` ADD COLUMN `icon` VARCHAR(255) DEFAULT '';
ALTER TABLE `tevento` MODIFY COLUMN `event_type` ENUM('going_unknown','unknown','alert_fired','alert_recovered','alert_ceased','alert_manual_validation','recon_host_detected','system','error','new_agent','going_up_warning','going_up_critical','going_down_warning','going_down_normal','going_down_critical','going_up_normal', 'configuration_change', 'ncm') DEFAULT 'unknown';

View File

@ -3970,15 +3970,20 @@ CREATE TABLE IF NOT EXISTS `tipam_network` (
`network` varchar(100) NOT NULL default '',
`name_network` varchar(255) default '',
`description` text NOT NULL,
`location` tinytext NOT NULL,
`location` int(10) unsigned NULL,
`id_recon_task` int(10) unsigned NOT NULL,
`scan_interval` tinyint(2) default 1,
`monitoring` tinyint(2) default 0,
`id_group` mediumint(8) unsigned NULL default 0,
`lightweight_mode` tinyint(2) default 0,
`users_operator` text,
`id_site` bigint unsigned,
`vrf` int(10) unsigned,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_recon_task`) REFERENCES trecon_task(`id_rt`) ON DELETE CASCADE
FOREIGN KEY (`id_recon_task`) REFERENCES trecon_task(`id_rt`) ON DELETE CASCADE,
FOREIGN KEY (`location`) REFERENCES `tipam_network_location`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (`vrf`) REFERENCES `tagente`(`id_agente`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tipam_ip` (
@ -4033,7 +4038,9 @@ CREATE TABLE IF NOT EXISTS `tipam_supernet` (
`address` varchar(250) NOT NULL,
`mask` varchar(250) NOT NULL,
`subneting_mask` varchar(250) default '',
PRIMARY KEY (`id`)
`id_site` bigint unsigned,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tipam_supernet_network` (
@ -4052,10 +4059,16 @@ CREATE TABLE IF NOT EXISTS `tipam_network_location` (
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `tipam_sites` (
`id` serial,
`name` varchar(100) UNIQUE NOT NULL default '',
`description` text,
`parent` bigint unsigned null,
PRIMARY KEY (`id`),
FOREIGN KEY (`parent`) REFERENCES `tipam_sites`(`id`) ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT IGNORE INTO `tipam_network_location` (`name`) SELECT `location` FROM `tipam_network` WHERE `location` <> '';
UPDATE `tipam_network` INNER JOIN `tipam_network_location` ON tipam_network_location.name=tipam_network.location SET tipam_network.location=tipam_network_location.id;
ALTER TABLE `tipam_network` MODIFY `location` int(10) unsigned NULL;
ALTER TABLE `tipam_network` ADD FOREIGN KEY (`location`) REFERENCES `tipam_network_location`(`id`) ON DELETE CASCADE;
SET @insert_type = 3;
SET @insert_name = 'IPAM Recon';
@ -4089,6 +4102,7 @@ CREATE TABLE IF NOT EXISTS `tsync_queue` (
`operation` text,
`table` text,
`error` MEDIUMTEXT,
`result` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -1607,6 +1607,15 @@ if ($update_module || $create_module) {
);
}
if ($prediction_module === MODULE_PREDICTION_PLANNING) {
$custom_string_2 = get_parameter('estimation_type', 'estimation_calculation');
if ($custom_string_2 === 'estimation_calculation') {
$custom_string_1 = get_parameter('estimation_days', -1);
} else {
$custom_string_1 = get_parameter('estimation_interval', '300');
}
}
$active_snmp_v3 = get_parameter('active_snmp_v3');
/*
@ -1792,7 +1801,7 @@ if ($update_module) {
"Fail to try update module '".io_safe_output($name)."' for agent ".io_safe_output($agent['alias'])
);
} else {
if ($prediction_module == 3) {
if ($prediction_module == MODULE_PREDICTION_SYNTHETIC) {
enterprise_hook(
'modules_create_synthetic_operations',
[
@ -1937,7 +1946,7 @@ if ($create_module) {
}
}
if ($prediction_module == 3 && $serialize_ops == '') {
if ($prediction_module == MODULE_PREDICTION_SYNTHETIC && $serialize_ops == '') {
$id_agent_module = false;
} else {
$id_agent_module = modules_create_agent_module(
@ -1978,7 +1987,7 @@ if ($create_module) {
"Fail to try added module '".io_safe_output($name)."' for agent ".io_safe_output($agent['alias'])
);
} else {
if ($prediction_module == 3) {
if ($prediction_module == MODULE_PREDICTION_SYNTHETIC) {
enterprise_hook(
'modules_create_synthetic_operations',
[

View File

@ -14,6 +14,7 @@
enterprise_include_once('include/functions_policies.php');
enterprise_include_once('godmode/agentes/module_manager_editor_prediction.php');
require_once 'include/functions_agents.php';
ui_require_jquery_file('validate');
$disabledBecauseInPolicy = false;
$disabledTextBecauseInPolicy = '';
@ -36,9 +37,9 @@ if ($row !== false && is_array($row)) {
// Services are an Enterprise feature.
$custom_integer_1 = $row['custom_integer_1'];
switch ($prediction_module) {
switch ((int) $prediction_module) {
case MODULE_PREDICTION_SERVICE:
$is_service = true;
$selected = 'service_selected';
$custom_integer_2 = 0;
break;
@ -61,20 +62,33 @@ if ($row !== false && is_array($row)) {
if (isset($first_op[1]) && $first_op[1] == 'avg') {
$is_synthetic_avg = true;
$selected = 'synthetic_avg_selected';
} else {
$is_synthetic = true;
$selected = 'synthetic_selected';
}
$custom_integer_1 = 0;
$custom_integer_2 = 0;
break;
case MODULE_PREDICTION_TRENDING:
$selected = 'trending_selected';
$prediction_module = $custom_integer_1;
break;
case MODULE_PREDICTION_PLANNING:
$selected = 'capacity_planning';
$prediction_module = $custom_integer_1;
$estimation_interval = $custom_string_1;
$estimation_type = $custom_string_2;
break;
default:
$prediction_module = $custom_integer_1;
break;
}
} else {
$selected = 'capacity_planning';
$custom_integer_1 = 0;
}
@ -97,7 +111,7 @@ $data[0] = __('Source module');
$data[0] .= ui_print_help_icon('prediction_source_module', true);
$data[1] = '';
// Services and Synthetic are an Enterprise feature.
$module_service_synthetic_selector = enterprise_hook('get_module_service_synthetic_selector', [$is_service, $is_synthetic, $is_synthetic_avg]);
$module_service_synthetic_selector = enterprise_hook('get_module_service_synthetic_selector', [$selected]);
if ($module_service_synthetic_selector !== ENTERPRISE_NOT_HOOK) {
$data[1] = $module_service_synthetic_selector;
@ -112,16 +126,17 @@ $data[1] = '<div id="module_data" class="w50p float-left top-1em">';
$data[1] .= html_print_label(__('Agent'), 'agent_name', true).'<br/>';
// Get module and agent of the target prediction module
if (!empty($prediction_module)) {
if (empty($prediction_module) === false) {
$id_agente_clean = modules_get_agentmodule_agent($prediction_module);
$prediction_module_agent = modules_get_agentmodule_agent_name($prediction_module);
$agent_name_clean = $prediction_module_agent;
$agent_alias = agents_get_alias($id_agente_clean);
} else {
$id_agente_clean = $id_agente;
$agent_name_clean = $agent_name;
$id_agente_clean = 0;
$agent_name_clean = '';
$agent_alias = '';
}
$agent_alias = agents_get_alias($id_agente_clean);
$params = [];
$params['return'] = true;
@ -135,7 +150,8 @@ $params['use_hidden_input_idagent'] = true;
$params['hidden_input_idagent_id'] = 'hidden-id_agente_module_prediction';
$data[1] .= ui_print_agent_autocomplete_input($params);
$data[1] .= html_print_label(__('Module'), 'prediction_module', true);
$data[1] .= '<br />';
$data[1] .= html_print_label(__('Module'), 'prediction_module', true).'<br />';
if ($id_agente) {
$sql = 'SELECT id_agente_modulo, nombre
FROM tagente_modulo
@ -143,19 +159,23 @@ if ($id_agente) {
AND history_data = 1
AND id_agente = '.$id_agente_clean.'
AND id_agente_modulo <> '.$id_agente_modulo;
$data[1] .= html_print_select_from_sql(
$sql,
'prediction_module',
$prediction_module,
false,
__('Select Module'),
0,
true
$data[1] .= html_print_input(
[
'type' => 'select_from_sql',
'sql' => $sql,
'name' => 'prediction_module',
'selected' => $prediction_module,
'nothing' => __('Select Module'),
'nothing_value' => 0,
'return' => true,
]
);
} else {
$data[1] .= '<select id="prediction_module" name="custom_integer_1" disabled="disabled"><option value="0">Select an Agent first</option></select>';
}
$data[1] .= '<br />';
$data[1] .= html_print_label(__('Period'), 'custom_integer_2', true).'<br/>';
$periods[0] = __('Weekly');
@ -169,6 +189,56 @@ $data[1] .= '</div>';
$table_simple->colspan['prediction_module'][1] = 3;
push_table_simple($data, 'prediction_module');
$data = [];
$data[0] = '';
$data[1] .= html_print_label(__('Calculation type'), 'estimation_type', true).'<br/>';
$data[1] .= html_print_input(
[
'type' => 'select',
'return' => 'true',
'name' => 'estimation_type',
'class' => 'w250px',
'fields' => [
'estimation_absolute' => __('Estimated absolute value'),
'estimation_calculation' => __('Calculation of days to reach limit'),
],
'selected' => $estimation_type,
],
'div',
false
);
$data[1] .= '<div id="estimation_interval_row">';
$data[1] .= html_print_label(__('Future estimation'), 'estimation_interval', true).'<br/>';
$data[1] .= html_print_input(
[
'type' => 'interval',
'return' => 'true',
'name' => 'estimation_interval',
'value' => $estimation_interval,
],
'div',
false
);
$data[1] .= '</div>';
$data[1] .= '<div id="estimation_days_row">';
$data[1] .= html_print_label(__('Limit value'), 'estimation_days', true).'<br/>';
$data[1] .= html_print_input(
[
'type' => 'number',
'return' => 'true',
'id' => 'estimation_days',
'name' => 'estimation_days',
'value' => $estimation_interval,
]
);
$data[1] .= '</div>';
push_table_simple($data, 'capacity_planning');
// Services are an Enterprise feature.
$selector_form = enterprise_hook('get_selector_form', [$custom_integer_1]);
if ($selector_form !== ENTERPRISE_NOT_HOOK) {
@ -187,10 +257,20 @@ if ($synthetic_module_form !== ENTERPRISE_NOT_HOOK) {
$data[0] = '';
$data[1] = $synthetic_module_form;
$table_simple->colspan['synthetic_module'][1] = 3;
push_table_simple($data, 'synthetic_module');
}
$trending_module_form = enterprise_hook('get_trending_module_form', [$custom_string_1]);
if ($trending_module_form !== ENTERPRISE_NOT_HOOK) {
$data = [];
$data[0] = '';
$data[1] .= $trending_module_form;
push_table_simple($data, 'trending_module');
}
// Netflow modules are an Enterprise feature.
$netflow_module_form = enterprise_hook('get_netflow_module_form', [$custom_integer_1]);
if ($netflow_module_form !== ENTERPRISE_NOT_HOOK) {
@ -214,9 +294,7 @@ unset($table_advanced->data[3]);
enterprise_hook(
'setup_services_synth',
[
$is_service,
$is_synthetic,
$is_synthetic_avg,
$selected,
$is_netflow,
$ops,
]

View File

@ -136,10 +136,10 @@ $percentil = false;
$time_compare_overlapped = false;
// Added for events items.
$show_summary_group = false;
$show_summary_group = false;
$filter_event_severity = false;
$filter_event_type = false;
$filter_event_status = false;
$filter_event_type = false;
$filter_event_status = false;
$event_graph_by_agent = false;
$event_graph_by_user_validator = false;
$event_graph_by_criticity = false;
@ -175,6 +175,8 @@ $agent_max_value = true;
$agent_min_value = true;
$uncompressed_module = true;
$only_data = false;
// Users.
$id_users = [];
$users_groups = [];
@ -185,6 +187,16 @@ $nothing_value = 0;
$graph_render = (empty($config['type_mode_graph']) === true) ? 0 : $config['type_mode_graph'];
$valuesGroupBy = [0 => __('None')];
$valuesGroupByDefaultAlertActions = [
'agent' => __('Agent'),
'module' => __('Module'),
'group' => __('Group'),
];
if (is_metaconsole() === false) {
$valuesGroupByDefaultAlertActions['template'] = __('Template');
}
switch ($action) {
case 'new':
$actionParameter = 'save';
@ -733,21 +745,73 @@ switch ($action) {
case 'agent_module':
$description = $item['description'];
$es = json_decode($item['external_source'], true);
$id_agents = $es['id_agents'];
// Decode agents and modules.
$id_agents = json_decode(
io_safe_output(base64_decode($es['id_agents'])),
true
);
$module = json_decode(
io_safe_output(base64_decode($es['module'])),
true
);
$selection_a_m = get_parameter('selection');
$recursion = $item['recursion'];
if ((count($es['module']) == 1) && ($es['module'][0] == 0)) {
$module = '';
} else {
$module = $es['module'];
}
$group = $item['id_group'];
$modulegroup = $item['id_module_group'];
$idAgentModule = $module;
break;
case 'alert_report_actions':
$description = $item['description'];
$es = json_decode($item['external_source'], true);
// Decode agents and modules.
$id_agents = json_decode(
io_safe_output(base64_decode($es['id_agents'])),
true
);
$module = json_decode(
io_safe_output(base64_decode($es['module'])),
true
);
$selection_a_m = get_parameter('selection');
$recursion = $item['recursion'];
$group = $item['id_group'];
$modulegroup = $item['id_module_group'];
$idAgentModule = $module;
$alert_templates_selected = $es['templates'];
$alert_actions_selected = $es['actions'];
$show_summary = $es['show_summary'];
$group_by = $es['group_by'];
$only_data = $es['only_data'];
$period = $item['period'];
$lapse = $item['lapse'];
// Set values.
$valuesGroupBy = [
'agent' => __('Agent'),
'module' => __('Module'),
'group' => __('Group'),
];
if (is_metaconsole() === false) {
$valuesGroupBy['template'] = __('Template');
}
$lapse_calc = 1;
break;
case 'agents_inventory':
$description = $item['description'];
$es = json_decode($item['external_source'], true);
@ -1652,30 +1716,12 @@ $class = 'databox filters';
<td class="bolder"><?php echo __('Agents'); ?></td>
<td>
<?php
$all_agent_log = agents_get_agents(false, ['id_agente', 'alias']);
foreach ($all_agent_log as $key => $value) {
$agents2[$value['id_agente']] = $value['alias'];
}
if ((empty($agents2)) || $agents2 == -1) {
$agents = [];
}
$agents_select = [];
if (is_array($id_agents) || is_object($id_agents)) {
foreach ($id_agents as $id) {
foreach ($agents2 as $key => $a) {
if ($key == (int) $id) {
$agents_select[$key] = $key;
}
}
}
}
$all_agents = agents_get_agents_selected($group);
html_print_select(
$agents2,
$all_agents,
'id_agents2[]',
$agents_select,
$id_agents,
$script = '',
'',
0,
@ -1684,7 +1730,23 @@ $class = 'databox filters';
true,
'',
false,
'min-width: 180px'
'min-width: 500px; max-height: 100px',
false,
false,
false,
'',
false,
false,
false,
false,
true,
true,
true
);
html_print_input_hidden(
'id_agents2-multiple-text',
json_encode($agents_select)
);
?>
</td>
@ -1721,48 +1783,146 @@ $class = 'databox filters';
<td class="bolder"><?php echo __('Modules'); ?></td>
<td>
<?php
if (empty($id_agents) || $id_agents == null || $id_agents === 0) {
$all_modules = '';
if (empty($id_agents) === true) {
$all_modules = [];
$idAgentModule = [];
} else {
$all_modules = db_get_all_rows_sql(
'SELECT DISTINCT nombre FROM
tagente_modulo WHERE id_agente IN ('.implode(',', array_values($id_agents)).')'
$all_modules = get_modules_agents(
$modulegroup,
$id_agents,
!$selection_a_m,
true
);
}
if ((empty($all_modules)) || $all_modules == -1) {
$all_modules = [];
}
$modules_select = [];
$all_modules_structured = [];
if (is_array($idAgentModule) || is_object($idAgentModule)) {
foreach ($idAgentModule as $id) {
foreach ($all_modules as $key => $a) {
if ($a['id_agente_modulo'] == (int) $id) {
$modules_select[$a['id_agente_modulo']] = $a['id_agente_modulo'];
}
}
}
}
foreach ($all_modules as $a) {
$all_modules_structured[$a['id_agente_modulo']] = $a['nombre'];
}
html_print_select(
$all_modules_structured,
$all_modules,
'module[]',
$modules_select,
$idAgentModule,
$script = '',
__('None'),
'',
0,
false,
true,
true,
'',
false,
'min-width: 180px'
'min-width: 500px; max-width: 500px; max-height: 100px',
false,
false,
false,
'',
false,
false,
false,
false,
true,
true,
true
);
html_print_input_hidden(
'module-multiple-text',
json_encode($agents_select)
);
?>
</td>
</tr>
<tr id="row_alert_templates" class="datos">
<td class="bolder"><?php echo __('Templates'); ?></td>
<td>
<?php
$alert_templates = [];
$own_info = get_user_info($config['id_user']);
if ($own_info['is_admin']) {
$alert_templates = alerts_get_alert_templates(
false,
[
'id',
'name',
]
);
} else {
$usr_groups = users_get_groups($config['id_user'], 'LW', true);
$filter_groups = '';
$filter_groups = implode(',', array_keys($usr_groups));
$alert_templates = alerts_get_alert_templates(
['id_group IN ('.$filter_groups.')'],
[
'id',
'name',
]
);
}
$alert_templates = array_reduce(
$alert_templates,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
html_print_select(
$alert_templates,
'alert_templates[]',
$alert_templates_selected,
'',
'',
0,
false,
true,
true,
'',
false,
'min-width: 500px; max-height: 100px',
false,
false,
false,
'',
false,
false,
false,
false,
true,
true,
true
);
?>
</td>
</tr>
<tr id="row_alert_actions" class="datos">
<td class="bolder"><?php echo __('Actions'); ?></td>
<td>
<?php
$alert_actions = alerts_get_alert_actions(true);
html_print_select(
$alert_actions,
'alert_actions[]',
$alert_actions_selected,
'',
'',
0,
false,
true,
true,
'',
false,
'min-width: 500px; max-height: 100px',
false,
false,
false,
'',
false,
false,
false,
false,
true,
true,
true
);
?>
</td>
@ -2556,6 +2716,23 @@ $class = 'databox filters';
</td>
</tr>
<tr id="row_show_only_data" class="datos">
<td class="bolder">
<?php
echo __('Only data');
?>
</td>
<td>
<?php
html_print_checkbox_switch(
'only_data',
true,
$only_data
);
?>
</td>
</tr>
<tr id="row_event_severity" class="datos">
<td class="bolder"><?php echo __('Severity'); ?></td>
<td>
@ -2924,8 +3101,7 @@ $class = 'databox filters';
echo __('Time lapse intervals');
ui_print_help_tip(
__(
'Lapses of time in which the period is divided to make more precise calculations
'
'Lapses of time in which the period is divided to make more precise calculations'
)
);
?>
@ -2936,7 +3112,7 @@ $class = 'databox filters';
'lapse',
$lapse,
'',
'',
__('None'),
'0',
10,
'',
@ -3112,7 +3288,59 @@ $class = 'databox filters';
?>
</td>
</tr>
<tr id="row_show_summary" class="datos">
<td class="bolder">
<?php
echo __('Show Summary');
?>
</td>
<td>
<?php
html_print_checkbox_switch(
'show_summary',
true,
$show_summary
);
?>
</td>
</tr>
<tr id="row_group_by" class="datos">
<td class="bolder">
<?php
echo __('Group by');
?>
</td>
<td>
<?php
html_print_select(
$valuesGroupBy,
'group_by',
$group_by,
'',
'',
0,
false,
false,
false,
'',
false,
'',
false,
false,
false,
'',
false,
false,
false,
false,
true
);
?>
</td>
</tr>
<tr id="row_landscape" class="datos">
<td class="bolder">
<?php
@ -4256,12 +4484,12 @@ $(document).ready (function () {
// Load selected modules by default
$("#id_agents2").trigger('click');
$('#combo_server').change (function (){
$('#combo_server').change(function () {
$("#id_agents").html('');
$("#id_agents2").html('');
$("#module").html('');
$("#inventory_modules").html('');
})
$("#id_agents2").html('');
$("#module").html('');
$("#inventory_modules").html('');
});
$("#text-url").keyup (
function () {
@ -4277,7 +4505,6 @@ $(document).ready (function () {
$("#combo_group").change (
function () {
// Alert report group must show all matches when selecting All group
// ignoring 'recursion' option. #6497.
if ($("#combo_group").val() == 0) {
@ -4288,7 +4515,12 @@ $(document).ready (function () {
}
$("#id_agents2").html('');
// Check agent all.
$("#checkbox-id_agents2-check-all").prop('checked', false);
$("#module").html('');
// Check module all.
$("#checkbox-module-check-all").prop('checked', false);
$("#inventory_modules").html('');
jQuery.post ("ajax.php",
{"page" : "operation/agentes/ver_agente",
@ -4314,7 +4546,6 @@ $(document).ready (function () {
);
}
);
$("#combo_group").change();
$("#checkbox-recursion").change (
function () {
@ -4328,6 +4559,11 @@ $(document).ready (function () {
},
function (data, status) {
$("#id_agents2").html('');
// Check agent all.
$("#checkbox-id_agents2-check-all").prop('checked', false);
$("#module").html('');
// Check module all.
$("#checkbox-module-check-all").prop('checked', false);
jQuery.each (data, function (id, value) {
// Remove keys_prefix from the index
id = id.substring(1);
@ -4351,14 +4587,17 @@ $(document).ready (function () {
"get_modules_group_json" : 1,
"id_module_group" : this.value,
"id_agents" : $("#id_agents2").val(),
"selection" : $("#selection_agent_module").val()
"selection" : $("#selection_agent_module").val(),
"select_mode": 1
},
function (data, status) {
$("#module").html('');
// Check module all.
$("#checkbox-module-check-all").prop('checked', false);
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
},
@ -4372,17 +4611,20 @@ $(document).ready (function () {
jQuery.post ("ajax.php",
{"page" : "operation/agentes/ver_agente",
"get_modules_group_json" : 1,
"selection" : $("#selection_agent_module").val(),
"id_module_group" : $("#combo_modulegroup").val(),
"id_agents" : $("#id_agents2").val(),
"selection" : $("#selection_agent_module").val()
"select_mode": 1
},
function (data, status) {
$("#module").html('');
// Check module all.
$("#checkbox-module-check-all").prop('checked', false);
if(data){
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
}
@ -4399,15 +4641,18 @@ $(document).ready (function () {
"get_modules_group_json" : 1,
"id_module_group" : $("#combo_modulegroup").val(),
"id_agents" : $("#id_agents2").val(),
"selection" : $("#selection_agent_module").val()
"selection" : $("#selection_agent_module").val(),
"select_mode": 1
},
function (data, status) {
$("#module").html('');
// Check module all.
$("#checkbox-module-check-all").prop('checked', false);
if(data){
jQuery.each (data, function (id, value) {
option = $("<option></option>")
.attr ("value", value["id_agente_modulo"])
.html (value["nombre"]);
.attr ("value", id)
.html (value);
$("#module").append (option);
});
}
@ -4498,6 +4743,15 @@ $(document).ready (function () {
}
switch (type){
case 'agent_module':
case 'alert_report_actions':
var agents_multiple = $('#id_agents2').val();
var modules_multiple = $('#module').val();
$('#hidden-id_agents2-multiple-text').val(JSON.stringify(agents_multiple));
$('#hidden-module-multiple-text').val(JSON.stringify(modules_multiple));
$('#id_agents2').val('');
$('#module').val('');
break;
case 'alert_report_module':
case 'alert_report_agent':
case 'event_report_agent':
@ -4522,12 +4776,6 @@ $(document).ready (function () {
return false;
}
break;
case 'agent_module':
if ($("select#id_agents2>option:selected").val() == undefined) {
dialog_message('#message_no_agent');
return false;
}
break;
case 'inventory':
case 'inventory_changes':
if ($("select#id_agents>option:selected").val() == undefined) {
@ -4572,18 +4820,11 @@ $(document).ready (function () {
case 'sumatory':
case 'historical_data':
case 'increment':
if ($("#id_agent_module").val() == 0) {
dialog_message('#message_no_module');
return false;
}
break;
case 'agent_module':
if ($("select#module>option:selected").val() == undefined) {
dialog_message('#message_no_module');
return false;
}
break;
case 'inventory':
case 'inventory_changes':
if ($("select#inventory_modules>option:selected").val() == 0) {
@ -4636,6 +4877,15 @@ $(document).ready (function () {
return false;
}
switch (type){
case 'agent_module':
case 'alert_report_actions':
var agents_multiple = $('#id_agents2').val();
var modules_multiple = $('#module').val();
$('#hidden-id_agents2-multiple-text').val(JSON.stringify(agents_multiple));
$('#hidden-module-multiple-text').val(JSON.stringify(modules_multiple));
$('#id_agents2').val('');
$('#module').val('');
break;
case 'alert_report_module':
case 'alert_report_agent':
case 'event_report_agent':
@ -4660,12 +4910,6 @@ $(document).ready (function () {
return false;
}
break;
case 'agent_module':
if ($("select#id_agents2>option:selected").val() == undefined) {
dialog_message('#message_no_agent');
return false;
}
break;
case 'inventory':
if ($("select#id_agents>option:selected").val() == undefined) {
dialog_message('#message_no_agent');
@ -4705,18 +4949,11 @@ $(document).ready (function () {
case 'sumatory':
case 'historical_data':
case 'increment':
if ($("#id_agent_module").val() == 0) {
dialog_message('#message_no_module');
return false;
}
break;
case 'agent_module':
if ($("select#module>option:selected").val() == undefined) {
dialog_message('#message_no_module');
return false;
}
break;
case 'inventory':
if ($("select#inventory_modules>option:selected").val() == 0) {
dialog_message('#message_no_module');
@ -5489,6 +5726,7 @@ function addGeneralRow() {
}
function chooseType() {
var meta = '<?php echo (is_metaconsole() === true) ? 1 : 0; ?>';
type = $("#type").val();
$("#row_description").hide();
$("#row_label").hide();
@ -5542,6 +5780,8 @@ function chooseType() {
$('#row_hide_notinit_agents').hide();
$('#row_priority_mode').hide();
$("#row_module_group").hide();
$("#row_alert_templates").hide();
$("#row_alert_actions").hide();
$("#row_servers").hide();
$("#row_sort").hide();
$("#row_date").hide();
@ -5566,6 +5806,7 @@ function chooseType() {
$("#select_agent_modules").hide();
$("#modules_row").hide();
$("#row_show_summary_group").hide();
$("#row_show_only_data").hide();
$("#row_event_severity").hide();
$("#row_event_type").hide();
$("#row_event_status").hide();
@ -5590,6 +5831,8 @@ function chooseType() {
$("#row_network_filter").hide();
$("#row_alive_ip").hide();
$("#row_agent_not_assigned_to_ip").hide();
$("#row_show_summary").hide();
$("#row_group_by").hide();
// SLA list default state.
$("#sla_list").hide();
@ -5900,6 +6143,37 @@ function chooseType() {
$("#row_historical_db_check").hide();
break;
case 'alert_report_actions':
$("#row_description").show();
$("#row_group").show();
$("#select_agent_modules").show();
$("#agents_modules_row").show();
$("#modules_row").show();
if(meta == 0){
$("#row_alert_templates").show();
}
$("#row_alert_actions").show();
$("#row_period").show();
$("#row_lapse").show();
$("#row_show_summary").show();
$("#row_show_only_data").show();
$("#row_group_by").show();
if('<?php echo $action; ?>' === 'new'){
$("#group_by").html('');
var dataDefault = '<?php echo json_encode($valuesGroupByDefaultAlertActions); ?>';
Object.entries(JSON.parse(dataDefault)).forEach(function (item) {
option = $("<option></option>")
.attr ("value", item[0])
.html (item[1]);
$("#group_by").append(option);
});
$("#lapse_select").attr('disabled', false);
$("#lapse_select").val('0').trigger('change');
$("#hidden-lapse").val('0');
}
break;
case 'event_report_group':
$("#row_description").show();
$("#row_period").show();

View File

@ -1676,22 +1676,77 @@ switch ($action) {
break;
case 'agent_module':
$agents_to_report = get_parameter('id_agents2');
$modules_to_report = get_parameter(
'module',
''
$agents_to_report_text = get_parameter('id_agents2-multiple-text', '');
$modules_to_report_text = get_parameter('module-multiple-text', '');
// Decode json check modules.
$agents_to_report = json_decode(
io_safe_output($agents_to_report_text),
true
);
$modules_to_report = json_decode(
io_safe_output($modules_to_report_text),
true
);
$es['module'] = get_same_modules(
$es['module'] = get_same_modules_all(
$agents_to_report,
$modules_to_report
);
$es['id_agents'] = $agents_to_report;
// Encode json modules and agents.
$es['module'] = base64_encode(json_encode($es['module']));
$es['id_agents'] = base64_encode(json_encode($agents_to_report));
$values['external_source'] = json_encode($es);
$good_format = true;
break;
case 'alert_report_actions':
$alert_templates_to_report = get_parameter('alert_templates');
$alert_actions_to_report = get_parameter('alert_actions');
$show_summary = get_parameter('show_summary', 0);
$group_by = get_parameter('group_by');
$only_data = get_parameter('only_data', 0);
$agents_to_report_text = get_parameter('id_agents2-multiple-text');
$modules_to_report_text = get_parameter('module-multiple-text', '');
// Decode json check modules.
$agents_to_report = json_decode(
io_safe_output($agents_to_report_text),
true
);
$modules_to_report = json_decode(
io_safe_output($modules_to_report_text),
true
);
$es['module'] = get_same_modules_all(
$agents_to_report,
$modules_to_report
);
// Encode json modules and agents.
$es['module'] = base64_encode(json_encode($es['module']));
$es['id_agents'] = base64_encode(json_encode($agents_to_report));
$es['templates'] = $alert_templates_to_report;
$es['actions'] = $alert_actions_to_report;
$es['show_summary'] = $show_summary;
$es['group_by'] = $group_by;
$es['only_data'] = $only_data;
$values['external_source'] = json_encode($es);
$values['period'] = get_parameter('period');
$values['lapse_calc'] = get_parameter(
'lapse_calc'
);
$values['lapse'] = get_parameter('lapse');
$good_format = true;
break;
case 'inventory':
$values['period'] = 0;
$es['date'] = get_parameter('date');
@ -2422,22 +2477,78 @@ switch ($action) {
break;
case 'agent_module':
$agents_to_report = get_parameter('id_agents2');
$modules_to_report = get_parameter(
'module',
''
$agents_to_report_text = get_parameter('id_agents2-multiple-text');
$modules_to_report_text = get_parameter('module-multiple-text', '');
// Decode json check modules.
$agents_to_report = json_decode(
io_safe_output($agents_to_report_text),
true
);
$modules_to_report = json_decode(
io_safe_output($modules_to_report_text),
true
);
$es['module'] = get_same_modules(
$es['module'] = get_same_modules_all(
$agents_to_report,
$modules_to_report
);
$es['id_agents'] = $agents_to_report;
// Encode json modules and agents.
$es['module'] = base64_encode(json_encode($es['module']));
$es['id_agents'] = base64_encode(json_encode($agents_to_report));
$values['external_source'] = json_encode($es);
$good_format = true;
break;
case 'alert_report_actions':
$alert_templates_to_report = get_parameter('alert_templates');
$alert_actions_to_report = get_parameter('alert_actions');
$show_summary = get_parameter('show_summary', 0);
$group_by = get_parameter('group_by');
$only_data = get_parameter('only_data', 0);
$agents_to_report_text = get_parameter('id_agents2-multiple-text');
$modules_to_report_text = get_parameter('module-multiple-text', '');
// Decode json check modules.
$agents_to_report = json_decode(
io_safe_output($agents_to_report_text),
true
);
$modules_to_report = json_decode(
io_safe_output($modules_to_report_text),
true
);
$es['module'] = get_same_modules_all(
$agents_to_report,
$modules_to_report
);
// Encode json modules and agents.
$es['module'] = base64_encode(json_encode($es['module']));
$es['id_agents'] = base64_encode(json_encode($agents_to_report));
$es['templates'] = $alert_templates_to_report;
$es['actions'] = $alert_actions_to_report;
$es['show_summary'] = $show_summary;
$es['group_by'] = $group_by;
$es['only_data'] = $only_data;
$values['external_source'] = json_encode($es);
$values['period'] = get_parameter('period');
$values['lapse_calc'] = get_parameter(
'lapse_calc'
);
$values['lapse'] = get_parameter('lapse');
$good_format = true;
break;
case 'inventory_changes':
$values['period'] = get_parameter('period');
$es['id_agents'] = get_parameter('id_agents');

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -83,10 +83,10 @@ $in_process_event = get_parameter('in_process_event', 0);
$validate_event = get_parameter('validate_event', 0);
$delete_event = get_parameter('delete_event', 0);
$get_event_filters = get_parameter('get_event_filters', 0);
$get_comments = get_parameter('get_comments', 0);
$get_comments = (bool) get_parameter('get_comments', false);
$get_events_fired = (bool) get_parameter('get_events_fired');
$get_id_source_event = get_parameter('get_id_source_event');
if ($get_comments) {
if ($get_comments === true) {
$event = get_parameter('event', false);
$filter = get_parameter('filter', false);
@ -94,6 +94,8 @@ if ($get_comments) {
return __('Failed to retrieve comments');
}
$eventsGrouped = [];
if ($filter['group_rep'] == 1) {
$events = events_get_all(
['te.*'],
@ -119,23 +121,52 @@ if ($get_comments) {
// True for show comments of validated events.
true
);
if ($events !== false) {
$event = $events[0];
}
} else {
$events = events_get_event(
$event['id_evento'],
false,
$meta,
$history
);
// Consider if the event is grouped.
if (isset($event['event_rep']) === true && $event['event_rep'] > 0) {
// Evaluate if we are in metaconsole or not.
$eventTable = (is_metaconsole() === true) ? 'tmetaconsole_event' : 'tevento';
// Default grouped message filtering (evento and estado).
$whereGrouped = sprintf(
'`evento` = "%s" AND `estado` = "%s"',
io_safe_output($event['evento']),
$event['estado']
);
// If id_agente is reported, filter the messages by them as well.
if ((int) $event['id_agente'] > 0) {
$whereGrouped .= sprintf(' AND `id_agente` = "%s"', $event['id_agente']);
}
if ($events !== false) {
$event = $events;
// Get grouped comments.
$eventsGrouped = db_get_all_rows_sql(
sprintf(
'SELECT `user_comment`
FROM `%s`
WHERE %s',
$eventTable,
$whereGrouped
)
);
} else {
$events = events_get_event(
$event['id_evento'],
false,
is_metaconsole(),
$history
);
if ($events !== false) {
$event = $events;
}
}
}
echo events_page_comments($event, true);
// End of get_comments.
echo events_page_comments($event, true, $eventsGrouped);
return;
}
@ -1207,26 +1238,19 @@ if ($dialogue_event_response) {
}
}
if ($add_comment) {
$aviability_comment = true;
$comment = get_parameter('comment');
if ($add_comment === true) {
$comment = (string) get_parameter('comment');
$eventId = (int) get_parameter('event_id');
// Safe comments for hacks.
if (preg_match('/script/i', io_safe_output($comment))) {
$aviability_comment = false;
$return = false;
}
$event_id = get_parameter('event_id');
if ($aviability_comment !== false) {
$return = events_comment($event_id, $comment, 'Added comment', $meta, $history);
}
if ($return) {
echo 'comment_ok';
} else {
echo 'comment_error';
$return = events_comment($eventId, $comment, 'Added comment', $meta, $history);
}
echo ($return === true) ? 'comment_ok' : 'comment_error';
return;
}

View File

@ -20,7 +20,7 @@
/**
* Pandora build version and version
*/
$build_version = 'PC211207';
$build_version = 'PC211214';
$pandora_version = 'v7.0NG.758.1';
// Do not overwrite default timezone set if defined.

View File

@ -368,12 +368,15 @@ define('MODULE_WUX', 8);
define('MODULE_WIZARD', 9);
// Type of Modules of Prediction.
define('MODULE_PREDICTION_PLANNING', 1);
define('MODULE_PREDICTION_SERVICE', 2);
define('MODULE_PREDICTION_SYNTHETIC', 3);
define('MODULE_PREDICTION_NETFLOW', 4);
define('MODULE_PREDICTION_CLUSTER', 5);
define('MODULE_PREDICTION_CLUSTER_AA', 6);
define('MODULE_PREDICTION_CLUSTER_AP', 7);
define('MODULE_PREDICTION_TRENDING', 8);
// Forced agent OS ID for cluster agents.
define('CLUSTER_OS_ID', 100);

View File

@ -1295,57 +1295,6 @@ function mysql_db_get_all_row_by_steps_sql($new=true, &$result, $sql=null)
}
/**
* Starts a database transaction.
*/
function mysql_db_process_sql_begin()
{
global $config;
if ($config['mysqli']) {
mysqli_query($config['dbconnection'], 'SET AUTOCOMMIT = 0');
mysqli_query($config['dbconnection'], 'START TRANSACTION');
} else {
mysql_query('SET AUTOCOMMIT = 0');
mysql_query('START TRANSACTION');
}
}
/**
* Commits a database transaction.
*/
function mysql_db_process_sql_commit()
{
global $config;
if ($config['mysqli']) {
mysqli_query($config['dbconnection'], 'COMMIT');
mysqli_query($config['dbconnection'], 'SET AUTOCOMMIT = 1');
} else {
mysql_query('COMMIT');
mysql_query('SET AUTOCOMMIT = 1');
}
}
/**
* Rollbacks a database transaction.
*/
function mysql_db_process_sql_rollback()
{
global $config;
if ($config['mysqli']) {
mysqli_query($config['dbconnection'], 'ROLLBACK ');
mysqli_query($config['dbconnection'], 'SET AUTOCOMMIT = 1');
} else {
mysql_query('ROLLBACK ');
mysql_query('SET AUTOCOMMIT = 1');
}
}
/**
* Get last error.
*
@ -1441,7 +1390,7 @@ function mysql_db_process_file($path, $handle_error=true)
$query = '';
// Begin the transaction
mysql_db_process_sql_begin();
db_process_sql_begin();
foreach ($file_content as $sql_line) {
if (trim($sql_line) != '' && strpos($sql_line, '--') === false) {
@ -1456,7 +1405,7 @@ function mysql_db_process_file($path, $handle_error=true)
if (!$result = $query_result) {
// Error. Rollback the transaction
mysql_db_process_sql_rollback();
db_process_sql_rollback();
if ($config['mysqli']) {
$error_message = mysqli_error($config['dbconnection']);
@ -1493,7 +1442,7 @@ function mysql_db_process_file($path, $handle_error=true)
}
// No errors. Commit the transaction
mysql_db_process_sql_commit();
db_process_sql_commit();
return true;
} else {
return false;
@ -1532,7 +1481,7 @@ function db_run_sql_file($location)
$mysqli->query($config['dbconnection'], 'START TRANSACTION');
} else {
// Run commands
mysql_db_process_sql_begin();
db_process_sql_begin();
// Begin transaction
}
@ -1558,7 +1507,7 @@ function db_run_sql_file($location)
$mysqli->query($config['dbconnection'], 'COMMIT');
$mysqli->query($config['dbconnection'], 'SET AUTOCOMMIT = 1');
} else {
mysql_db_process_sql_commit();
db_process_sql_commit();
// Save results
}
@ -1568,7 +1517,7 @@ function db_run_sql_file($location)
$mysqli->query($config['dbconnection'], 'ROLLBACK ');
$mysqli->query($config['dbconnection'], 'SET AUTOCOMMIT = 1');
} else {
mysql_db_process_sql_rollback();
db_process_sql_rollback();
// Undo results
}

View File

@ -733,6 +733,63 @@ function agents_get_agents(
}
function agents_get_agents_selected($group)
{
if (is_metaconsole() === true) {
$all = agents_get_agents(
['id_grupo' => $group],
[
'id_tagente',
'id_tmetaconsole_setup',
'id_agente',
'alias',
],
'AR',
[
'field' => 'alias',
'order' => 'ASC',
],
false,
0,
true
);
$all = array_reduce(
$all,
function ($carry, $item) {
$carry[$item['id_tmetaconsole_setup'].'|'.$item['id_tagente']] = $item['alias'];
return $carry;
},
[]
);
} else {
$all = agents_get_agents(
['id_grupo' => $group],
[
'id_agente',
'alias',
],
'AR',
[
'field' => 'alias',
'order' => 'ASC',
]
);
$all = array_reduce(
$all,
function ($carry, $item) {
$carry[$item['id_agente']] = $item['alias'];
return $carry;
},
[]
);
}
return $all;
}
/**
* Get all the alerts of an agent, simple and combined.
*
@ -1649,6 +1706,85 @@ function agents_get_name($id_agent, $case='none')
}
/**
* Get the agents names of an agent.
*
* @param array $array_ids Agents ids.
*
* @return array Id => name.
*/
function agents_get_alias_array($array_ids)
{
if (is_array($array_ids) === false || empty($array_ids) === true) {
return [];
}
if ((bool) is_metaconsole() === true) {
$agents = array_reduce(
$array_ids,
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
$result = [];
foreach ($agents as $tserver => $id_agents) {
$sql = sprintf(
'SELECT id_tagente as id, alias as `name`
FROM tmetaconsole_agent
WHERE id_tagente IN (%s) AND id_tmetaconsole_setup = %d',
implode(',', $id_agents),
$tserver
);
$data_server = db_get_all_rows_sql($sql);
if ($data_server === false) {
$data_server = [];
}
$data_server = array_reduce(
$data_server,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
$result[$tserver] = $data_server;
}
} else {
$sql = sprintf(
'SELECT id_agente as id, alias as `name`
FROM tagente
WHERE id_agente IN (%s)',
implode(',', $array_ids)
);
$result = db_get_all_rows_sql($sql);
if ($result === false) {
$result = [];
}
$result = array_reduce(
$result,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
}
return $result;
}
/**
* Get alias of an agent (cached function).
*

View File

@ -2837,3 +2837,588 @@ function alerts_get_agent_modules(
return $agent_modules;
}
function alerts_get_actions_names($actions, $reduce=false)
{
$where = '';
if (empty($actions) === false) {
if (is_array($actions) === true) {
$where = sprintf(
'WHERE id IN (%s)',
implode(',', $actions)
);
} else {
$where = sprintf('WHERE id = %d', $actions);
}
}
$sql = sprintf(
'SELECT id, `name`
FROM talert_actions
%s',
$where
);
$result = db_get_all_rows_sql($sql);
if ($result === false) {
$result = [];
}
if ($reduce === true) {
$result = array_reduce(
$result,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
}
return $result;
}
/**
* Alert fired.
*
* @param array $filters Filters.
* @param array $groupsBy Groupby and lapse.
*
* @return array Result data.
*/
function alerts_get_alert_fired($filters=[], $groupsBy=[])
{
global $config;
$table = 'tevento';
if (is_metaconsole() === true) {
$table = 'tmetaconsole_event';
}
$filter_date = '';
if (isset($filters['period']) === true
&& empty($filters['period']) === false
) {
$filter_date = sprintf(
'AND %s.utimestamp > %d',
$table,
(time() - $filters['period'])
);
}
$filter_group = '';
if (isset($filters['group']) === true
&& empty($filters['group']) === false
) {
$filter_group = sprintf(
'AND %s.id_grupo = %d',
$table,
$filters['group']
);
}
$filter_agents = '';
if (isset($filters['agents']) === true
&& empty($filters['agents']) === false
) {
if (is_metaconsole() === true) {
$agents = array_reduce(
$filters['agents'],
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
$filter_agents .= ' AND ( ';
$i = 0;
foreach ($agents as $tserver => $agent) {
if ($i !== 0) {
$filter_agents .= ' OR ';
}
$filter_agents .= sprintf(
'( %s.id_agente IN (%s) AND %s.server_id = %d )',
$table,
implode(',', $agent),
$table,
(int) $tserver
);
$i++;
}
$filter_agents .= ' )';
} else {
$filter_agents = sprintf(
'AND %s.id_agente IN (%s)',
$table,
implode(',', $filters['agents'])
);
}
}
$filter_modules = '';
if (isset($filters['modules']) === true
&& empty($filters['modules']) === false
) {
if (is_metaconsole() === true) {
$modules = array_reduce(
$filters['modules'],
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
$filter_modules .= ' AND ( ';
$i = 0;
foreach ($modules as $tserver => $module) {
if ($i !== 0) {
$filter_modules .= ' OR ';
}
$filter_modules .= sprintf(
'( %s.id_agentmodule IN (%s) AND %s.server_id = %d )',
$table,
implode(',', $module),
$table,
(int) $tserver
);
$i++;
}
$filter_modules .= ' )';
} else {
$filter_modules = sprintf(
'AND %s.id_agentmodule IN (%s)',
$table,
implode(',', $filters['modules'])
);
}
}
$filter_templates = '';
if (isset($filters['templates']) === true
&& empty($filters['templates']) === false
) {
if (is_metaconsole() === false) {
$filter_templates = sprintf(
'AND talert_template_modules.id_alert_template IN (%s)',
implode(',', $filters['templates'])
);
}
}
$total = (bool) $filters['show_summary'];
$only_data = (bool) $filters['only_data'];
$actions_names = alerts_get_actions_names($filters['actions'], true);
$group_array = [];
$filter_actions = '';
$fields_actions = [];
if (isset($filters['actions']) === true
&& empty($filters['actions']) === false
) {
$filter_actions .= 'AND ( ';
$first = true;
foreach ($actions_names as $name_action) {
if ($first === false) {
$filter_actions .= ' OR ';
}
$filter_actions .= sprintf(
"JSON_CONTAINS(%s.custom_data, '\"%s\"', '\$.actions')",
$table,
io_safe_output($name_action)
);
$fields_actions[$name_action] = sprintf(
"SUM(JSON_CONTAINS(%s.custom_data, '\"%s\"', '\$.actions')) as '%s'",
$table,
io_safe_output($name_action),
io_safe_output($name_action)
);
$first = false;
}
$filter_actions .= ' ) ';
} else {
foreach ($actions_names as $name_action) {
$fields[] = sprintf(
"SUM(JSON_CONTAINS(%s.custom_data, '\"%s\"', '\$.actions')) as '%s'",
$table,
io_safe_output($name_action),
io_safe_output($name_action)
);
}
}
if (is_array($fields_actions) === true
&& empty($fields_actions) === false
) {
foreach ($fields_actions as $name => $field) {
$fields[] = $field;
}
}
$names_search = [];
$names_server = [];
if (isset($groupsBy['group_by']) === true) {
switch ($groupsBy['group_by']) {
case 'module':
$fields[] = $table.'.id_agentmodule as module';
$group_array[] = $table.'.id_agentmodule';
$names_search = modules_get_agentmodule_name_array(
array_values($filters['modules'])
);
if (is_metaconsole() === true) {
$fields[] = $table.'.server_id as server';
$group_array[] = $table.'.server_id';
$names_server = metaconsole_get_names();
}
break;
case 'template':
if (is_metaconsole() === false) {
$fields[] = 'talert_template_modules.id_alert_template as template';
$group_array[] = 'talert_template_modules.id_alert_template';
$names_search = alerts_get_templates_name_array(
array_values($filters['templates'])
);
}
break;
case 'agent':
$fields[] = $table.'.id_agente as agent';
$group_array[] = $table.'.id_agente';
$names_search = agents_get_alias_array(
array_values($filters['agents'])
);
if (is_metaconsole() === true) {
$fields[] = $table.'.server_id as server';
$group_array[] = $table.'.server_id';
$names_server = metaconsole_get_names();
}
break;
case 'group':
$fields[] = $table.'.id_grupo as `group`';
$group_array[] = $table.'.id_grupo';
$names_search = users_get_groups($config['user'], 'AR', false);
break;
default:
// Nothing.
break;
}
}
if (isset($groupsBy['lapse']) === true
&& empty($groupsBy['lapse']) === false
) {
$fields[] = sprintf(
'%s.utimestamp AS Period',
$table
);
$group_array[] = 'period';
}
$group_by = '';
if (is_array($group_array) === true && empty($group_array) === false) {
$group_by = sprintf(' GROUP BY %s', implode(", \n", $group_array));
}
$innerJoin = '';
if (is_metaconsole() === false) {
$innerJoin = sprintf(
'INNER JOIN talert_template_modules
ON talert_template_modules.id = %s.id_alert_am',
$table
);
}
$query = sprintf(
'SELECT
%s
FROM %s
%s
WHERE custom_data != ""
AND %s.event_type="alert_fired"
%s
%s
%s
%s
%s
%s
%s',
implode(", \n", $fields),
$table,
$innerJoin,
$table,
$filter_date,
$filter_group,
$filter_agents,
$filter_modules,
$filter_actions,
$filter_templates,
$group_by
);
$data_query = db_get_all_rows_sql($query);
if ($data_query === false) {
$data_query = [];
}
if (empty($data_query) === false) {
$data = array_reduce(
$data_query,
function ($carry, $item) use ($groupsBy) {
$period = (isset($item['Period']) === true) ? (int) $item['Period'] : 0;
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
$grby = $item[$groupsBy['group_by']];
$server = $item['server'];
unset($item['Period']);
unset($item[$groupsBy['group_by']]);
unset($item['server']);
$carry[$period][$server][$grby] = $item;
} else {
$grby = $item[$groupsBy['group_by']];
unset($item['Period']);
unset($item[$groupsBy['group_by']]);
$carry[$period][$grby] = $item;
}
return $carry;
},
[]
);
$intervals = [];
if (isset($groupsBy['lapse']) === true
&& empty($groupsBy['lapse']) === false
) {
$tend = time();
$tstart = ($tend - (int) $filters['period']);
for ($current_time = $tstart; $current_time < $tend; ($current_time += $groupsBy['lapse'])) {
$intervals[] = (int) $current_time;
}
}
$first_element = reset($data);
$first_element = reset($first_element);
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
$first_element = reset($first_element);
}
$clone = [];
foreach ($first_element as $key_clone => $value_clone) {
$clone[$key_clone] = 0;
}
$result = [];
if (empty($intervals) === true) {
foreach ($data as $period => $array_data) {
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
foreach ($names_search as $server => $names) {
foreach ($names as $id => $name) {
$name = $names_server[$server].' &raquo; '.$name;
if (isset($array_data[$server][$id]) === true) {
$result[$period][$server.'|'.$id] = $array_data[$server][$id];
$result[$period][$server.'|'.$id][$groupsBy['group_by']] = $name;
} else {
if ($only_data === false) {
$clone[$groupsBy['group_by']] = $name;
$result[$period][$server.'|'.$id] = $clone;
}
}
}
}
} else {
foreach ($names_search as $id => $name) {
if (isset($array_data[$id]) === true) {
$result[$period][$id] = $array_data[$id];
$result[$period][$id][$groupsBy['group_by']] = $name;
} else {
if ($only_data === false) {
$clone[$groupsBy['group_by']] = $name;
$result[$period][$id] = $clone;
}
}
}
}
}
} else {
$period_lapse = (int) $groupsBy['lapse'];
foreach ($intervals as $interval) {
$start_interval = $interval;
$end_interval = ($interval + $period_lapse);
if ($only_data === false) {
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
foreach ($names_search as $server => $names) {
foreach ($names as $id => $name) {
$result_name = $names_server[$server].' &raquo; '.$name;
$result[$start_interval][$server.'|'.$id] = $clone;
$result[$start_interval][$server.'|'.$id][$groupsBy['group_by']] = $result_name;
}
}
} else {
foreach ($names_search as $id => $name) {
$result[$start_interval][$id] = $clone;
$result[$start_interval][$id][$groupsBy['group_by']] = $name;
}
}
} else {
foreach ($data as $period => $array_data) {
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
foreach ($array_data as $server => $datas) {
foreach ($datas as $id_data => $value_data) {
$name = $names_server[$server].' &raquo; '.$names_search[$server][$id_data];
$result[$start_interval][$server.'|'.$id_data] = $clone;
$result[$start_interval][$server.'|'.$id_data][$groupsBy['group_by']] = $name;
}
}
} else {
foreach ($array_data as $id_data => $value_data) {
$name = $names_search[$id_data];
$result[$start_interval][$id_data] = $clone;
$result[$start_interval][$id_data][$groupsBy['group_by']] = $name;
}
}
}
}
foreach ($data as $period => $array_data) {
$period_time = (int) $period;
if ($start_interval < $period_time && $period_time <= $end_interval) {
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
foreach ($array_data as $server => $datas) {
foreach ($datas as $id_data => $value_data) {
foreach ($value_data as $key_data => $v) {
if ($key_data !== $groupsBy['group_by']) {
if (isset($result[$start_interval][$server.'|'.$id_data][$key_data])) {
$result[$start_interval][$server.'|'.$id_data][$key_data] += $v;
} else {
$result[$start_interval][$server.'|'.$id_data][$key_data] = $v;
}
}
}
}
}
} else {
foreach ($array_data as $id_data => $value_data) {
foreach ($value_data as $key_data => $v) {
if ($key_data !== $groupsBy['group_by']) {
if (isset($result[$start_interval][$id_data][$key_data])) {
$result[$start_interval][$id_data][$key_data] += $v;
} else {
$result[$start_interval][$id_data][$key_data] = $v;
}
}
}
}
}
unset($data[$period]);
}
}
}
}
}
$result['data'] = $result;
if ($total === true) {
$total_values = [];
foreach ($data_query as $key => $array_data) {
foreach ($array_data as $key_value => $v) {
$total_values[$key_value] = ($total_values[$key_value] + $v);
}
}
if (is_metaconsole() === true
&& ($groupsBy['group_by'] === 'agent'
|| $groupsBy['group_by'] === 'module')
) {
unset($total_values['server']);
}
unset($total_values['Period']);
$result['summary']['total'] = $total_values;
$result['summary']['total'][$groupsBy['group_by']] = __('Total');
}
return $result;
}
/**
* Get the templates names of an agent.
*
* @param array $array_ids Templates ids.
*
* @return array Id => name.
*/
function alerts_get_templates_name_array($array_ids)
{
if (is_array($array_ids) === false || empty($array_ids) === true) {
return [];
}
$sql = sprintf(
'SELECT id, `name`
FROM talert_templates
WHERE id IN (%s)',
implode(',', $array_ids)
);
$result = db_get_all_rows_sql($sql);
if ($result === false) {
$result = [];
}
$result = array_reduce(
$result,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
return $result;
}

View File

@ -1377,42 +1377,56 @@ function db_process_sql($sql, $rettype='affected_rows', $dbconnection='', $cache
break;
}
if ($rc !== false) {
if (enterprise_hook('is_metaconsole') === true
&& isset($config['centralized_management']) === true
&& (bool) $config['centralized_management'] === true
&& $dbconnection === ''
) {
$errors = null;
try {
// Synchronize changes to nodes if needed.
$sync = new Synchronizer();
if ($sync !== null) {
if ($sync->queue($sql) === false) {
// Launch events per failed query.
$errors = $sync->getLatestErrors();
if ($errors !== null) {
$errors = join(', ', $errors);
} else {
$errors = '';
}
}
}
} catch (\Exception $e) {
$errors = $e->getMessage();
}
if ($errors !== null) {
// TODO: Generate pandora event.
error_log($errors);
}
}
}
db_sync($dbconnection, $sql, $rc);
return $rc;
}
/**
* Propagate to nodes.
*
* @param mixed $dbconnection Dbconnection.
* @param mixed $sql Sql.
* @param mixed $rc Rc.
*
* @return void
*/
function db_sync($dbconnection, $sql, $rc)
{
global $config;
if (enterprise_hook('is_metaconsole') === true
&& isset($config['centralized_management']) === true
&& (bool) $config['centralized_management'] === true
&& $dbconnection === ''
) {
$errors = null;
try {
// Synchronize changes to nodes if needed.
$sync = new Synchronizer();
if ($sync !== null) {
if ($sync->queue($sql, $rc) === false) {
// Launch events per failed query.
$errors = $sync->getLatestErrors();
if ($errors !== null) {
$errors = join(', ', $errors);
} else {
$errors = '';
}
}
}
} catch (\Exception $e) {
$errors = $e->getMessage();
}
if ($errors !== null) {
// TODO: Generate pandora event.
error_log($errors);
}
}
}
/**
* Get all the rows in a table of the database.
*
@ -1808,20 +1822,20 @@ function db_process_sql_delete($table, $where, $where_join='AND')
function db_process_sql_begin()
{
global $config;
$null = null;
switch ($config['dbtype']) {
case 'mysql':
return mysql_db_process_sql_begin();
break;
case 'postgresql':
return postgresql_db_process_sql_begin();
break;
case 'oracle':
return oracle_db_process_sql_begin();
break;
default:
case 'mysql':
db_process_sql('SET AUTOCOMMIT = 0', 'affected_rows', '', false, $null, false);
db_process_sql('START TRANSACTION', 'affected_rows', '', false, $null, false);
break;
}
}
@ -1832,20 +1846,20 @@ function db_process_sql_begin()
function db_process_sql_commit()
{
global $config;
$null = null;
switch ($config['dbtype']) {
case 'mysql':
return mysql_db_process_sql_commit();
break;
case 'postgresql':
return postgresql_db_process_sql_commit();
break;
case 'oracle':
return oracle_db_process_sql_commit();
break;
default:
case 'mysql':
db_process_sql('COMMIT', 'affected_rows', '', false, $null, false);
db_process_sql('SET AUTOCOMMIT = 1', 'affected_rows', '', false, $null, false);
break;
}
}
@ -1856,20 +1870,20 @@ function db_process_sql_commit()
function db_process_sql_rollback()
{
global $config;
$null = null;
switch ($config['dbtype']) {
case 'mysql':
return mysql_db_process_sql_rollback();
break;
case 'postgresql':
return postgresql_db_process_sql_rollback();
break;
case 'oracle':
return oracle_db_process_sql_rollback();
break;
default:
case 'mysql':
db_process_sql('ROLLBACK', 'affected_rows', '', false, $null, false);
db_process_sql('SET AUTOCOMMIT = 1', 'affected_rows', '', false, $null, false);
break;
}
}
@ -1889,6 +1903,7 @@ function db_print_database_debug()
echo '<div class="database_debug_title">'.__('Database debug').'</div>';
$table = new stdClass();
$table->id = 'database_debug';
$table->cellpadding = '0';
$table->width = '95%';
@ -1946,18 +1961,15 @@ function db_get_last_error()
global $config;
switch ($config['dbtype']) {
case 'mysql':
return mysql_db_get_last_error();
break;
case 'postgresql':
return postgresql_db_get_last_error();
break;
case 'oracle':
return oracle_db_get_last_error();
break;
case 'mysql':
default:
return mysql_db_get_last_error();
}
}
@ -1975,18 +1987,15 @@ function db_get_type_field_table($table, $field)
global $config;
switch ($config['dbtype']) {
case 'mysql':
return mysql_db_get_type_field_table($table, $field);
break;
case 'postgresql':
return postgresql_db_get_type_field_table($table, $field);
break;
case 'oracle':
return oracle_db_get_type_field_table($table, $field);
break;
case 'mysql':
default:
return mysql_db_get_type_field_table($table, $field);
}
}

View File

@ -25,6 +25,8 @@
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
require_once $config['homedir'].'/include/functions_ui.php';
@ -35,7 +37,7 @@ enterprise_include_once('include/functions_metaconsole.php');
enterprise_include_once('meta/include/functions_events_meta.php');
enterprise_include_once('meta/include/functions_agents_meta.php');
enterprise_include_once('meta/include/functions_modules_meta.php');
if (is_metaconsole()) {
if (is_metaconsole() === true) {
$id_source_event = get_parameter('id_source_event');
}
@ -1619,14 +1621,14 @@ function events_get_events($filter=false, $fields=false)
*/
function events_get_event($id, $fields=false, $meta=false, $history=false)
{
if (empty($id)) {
if (empty($id) === true) {
return false;
}
global $config;
if (is_array($fields)) {
if (! in_array('id_grupo', $fields)) {
if (is_array($fields) === true) {
if (in_array('id_grupo', $fields) === false) {
$fields[] = 'id_grupo';
}
}
@ -1634,7 +1636,7 @@ function events_get_event($id, $fields=false, $meta=false, $history=false)
$table = events_get_events_table($meta, $history);
$event = db_get_row($table, 'id_evento', $id, $fields);
if (! check_acl($config['id_user'], $event['id_grupo'], 'ER')) {
if ((bool) check_acl($config['id_user'], $event['id_grupo'], 'ER') === false) {
return false;
}
@ -2255,7 +2257,7 @@ function events_comment(
// If comments are not stored in json, the format is old.
$event_comments_array = json_decode($event_comments[0]['user_comment']);
if (empty($event_comments_array)) {
if (empty($event_comments_array) === true) {
$comments_format = 'old';
} else {
$comments_format = 'new';
@ -2268,6 +2270,7 @@ function events_comment(
$comment_for_json['action'] = $action;
$comment_for_json['id_user'] = $config['id_user'];
$comment_for_json['utimestamp'] = time();
$comment_for_json['event_id'] = $first_event;
$event_comments_array[] = $comment_for_json;
@ -2282,11 +2285,11 @@ function events_comment(
break;
case 'old':
// Give old ugly format to comment. TODO: Change this method for
// aux table or json.
// Give old ugly format to comment.
// Change this method for aux table or json.
$comment = str_replace(["\r\n", "\r", "\n"], '<br>', $comment);
if ($comment != '') {
if ($comment !== '') {
$commentbox = '<div class="comment_box">'.io_safe_input($comment).'</div>';
} else {
$commentbox = '';
@ -5106,11 +5109,13 @@ function events_page_general($event)
/**
* Generate 'comments' page for event viewer.
*
* @param array $event Event.
* @param array $event Event.
* @param boolean $ajax If the query come from AJAX.
* @param boolean $grouped If the event must shown comments grouped.
*
* @return string HTML.
*/
function events_page_comments($event, $ajax=false)
function events_page_comments($event, $ajax=false, $groupedComments=[])
{
// Comments.
global $config;
@ -5121,23 +5126,53 @@ function events_page_comments($event, $ajax=false)
$table_comments->head = [];
$table_comments->class = 'table_modal_alternate';
$comments = ($event['user_comment'] ?? '');
$comments = (empty($groupedComments) === true) ? $event['user_comment'] : $groupedComments;
if (empty($comments)) {
if (empty($comments) === true) {
$table_comments->style[0] = 'text-align:center;';
$table_comments->colspan[0][0] = 2;
$data = [];
$data[0] = __('There are no comments');
$table_comments->data[] = $data;
} else {
if (is_array($comments)) {
if (is_array($comments) === true) {
$comments_array = [];
foreach ($comments as $comm) {
if (empty($comm)) {
if (empty($comm) === true) {
continue;
}
// If exists user_comments, come from grouped events and must be handled like this.
if (isset($comm['user_comment']) === true) {
$comm = $comm['user_comment'];
}
$comments_array[] = io_safe_output(json_decode($comm, true));
}
// Plain comments. Can be improved.
$sortedCommentsArray = [];
foreach ($comments_array as $comm) {
foreach ($comm as $subComm) {
$sortedCommentsArray[] = $subComm;
}
}
// Sorting the comments by utimestamp (newer is first).
usort(
$sortedCommentsArray,
function ($a, $b) {
if ($a['utimestamp'] == $b['utimestamp']) {
return 0;
}
return ($a['utimestamp'] > $b['utimestamp']) ? -1 : 1;
}
);
// Clean the unsorted comments and return it to the original array.
$comments_array = [];
$comments_array[] = $sortedCommentsArray;
} else {
$comments = str_replace(["\n", '&#x0a;'], '<br>', $comments);
// If comments are not stored in json, the format is old.
@ -5145,23 +5180,28 @@ function events_page_comments($event, $ajax=false)
}
foreach ($comments_array as $comm) {
// Show the comments more recent first.
if (is_array($comm)) {
$comm = array_reverse($comm);
}
if (empty($comm)) {
$comments_format = 'old';
} else {
$comments_format = 'new';
}
$comments_format = (empty($comm) === true) ? 'old' : 'new';
switch ($comments_format) {
case 'new':
foreach ($comm as $c) {
$data[0] = '<b>'.$c['action'].' by '.$c['id_user'].'</b>';
$data[0] .= '<br><br><i>'.date($config['date_format'], $c['utimestamp']).'</i>';
$eventIdExplanation = (empty($groupedComments) === false) ? sprintf(' (#%d)', $c['event_id']) : '';
$data[0] = sprintf(
'<b>%s %s %s%s</b>',
$c['action'],
__('by'),
$c['id_user'],
$eventIdExplanation
);
$data[0] .= sprintf(
'<br><br><i>%s</i>',
date($config['date_format'], $c['utimestamp'])
);
$data[1] = '<p class="break_word">'.stripslashes(str_replace(['\n', '\r'], '<br/>', $c['comment'])).'</p>';
$table_comments->data[] = $data;
}
break;
@ -5251,7 +5291,7 @@ function events_page_comments($event, $ajax=false)
);
}
if ($ajax) {
if ($ajax === true) {
return $comments_form.html_print_table($table_comments, true);
}

View File

@ -729,7 +729,8 @@ function html_print_select(
$required=false,
$truncate_size=false,
$select2_enable=true,
$multiple_select2=false
$select2_multiple_enable=false,
$select2_multiple_enable_all=false
) {
$output = "\n";
@ -791,6 +792,12 @@ function html_print_select(
$required = 'required';
}
if ($select2_multiple_enable === true
&& $select2_multiple_enable_all === true
) {
$output .= '<div class="flex-row-center">';
}
$output .= '<select '.$required.' onclick="'.$script.'" id="'.$id.'" name="'.$name.'"'.$attributes.' '.$styleText.'>';
if ($nothing !== false) {
@ -890,6 +897,24 @@ function html_print_select(
}
$output .= '</select>';
if ($select2_multiple_enable === true
&& $select2_multiple_enable_all === true
) {
$output .= '<div class="margin-left-2 flex-column">';
$output .= '<span>'.__('All').'</span>';
$output .= html_print_checkbox_switch(
$id.'-check-all',
1,
false,
true,
$disabled,
'checkMultipleAll('.$id.')'
);
$output .= '</div>';
$output .= '</div>';
}
if ($modal && !enterprise_installed()) {
$output .= "
<div id='".$message."' class='publienterprise publicenterprise_div' title='Community version'><img data-title='".__('Enterprise version not installed')."' class='img_help forced_title' data-use_title_for_force_title='1' src='images/alert_enterprise.png'></div>
@ -901,8 +926,7 @@ function html_print_select(
$select2 = 'select2_dark.min';
}
// Note that multiple_select2 is introduced as a workaround to overcome the pointless limitation of preventing "multiple" select inputs from using select2 library without affecting the existing calls to this function.
if ($multiple === false && $select2_enable === true || $multiple_select2 === true) {
if (($multiple === false || $select2_multiple_enable === true) && $select2_enable === true) {
if (is_ajax()) {
$output .= '<script src="';
$output .= ui_get_full_url(
@ -944,6 +968,32 @@ function html_print_select(
});';
}
if ($select2_multiple_enable === true
&& $select2_multiple_enable_all === true
) {
$output .= '$("#'.$id.'").on("change", function(e) {
var checked = false;
if(e.target.length !== $("#'.$id.' > option:selected").length) {
checked = false;
} else {
checked = true;
}
$("#checkbox-'.$id.'-check-all").prop("checked", checked);
});';
$output .= '$("#'.$id.'").trigger("change");';
$output .= 'function checkMultipleAll(id){
if ($("#checkbox-"+id.id+"-check-all").is(":checked")) {
$("#"+id.id+" > option").prop("selected", "selected");
$("#"+id.id).trigger("change");
} else {
$("#"+id.id).val(null).trigger("change");
}
}';
}
$output .= '</script>';
}

View File

@ -26,6 +26,8 @@
* ============================================================================
*/
use PandoraFMS\Enterprise\Metaconsole\Node;
// Begin.
require_once $config['homedir'].'/include/functions_agents.php';
require_once $config['homedir'].'/include/functions_users.php';
@ -1435,6 +1437,90 @@ function modules_get_agentmodule_name($id_agente_modulo)
}
/**
* Get the module names of an agent module.
*
* @param array $array_ids Agents module ids.
*
* @return array Id => name.
*/
function modules_get_agentmodule_name_array($array_ids)
{
if (is_array($array_ids) === false || empty($array_ids) === true) {
return [];
}
if ((bool) is_metaconsole() === true) {
$modules = array_reduce(
$array_ids,
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
$result = [];
foreach ($modules as $tserver => $id_modules) {
if (metaconsole_connect(null, $tserver) == NOERR) {
$result_modules = modules_get_agentmodule_name_array_data(
$id_modules
);
$result[$tserver] = $result_modules;
metaconsole_restore_db();
}
}
} else {
$result = modules_get_agentmodule_name_array_data(
$array_ids
);
}
return $result;
}
/**
* Data names.
*
* @param array $array_ids Ids.
*
* @return array
*/
function modules_get_agentmodule_name_array_data($array_ids)
{
if (is_array($array_ids) === false || empty($array_ids) === true) {
return [];
}
$sql = sprintf(
'SELECT id_agente_modulo as id, nombre as `name`
FROM tagente_modulo
WHERE id_agente_modulo IN (%s)',
implode(',', $array_ids)
);
$result = db_get_all_rows_sql($sql);
if ($result === false) {
$result = [];
}
$result = array_reduce(
$result,
function ($carry, $item) {
$carry[$item['id']] = $item['name'];
return $carry;
},
[]
);
return $result;
}
/**
* Get the module descripcion of an agent module.
*
@ -3469,32 +3555,271 @@ function modules_get_agentmodule_mininterval_no_async($id_agent)
}
function get_same_modules($agents, $modules)
function get_modules_agents($id_module_group, $id_agents, $selection, $select_mode=true)
{
$modules_to_report = [];
if ($modules != '') {
foreach ($modules as $m) {
$module_name = modules_get_agentmodule_name($m);
foreach ($agents as $a) {
$module_in_agent = db_get_value_filter(
'id_agente_modulo',
'tagente_modulo',
[
'id_agente' => $a,
'nombre' => $module_name,
]
);
if ($module_in_agent) {
$modules_to_report[] = $module_in_agent;
if ((bool) is_metaconsole() === true) {
if ($select_mode === true) {
$agents = array_reduce(
$id_agents,
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
} else {
if (count($id_agents) > 0) {
$rows = db_get_all_rows_sql(
sprintf(
'SELECT `id_agente`, `id_tagente`, `id_tmetaconsole_setup`
FROM `tmetaconsole_agent`
WHERE `id_agente` IN (%s)',
implode(',', $id_agents)
)
);
} else {
$rows = [];
}
$agents = array_reduce(
$rows,
function ($carry, $item) {
if ($carry[$item['id_tmetaconsole_setup']] === null) {
$carry[$item['id_tmetaconsole_setup']] = [];
}
$carry[$item['id_tmetaconsole_setup']][] = $item['id_tagente'];
return $carry;
},
[]
);
}
$modules = [];
foreach ($agents as $tserver => $id_agents) {
if (metaconsole_connect(null, $tserver) == NOERR) {
$modules[$tserver] = select_modules_for_agent_group(
$id_module_group,
$id_agents,
$selection,
false,
false,
true
);
metaconsole_restore_db();
}
}
if (!$selection) {
// Common modules.
$final_modules = [];
$nodes_consulted = count($modules);
foreach ($modules as $tserver => $mods) {
foreach ($mods as $module) {
if ($final_modules[$module['nombre']] === null) {
$final_modules[$module['nombre']] = 0;
}
$final_modules[$module['nombre']]++;
}
}
$modules = [];
foreach ($final_modules as $module_name => $occurrences) {
if ($occurrences === $nodes_consulted) {
// Module already present in ALL nodes.
$modules[] = [
'id_agente_modulo' => $module_name,
'nombre' => $module_name,
];
}
}
} else {
// All modules.
$return = [];
$nodes = [];
foreach ($agents as $tserver => $id_agents) {
try {
$nodes[$tserver] = new Node($tserver);
} catch (Exception $e) {
hd($e);
}
$return = array_reduce(
$modules[$tserver],
function ($carry, $item) use ($tserver, $nodes) {
$t = [];
foreach ($item as $k => $v) {
$t[$k] = $v;
}
$t['id_node'] = $tserver;
if ($nodes[$tserver] !== null) {
$t['nombre'] = io_safe_output(
$nodes[$tserver]->server_name().' &raquo; '.$t['nombre']
);
}
$carry[] = $t;
return $carry;
},
$return
);
}
$modules = $return;
}
$modules = array_reduce(
$modules,
function ($carry, $item) {
$carry[$item['id_node'].'|'.$item['id_agente_modulo']] = $item['nombre'];
return $carry;
},
[]
);
} else {
$modules = select_modules_for_agent_group(
$id_module_group,
$id_agents,
$selection,
false
);
}
$modules_to_report = array_merge($modules_to_report, $modules);
return $modules;
}
/**
* List all modules in agents selection.
*
* @param array $agents Agents ids array.
* @param array $modules Modules ids array.
*
* @return array
*/
function get_same_modules($agents, $modules)
{
if (is_array($agents) === false || empty($agents) === true) {
return [];
}
$name_modules = modules_get_agentmodule_name_array_data(
array_values($modules)
);
$sql = sprintf(
'SELECT id_agente_modulo as id,
nombre as `name`
FROM tagente_modulo
WHERE id_agente IN (%s)',
implode(',', array_values($agents))
);
$all = db_get_all_rows_sql($sql);
if ($all === false) {
$all = [];
}
$all = array_reduce(
$all,
function ($carry, $item) use ($name_modules) {
if (array_search($item['name'], $name_modules)) {
$carry[$item['id']] = $item['id'];
}
return $carry;
},
[]
);
$modules_to_report = array_merge($all, $modules);
$modules_to_report = array_unique($modules_to_report);
return $modules_to_report;
return $all;
}
/**
* List all modules in agents selection to metaconsole or node.
*
* @param array $agents Agents ids array.
* @param array $modules Modules ids array.
*
* @return array List modules [server|id_module, ...].
*/
function get_same_modules_all($agents, $modules, $select_mode=true)
{
if (is_array($agents) === false || empty($agents) === true) {
return [];
}
if (is_metaconsole() === true) {
$modules = array_reduce(
$modules,
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
if ($select_mode === true) {
$agents = array_reduce(
$agents,
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
}
);
} else {
$rows = db_get_all_rows_sql(
sprintf(
'SELECT `id_agente`, `id_tagente`, `id_tmetaconsole_setup`
FROM `tmetaconsole_agent`
WHERE `id_agente` IN (%s)',
implode(',', $agents)
)
);
$agents = array_reduce(
$rows,
function ($carry, $item) {
if ($carry[$item['id_tmetaconsole_setup']] === null) {
$carry[$item['id_tmetaconsole_setup']] = [];
}
$carry[$item['id_tmetaconsole_setup']][] = $item['id_tagente'];
return $carry;
},
[]
);
}
$result = [];
foreach ($agents as $tserver => $id_agents) {
if (metaconsole_connect(null, $tserver) == NOERR) {
$same_modules = get_same_modules($id_agents, $modules[$tserver]);
foreach ($same_modules as $id_module) {
$result[] = $tserver.'|'.$id_module;
}
metaconsole_restore_db();
}
}
} else {
$result = get_same_modules($agents, $modules);
}
return $result;
}

View File

@ -734,6 +734,13 @@ function reporting_make_reporting_data(
);
break;
case 'alert_report_actions':
$report['contents'][] = reporting_alert_report_actions(
$report,
$content
);
break;
case 'agents_inventory':
$report['contents'][] = reporting_agents_inventory(
$report,
@ -2666,15 +2673,119 @@ function reporting_inventory($report, $content, $type)
}
/**
* Build data for report alert actions.
*
* @param array $report Report info.
* @param array $content Content.
*
* @return array Result data.
*/
function reporting_alert_report_actions($report, $content)
{
$return = [];
$return['type'] = 'alert_report_actions';
if (empty($content['name']) === true) {
$content['name'] = __('Alert actions');
}
$return['title'] = io_safe_output($content['name']);
$return['landscape'] = $content['landscape'];
$return['pagebreak'] = $content['pagebreak'];
$return['subtitle'] = __('Actions');
$return['description'] = io_safe_output($content['description']);
$return['date'] = reporting_get_date_text($report, $content);
$return['data'] = [];
$es = json_decode($content['external_source'], true);
if (isset($report['id_template']) === true
&& empty($report['id_template']) === false
) {
if (is_metaconsole() === true) {
$server_id = metaconsole_get_id_server($content['server_name']);
$modules = [$server_id.'|'.$content['id_agent_module']];
$agents = [$server_id.'|'.$content['id_agent']];
} else {
$modules = [$content['id_agent_module']];
$agents = [$content['id_agent']];
}
} else {
$modules = json_decode(
io_safe_output(base64_decode($es['module'])),
true
);
$agents = json_decode(
io_safe_output(base64_decode($es['id_agents'])),
true
);
}
$period = $content['period'];
$id_group = $content['id_group'];
$templates = $es['templates'];
$actions = $es['actions'];
$show_summary = $es['show_summary'];
$group_by = $es['group_by'];
$lapse = $content['lapse'];
$only_data = $es['only_data'];
$filters = [
'group' => $id_group,
'agents' => $agents,
'modules' => $modules,
'templates' => $templates,
'actions' => $actions,
'period' => $period,
'show_summary' => (bool) $show_summary,
'only_data' => (bool) $only_data,
];
$groupsBy = [
'group_by' => $group_by,
'lapse' => $lapse,
];
$return['filters'] = $filters;
$return['groupsBy'] = $groupsBy;
$return['data'] = alerts_get_alert_fired($filters, $groupsBy);
return reporting_check_structure_content($return);
}
/**
* Data report agent/module.
*
* @param array $report Report info.
* @param array $content Content info.
*
* @return array Structure Content.
*/
function reporting_agent_module($report, $content)
{
global $config;
$agents_and_modules = json_decode($content['external_source'], true);
$agents = [];
$agents = $agents_and_modules['id_agents'];
$modules = $agents_and_modules['module'];
$id_group = $content['id_group'];
$id_module_group = $content['id_module_group'];
$external_source = json_decode(
$content['external_source'],
true
);
$agents = json_decode(
io_safe_output(
base64_decode($external_source['id_agents'])
),
true
);
$modules = json_decode(
io_safe_output(
base64_decode($external_source['module'])
),
true
);
$return['type'] = 'agent_module';
@ -2708,7 +2819,9 @@ function reporting_agent_module($report, $content)
$cont = 0;
foreach ($modules as $modul_id) {
$modules_by_name[$cont]['name'] = io_safe_output(modules_get_agentmodule_name($modul_id));
$modules_by_name[$cont]['name'] = io_safe_output(
modules_get_agentmodule_name($modul_id)
);
$modules_by_name[$cont]['id'] = $modul_id;
$cont++;
}

View File

@ -377,6 +377,10 @@ function reporting_html_print_report($report, $mini=false, $report_info=1)
reporting_html_agent_module($table, $item);
break;
case 'alert_report_actions':
reporting_html_alert_report_actions($table, $item);
break;
case 'agents_inventory':
reporting_html_agents_inventory($table, $item);
break;
@ -2733,6 +2737,101 @@ function reporting_html_group_configuration($table, $item, $pdf=0)
}
/**
* Html output report alert actions
*
* @param object $table Table.
* @param array $item Data for draw report.
* @param integer $pdf PDF output.
*
* @return string Html output.
*/
function reporting_html_alert_report_actions($table, $item, $pdf=0)
{
$data = $item['data'];
$groupsBy = $item['groupsBy'];
$output = '';
if (isset($data['data']) === true
&& empty($data['data']) === false
) {
foreach ($data['data'] as $period => $data_array) {
if (empty($period) === false) {
$output .= '<h1 class="h1-report-alert-actions">';
$output .= __('From').' ';
$output .= date(
'd-m-Y H:i:s',
$period
);
$output .= ' '.__('to').' ';
$output .= date('d-m-Y H:i:s', ($period + (int) $groupsBy['lapse']));
$output .= '</h1>';
}
$output .= get_alert_table($data_array);
}
if (isset($data['summary']) === true
&& empty($data['summary']) === false
) {
$output .= '<h1 class="h1-report-alert-actions">';
$output .= __('Total summary');
$output .= '</h1>';
$output .= get_alert_table($data['summary']);
}
} else {
$output .= ui_print_empty_data(
__('No alerts fired'),
'',
true
);
}
if ($pdf === 0) {
$table->colspan['alert_report_action']['cell'] = 3;
$table->cellstyle['alert_report_action']['cell'] = 'text-align: center;';
$table->data['alert_report_action']['cell'] = $output;
} else {
return $output;
}
}
/**
* Draw alert action table.
*
* @param array $data Data.
*
* @return string Html output.
*/
function get_alert_table($data)
{
$table = new StdCLass();
$table->width = '100%';
$table->data = [];
$table->head = [];
$table->headstyle = [];
$table->cellstyle = [];
$table->headstyle[0] = 'text-align:left;';
$head = reset($data);
foreach (array_reverse(array_keys($head)) as $name) {
$table->head[] = ucfirst($name);
}
foreach ($data as $key => $params) {
$table->cellstyle[$key][0] = 'text-align:left;';
foreach (array_reverse($params) as $name => $value) {
$table->data[$key][] = $value;
}
}
return html_print_table($table, true);
}
/**
* This type of report element will generate the interface graphs
* of all those devices that belong to the selected group.

View File

@ -834,6 +834,7 @@ function reports_get_report_types($template=false, $not_editor=false)
'optgroup' => __('Alerts'),
'name' => __('Agent alert report '),
];
if (!$template) {
$types['alert_report_group'] = [
'optgroup' => __('Alerts'),
@ -841,6 +842,11 @@ function reports_get_report_types($template=false, $not_editor=false)
];
}
$types['alert_report_actions'] = [
'optgroup' => __('Alerts'),
'name' => __('Actions alert report '),
];
$types['event_report_module'] = [
'optgroup' => __('Events'),
'name' => __('Module event report'),

View File

@ -329,7 +329,7 @@ function ui_print_message($message, $class='', $attributes='', $return=false, $t
if (!$no_close_bool) {
// Use the no_meta parameter because this image is only in
// the base console.
$output .= '<a href="javascript: close_info_box(\''.$id.'\')">'.html_print_image('images/blade.png', true, false, false, true).'</a>';
$output .= '<a href="javascript: close_info_box(\''.$id.'\')">'.html_print_image('images/blade.png', true, false, false, false).'</a>';
}
$output .= '</td>
@ -3460,6 +3460,11 @@ function ui_print_datatable(array $parameters)
}
}
$export_columns = '';
if ($parameters['csv_exclude_latest'] === true) {
$export_columns = ',columns: \'th:not(:last-child)\'';
}
$js .= '
if (dt_'.$table_id.'.page.info().pages > 1) {
$("#'.$table_id.'_wrapper > .dataTables_paginate.paging_simple_numbers").show()
@ -3490,8 +3495,7 @@ function ui_print_datatable(array $parameters)
order : "current",
page : "All",
search : "applied"
},
columns: [1,'.$columns.']
}'.$export_columns.'
}
}
],

View File

@ -576,7 +576,6 @@ function event_comment(current_event) {
return;
}
var event_id = event.id_evento;
var comment = $("#textarea_comment").val();
var meta = 0;
if ($("#hidden-meta").val() != undefined) {
@ -596,7 +595,11 @@ function event_comment(current_event) {
var params = [];
params.push("page=include/ajax/events");
params.push("add_comment=1");
params.push("event_id=" + event_id);
if (event.event_rep > 0) {
params.push("event_id=" + event.max_id_evento);
} else {
params.push("event_id=" + event.id_evento);
}
params.push("comment=" + comment);
params.push("meta=" + meta);
params.push("history=" + history);

View File

@ -43,6 +43,13 @@ abstract class Entity
*/
protected $existsInDB;
/**
* Fields to identify register.
*
* @var array
*/
protected $primaryKeys;
/**
* Entity fields (from table).
*
@ -152,6 +159,8 @@ abstract class Entity
if (is_array($filters) === true) {
// New one.
$this->primaryKeys = array_keys($filters);
$data = \db_get_row_filter(
$this->table,
$filters,
@ -318,8 +327,94 @@ abstract class Entity
* Saves current object definition to database.
*
* @return boolean Success or not.
* @throws \Exception On error.
*/
public abstract function save();
public function save()
{
$updates = $this->fields;
// Clean null fields.
foreach ($updates as $k => $v) {
if ($v === null) {
unset($updates[$k]);
}
}
if ($this->existsInDB === true) {
// Update.
$where = [];
foreach ($this->primaryKeys as $key) {
$where[$key] = $this->fields[$key];
}
if (empty($where) === true) {
throw new \Exception(
__METHOD__.' error: Cannot identify object'
);
}
$rs = \db_process_sql_update(
$this->table,
$updates,
$where
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
} else {
// New register.
$rs = \db_process_sql_insert(
$this->table,
$updates
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
$this->existsInDB = true;
}
return true;
}
/**
* Remove this entity.
*
* @return void
* @throws \Exception If no primary keys are defined.
*/
public function delete()
{
if ($this->existsInDB === true) {
$where = [];
foreach ($this->primaryKeys as $key) {
$where[$key] = $this->fields[$key];
}
if (empty($where) === true) {
throw new \Exception(
__METHOD__.' error: Cannot identify object on deletion'
);
}
\db_process_sql_delete(
$this->table,
$where
);
}
}
}

View File

@ -8392,3 +8392,41 @@ div.stat-win-spinner img {
#license_error_msg_dialog {
min-height: 350px !important;
}
.select2-container--default
.select2-selection--multiple
.select2-selection__rendered {
padding: 5px 10px 10px !important;
max-height: 120px;
overflow: auto !important;
}
.select2-container--default
.select2-selection--multiple
.select2-selection__choice {
background-color: #82b92e !important;
border: 1px solid #82b92e !important;
padding: 0.3em 0.6em !important;
color: #fff;
font-size: 1em;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
align-content: center;
}
.select2-container--default
.select2-selection--multiple
.select2-selection__choice__remove {
color: #fff !important;
font-size: 1.2em;
margin-right: 5px !important;
}
.h1-report-alert-actions {
text-transform: none;
text-align: left;
margin: 5px;
font-size: 12px;
}

View File

@ -129,7 +129,7 @@
<div style='height: 10px'>
<?php
$version = '7.0NG.758.1';
$build = '211207';
$build = '211214';
$banner = "v$version Build $build";
error_reporting(0);

View File

@ -192,126 +192,25 @@ if (is_ajax()) {
return;
}
if ($get_modules_group_json) {
if ($get_modules_group_json === true) {
$id_group = (int) get_parameter('id_module_group', 0);
$id_agents = get_parameter('id_agents', null);
$selection = get_parameter('selection');
$select_mode = (bool) get_parameter('select_mode', 0);
if ($id_agents === null) {
echo '[]';
return;
}
if ((bool) is_metaconsole() === true) {
if (count($id_agents) > 0) {
$rows = db_get_all_rows_sql(
sprintf(
'SELECT `id_agente`, `id_tagente`, `id_tmetaconsole_setup`
FROM `tmetaconsole_agent`
WHERE `id_agente` IN (%s)',
implode(',', $id_agents)
)
);
} else {
$rows = [];
}
$agents = array_reduce(
$rows,
function ($carry, $item) {
if ($carry[$item['id_tmetaconsole_setup']] === null) {
$carry[$item['id_tmetaconsole_setup']] = [];
}
$carry[$item['id_tmetaconsole_setup']][] = $item['id_tagente'];
return $carry;
},
[]
);
$modules = [];
foreach ($agents as $tserver => $id_agents) {
if (metaconsole_connect(null, $tserver) == NOERR) {
$modules[$tserver] = select_modules_for_agent_group(
$id_group,
$id_agents,
$selection,
false,
false,
true
);
metaconsole_restore_db();
}
}
if (!$selection) {
// Common modules.
$final_modules = [];
$nodes_consulted = count($modules);
foreach ($modules as $tserver => $mods) {
foreach ($mods as $module) {
if ($final_modules[$module['nombre']] === null) {
$final_modules[$module['nombre']] = 0;
}
$final_modules[$module['nombre']]++;
}
}
$modules = [];
foreach ($final_modules as $module_name => $occurrences) {
if ($occurrences === $nodes_consulted) {
// Module already present in ALL nodes.
$modules[] = [
'id_agente_modulo' => $module_name,
'nombre' => $module_name,
];
}
}
} else {
// All modules.
$return = [];
$nodes = [];
foreach ($agents as $tserver => $id_agents) {
try {
$nodes[$tserver] = new Node($tserver);
} catch (Exception $e) {
hd($e);
}
$return = array_reduce(
$modules[$tserver],
function ($carry, $item) use ($tserver, $nodes) {
$t = [];
foreach ($item as $k => $v) {
$t[$k] = $v;
}
$t['id_node'] = $tserver;
if ($nodes[$tserver] !== null) {
$t['nombre'] = io_safe_output(
$nodes[$tserver]->server_name().' &raquo; '.$t['nombre']
);
}
$carry[] = $t;
return $carry;
},
$return
);
}
$modules = $return;
}
echo json_encode($modules);
} else {
select_modules_for_agent_group($id_group, $id_agents, $selection);
}
$modules = get_modules_agents(
$id_group,
$id_agents,
$selection,
$select_mode
);
echo json_encode($modules);
return;
}
if ($filter_modules_group_json) {

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.758.1
%define release 211207
%define release 211214
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.758.1
%define release 211207
%define release 211214
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.758.1
%define release 211207
%define release 211214
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2

View File

@ -3959,6 +3959,18 @@ CREATE TABLE IF NOT EXISTS `tipam_network_location` (
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- Table `tipam_sites`
-- ----------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tipam_sites` (
`id` serial,
`name` varchar(100) UNIQUE NOT NULL default '',
`description` text,
`parent` bigint unsigned null,
PRIMARY KEY (`id`),
FOREIGN KEY (`parent`) REFERENCES `tipam_sites`(`id`) ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- Table `tipam_network`
-- ----------------------------------------------------------------------
@ -3974,9 +3986,13 @@ CREATE TABLE IF NOT EXISTS `tipam_network` (
`id_group` mediumint(8) unsigned NULL default 0,
`lightweight_mode` tinyint(2) default 0,
`users_operator` text,
`id_site` bigint unsigned,
`vrf` int(10) unsigned,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_recon_task`) REFERENCES trecon_task(`id_rt`) ON DELETE CASCADE,
FOREIGN KEY (`location`) REFERENCES `tipam_network_location`(`id`) ON DELETE CASCADE
FOREIGN KEY (`location`) REFERENCES `tipam_network_location`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (`vrf`) REFERENCES `tagente`(`id_agente`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
@ -4043,7 +4059,9 @@ CREATE TABLE IF NOT EXISTS `tipam_supernet` (
`address` varchar(250) NOT NULL,
`mask` varchar(250) NOT NULL,
`subneting_mask` varchar(250) default '',
PRIMARY KEY (`id`)
`id_site` bigint unsigned,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_site`) REFERENCES `tipam_sites`(`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
@ -4069,6 +4087,7 @@ CREATE TABLE IF NOT EXISTS `tsync_queue` (
`operation` text,
`table` text,
`error` MEDIUMTEXT,
`result` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -1,5 +1,5 @@
package: pandorafms-server
Version: 7.0NG.758.1-211207
Version: 7.0NG.758.1-211214
Architecture: all
Priority: optional
Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
pandora_version="7.0NG.758.1-211207"
pandora_version="7.0NG.758.1-211214"
package_cpan=0
package_pandora=1

View File

@ -46,7 +46,7 @@ our @EXPORT = qw(
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.758.1";
my $pandora_build = "211207";
my $pandora_build = "211214";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash

View File

@ -34,7 +34,7 @@ our @ISA = qw(Exporter);
# version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.758.1";
my $pandora_build = "211207";
my $pandora_build = "211214";
our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] );

View File

@ -26,7 +26,7 @@ use Thread::Semaphore;
use IO::Socket::INET;
use Net::Ping;
use POSIX qw(strftime);
use POSIX qw(floor strftime);
# Default lib dir for RPM and DEB packages
use lib '/usr/lib/perl5';
@ -35,6 +35,7 @@ use PandoraFMS::Tools;
use PandoraFMS::DB;
use PandoraFMS::Core;
use PandoraFMS::ProducerConsumerServer;
use PandoraFMS::Statistics::Regression;
#For debug
#use Data::Dumper;
@ -224,134 +225,136 @@ sub exec_prediction_module ($$$$) {
return;
}
# Get a full hash for target agent_module record reference ($target_module)
my $target_module = get_db_single_row ($dbh, 'SELECT * FROM tagente_modulo WHERE id_agente_modulo = ?', $agent_module->{'custom_integer_1'});
return unless defined $target_module;
# Prediction mode explanation
#
# 0 is for target type of generic_proc. It compares latest data with current data. Needs to get
# data on a "middle" interval, so if interval is 300, get data to compare with 150 before
# and 150 in the future. If current data is ABOVE or BELOW average +- typical_deviation
# this is a BAD value (0), if not is ok (1) and written in target module as is.
# more interval configured for this module, more "margin" has to compare data.
#
# 1 is for target type of generic_data. It get's data in the future, using the interval given in
# module. It gets average from current timestamp to INTERVAL in the future and gets average
# value. Typical deviation is not used here.
# 0 proc, 1 data
my $prediction_mode = ($agent_module->{'id_tipo_modulo'} == 2) ? 0 : 1;
# Initialize another global sub variables.
my $module_data = 0; # 0 data for default
# Get current timestamp
my $utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
# Get different data from each week one month ago (4 values)
# $agent_module->{'module_interval'} uses a margin of interval to get average data from the past
my @week_data;
my @week_utimestamp;
for (my $i=0; $i<4; $i++) {
$week_utimestamp[$i] = $utimestamp - (84600*7*($i+1));
# Adjust for proc prediction
if ($prediction_mode == 0) {
$week_utimestamp[$i] = $week_utimestamp[$i] - ($agent_module->{'module_interval'} / 2);
}
# Trend module.
if ($agent_module->{'prediction_module'} == 8) {
logger ($pa_config, "Executing trend module " . $agent_module->{'nombre'}, 10);
enterprise_hook ('exec_trend_module', [$pa_config, $agent_module, $server_id, $dbh]);
return;
}
# Let's calculate statistical average using past data
# n = total of real data values
my ($n, $average, $temp1) = (0, 0, 0);
for (my $i=0; $i < 4; $i++) {
my ($first_data, $last_data, $average_interval);
my $sum_data = 0;
$temp1 = $week_utimestamp[$i] + $agent_module->{'module_interval'};
# Get data for week $i in the past
$average_interval = get_db_value ($dbh, 'SELECT AVG(datos)
FROM tagente_datos
WHERE id_agente_modulo = ?
AND utimestamp > ?
AND utimestamp < ?', $target_module->{'id_agente_modulo'}, $week_utimestamp[$i], $temp1);
# Need to get data outside interval because no data.
if (!(defined($average_interval)) || ($average_interval == 0)) {
$last_data = get_db_value ($dbh, 'SELECT datos
FROM tagente_datos
WHERE id_agente_modulo = ?
AND utimestamp > ?
LIMIT 1', $target_module->{'id_agente_modulo'}, $week_utimestamp[$i]);
next unless defined ($last_data);
$first_data = get_db_value ($dbh, 'SELECT datos
FROM tagente_datos
WHERE id_agente_modulo = ?
AND utimestamp < ?
LIMIT 1', $target_module->{'id_agente_modulo'}, $temp1);
next unless defined ($first_data);
$sum_data++ if ($last_data != 0);
$sum_data++ if ($first_data != 0);
$week_data[$i] = ($sum_data > 0) ? (($last_data + $first_data) / $sum_data) : 0;
}
else {
$week_data[$i] = $average_interval;
}
# It's possible that one of the week_data[i] values was not valid (NULL)
# so recheck it and relay on n=0 for "no data" values set to 0 in result
# Calculate total ammount of valida data for each data sample
if ((is_numeric($week_data[$i])) && ($week_data[$i] > 0)) {
$n++;
# Average SUM
$average = $average + $week_data[$i];
}
# Capacity planning module.
exec_capacity_planning_module($pa_config, $agent_module, $server_id, $dbh);
}
########################################################################
# Execute a capacity planning module.
########################################################################
sub exec_capacity_planning_module($$$$) {
my ($pa_config, $module, $server_id, $dbh) = @_;
my $pred;
# Retrieve the target module.
my $target_module = get_db_single_row($dbh, 'SELECT * FROM tagente_modulo WHERE id_agente_modulo = ?', $module->{'custom_integer_1'});
if (!defined($target_module)) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Real average value
$average = ($n > 0) ? ($average / $n) : 0;
# (PROC) Compare with current data
if ($prediction_mode == 0) {
# Calculate typical deviation
my $typical_deviation = 0;
for (my $i=0; $i< $n; $i++) {
if ((is_numeric($week_data[$i])) && ($week_data[$i] > 0)) {
$typical_deviation = $typical_deviation + (($week_data[$i] - $average)**2);
# Set the period.
my $period;
# Weekly.
if ($module->{'custom_integer_2'} == 0) {
$period = 604800;
}
# Monthly.
elsif ($module->{'custom_integer_2'} == 1) {
$period = 2678400;
}
# Daily.
else {
$period = 86400;
}
# Set other parameters.
my $now = time();
my $from = $now - $period;
my $type = $module->{'custom_string_2'};
my $target_value = $module->{'custom_string_1'};
# Fit a line of the form: y = theta_0 + x * theta_1
my ($theta_0, $theta_1);
eval {
($theta_0, $theta_1) = linear_regression($target_module, $from, $now, $dbh);
};
if (!defined($theta_0) || !defined($theta_1)) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Predict the value.
if ($type eq 'estimation_absolute') {
# y = theta_0 + x * theta_1
$pred = $theta_0 + ($now + $target_value) * $theta_1;
}
# Predict the date.
else {
# Infinity.
if ($theta_1 == 0) {
$pred = -1;
} else {
# x = (y - theta_0) / theta_1
$pred = ($target_value - $theta_0) / $theta_1;
# Convert the prediction from a unix timestamp to days from now.
$pred = ($pred - $now) / 86400;
# We are not interested in past dates.
if ($pred < 0) {
$pred = -1;
}
}
$typical_deviation = ($n > 1) ? sqrt ($typical_deviation / ($n-1)) : 0;
my $current_value = get_db_value ($dbh, 'SELECT datos
FROM tagente_estado
WHERE id_agente_modulo = ?', $target_module->{'id_agente_modulo'});
if ( ($current_value > ($average - $typical_deviation)) && ($current_value < ($average + $typical_deviation)) ){
$module_data = 1; # OK !!
}
else {
$module_data = 0; # Out of predictions
}
}
else {
# Prediction based on data
$module_data = $average;
}
my %data = ("data" => $module_data);
pandora_process_module ($pa_config, \%data, '', $agent_module, '', $timestamp, $utimestamp, $server_id, $dbh);
my $agent_os_version = get_db_value ($dbh, 'SELECT os_version
FROM tagente
WHERE id_agente = ?', $agent_module->{'id_agente'});
# Update the module.
my %data = ("data" => $pred);
my $utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
pandora_process_module ($pa_config, \%data, '', $module, '', $timestamp, $utimestamp, $server_id, $dbh);
# Update the agent.
my $agent_os_version = get_db_value ($dbh, 'SELECT os_version FROM tagente WHERE id_agente = ?', $module->{'id_agente'});
if ($agent_os_version eq ''){
$agent_os_version = $pa_config->{'servername'}.'_Prediction';
}
pandora_update_agent ($pa_config, $timestamp, $agent_module->{'id_agente'}, undef, undef, -1, $dbh);
pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh);
}
########################################################################
# Perform linear regression on the given module.
########################################################################
sub linear_regression($$$$) {
my ($module, $from, $to, $dbh) = @_;
# Should not happen.
return if ($module->{'module_interval'} < 1);
# Retrieve the data.
my @rows = get_db_rows($dbh, 'SELECT datos, utimestamp FROM tagente_datos WHERE id_agente_modulo = ? AND utimestamp > ? AND utimestamp < ? ORDER BY utimestamp ASC', $module->{'id_agente_modulo'}, $from, $to);
return if scalar(@rows) <= 0;
# Perform linear regression on the data.
my $reg = PandoraFMS::Statistics::Regression->new( "linear regression", ["const", "x"] );
my $prev_utimestamp = $from;
foreach my $row (@rows) {
my ($utimestamp, $data) = ($row->{'utimestamp'}, $row->{'datos'});
# Elapsed time.
my $elapsed = $utimestamp - $prev_utimestamp;
$elapsed = 1 unless $elapsed > 0;
$prev_utimestamp = $utimestamp;
# Number of points (Pandora compresses data!)
my $local_count = floor($elapsed / $module->{'module_interval'});
$local_count = 1 if $local_count <= 0;
# Add the points.
for (my $i = 0; $i < $local_count; $i++) {
$reg->include($data, [1.0, $utimestamp]);
}
}
return $reg->theta();
}
1;

View File

@ -0,0 +1,776 @@
################################################################
# Statistics::Regression package included in Pandora FMS.
# See: https://metacpan.org/pod/Statistics::Regression
################################################################
package PandoraFMS::Statistics::Regression;
$VERSION = '0.53';
my $DATE = "2007/07/07";
my $MNAME= "$0::Statistics::Regression";
use strict;
use warnings FATAL => qw{ uninitialized };
use Carp;
################################################################
=pod
=head1 NAME
Regression.pm - weighted linear regression package (line+plane fitting)
=head1 SYNOPSIS
use Statistics::Regression;
# Create regression object
my $reg = Statistics::Regression->new( "sample regression", [ "const", "someX", "someY" ] );
# Add data points
$reg->include( 2.0, [ 1.0, 3.0, -1.0 ] );
$reg->include( 1.0, [ 1.0, 5.0, 2.0 ] );
$reg->include( 20.0, [ 1.0, 31.0, 0.0 ] );
$reg->include( 15.0, [ 1.0, 11.0, 2.0 ] );
or
my %d;
$d{const} = 1.0; $d{someX}= 5.0; $d{someY}= 2.0; $d{ignored}="anything else";
$reg->include( 3.0, \%d ); # names are picked off the Regression specification
Please note that *you* must provide the constant if you want one.
# Finally, print the result
$reg->print();
This prints the following:
****************************************************************
Regression 'sample regression'
****************************************************************
Name Theta StdErr T-stat
[0='const'] 0.2950 6.0512 0.05
[1='someX'] 0.6723 0.3278 2.05
[2='someY'] 1.0688 2.7954 0.38
R^2= 0.808, N= 4
****************************************************************
The hash input method has the advantage that you can now just
fill the observation hashes with all your variables, and use the
same code to run regression, changing the regression
specification at one and only one spot (the new() invokation).
You do not need to change the inputs in the include() statement.
For example,
my @obs; ## a global variable. observations are like: %oneobs= %{$obs[1]};
sub run_regression {
my $reg = Statistics::Regression->new( $_[0], $_[2] );
foreach my $obshashptr (@obs) { $reg->include( $_[1], $_[3] ); }
$reg->print();
}
run_regression("bivariate regression", $obshashptr->{someY}, [ "const", "someX" ] );
run_regression("trivariate regression", $obshashptr->{someY}, [ "const", "someX", "someZ" ] );
Of course, you can use the subroutines to do the printing work yourself:
my @theta = $reg->theta();
my @se = $reg->standarderrors();
my $rsq = $reg->rsq();
my $adjrsq = $reg->adjrsq();
my $ybar = $reg->ybar(); ## the average of the y vector
my $sst = $reg->sst(); ## the sum-squares-total
my $sigmasq= $reg->sigmasq(); ## the variance of the residual
my $k = $reg->k(); ## the number of variables
my $n = $reg->n(); ## the number of observations
In addition, there are some other helper routines, and a
subroutine linearcombination_variance(). If you don't know what
this is, don't use it.
=head1 BACKGROUND WARNING
You should have an understanding of OLS regressions if you want
to use this package. You can get this from an introductory
college econometrics class and/or from most intermediate college
statistics classes. If you do not have this background
knowledge, then this package will remain a mystery to you.
There is no support for this package--please don't expect any.
=head1 DESCRIPTION
Regression.pm is a multivariate linear regression package. That
is, it estimates the c coefficients for a line-fit of the type
y= c(0)*x(0) + c(1)*x1 + c(2)*x2 + ... + c(k)*xk
given a data set of N observations, each with k independent x
variables and one y variable. Naturally, N must be greater than
k---and preferably considerably greater. Any reasonable
undergraduate statistics book will explain what a regression is.
Most of the time, the user will provide a constant ('1') as x(0)
for each observation in order to allow the regression package to
fit an intercept.
=head1 ALGORITHM
=head2 Original Algorithm (ALGOL-60):
W. M. Gentleman, University of Waterloo, "Basic
Description For Large, Sparse Or Weighted Linear Least
Squares Problems (Algorithm AS 75)," Applied Statistics
(1974) Vol 23; No. 3
Gentleman's algorithm is I<the> statistical standard. Insertion
of a new observation can be done one observation at any time
(WITH A WEIGHT!), and still only takes a low quadratic time.
The storage space requirement is of quadratic order (in the
indep variables). A practically infinite number of observations
can easily be processed!
=head2 Internal Data Structures
R=Rbar is an upperright triangular matrix, kept in normalized
form with implicit 1's on the diagonal. D is a diagonal scaling
matrix. These correspond to "standard Regression usage" as
X' X = R' D R
A backsubsitution routine (in thetacov) allows to invert the R
matrix (the inverse is upper-right triangular, too!). Call this
matrix H, that is H=R^(-1).
(X' X)^(-1) = [(R' D^(1/2)') (D^(1/2) R)]^(-1)
= [ R^-1 D^(-1/2) ] [ R^-1 D^(-1/2) ]'
=head1 BUGS/PROBLEMS
None known.
=over 4
=item Perl Problem
Unfortunately, perl is unaware of IEEE number representations.
This makes it a pain to test whether an observation contains any
missing variables (coded as 'NaN' in Regression.pm).
=back
=for comment
pod2html -noindex -title "perl weighted least squares regression package" Regression.pm > Regression.html
=head1 VERSION and RECENT CHANGES
2007/04/04: Added Coefficient Standard Errors
2007/07/01: Added self-test use (if invoked as perl Regression.pm)
at the end. cleaned up some print sprintf.
changed syntax on new() to eliminate passing K.
2007/07/07: allowed passing hash with names to include().
=head1 AUTHOR
Naturally, Gentleman invented this algorithm. It was adaptated
by Ivo Welch. Alan Miller (alan\@dmsmelb.mel.dms.CSIRO.AU)
pointed out nicer ways to compute the R^2. Ivan Tubert-Brohman
helped wrap the module as as a standard CPAN distribution.
=head1 LICENSE
This module is released for free public use under a GPL license.
(C) Ivo Welch, 2001,2004, 2007.
=cut
################################################################
#### let's start with handling of missing data ("nan" or "NaN")
################################################################
use constant TINY => 1e-8;
my $nan= "NaN";
sub isNaN {
if ($_[0] !~ /[0-9nan]/) { confess "$MNAME:isNaN: definitely not a number in NaN: '$_[0]'"; }
return ($_[0]=~ /NaN/i) || ($_[0] != $_[0]);
}
################################################################
### my $reg = Statistics::Regression->new($regname, \@var_names)
###
### Receives the number of variables on each observations (i.e.,
### an integer) and returns the blessed data structure as a
### Statistics::Regression object. Also takes an optional name
### for this regression to remember, as well as a reference to a
### k*1 array of names for the X coefficients.
###
### I have now made it mandatory to give some names.
###
################################################################
sub new {
my $classname= shift; (!ref($classname)) or confess "$MNAME:new: bad class call to new ($classname).\n";
my $regname= shift || "no-name";
my $xnameptr= shift;
(defined($regname)) or confess "$MNAME:new: bad name in for regression. no undef allowed.\n";
(!ref($regname)) or confess "$MNAME:new: bad name in for regression.\n";
(defined($xnameptr)) or confess "$MNAME:new: You must provide variable names, because this tells me the number of columns. no undef allowed.\n";
(ref($xnameptr) eq "ARRAY") or confess "$MNAME:new: bad xnames for regression. Must be pointer.\n";
my $K= (@{$xnameptr});
if (!defined($K)) { confess "$MNAME:new: cannot determine the number of variables"; }
if ($K<=1) { confess "$MNAME:new: Cannot run a regression without at least two variables."; }
sub zerovec {
my @rv;
for (my $i=0; $i<=$_[0]; ++$i) { $rv[$i]=0; }
return \@rv;
}
bless {
k => $K,
regname => $regname,
xnames => $xnameptr,
# constantly updated
n => 0,
sse => 0,
syy => 0,
sy => 0,
wghtn => 0,
d => zerovec($K),
thetabar => zerovec($K),
rbarsize => ($K+1)*$K/2+1,
rbar => zerovec(($K+1)*$K/2+1),
# other constants
neverabort => 0,
# computed on demand
theta => undef,
sigmasq => undef,
rsq => undef,
adjrsq => undef
}, $classname;
}
################################################################
### $reg->include( $y, [ $x1, $x2, $x3 ... $xk ], $weight );
###
### Add one new observation. The weight is optional. Note that
### inclusion with a weight of -1 can be used to delete an
### observation.
###
### The error checking and transfer of arguments is clutzy, but
### works. if I had POSIX assured, I could do better number
### checking. right now, I don't do any.
###
### Returns the number of observations so far included.
################################################################
sub include {
my $this = shift;
my $yelement= shift;
my $xin= shift;
my $weight= shift || 1.0;
# modest input checking;
(ref($this)) or confess "$MNAME:include: bad class call to include.\n";
(defined($yelement)) or confess "$MNAME:include: bad call for y to include. no undef allowed.\n";
(!ref($yelement)) or confess "$MNAME:include: bad call for y to include. need scalar.\n";
(defined($xin)) or confess "$MNAME:include: bad call for x to include. no undef allowed.\n";
(ref($xin)) or confess "$MNAME:include: bad call for x to include. need reference.\n";
(!ref($weight)) or confess "$MNAME:include: bad call for weight to include. need scalar.\n";
# omit observations with missing observations;
(defined($yelement)) or confess "$MNAME:include: you must give a y value (predictor).";
(isNaN($yelement)) and return $this->{n}; # ignore this observation;
## should check for number, not string
# check and transfer the X vector
my @xrow;
if (ref($xin) eq "ARRAY") { @xrow= @{$xin}; }
else {
my $xctr=0;
foreach my $nm (@{$this->{xnames}}) {
(defined($xin->{$nm})) or confess "$MNAME:include: Variable '$nm' needs to be set in hash.\n";
$xrow[$xctr]= $xin->{$nm};
++$xctr;
}
}
my @xcopy;
for (my $i=1; $i<=$this->{k}; ++$i) {
(defined($xrow[$i-1]))
or confess "$MNAME:include: Internal Error: at N=".($this->{n}).", the x[".($i-1)."] is undef. use NaN for missing.";
(isNaN($xrow[$i-1])) and return $this->{n};
$xcopy[$i]= $xrow[$i-1];
## should check for number, not string
}
################ now comes the real routine
$this->{syy}+= ($weight*($yelement*$yelement));
$this->{sy}+= ($weight*($yelement));
if ($weight>=0.0) { ++$this->{n}; } else { --$this->{n}; }
$this->{wghtn}+= $weight;
for (my $i=1; $i<=$this->{k};++$i) {
if ($weight==0.0) { return $this->{n}; }
if (abs($xcopy[$i])>(TINY)) {
my $xi=$xcopy[$i];
my $di=$this->{d}->[$i];
my $dprimei=$di+$weight*($xi*$xi);
my $cbar= $di/$dprimei;
my $sbar= $weight*$xi/$dprimei;
$weight*=($cbar);
$this->{d}->[$i]=$dprimei;
my $nextr=int( (($i-1)*( (2.0*$this->{k}-$i))/2.0+1) );
if (!($nextr<=$this->{rbarsize}) ) { confess "$MNAME:include: Internal Error 2"; }
my $xk;
for (my $kc=$i+1;$kc<=$this->{k};++$kc) {
$xk=$xcopy[$kc]; $xcopy[$kc]=$xk-$xi*$this->{rbar}->[$nextr];
$this->{rbar}->[$nextr]= $cbar * $this->{rbar}->[$nextr]+$sbar*$xk;
++$nextr;
}
$xk=$yelement; $yelement-= $xi*$this->{thetabar}->[$i];
$this->{thetabar}->[$i]= $cbar*$this->{thetabar}->[$i]+$sbar*$xk;
}
}
$this->{sse}+=$weight*($yelement*$yelement);
# indicate that Theta is garbage now
$this->{theta}= undef;
$this->{sigmasq}= undef; $this->{rsq}= undef; $this->{adjrsq}= undef;
return $this->{n};
}
################################################################
###
### $reg->rsq(), $reg->adjrsq(), $reg->sigmasq(), $reg->ybar(),
### $reg->sst(), $reg->k(), $reg->n()
###
### These methods provide common auxiliary information. rsq,
### adjrsq, sigmasq, sst, and ybar have not been checked but are
### likely correct. The results are stored for later usage,
### although this is somewhat unnecessary because the
### computation is so simple anyway.
################################################################
sub rsq {
my $this= shift;
return $this->{rsq}= 1.0- $this->{sse} / $this->sst();
}
sub adjrsq {
my $this= shift;
return $this->{adjrsq}= 1.0- (1.0- $this->rsq())*($this->{n}-1)/($this->{n} - $this->{k});
}
sub sigmasq {
my $this= shift;
return $this->{sigmasq}= ($this->{n}<=$this->{k}) ? "Inf" : ($this->{sse}/($this->{n} - $this->{k}));
}
sub ybar {
my $this= shift;
return $this->{ybar}= $this->{sy}/$this->{wghtn};
}
sub sst {
my $this= shift;
return $this->{sst}= ($this->{syy} - $this->{wghtn}*($this->ybar())**2);
}
sub k {
my $this= shift;
return $this->{k};
}
sub n {
my $this= shift;
return $this->{n};
}
################################################################
### $reg->print() [no arguments!]
###
### prints the estimated coefficients, and R^2 and N. For an
### example see the Synopsis.
################################################################
sub print {
my $this= shift;
print "****************************************************************\n";
print "Regression '$this->{regname}'\n";
print "****************************************************************\n";
my $theta= $this->theta();
my @standarderrors= $this->standarderrors();
printf "%-15s\t%12s\t%12s\t%7s\n", "Name", "Theta", "StdErr", "T-stat";
for (my $i=0; $i< $this->k(); ++$i) {
my $name= "[$i".(defined($this->{xnames}->[$i]) ? "='$this->{xnames}->[$i]'":"")."]";
printf "%-15s\t", $name;
printf "%12.4f\t", $theta->[$i];
printf "%12.4f\t", $standarderrors[$i];
printf "%7.2f", ($theta->[$i]/$standarderrors[$i]);
printf "\n";
}
print "\nR^2= ".sprintf("%.3f", $this->rsq()).", N= ".$this->n().", K= ".$this->k()."\n";
print "****************************************************************\n";
}
################################################################
### $theta = $reg->theta or @theta = $reg->theta
###
### This is the work horse. It estimates and returns the vector
### of coefficients. In scalar context returns an array
### reference; in list context it returns the list of
### coefficients.
################################################################
sub theta {
my $this= shift;
if (defined($this->{theta})) {
return wantarray ? @{$this->{theta}} : $this->{theta};
}
if ($this->{n} < $this->{k}) { return; }
for (my $i=($this->{k}); $i>=1; --$i) {
$this->{theta}->[$i]= $this->{thetabar}->[$i];
my $nextr= int (($i-1)*((2.0*$this->{k}-$i))/2.0+1);
if (!($nextr<=$this->{rbarsize})) { confess "$MNAME:theta: Internal Error 3"; }
for (my $kc=$i+1;$kc<=$this->{k};++$kc) {
$this->{theta}->[$i]-=($this->{rbar}->[$nextr]*$this->{theta}->[$kc]);
++$nextr;
}
}
my $ref = $this->{theta}; shift(@$ref); # we are counting from 0
# if in a scalar context, otherwise please return the array directly
wantarray ? @{$this->{theta}} : $this->{theta};
}
################################################################
### @se= $reg->standarderrors()
###
### This is the most difficult routine. Take it on faith.
###
### R=Rbar is an upperright triangular matrix, kept in normalized
### form with implicit 1's on the diagonal. D is a diagonal scaling
### matrix. These correspond to "standard Regression usage" as
###
### X' X = R' D R
###
### A backsubsitution routine (in thetacov) allows to invert the R
### matrix (the inverse is upper-right triangular, too!). Call this
### matrix H, that is H=R^(-1).
###
### (X' X)^(-1) = [(R' D^(1/2)') (D^(1/2) R)]^(-1)
### = [ R^-1 D^(-1/2) ] [ R^-1 D^(-1/2) ]'
###
### Let's work this for our example, where
###
### $reg->include( 2.0, [ 1.0, 3.0, -1.0 ] );
### $reg->include( 1.0, [ 1.0, 5.0, 2.0 ] );
### $reg->include( 20.0, [ 1.0, 31.0, 0.0 ] );
### $reg->include( 15.0, [ 1.0, 11.0, 2.0 ] );
###
### For debuggin, the X'X matrix for our example is
### 4, 50, 3
### 50 1116 29
### 3 29 9
###
### Its inverse is
### 0.70967 -0.027992 -0.146360
### -0.02799 0.002082 0.002622
### -0.14636 0.002622 0.151450
###
### Internally, this is kept as follows
###
### R is 1, 0, 0
### 12.5 1 0
### 0.75 -0.0173 1
###
### d is the diagonal(4,491,6.603) matrix, which as 1/sqrt becomes dhi= 0.5, 0.04513, 0.3892
###
### R * d * R' is indeed the X' X matrix.
###
### The inverse of R is
###
### 1, 0, 0
### -12.5 1 0
### -0.9664 0.01731 1
###
### in R, t(solve(R) %*% dhi) %*% t( t(solve(R) %*% dhi) ) is the correct inverse.
###
### The routine has a debug switch which makes it come out very verbose.
################################################################
my $debug=0;
sub standarderrors {
my $this= shift;
our $K= $this->{k}; # convenience
our @u;
sub ui {
if ($debug) {
($_[0]<1)||($_[0]>$K) and confess "$MNAME:standarderrors: bad index 0 $_[0]\n";
($_[1]<1)||($_[1]>$K) and confess "$MNAME:standarderrors: bad index 1 $_[0]\n";
}
return (($K*($_[0]-1))+($_[1]-1));
}
sub giveuclear {
for (my $i=0; $i<($K**2); ++$i) { $u[$i]=0.0; }
return (wantarray) ? @u : \@u;
}
sub u { return $u[ui($_[0], $_[1])]; }
sub setu { return $u[ui($_[0], $_[1])]= $_[2]; }
sub add2u { return $u[ui($_[0], $_[1])]+= $_[2]; }
sub mult2u { return $u[ui($_[0], $_[1])]*= $_[2]; }
(defined($K)) or confess "$MNAME:standarderrors: Internal Error: I forgot the number of variables.\n";
if ($debug) {
print "The Start Matrix is:\n";
for (my $i=1; $i<=$K; ++$i) {
print "[$i]:\t";
for (my $j=1; $j<=$K; ++$j) {
print $this->rbr($i, $j)."\t";
}
print "\n";
}
print "The Start d vector is:\n";
for (my $i=1; $i<=$K; ++$i) {
print "".$this->{d}[$i]."\t";
}
print "\n";
}
sub rbrindex {
return ($_[0] == $_[1]) ? -9 :
($_[0]>$_[1]) ? -8 :
((($_[0]-1.0)* (2.0*$K-$_[0])/2.0+1.0) + $_[1] - 1 - $_[0] ); }
# now a real member routine;
sub rbr {
my $this= shift;
return ($_[0] == $_[1]) ? 1 : ( ($_[0]>$_[1]) ? 0 : ($this->{rbar}[rbrindex($_[0],$_[1])]));
}
my $u= giveuclear();
for (my $j=$K; $j>=1; --$j) {
setu($j,$j, 1.0/($this->rbr($j,$j)));
for (my $k=$j-1; $k>=1; --$k) {
setu($k,$j,0);
for (my $i=$k+1; $i<=$j; ++$i) { add2u($k,$j, $this->rbr($k,$i)*u($i,$j)); }
mult2u($k,$j, (-1.0)/$this->rbr($k,$k));
}
}
if ($debug) {
print "The Inverse Matrix of R is:\n";
for (my $i=1; $i<=$K; ++$i) {
print "[$i]:\t";
for (my $j=1; $j<=$K; ++$j) {
print $u[ui($i,$j)]."\t";
}
print "\n";
}
}
for (my $i=1;$i<=$K;++$i) {
for (my $j=1;$j<=$K;++$j) {
if (abs($this->{d}[$j])<TINY) {
mult2u($i,$j, sqrt(1.0/TINY));
if (abs($this->{d}[$j])==0.0) {
if ($this->{neverabort}) {
for (my $i=0; $i<($K**2); ++$i) { $u[$i]= "NaN"; }
return undef;
}
else { confess "$MNAME:standarderrors: I cannot compute the theta-covariance matrix for variable $j ".($this->{d}[$j])."\n"; }
}
}
else { mult2u($i,$j, sqrt(1.0/$this->{d}[$j])); }
}
}
if ($debug) {
print "The Inverse Matrix of R multipled by D^(-1/2) is:\n";
for (my $i=1; $i<=$K; ++$i) {
print "[$i]:\t";
for (my $j=1; $j<=$K; ++$j) {
print $u[ui($i,$j)]."\t";
}
print "\n";
}
}
$this->{sigmasq}= ($this->{n}<=$K) ? "Inf" : ($this->{sse}/($this->{n} - $K));
my @xpxinv;
for (my $i=1;$i<=$K; ++$i) {
for (my $j=$i;$j<=$K;++$j) {
my $indexij= ui($i,$j);
$xpxinv[$indexij]= 0.0;
for (my $k=1;$k<=$K;++$k) {
$xpxinv[$indexij] += $u[ui($i,$k)]*$u[ui($j,$k)];
}
$xpxinv[ui($j,$i)]= $xpxinv[$indexij]; # this is symmetric
}
}
if ($debug) {
print "The full inverse matrix of X'X is:\n";
for (my $i=1; $i<=$K; ++$i) {
print "[$i]:\t";
for (my $j=1; $j<=$K; ++$j) {
print $xpxinv[ui($i,$j)]."\t";
}
print "\n";
}
print "The sigma^2 is ".$this->{sigmasq}."\n";
}
## 99% of the usage here will be to print the diagonal elements of sqrt ( (X' X) sigma^2 )
## so, let's make this our first returned object;
my @secoefs;
for (my $i=1; $i<=$K; ++$i) {
$secoefs[$i-1]= sqrt($xpxinv[ui($i,$i)] * $this->{sigmasq});
}
if ($debug) { for (my $i=0; $i<$K; ++$i) { print " $secoefs[$i] "; } print "\n"; }
# the following are clever return methods; if the user goes over the secoefs,
# almost surely an error will result, because he will run into xpxinv. For special
# usage, however, xpxinv may still be useful.
return ( @secoefs, \@xpxinv, $this->sigmasq );
}
################################
sub linearcombination_variance {
my $this= shift;
our $K= $this->{k}; # convenience
my @linear= @_;
($#linear+1 == $K) or confess "$MNAME:linearcombination_variance: ".
"Sorry, you must give a vector of length $K, not ".($#linear+1)."\n";
my @allback= $this->standarderrors(); # compute everything we need;
my $xpxinv= $allback[$this->{k}];
my $sigmasq= $allback[$this->{k}+1];
my $sum=0;
for (my $i=1; $i<=$K; ++$i) {
for (my $j=1; $j<=$K; ++$j) {
$sum+= $linear[$i-1]*$linear[$j-1]*$xpxinv->[ui($i,$j)];
}
}
$sum*=$sigmasq;
return $sum;
}
################################################################
### sub dump() was used internally for debugging.
################################################################
sub dump {
my $this= $_[0];
print "****************************************************************\n";
print "Regression '$this->{regname}'\n";
print "****************************************************************\n";
sub print1val {
no strict;
print "$_[1]($_[2])=\t". ((defined($_[0]->{ $_[2] }) ? $_[0]->{ $_[2] } : "intentionally undef"));
my $ref=$_[0]->{ $_[2] };
if (ref($ref) eq 'ARRAY') {
my $arrayref= $ref;
print " $#$arrayref+1 elements:\n";
if ($#$arrayref>30) {
print "\t";
for(my $i=0; $i<$#$arrayref+1; ++$i) { print "$i='$arrayref->[$i]';"; }
print "\n";
}
else {
for(my $i=0; $i<$#$arrayref+1; ++$i) { print "\t$i=\t'$arrayref->[$i]'\n"; }
}
}
elsif (ref($ref) eq 'HASH') {
my $hashref= $ref;
print " ".scalar(keys(%$hashref))." elements\n";
while (my ($key, $val) = each(%$hashref)) {
print "\t'$key'=>'$val';\n";
}
}
else {
print " [was scalar]\n"; }
}
while (my ($key, $val) = each(%$this)) {
$this->print1val($key, $key);
}
print "****************************************************************\n";
}
################################################################
### The Test Program. Invoke as "perl Regression.pm".
################################################################
if ($0 eq "Regression.pm") {
# Create regression object
my $reg = Statistics::Regression->new( "sample regression", [ "const", "someX", "someY" ] );
# Add data points
$reg->include( 2.0, [ 1.0, 3.0, -1.0 ] );
$reg->include( 1.0, [ 1.0, 5.0, 2.0 ] );
$reg->include( 20.0, [ 1.0, 31.0, 0.0 ] );
my %inhash= ( const => 1.0, someX => 11.0, someY => 2.0, ignored => "ignored" );
$reg->include( 15.0, \%inhash );
# $reg->include( 15.0, [ 1.0, 11.0, 2.0 ] );
# Print the result
$reg->print();
}
1;

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.758.1
%define release 211207
%define release 211214
Summary: Pandora FMS Server
Name: %{name}

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_server
%define version 7.0NG.758.1
%define release 211207
%define release 211214
Summary: Pandora FMS Server
Name: %{name}

View File

@ -9,7 +9,7 @@
# **********************************************************************
PI_VERSION="7.0NG.758.1"
PI_BUILD="211207"
PI_BUILD="211214"
MODE=$1
if [ $# -gt 1 ]; then

View File

@ -35,7 +35,7 @@ use PandoraFMS::Config;
use PandoraFMS::DB;
# version: define current version
my $version = "7.0NG.758.1 Build 211207";
my $version = "7.0NG.758.1 Build 211214";
# Pandora server configuration
my %conf;

View File

@ -36,7 +36,7 @@ use Encode::Locale;
Encode::Locale::decode_argv;
# version: define current version
my $version = "7.0NG.758.1 Build 211207";
my $version = "7.0NG.758.1 Build 211214";
# save program name for logging
my $progname = basename($0);