Merge remote-tracking branch 'origin/develop' into ent-11931-made-selector-de-modulo-donde-se-activa-made-monitoring-anomaly-detection-engine

This commit is contained in:
Calvo 2023-10-24 14:02:36 +02:00
commit 715f6abc69
90 changed files with 12308 additions and 6881 deletions
pandora_agents
pandora_console
pandora_server

View File

@ -1,5 +1,5 @@
package: pandorafms-agent-unix
Version: 7.0NG.773.3-231020
Version: 7.0NG.773.3-231024
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.773.3-231020"
pandora_version="7.0NG.773.3-231024"
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

@ -313,6 +313,6 @@ module_plugin autodiscover --default
#Hardening plugin for security compliance analysis. Enable to use it.
#module_begin
#module_plugin /usr/share/pandora_agent/plugins/pandora_sca
#module_plugin /usr/share/pandora_agent/plugins/pandora_sca -t 150
#module_absoluteinterval 7d
#module_end
#module_end

View File

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

View File

@ -4,7 +4,7 @@
%global __os_install_post %{nil}
%define name pandorafms_agent_linux
%define version 7.0NG.773.3
%define release 231020
%define release 231024
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -5,7 +5,7 @@
%define name pandorafms_agent_linux_bin
%define source_name pandorafms_agent_linux
%define version 7.0NG.773.3
%define release 231020
%define release 231024
Summary: Pandora FMS Linux agent, binary version
Name: %{name}

View File

@ -4,7 +4,7 @@
%global __os_install_post %{nil}
%define name pandorafms_agent_linux
%define version 7.0NG.773.3
%define release 231020
%define release 231024
Summary: Pandora FMS Linux agent, PERL version
Name: %{name}

View File

@ -10,7 +10,7 @@
# **********************************************************************
PI_VERSION="7.0NG.773.3"
PI_BUILD="231020"
PI_BUILD="231024"
OS_NAME=`uname -s`
FORCE=0

View File

@ -526,7 +526,7 @@ module_plugin "%PROGRAMFILES%\Pandora_Agent\util\autodiscover.exe" --default
# Hardening plugin for security compliance analysis.
#module_begin
#module_plugin "%PROGRAMFILES%\Pandora_Agent\util\pandora_sca.exe"
#module_plugin "%PROGRAMFILES%\Pandora_Agent\util\pandora_sca.exe -t 150"
#module_absoluteinterval 7d
#module_end

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6d93bd9d56c938063045fa2093198d324746f84df2b74567648f3baebd635657
size 5248006
oid sha256:db207ef67053764be7e9b42cd04ea5509cc2a023548aab1c037745ca277b68a3
size 4858753

View File

@ -186,7 +186,7 @@ UpgradeApplicationID
{}
Version
{231020}
{231024}
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.773.3 Build 231020")
#define PANDORA_VERSION ("7.0NG.773.3 Build 231024")
string pandora_path;
string pandora_dir;

View File

@ -11,7 +11,7 @@ BEGIN
VALUE "LegalCopyright", "Pandora FMS"
VALUE "OriginalFilename", "PandoraAgent.exe"
VALUE "ProductName", "Pandora FMS Windows Agent"
VALUE "ProductVersion", "(7.0NG.773.3(Build 231020))"
VALUE "ProductVersion", "(7.0NG.773.3(Build 231024))"
VALUE "FileVersion", "1.0.0.0"
END
END

View File

@ -1,5 +1,5 @@
package: pandorafms-console
Version: 7.0NG.773.3-231020
Version: 7.0NG.773.3-231024
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.773.3-231020"
pandora_version="7.0NG.773.3-231024"
package_pear=0
package_pandora=1

View File

@ -106,6 +106,7 @@ enterprise/godmode/alerts/alert_events.php
enterprise/godmode/alerts/alert_events_list.php
enterprise/godmode/alerts/alert_events_rules.php
enterprise/godmode/alerts/configure_alert_rule.php
enterprise/godmode/alerts/alert_correlation.php
enterprise/include/functions_networkmap.php
enterprise/operation/agentes/pandora_networkmap.view.php
enterprise/include/ajax/map_enterprise.ajax.php

View File

@ -6,6 +6,98 @@ ALTER TABLE `ttrap` ADD COLUMN `utimestamp` INT UNSIGNED NOT NULL DEFAULT 0;
UPDATE ttrap SET utimestamp=UNIX_TIMESTAMP(timestamp);
CREATE TABLE IF NOT EXISTS `tlog_alert` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT ,
`description` MEDIUMTEXT,
`order` INT UNSIGNED DEFAULT 0,
`mode` ENUM('PASS','DROP'),
`field1` TEXT ,
`field2` TEXT ,
`field3` TEXT ,
`field4` TEXT ,
`field5` TEXT ,
`field6` TEXT ,
`field7` TEXT ,
`field8` TEXT ,
`field9` TEXT ,
`field10` TEXT ,
`time_threshold` INT NOT NULL DEFAULT 86400,
`max_alerts` INT UNSIGNED NOT NULL DEFAULT 1,
`min_alerts` INT UNSIGNED NOT NULL DEFAULT 0,
`time_from` time DEFAULT '00:00:00',
`time_to` time DEFAULT '00:00:00',
`monday` TINYINT DEFAULT 1,
`tuesday` TINYINT DEFAULT 1,
`wednesday` TINYINT DEFAULT 1,
`thursday` TINYINT DEFAULT 1,
`friday` TINYINT DEFAULT 1,
`saturday` TINYINT DEFAULT 1,
`sunday` TINYINT DEFAULT 1,
`recovery_notify` TINYINT DEFAULT 0,
`field1_recovery` TEXT,
`field2_recovery` TEXT,
`field3_recovery` TEXT,
`field4_recovery` TEXT,
`field5_recovery` TEXT,
`field6_recovery` TEXT,
`field7_recovery` TEXT,
`field8_recovery` TEXT,
`field9_recovery` TEXT,
`field10_recovery` TEXT,
`id_group` MEDIUMINT UNSIGNED NULL DEFAULT 0,
`internal_counter` INT DEFAULT 0,
`last_fired` BIGINT NOT NULL DEFAULT 0,
`last_reference` BIGINT NOT NULL DEFAULT 0,
`times_fired` INT NOT NULL DEFAULT 0,
`disabled` TINYINT DEFAULT 0,
`standby` TINYINT DEFAULT 0,
`priority` TINYINT DEFAULT 0,
`force_execution` TINYINT DEFAULT 0,
`group_by` enum ('','id_agente','id_agentmodule','id_alert_am','id_grupo') DEFAULT '',
`special_days` TINYINT DEFAULT 0,
`disable_event` TINYINT DEFAULT 0,
`id_template_conditions` INT UNSIGNED NOT NULL DEFAULT 0,
`id_template_fields` INT UNSIGNED NOT NULL DEFAULT 0,
`last_evaluation` BIGINT NOT NULL DEFAULT 0,
`pool_occurrences` INT UNSIGNED NOT NULL DEFAULT 0,
`schedule` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tlog_rule` (
`id_log_rule` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_log_alert` INT UNSIGNED NOT NULL,
`operation` ENUM('NOP', 'AND','OR','XOR','NAND','NOR','NXOR'),
`order` INT UNSIGNED DEFAULT 0,
`window` INT NOT NULL DEFAULT 0,
`count` INT NOT NULL DEFAULT 1,
`name` TEXT,
`log_content` TEXT,
`log_source` TEXT,
`log_agent` TEXT,
`operator_log_content` TEXT COMMENT 'Operator for log_content',
`operator_log_source` TEXT COMMENT 'Operator for log_source',
`operator_log_agent` TEXT COMMENT 'Operator for log_agent',
PRIMARY KEY (`id_log_rule`),
KEY `idx_id_log_alert` (`id_log_alert`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tlog_alert_action` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_log_alert` INT UNSIGNED NOT NULL,
`id_alert_action` INT UNSIGNED NOT NULL,
`fires_min` INT UNSIGNED DEFAULT 0,
`fires_max` INT UNSIGNED DEFAULT 0,
`module_action_threshold` INT NOT NULL DEFAULT 0,
`last_execution` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_log_alert`) REFERENCES tlog_alert(`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`id_alert_action`) REFERENCES talert_actions(`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tgraph_analytics_filter` (
`id` INT NOT NULL auto_increment,
`filter_name` VARCHAR(45) NULL,
@ -271,5 +363,10 @@ SET @id_os = 9;
INSERT INTO tmodule_inventory (`id_os`, `name`, `description`, `interpreter`, `data_format`, `code`, `block_mode`,`script_mode`)
SELECT * FROM (SELECT @id_os id_os, @tmodule_name name, @tmodule_description description, '' interpreter, 'ID:STATUS' data_format, '' code, '0' block_mode, 2 script_mode) AS tmp
WHERE NOT EXISTS (SELECT name, description FROM tmodule_inventory WHERE name = @tmodule_name and description = @tmodule_description and id_os = @id_os);
INSERT INTO tmodule_group (name) SELECT ('Security') WHERE NOT EXISTS (SELECT name FROM tmodule_group WHERE LOWER(name) = 'security');
ALTER TABLE tagente_modulo ADD COLUMN `last_compact` TIMESTAMP NOT NULL DEFAULT 0;
UPDATE `tevent_alert` ea INNER JOIN `tevent_rule` er ON ea.id = er.id_event_alert SET disabled=1 WHERE er.log_agent IS NOT NULL OR er.log_content IS NOT NULL OR er.log_source IS NOT NULL;
COMMIT;

View File

@ -26,14 +26,16 @@
* ============================================================================
*/
use PandoraFMS\TacticalView\GeneralTacticalView;
// Config functions.
require_once 'include/config.php';
require_once 'include/config.php';
// This solves problems in enterprise load.
global $config;
// This solves problems in enterprise load.
global $config;
check_login();
// ACL Check.
check_login();
// ACL Check.
if (check_acl($config['id_user'], 0, 'AR') === 0) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
@ -43,322 +45,5 @@ if (check_acl($config['id_user'], 0, 'AR') === 0) {
exit;
}
require_once 'include/functions_reporting.php';
require_once 'include/functions_tactical.php';
require_once $config['homedir'].'/include/functions_graph.php';
if (tags_has_user_acl_tags()) {
ui_print_tags_warning();
}
$all_data = tactical_status_modules_agents(
$config['id_user'],
false,
'AR'
);
$data = [];
$data['monitor_not_init'] = (int) $all_data['_monitors_not_init_'];
$data['monitor_unknown'] = (int) $all_data['_monitors_unknown_'];
$data['monitor_ok'] = (int) $all_data['_monitors_ok_'];
$data['monitor_warning'] = (int) $all_data['_monitors_warning_'];
$data['monitor_critical'] = (int) $all_data['_monitors_critical_'];
$data['monitor_not_normal'] = (int) $all_data['_monitor_not_normal_'];
$data['monitor_alerts'] = (int) $all_data['_monitors_alerts_'];
$data['monitor_alerts_fired'] = (int) $all_data['_monitors_alerts_fired_'];
$data['monitor_total'] = (int) $all_data['_monitor_total_'];
$data['total_agents'] = (int) $all_data['_total_agents_'];
$data['monitor_checks'] = (int) $all_data['_monitor_checks_'];
if (!empty($all_data)) {
if ($data['monitor_not_normal'] > 0 && $data['monitor_checks'] > 0) {
$data['monitor_health'] = format_numeric((100 - ($data['monitor_not_normal'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['monitor_health'] = 100;
}
if ($data['monitor_not_init'] > 0 && $data['monitor_checks'] > 0) {
$data['module_sanity'] = format_numeric((100 - ($data['monitor_not_init'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['module_sanity'] = 100;
}
if (isset($data['alerts'])) {
if ($data['monitor_alerts_fired'] > 0 && $data['alerts'] > 0) {
$data['alert_level'] = format_numeric((100 - ($data['monitor_alerts_fired'] / ($data['alerts'] / 100))), 1);
} else {
$data['alert_level'] = 100;
}
} else {
$data['alert_level'] = 100;
$data['alerts'] = 0;
}
$data['monitor_bad'] = ($data['monitor_critical'] + $data['monitor_warning']);
if ($data['monitor_bad'] > 0 && $data['monitor_checks'] > 0) {
$data['global_health'] = format_numeric((100 - ($data['monitor_bad'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['global_health'] = 100;
}
$data['server_sanity'] = format_numeric((100 - $data['module_sanity']), 1);
}
ui_require_css_file('logon');
echo '<div id="welcome_panel">';
//
// Overview Table.
//
$table = new stdClass();
$table->class = 'no-class';
$table->cellpadding = 4;
$table->cellspacing = 4;
$table->head = [];
$table->data = [];
$table->headstyle[0] = 'text-align:center;';
$table->width = '100%';
$table->head_colspan[0] = 4;
// Indicators.
$tdata = [];
$stats = reporting_get_stats_indicators($data, 120, 10, false);
$status = '<table class="status_tactical">';
foreach ($stats as $stat) {
$status .= '<tr><td><b>'.$stat['title'].'</b></td><td>'.$stat['graph'].'</td></tr>';
}
$status .= '</table>';
$table->rowclass = [];
$table->rowclass[0] = 'w100p';
$table->rowclass[1] = 'w100p';
$table->rowclass[2] = 'w100p';
$table->rowclass[3] = 'w100p';
$table->rowclass[4] = 'w100p';
$table->rowclass[5] = 'w100p';
$table->data[0][0] = $status;
$table->data[] = $tdata;
// Alerts.
$tdata = [];
$tdata[0] = reporting_get_stats_alerts($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Modules by status.
$tdata = [];
$data_agents = [
__('Critical') => $data['monitor_critical'],
__('Warning') => $data['monitor_warning'],
__('Normal') => $data['monitor_ok'],
__('Unknown') => $data['monitor_unknown'],
__('Not init') => $data['monitor_not_init'],
];
$tdata[0] = reporting_get_stats_modules_status($data, 180, 100, false, $data_agents);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Total agents and modules.
$tdata = [];
$tdata[0] = reporting_get_stats_agents_monitors($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
// Users.
if (users_is_admin() || check_acl($config['id_user'], 0, 'UM')) {
$tdata = [];
$tdata[0] = reporting_get_stats_users($data);
$table->rowclass[] = '';
$table->data[] = $tdata;
}
ui_toggle(
html_print_table($table, true),
__('%s Overview', get_product_name()),
'',
'overview',
false
);
unset($table);
echo '<div id="right">';
// News.
require_once 'general/news_dialog.php';
$options = [];
$options['id_user'] = $config['id_user'];
$options['modal'] = false;
$options['limit'] = 3;
$news = get_news($options);
if (!empty($news)) {
ui_require_css_file('news');
// NEWS BOARD.
if ($config['prominent_time'] == 'timestamp') {
$comparation_suffix = '';
} else {
$comparation_suffix = __('ago');
}
$output_news = '<div id="news_board" class="new">';
foreach ($news as $article) {
$default = false;
if ($article['text'] == '&amp;lt;p&#x20;style=&quot;text-align:&#x20;center;&#x20;font-size:&#x20;13px;&quot;&amp;gt;Hello,&#x20;congratulations,&#x20;if&#x20;you&apos;ve&#x20;arrived&#x20;here&#x20;you&#x20;already&#x20;have&#x20;an&#x20;operational&#x20;monitoring&#x20;console.&#x20;Remember&#x20;that&#x20;our&#x20;forums&#x20;and&#x20;online&#x20;documentation&#x20;are&#x20;available&#x20;24x7&#x20;to&#x20;get&#x20;you&#x20;out&#x20;of&#x20;any&#x20;trouble.&#x20;You&#x20;can&#x20;replace&#x20;this&#x20;message&#x20;with&#x20;a&#x20;personalized&#x20;one&#x20;at&#x20;Admin&#x20;tools&#x20;-&amp;amp;gt;&#x20;Site&#x20;news.&amp;lt;/p&amp;gt;&#x20;') {
$article['subject'] = __('Welcome to Pandora FMS Console');
$default = true;
}
$text_bbdd = io_safe_output($article['text']);
$text = html_entity_decode($text_bbdd);
$output_news .= '<div class="new-board">';
$output_news .= '<div class="new-board-header">';
$output_news .= '<span class="new-board-title">'.$article['subject'].'</span>';
$output_news .= '<span class="new-board-author">'.__('By').' '.$article['author'].' '.ui_print_timestamp($article['timestamp'], true).'</span>';
$output_news .= '</div>';
$output_news .= '<div class="new content">';
if ($default) {
$output_news .= '<div class="default-new">';
$output_news .= '<div class="default-image-new">';
$output_news .= '<img src="./images/welcome_image.svg" alt="img colabora con nosotros - Support">';
$output_news .= '</div><div class="default-text-new">';
$output_news .= '
<p>'.__('Welcome to our monitoring tool so grand,').'
<br>'.__('Where data insights are at your command.').'
<br>'.__('Sales, marketing, operations too,').'
<br>'.__("Customer support, we've got you.").'
</p>
<p>'.__('Our interface is user-friendly,').'
<br>'.__("Customize your dashboard, it's easy.").'
<br>'.__('Set up alerts and gain insights so keen,').'
<br>'.__("Optimize your data, like you've never seen.").'
</p>
<p>'.__('Unleash its power now, and join the pro league,').'
<br>'.__('Unlock the potential of your data to intrigue.').'
<br>'.__('Monitoring made simple, efficient and fun,').'
<br>'.__('Discover a whole new way to get things done.').'
</p>
<p>'.__('And take control of your IT once and for all.').'</p>
<span>'.__('You can replace this message with a personalized one at Admin tools -> Site news.').'</span>
';
$output_news .= '</div></div>';
} else {
$text = str_replace('<script', '&lt;script', $text);
$text = str_replace('</script', '&lt;/script', $text);
$output_news .= nl2br($text);
}
$output_news .= '</div></div>';
}
$output_news .= '</div>';
// News board.
ui_toggle(
$output_news,
__('News board'),
'',
'news',
false
);
// END OF NEWS BOARD.
}
// LAST ACTIVITY.
// Show last activity from this user.
$table = new stdClass();
$table->class = 'no-td-padding info_table';
$table->cellpadding = 0;
$table->cellspacing = 0;
$table->width = '100%';
// Don't specify px.
$table->data = [];
$table->size = [];
$table->headstyle = [];
$table->size[0] = '5%';
$table->size[1] = '15%';
$table->headstyle[1] = 'min-width: 12em;';
$table->size[2] = '5%';
$table->headstyle[2] = 'min-width: 65px;';
$table->size[3] = '10%';
$table->size[4] = '25%';
$table->head = [];
$table->head[0] = __('User');
$table->head[1] = __('Action');
$table->head[2] = __('Date');
$table->head[3] = __('Source IP');
$table->head[4] = __('Comments');
$table->align[4] = 'left';
$sql = sprintf(
'SELECT id_usuario,accion, ip_origen,descripcion,utimestamp
FROM tsesion
WHERE (`utimestamp` > UNIX_TIMESTAMP(NOW()) - '.SECONDS_1WEEK.")
AND `id_usuario` = '%s' ORDER BY `utimestamp` DESC LIMIT 10",
$config['id_user']
);
$sessions = db_get_all_rows_sql($sql);
if ($sessions === false) {
$sessions = [];
}
foreach ($sessions as $session) {
$data = [];
$session_id_usuario = $session['id_usuario'];
$session_ip_origen = $session['ip_origen'];
$data[0] = '<strong>'.$session_id_usuario.'</strong>';
$data[1] = ui_print_session_action_icon($session['accion'], true).' '.$session['accion'];
$data[2] = ui_print_help_tip(
date($config['date_format'], $session['utimestamp']),
true
).human_time_comparation($session['utimestamp'], 'tiny');
$data[3] = $session_ip_origen;
$description = io_safe_output(str_replace([',', ', '], ', ', $session['descripcion']));
if (strlen($description) > 100) {
$data[4] = '<div >'.io_safe_input(substr($description, 0, 150)).'...</div>';
} else {
$data[4] = '<div >'.io_safe_input($description).'</div>';
}
array_push($table->data, $data);
}
$activity = html_print_table($table, true);
unset($table);
ui_toggle(
$activity,
__('Latest activity'),
'',
'activity',
false,
false,
'',
'white-box-content padded'
);
// END OF LAST ACTIVIYY.
// Close right panel.
echo '</div>';
// Close welcome panel.
echo '</div>';
$tacticalView = new GeneralTacticalView();
$tacticalView->render();

View File

@ -384,6 +384,7 @@ if ($access_console_node === true) {
$sub['godmode/alerts/alert_special_days']['pages'] = ['godmode/alerts/configure_alert_special_days'];
enterprise_hook('eventalerts_submenu');
enterprise_hook('alert_log_submenu');
$sub['godmode/snmpconsole/snmp_alert']['text'] = __('SNMP alerts');
$sub['godmode/snmpconsole/snmp_alert']['id'] = 'SNMP_alerts';
enterprise_hook('alert_inventory_submenu');

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>59DFD8E8-D019-4076-8FED-D5B81BE90197</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1185, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(15, 71)">
<g id="Groups" transform="translate(68, 0)">
<rect id="Rectangle" x="0" y="0" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy-2" x="0" y="21.6" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy" x="21.6" y="0" width="5.4" height="5.4" rx="0.5"></rect>
<rect id="Rectangle-Copy-3" x="21.6" y="21.6" width="5.4" height="5.4" rx="0.5"></rect>
<path d="M24.3,2.7 L24.3,24.3 L2.7,24.3 L2.7,2.7 L24.3,2.7 Z M19.06875,10.8 L17.55,10.8 L17.55,16.36875 C17.55,17.0211364 17.0211364,17.55 16.36875,17.55 L10.8,17.549 L10.8,19.06875 C10.8,19.7211364 11.3288636,20.25 11.98125,20.25 L19.06875,20.25 C19.7211364,20.25 20.25,19.7211364 20.25,19.06875 L20.25,11.98125 C20.25,11.3288636 19.7211364,10.8 19.06875,10.8 Z M15.01875,6.75 L7.93125,6.75 C7.27886364,6.75 6.75,7.27886364 6.75,7.93125 L6.75,15.01875 C6.75,15.6711364 7.27886364,16.2 7.93125,16.2 L15.01875,16.2 C15.6711364,16.2 16.2,15.6711364 16.2,15.01875 L16.2,7.93125 C16.2,7.27886364 15.6711364,6.75 15.01875,6.75 Z" id="Rectangle-2"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.8 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>04A64774-B33A-4338-8092-D83F51BBE8C1</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1218, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(49, 203)">
<g id="Module-template" transform="translate(67, 0)">
<path d="M1,0 L26,0 C26.5522847,-1.01453063e-16 27,0.44771525 27,1 L27,8.45 C27,9.00228475 26.5522847,9.45 26,9.45 L1,9.45 C0.44771525,9.45 6.76353751e-17,9.00228475 0,8.45 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 Z M11.8,10.8 L26,10.8 C26.5522847,10.8 27,11.2477153 27,11.8 L27,26 C27,26.5522847 26.5522847,27 26,27 L11.8,27 C11.2477153,27 10.8,26.5522847 10.8,26 L10.8,11.8 C10.8,11.2477153 11.2477153,10.8 11.8,10.8 Z" id="Rectangle-2"></path>
<path d="M8.45,10.8 C9.00228475,10.8 9.45,11.2477153 9.45,11.8 L9.45,26 C9.45,26.5522847 9.00228475,27 8.45,27 L1,27 C0.44771525,27 0,26.5522847 0,26 L0,11.8 C0,11.2477153 0.44771525,10.8 1,10.8 L8.45,10.8 Z M7.45,12.8 L2,12.8 L2,25 L7.45,25 L7.45,12.8 Z" id="Rectangle" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.5 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CD5F043F-0CA1-4012-8590-20C64D7E7E0D</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1378, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(208, 71)">
<g id="Modules" transform="translate(68, 0)">
<path d="M25.3705078,4.29521484 L14.6865234,0.218847656 C14.3015625,0.0729316406 13.9007813,0 13.5,0 C13.0992187,0 12.6984375,0.0729316406 12.3134766,0.218583984 L1.62896484,4.29521484 C0.648105469,4.66962891 0,5.6109375 0,6.66035156 L0,20.3396484 C0,21.3895898 0.648105469,22.3303711 1.62896484,22.7047852 L12.3129492,26.7811523 C12.6984375,26.9261719 13.0992188,27 13.5,27 C13.9007813,27 14.3031445,26.9270684 14.6849414,26.781416 L25.3689258,22.7050488 C26.3513672,22.3330078 27,21.3890625 27,20.3396484 L27,6.66035156 C27,5.6109375 26.3513672,4.66962891 25.3705078,4.29521484 Z M13.0008122,3 L22,6.5303428 L13.0008122,10 L4,6.5314563 L13.0008122,3 Z M15,23 L15,13.1237485 L23,10 L23,19.8137765 L15,23 Z"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.4 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>E1DA8ECF-DB7D-48B5-96B0-3C6199FCC8EB</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1476, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(306, 203)">
<g id="Not-init-module" transform="translate(68, 0)">
<path d="M1.51937106,7.28411239 C4.95205428,0.667087472 13.0993581,-1.91380755 19.7156094,1.51964932 C20.0173327,1.67592653 20.3097722,1.84226119 20.5937016,2.017106 L18.0128066,3.66652692 L18.009712,3.66575327 L12.8138814,6.98548365 L12.710986,2.70797508 C11.8669343,2.76986705 11.0344873,2.93078616 10.2322127,3.18531688 C7.59329397,4.02163208 5.27234521,5.86523905 3.8960226,8.51730983 C2.52047363,11.1693806 2.34872342,14.1285903 3.18503863,16.767509 C3.79544815,18.6923492 4.94122319,20.4477601 6.54499878,21.7908158 L4.20161418,23.2878278 C-0.0495902992,19.2532452 -1.31528102,12.7468521 1.51937106,7.28411239 Z M22.8349645,3.74853378 C27.0567703,7.78621097 28.3062144,14.2693945 25.4800724,19.7158876 C22.0473892,26.3329125 13.9008591,28.9138076 7.28383414,25.4803507 C6.99990474,25.3333573 6.72371184,25.17708 6.45448178,25.0122927 L6.50167441,24.9821203 L6.47769127,24.980573 L14.2312074,20.0261211 L14.2025824,24.2982141 C15.0760328,24.240964 15.9378784,24.077724 16.7672308,23.8146831 C19.4069232,22.9783679 21.7270983,21.134761 23.1034209,18.4826902 C24.4797435,15.8306194 24.6507201,12.8714097 23.8144049,10.232491 C23.2101845,8.32389744 22.0783352,6.58241222 20.4954481,5.24399843 Z M19.2403271,12.073777 C19.4297542,12.073777 19.5833153,12.227338 19.5833153,12.4167651 L19.5833153,14.5824612 C19.5833153,14.7718883 19.4297542,14.9254494 19.2403271,14.9254494 L7.75834273,14.9254494 C7.5689156,14.9254494 7.41535457,14.7718883 7.41535457,14.5824612 L7.41535457,12.4167651 C7.41535457,12.227338 7.5689156,12.073777 7.75834273,12.073777 L19.2403271,12.073777 Z"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 2.3 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>E2220716-B06D-4CCD-8005-3668217A51C4</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1764, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(594, 71)">
<g id="Plugins" transform="translate(68, 0)">
<path d="M27,18.9 L27,24.3 C27,25.7911688 25.7911688,27 24.3,27 L18.9,27 L18.9,24.3 C18.9,22.8088312 17.6911688,21.6 16.2,21.6 C14.7088312,21.6 13.5,22.8088312 13.5,24.3 L13.5,27 L8.1,27 C6.60883118,27 5.4,25.7911688 5.4,24.3 L5.4,18.9 L2.7,18.9 C1.20883118,18.9 0,17.6911688 0,16.2 C0,14.7088312 1.20883118,13.5 2.7,13.5 L5.4,13.5 L5.4,8.1 C5.4,6.615 6.615,5.4 8.1,5.4 L13.5,5.4 L13.5,2.7 C13.5,1.20883118 14.7088312,0 16.2,0 C17.6911688,0 18.9,1.20883118 18.9,2.7 L18.9,5.4 L24.3,5.4 C25.7911688,5.4 27,6.60883118 27,8.1 L27,13.5 L24.3,13.5 C22.8088312,13.5 21.6,14.7088312 21.6,16.2 C21.6,17.6911688 22.8088312,18.9 24.3,18.9 L27,18.9 Z" id="Path"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.4 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="21px" height="27px" viewBox="0 0 21 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>7780B3A6-04AD-41C0-83B2-12DA21E87CFC</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1574, -1810)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(401, 71)">
<g id="Policies" transform="translate(71, 0)">
<path d="M18,0 C19.6568542,-3.04359188e-16 21,1.34314575 21,3 L21,24 C21,25.6568542 19.6568542,27 18,27 L3,27 C1.34314575,27 2.02906125e-16,25.6568542 0,24 L0,3 C-2.02906125e-16,1.34314575 1.34314575,3.04359188e-16 3,0 L18,0 Z M15.35625,16.605 C14.83125,16.065 14.04375,16.065 13.51875,16.605 L9.1875,21.06 L7.48125,19.305 C7.021875,18.765 6.16875,18.765 5.64375,19.305 C5.11875,19.845 5.11875,20.655 5.64375,21.195 L8.26875,23.895 C8.53125,24.165 8.859375,24.3 9.1875,24.3 C9.515625,24.3 9.84375,24.165 10.10625,23.895 L15.35625,18.495 C15.88125,17.955 15.88125,17.145 15.35625,16.605 Z M16.0625,9.45 L4.9375,9.45 C4.38521525,9.45 3.9375,9.89771525 3.9375,10.45 L3.9375,11.15 C3.9375,11.7022847 4.38521525,12.15 4.9375,12.15 L16.0625,12.15 C16.6147847,12.15 17.0625,11.7022847 17.0625,11.15 L17.0625,10.45 C17.0625,9.89771525 16.6147847,9.45 16.0625,9.45 Z M16.0625,4.05 L4.9375,4.05 C4.38521525,4.05 3.9375,4.49771525 3.9375,5.05 L3.9375,5.75 C3.9375,6.30228475 4.38521525,6.75 4.9375,6.75 L16.0625,6.75 C16.6147847,6.75 17.0625,6.30228475 17.0625,5.75 L17.0625,5.05 C17.0625,4.49771525 16.6147847,4.05 16.0625,4.05 Z" id="Rectangle-2"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.9 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>A8855F06-D8BF-417A-841F-4FBE78913DFF</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-1734, -1942)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1739)">
<g id="Card-1/8" transform="translate(564, 203)">
<g id="Unknown-agent" transform="translate(68, 0)">
<path d="M17.4053571,0.0521205975 C18.4487143,-0.201907204 19.5132857,0.496117015 19.7948571,1.67348065 L21.5151429,8.89670596 C21.5252191,8.9391051 21.5342228,8.98182907 21.5421429,9.02482433 C24.8535,9.62786424 27,10.5953788 27,11.6865939 C27,13.5155941 20.9558571,15 13.5,15 C6.04414286,15 0,13.5155941 0,11.6865939 C0,10.5953788 2.1465,9.62786424 5.45785714,9.02482433 L5.48485714,8.89670596 L7.20514286,1.67568959 C7.48671429,0.493908078 8.55128571,-0.201907204 9.59464286,0.0521205975 C10.7787857,0.341491397 12.3042857,0.641906884 13.5,0.641906884 C14.6957143,0.641906884 16.2212143,0.33928246 17.4053571,0.0521205975 Z M7.7625,9.72284855 C7.63511282,9.70805077 7.50781825,9.75189759 7.40868802,9.84471966 C7.30955779,9.93754173 7.24673418,10.0717149 7.23407143,10.2176505 C7.22115184,10.3635566 7.25943347,10.5093566 7.34047424,10.6228979 C7.42151502,10.7364392 7.53865846,10.8083958 7.66607143,10.8228994 C9.4365,11.0283306 11.4152143,11.1431953 13.5,11.1431953 C15.5847857,11.1431953 17.5635,11.0283306 19.3339286,10.8228994 C19.5991436,10.7924003 19.7925566,10.5214212 19.7659286,10.2176505 C19.7393005,9.91387988 19.502715,9.69234949 19.2375,9.72284855 C17.3308445,9.93842752 15.4159177,10.0438538 13.5,10.0387266 C11.4460714,10.0387266 9.49821429,9.92607079 7.7625,9.72284855 Z M1.92582418,20 C1.92582418,19.65 1.98351648,19.312 2.08928571,19 L1.92582418,19 C1.39478115,19 0.964285714,18.5522847 0.964285714,18 C0.964285714,17.4477153 1.39478115,17 1.92582418,17 L8.65659341,17 C10.1098077,17.0001733 11.3359957,18.1245745 11.5181319,19.624 C12.7872537,19.2253356 14.1413177,19.2253356 15.4104396,19.624 C15.5925757,18.1245745 16.8187637,17.0001733 18.271978,17 L25.0027473,17 C25.5337903,17 25.9642857,17.4477153 25.9642857,18 C25.9642857,18.5522847 25.5337903,19 25.0027473,19 L24.8392857,19 C24.9450549,19.312 25.0027473,19.65 25.0027473,20 L25.0027473,22 C25.0027473,24.7614237 22.8502701,27 20.1950549,27 C17.5398398,27 15.3873626,24.7614237 15.3873626,22 L15.3873626,21.72 L14.9835165,21.58 C13.9973271,21.2383946 12.9312443,21.2383946 11.9450549,21.58 L11.5412088,21.72 L11.5412088,22 C11.5412088,24.7614237 9.38873163,27 6.73351648,27 C4.07830134,27 1.92582418,24.7614237 1.92582418,22 L1.92582418,20 L1.92582418,20 Z" id="Shape"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 2.9 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
<style type="text/css">
.st0{fill:#3F3F3F;}
</style>
<g>
<path class="st0" d="M4.8,8C4.8,8,4.8,8,4.8,8C4.8,8,4.9,8,4.8,8c0.3,0.1,0.5,0.1,0.7,0.2c0,0,0.1,0,0.1,0c0.3,0,0.5,0.1,0.8,0.1
c0.1,0,0.1,0,0.2,0c0.2,0,0.4,0,0.7,0.1c0.1,0,0.2,0,0.2,0c0.3,0,0.6,0,0.9,0c0.3,0,0.6,0,0.9,0c0.1,0,0.2,0,0.2,0
c0.2,0,0.4,0,0.7-0.1c0.1,0,0.1,0,0.2,0c0.3,0,0.5-0.1,0.8-0.1c0,0,0.1,0,0.1,0c0.2,0,0.4-0.1,0.6-0.1c0,0,0.1,0,0.1,0c0,0,0,0,0,0
c2-0.5,3.3-1.4,3.3-2.4V4.2c0-1.6-3.1-2.8-6.8-2.8S1.6,2.6,1.6,4.2v1.4C1.6,6.6,2.9,7.5,4.8,8z"/>
<path class="st0" d="M13.8,8.8c0.5,0.1,1,0.2,1.4,0.4l0-1.2C14.8,8.4,14.3,8.6,13.8,8.8z"/>
<path class="st0" d="M7.6,17.3c-1.1-0.6-1.9-1.4-2.7-2.3c-0.7-0.1-1.3-0.3-1.9-0.5c-0.5-0.2-1-0.5-1.5-0.8v1.8
c0,0.9,1.1,1.8,2.9,2.3c0,0,0,0,0,0c0,0,0,0,0.1,0c0.2,0.1,0.5,0.1,0.8,0.2c0.1,0,0.1,0,0.2,0C5.6,18,5.9,18,6.2,18.1
c0,0,0.1,0,0.1,0c0.3,0,0.6,0.1,0.9,0.1c0.1,0,0.1,0,0.2,0c0.3,0,0.6,0,1,0c0.3,0,0.7,0,1,0c0,0,0.1,0,0.1,0
C8.9,18,8.2,17.7,7.6,17.3z"/>
<path class="st0" d="M4,13.3c0.1-0.2,0.3-0.4,0.4-0.6c1-1.2,2.1-2.2,3.6-3c-0.4,0-0.8,0-1.2-0.1c-0.2,0-0.3,0-0.5-0.1
c-0.3,0-0.7-0.1-1-0.2C4.4,9.3,3.7,9.1,3,8.9C2.5,8.7,2,8.4,1.6,8l0,3.2C1.6,12.1,2.5,12.8,4,13.3z"/>
</g>
<g>
<path class="st0" d="M5.4,13.6c0.1-0.2,0.3-0.4,0.4-0.6c0.8-1.1,1.8-1.9,3.1-2.5c0.8-0.4,1.7-0.6,2.6-0.7c1.8-0.2,3.4,0.3,4.8,1.3
c0.9,0.6,1.8,1.5,2.4,2.3c0.2,0.2,0.2,0.4,0,0.7c-0.8,1.1-1.7,1.9-2.8,2.6c-0.9,0.5-2,0.9-3.1,1.1c-1.6,0.1-3.1-0.2-4.4-1.1
C7.3,16,6.5,15,5.6,14c0-0.1-0.1-0.1-0.1-0.2C5.4,13.7,5.4,13.6,5.4,13.6z M12.1,10.8c-1.6,0-2.7,1.4-2.7,2.9s1.4,2.7,2.9,2.7
c1.5,0,2.7-1.4,2.7-2.9C15,12,13.6,10.8,12.1,10.8z"/>
<path class="st0" d="M12.2,12.1c0.8,0,1.5,0.6,1.5,1.5c0,0.8-0.6,1.6-1.6,1.6c-0.8,0-1.5-0.6-1.5-1.5
C10.7,12.8,11.3,12.1,12.2,12.1z"/>
</g>
</svg>

After

(image error) Size: 2.1 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>AE320C3A-79E4-4E24-956A-B81125ACFA52@svg</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="100%" y2="100%" id="linearGradient-1">
<stop stop-color="#82B92E" offset="0%"></stop>
<stop stop-color="#2EB9A2" offset="100%"></stop>
</linearGradient>
<path d="M0,31.4018658 L0,11.5981342 C0,3.42952349 9.87916654,0 21.5,0 C33.1208335,0 43,3.42952349 43,11.5981342 L43,31.4018658 C43,39.5704765 33.1208335,43 21.5,43 C9.87916654,43 0,39.5704765 0,31.4018658 Z" id="path-2"></path>
</defs>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-324, -276)">
<g id="General-overview" transform="translate(309, 186)">
<g id="Card-1/8" transform="translate(15, 66)">
<g id="Status-check" transform="translate(0, 24)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="Mask" fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
<path d="M40.3336211,1.77120453 C41.5051939,0.599631653 43.4046889,0.599631653 44.5762617,1.77120453 C45.7009717,2.89591449 45.7459601,4.69147742 44.7112269,5.86985562 L44.5762617,6.01384522 L20.142225,30.447882 C19.017515,31.572592 17.2219521,31.6175804 16.0435739,30.5828472 L15.8995843,30.447882 L10.2105122,24.75881 C9.03893936,23.5872371 9.03893936,21.6877422 10.2105122,20.5161693 C11.3352222,19.3914593 13.1307851,19.3464709 14.3091633,20.3812041 L14.4531529,20.5161693 L18.021,24.084 L40.3336211,1.77120453 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero" mask="url(#mask-3)"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 2.0 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>CD9D3D2F-E199-427F-BC6C-532C8382EE45@svg</title>
<defs>
<linearGradient x1="100%" y1="5.25852345e-07%" x2="0%" y2="50%" id="linearGradient-1">
<stop stop-color="#F72222" offset="0%"></stop>
<stop stop-color="#E12D81" offset="100%"></stop>
</linearGradient>
<path d="M0,31.4018658 L0,11.5981342 C0,3.42952349 9.87916654,0 21.5,0 C33.1208335,0 43,3.42952349 43,11.5981342 L43,31.4018658 C43,39.5704765 33.1208335,43 21.5,43 C9.87916654,43 0,39.5704765 0,31.4018658 Z" id="path-2"></path>
</defs>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v4" transform="translate(-519, -276)">
<g id="General-overview" transform="translate(309, 186)">
<g id="Card-1/8" transform="translate(210, 66)">
<g id="Path" transform="translate(0, 24)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="Mask" fill="url(#linearGradient-1)" xlink:href="#path-2"></use>
<path d="M17.9773307,13.7437145 L18.1213203,13.8786797 L21.657,17.414 L25.1923882,13.8786797 C26.363961,12.7071068 28.263456,12.7071068 29.4350288,13.8786797 C30.5597388,15.0033896 30.6047272,16.7989525 29.569994,17.9773307 L29.4350288,18.1213203 L25.9,21.657 L29.4350288,25.1923882 C30.6066017,26.363961 30.6066017,28.263456 29.4350288,29.4350288 C28.3103189,30.5597388 26.514756,30.6047272 25.3363778,29.569994 L25.1923882,29.4350288 L21.657,25.9 L18.1213203,29.4350288 C16.9497475,30.6066017 15.0502525,30.6066017 13.8786797,29.4350288 C12.7539697,28.3103189 12.7089813,26.514756 13.7437145,25.3363778 L13.8786797,25.1923882 L17.414,21.657 L13.8786797,18.1213203 C12.7071068,16.9497475 12.7071068,15.0502525 13.8786797,13.8786797 C14.9565267,12.8008326 16.650487,12.7146048 17.8269121,13.6199964 L17.9773307,13.7437145 Z" id="Path-3" fill="#FFFFFF" fill-rule="nonzero" mask="url(#mask-3)"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 2.3 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="27px" height="27px" viewBox="0 0 27 27" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>F7C0551D-EEAD-4AA0-87B8-DE2D255390BB</title>
<g id="Welcome-dashboard---v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pandora-FMS---Tactical-view-v6" transform="translate(-1764, -1865)" fill="#95A3BF">
<g id="Log-storage" transform="translate(1102, 1662)">
<g id="Card-1/8" transform="translate(594, 203)">
<g id="System-event" transform="translate(68, 0)">
<path d="M11.7078546,2.70325912 C11.1257057,3.92992514 10.8,5.30192625 10.8,6.75 C10.8,11.9690909 15.0309091,16.2 20.25,16.2 C21.6996594,16.2 23.0730794,15.8735806 24.3007699,15.2902321 L24.3,20.4457055 C24.3,25.0619204 18.7171222,27 12.15,27 C5.58287783,27 0,25.0619204 0,20.4457055 L0,9.25429447 C0,4.79456141 5.2107929,2.83447266 11.4857292,2.70670994 Z M20.25,0 C23.9779221,0 27,3.02207794 27,6.75 C27,10.4779221 23.9779221,13.5 20.25,13.5 C16.5220779,13.5 13.5,10.4779221 13.5,6.75 C13.5,3.02207794 16.5220779,0 20.25,0 Z M21.6,4.05 L20.4317308,4.05 C20.3365385,4.59915254 19.7394231,5.05677966 18.9,5.06510015 L18.9,5.93875193 L20.2413462,5.93875193 L20.2413462,9.45 L21.6,9.45 L21.6,4.05 Z" id="Mask"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

(image error) Size: 1.4 KiB

View File

@ -0,0 +1,78 @@
<?php
/**
* Ajax secondary controller for general tactival view.
*
* @category Ajax general tactical view page.
* @package Pandora FMS
* @subpackage Opensource
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2023 Pandora FMS
* Please see https://pandorafms.com/community/ for full contribution list
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
// Only logged users have access to this endpoint.
check_login();
if (! check_acl($config['id_user'], 0, 'AR')) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access credential store'
);
if (is_ajax()) {
echo json_encode(['error' => 'noaccess']);
} else {
include 'general/noaccess.php';
}
exit;
}
// AJAX controller.
if (is_ajax()) {
$dir = $config['homedir'].'/include/lib/TacticalView/elements/';
$method = get_parameter('method');
$class = get_parameter('class');
$filepath = realpath($dir.'/'.$class.'.php');
if (is_readable($filepath) === false
|| is_dir($filepath) === true
|| preg_match('/.*\.php$/', $filepath) === false
) {
exit;
}
include_once $filepath;
if (class_exists($class) === true) {
$instance = new $class();
if ($instance->ajaxMethod($method) === true) {
echo $instance->{$method}();
} else {
$instance->error('Unavailable method.');
}
} else {
$class->error('Class not found. ['.$class.']');
}
exit;
}

View File

@ -256,6 +256,7 @@ class ConsoleSupervisor
/*
* Check if performance variables are corrects
*/
$this->checkPerformanceVariables();
/*
@ -289,6 +290,12 @@ class ConsoleSupervisor
*/
$this->checkMYSQLSettings();
/*
* Check log alerts version
*/
$this->checkLogAlerts();
}
@ -2099,8 +2106,8 @@ class ConsoleSupervisor
$this->notify(
[
'type' => 'NOTIF.EXT.ELASTICSEARCH',
'title' => __('Log collector cannot connect to ElasticSearch'),
'message' => __('ElasticSearch is not available using current configuration.'),
'title' => __('Log collector cannot connect to OpenSearch'),
'message' => __('OpenSearch is not available using current configuration.'),
'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup&section=log',
]
);
@ -3106,4 +3113,32 @@ class ConsoleSupervisor
}
/**
* Checks log alerts version.
*
* @return void
*/
public function checkLogAlerts()
{
global $config;
if ((bool) check_acl($config['id_user'], 0, 'LM') === true) {
$current_package = (int) $config['current_package'];
if ($current_package >= 774 && $current_package <= 777) {
$url = '__url__index.php?sec=galertas&sec2=enterprise/godmode/alerts/event_alerts';
$this->notify(
[
'type' => 'NOTIF.LOG.ALERT',
'title' => __('Alert correlation changed since version 774'),
'message' => __('Log correlation and log correlation with events will be disabled in this update. Some event correlation alerts may need to be modified to adapt to the new format'),
'url' => $url,
]
);
} else {
$this->cleanNotifications('NOTIF.LOG.ALERT');
}
}
}
}

View File

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

View File

@ -441,6 +441,7 @@ define('SERVER_TYPE_ALERT', 21);
define('SERVER_TYPE_CORRELATION', 22);
define('SERVER_TYPE_NCM', 23);
define('SERVER_TYPE_NETFLOW', 24);
define('SERVER_TYPE_LOG', 25);
define('SERVER_TYPE_MADE', 26);
// REPORTS.
@ -888,3 +889,8 @@ define('HOME_SCREEN_ALERT_DETAIL', 'alert_detail');
define('HOME_SCREEN_EXTERNAL_LINK', 'external_link');
define('HOME_SCREEN_OTHER', 'other');
define('HOME_SCREEN_DASHBOARD', 'dashboard');
// Alert correlation.
define('EVENT_ALERTS', 1);
define('LOG_ALERTS', 2);

View File

@ -1676,6 +1676,18 @@ function config_update_config()
if (config_update_value('Days_purge_old_information', (int) get_parameter('Days_purge_old_information'), true) === false) {
$error_update[] = __('Days to purge old information');
}
if (config_update_value('elasticsearch_user', get_parameter('elasticsearch_user'), true) === false) {
$error_update[] = __('User ElasticSearch server');
}
if (config_update_value('elasticsearch_pass', get_parameter('elasticsearch_pass'), true) === false) {
$error_update[] = __('Pass ElasticSearch server');
}
if (config_update_value('elasticsearch_https', get_parameter('elasticsearch_https'), true) === false) {
$error_update[] = __('Https ElasticSearch server');
}
break;
case 'hist_db':
@ -2466,7 +2478,19 @@ function config_process_config()
}
if (!isset($config['Days_purge_old_information'])) {
config_update_value('Days_purge_old_information', 90);
config_update_value('Days_purge_old_information', 30);
}
if (!isset($config['elasticsearch_user'])) {
config_update_value('elasticsearch_user', '');
}
if (!isset($config['elasticsearch_pass'])) {
config_update_value('elasticsearch_pass', '');
}
if (!isset($config['elasticsearch_https'])) {
config_update_value('elasticsearch_https', '');
}
if (!isset($config['font_size'])) {

View File

@ -2763,6 +2763,7 @@ function graph_agent_status(
'height' => $height,
'colors' => array_values($colors),
'legend' => ['display' => false],
'labels' => array_keys($data),
];
if ($donut_narrow_graph == true) {
@ -4624,12 +4625,17 @@ function graph_nodata_image($options)
return base64_encode($dataImg);
}
$widthImage = '200px';
if (isset($options['nodata_image']['width']) === true) {
$widthImage = $options['nodata_image']['width'];
}
return html_print_image(
'images/image_problem_area.png',
true,
[
'title' => __('No data'),
'style' => 'width: 200px;',
'style' => 'width: '.$widthImage.';',
]
);
}

View File

@ -7304,7 +7304,9 @@ function html_print_select_date_range(
$date_end='',
$time_end='',
$date_text=SECONDS_1DAY,
$class='w100p'
$class='w100p',
$date_format='Y/m/d',
$time_format='H:i:s'
) {
global $config;
@ -7326,21 +7328,21 @@ function html_print_select_date_range(
}
if ($date_end === '') {
$date_end = date('Y/m/d');
$date_end = date($date_format);
}
if ($date_init === '') {
$date_init = date('Y/m/d', strtotime($date_end.' -1 days'));
$date_init = date($date_format, strtotime($date_end.' -1 days'));
}
$date_init = date('Y/m/d', strtotime($date_init));
$date_init = date($date_format, strtotime($date_init));
if ($time_init === '') {
$time_init = date('H:i:s');
$time_init = date($time_format);
}
if ($time_end === '') {
$time_end = date('H:i:s');
$time_end = date($time_format);
}
$fields[SECONDS_1DAY] = __('Last 24hr');

View File

@ -906,7 +906,7 @@ function servers_get_info($id_server=-1, $sql_limit=-1)
'images/logs@svg.svg',
true,
[
'title' => __('Log server'),
'title' => __('Syslog server'),
'class' => 'main_menu_icon invert_filter',
]
);
@ -979,6 +979,19 @@ function servers_get_info($id_server=-1, $sql_limit=-1)
$id_modulo = 0;
break;
case SERVER_TYPE_LOG:
$server['img'] = html_print_image(
'images/log_server.svg',
true,
[
'title' => __('Log server'),
'class' => 'main_menu_icon invert_filter',
]
);
$server['type'] = 'log';
$id_modulo = 0;
break;
case SERVER_TYPE_MADE:
$server['img'] = html_print_image(
'images/Anomaly-detection@svg.svg',

View File

@ -7326,7 +7326,8 @@ function ui_query_result_editor($name='default')
]
);
html_print_submit_button(__('Execute query'), 'execute_query', false, ['icon' => 'update']);
$execute_button = html_print_submit_button(__('Execute query'), 'execute_query', false, ['icon' => 'update'], true);
html_print_action_buttons($execute_button);
}

View File

@ -725,6 +725,12 @@ function get_build_setup_charts($type, $options, $data)
$chart->options()->getElements()->center()->setColor($options['elements']['center']['color']);
}
}
if (isset($options['elements']['point']) === true) {
if (isset($options['elements']['point']['radius']) === true) {
$chart->options()->getElements()->point()->setRadius($options['elements']['point']['radius']);
}
}
}
// Set Responsive for responsive charts.
@ -1019,7 +1025,9 @@ function get_build_setup_charts($type, $options, $data)
) {
$scales = $chart->options()->getScales();
if ($options['scales']['x'] !== false) {
if (isset($options['scales']['x']) === true
&& $options['scales']['x'] !== false
) {
// Defaults scalesFont X.
$scalesXFonts = $scales->getX()->ticks()->getFonts();
$scalesXFonts->setFamily((empty($config['fontpath']) === true) ? 'lato' : $config['fontpath']);
@ -1028,7 +1036,9 @@ function get_build_setup_charts($type, $options, $data)
$scalesXFonts->setSize(((int) $config['font_size'] + 2));
}
if ($options['scales']['y'] !== false) {
if (isset($options['scales']['y']) === true
&& $options['scales']['y'] !== false
) {
// Defaults scalesFont Y.
$scalesYFonts = $scales->getY()->ticks()->getFonts();
$scalesYFonts->setFamily((empty($config['fontpath']) === true) ? 'lato' : $config['fontpath']);
@ -1037,7 +1047,9 @@ function get_build_setup_charts($type, $options, $data)
$scalesYFonts->setSize(((int) $config['font_size'] + 2));
}
if ($options['scales']['r'] !== false) {
if (isset($options['scales']['r']) === true
&& $options['scales']['r'] !== false
) {
// Defaults scalesFont R.
$scalesRFonts = $scales->getR()->pointLabels()->getFonts();
$scalesRFonts->setStyle('normal');
@ -1053,6 +1065,10 @@ function get_build_setup_charts($type, $options, $data)
$scales->getX()->setBounds($options['scales']['x']['bounds']);
}
if (isset($options['scales']['x']['display']) === true) {
$scales->getX()->setDisplay($options['scales']['x']['display']);
}
if (isset($options['scales']['x']['grid']) === true
&& empty($options['scales']['x']['grid']) === false
&& is_array($options['scales']['x']['grid']) === true
@ -1098,6 +1114,10 @@ function get_build_setup_charts($type, $options, $data)
$scales->getY()->setBounds($options['scales']['y']['bounds']);
}
if (isset($options['scales']['y']['display']) === true) {
$scales->getY()->setDisplay($options['scales']['y']['display']);
}
if (isset($options['scales']['y']['grid']) === true
&& empty($options['scales']['y']['grid']) === false
&& is_array($options['scales']['y']['grid']) === true
@ -1202,6 +1222,13 @@ function get_build_setup_charts($type, $options, $data)
$borders = array_values($defaultBorder);
}
if (isset($options['borderColors']) === true
&& empty($options['borderColors']) === false
&& is_array($options['borderColors']) === true
) {
$borders = $options['borderColors'];
}
// Set labels.
if (isset($options['labels']) === true
&& empty($options['labels']) === false

View File

@ -1,5 +1,8 @@
var editor = ace.edit("elasticsearch_editor");
editor.setValue(`GET _search \n{\n "query": {\n "match_all": {}\n }\n}`);
editor.setValue(`GET _search\n{\n "query": {\n "match_all": {}\n }\n}`);
editor.session.setMode("ace/mode/json");
editor.setTheme("ace/theme/textmate");
editor.session.setUseWorker(false);
editor.clearSelection();
var view = ace.edit("elasticsearch_view");

View File

@ -0,0 +1,94 @@
/* global $ */
$(document).ready(function() {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-last-24").html(data);
}
});
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsCriticalityGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-criticality").html(data);
}
});
// Prevent that graphs use same name.
setTimeout(() => {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsStatusGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-status-validate").html(data);
}
});
}, 100);
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getEventsStatusValidateGraph",
class: "Events"
},
type: "POST",
success: function(data) {
$("#events-status-pending-validate").html(data);
}
});
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: "getStatusHeatMap",
class: "Groups",
width: $("#heatmap-group").width() - 50,
height:
$("#heatmap-group").height() < 280 ? 280 : $("#heatmap-group").height()
},
type: "POST",
success: function(data) {
var title = $(data)[1];
var heatmap = $(data)[0];
$("#heatmap-group").html(heatmap);
$("#heatmap-title").html($(title).html());
}
});
});
function autoRefresh(interval, id, method, php_class) {
setInterval(() => {
$.ajax({
url: "ajax.php",
data: {
page: "include/ajax/general_tactical_view.ajax",
method: method,
class: php_class
},
type: "POST",
success: function(data) {
var content = $(data).html();
$("#" + id).html(content);
}
});
}, interval);
}

View File

@ -134,8 +134,9 @@ function render_counter() {
$(".counter-tips img:eq(0)").after(
"<span class='count-round-tip active'></span>"
);
if (totalTips > 1) {
for (let i = 1; i <= totalTips - 1; i++) {
var limitRound = totalTips > 28 ? 28 : totalTips;
if (limitRound > 1) {
for (let i = 1; i <= limitRound - 1; i++) {
$(".count-round-tip:eq(0)").after(
"<span class='count-round-tip'></span>"
);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
<?php
/**
* Element class parent for elements
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
namespace PandoraFMS\TacticalView;
/**
* Parent element for general tactical view elements
*/
class Element
{
/**
* Url of controller.
*
* @var string
*/
public $ajaxController;
/**
* List of available ajax methods.
*
* @var array
*/
protected $ajaxMethods = [];
/**
* Title of section
*
* @var string
*/
public $title;
/**
* Interval for refresh element, 0 for not refresh.
*
* @var integer
*/
public $interval;
/**
* Agent of automonitoritation
*
* @var array
*/
protected $monitoringAgent;
/**
* Refresh config for async method.
*
* @var array
*/
public $refreshConfig = [];
/**
* Contructor
*
* @param string $ajax_controller Controller.
*/
public function __construct(
$ajax_controller='include/ajax/general_tactical_view.ajax'
) {
$this->interval = 0;
$this->title = __('Default element');
$this->ajaxController = $ajax_controller;
// Without ACL.
$agent = db_get_row('tagente', 'nombre', 'pandora.internals', '*');
if (is_array($agent) === true) {
$this->monitoringAgent = $agent;
}
/*
// With ACL.
$agent = agents_get_agents(['nombre' => 'pandora.internals']);
if (is_array($agent) === true && count($agent) > 0) {
$this->monitoringAgent = $agent[0];
}
*/
}
/**
* Return error message to target.
*
* @param string $msg Error message.
*
* @return void
*/
public static function error(string $msg)
{
echo json_encode(['error' => $msg]);
}
/**
* Verifies target method is allowed to be called using AJAX call.
*
* @param string $method Method to be invoked via AJAX.
*
* @return boolean Available (true), or not (false).
*/
public function ajaxMethod(string $method):bool
{
return in_array($method, $this->ajaxMethods) === true;
}
/**
* Cut the text to display it on the labels.
*
* @param string $text Text for cut.
* @param integer $length Length max for text cutted.
*
* @return string
*/
protected function controlSizeText(string $text, int $length=14):string
{
if (mb_strlen($text) > $length) {
$newText = mb_substr($text, 0, $length).'...';
return $newText;
} else {
return $text;
}
}
/**
* Return a valur from Module of monitoring.
*
* @param string $moduleName Name of module value.
* @param integer $dateInit Date init for filter.
* @param integer $dateEnd Date end for filter.
*
* @return array Array of module data.
*/
protected function valueMonitoring(string $moduleName, int $dateInit=0, int $dateEnd=0):array
{
if (empty($this->monitoringAgent) === false) {
$module = modules_get_agentmodule_id(io_safe_input($moduleName), $this->monitoringAgent['id_agente']);
if (is_array($module) === true && key_exists('id_agente_modulo', $module) === true) {
if ($dateInit === 0 && $dateEnd === 0) {
$value = modules_get_last_value($module['id_agente_modulo']);
$rawData = [['datos' => $value]];
} else {
$rawData = modules_get_raw_data($module['id_agente_modulo'], $dateInit, $dateEnd);
}
if ($rawData === false || is_array($rawData) === false) {
return [['datos' => 0]];
} else {
return $rawData;
}
} else {
return [['datos' => 0]];
}
return [['datos' => 0]];
} else {
return [['datos' => 0]];
}
}
/**
* Simple image loading for async functions.
*
* @return string
*/
public static function loading():string
{
return html_print_div(
[
'content' => '<span></span>',
'class' => 'spinner-fixed inherit',
],
true
);
}
/**
* Return the name of class
*
* @return string
*/
public static function nameClass():string
{
return static::class;
}
}

View File

@ -0,0 +1,172 @@
<?php
/**
* General tactical view
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
namespace PandoraFMS\TacticalView;
use Exception;
use PandoraFMS\View;
/**
* General tactical view
*/
class GeneralTacticalView
{
/**
* List elements instanced for show in view.
*
* @var array
*/
protected $elements;
/**
* Constructor
*/
public function __construct()
{
ui_require_css_file('general_tactical_view');
ui_require_javascript_file('general_tactical_view');
$this->elements = $this->instanceElements();
}
/**
* Instantiate all the elements that will build the dashboard
*
* @return array
*/
public function instanceElements():array
{
global $config;
$dir = $config['homedir'].'/include/lib/TacticalView/elements/';
$handle = opendir($dir);
if ($handle === false) {
return [];
}
$ignores = [
'.',
'..',
];
$elements = [];
$elements['welcome'] = $this->getWelcomeMessage();
while (false !== ($file = readdir($handle))) {
try {
if (in_array($file, $ignores) === true) {
continue;
}
$filepath = realpath($dir.'/'.$file);
if (is_readable($filepath) === false
|| is_dir($filepath) === true
|| preg_match('/.*\.php$/', $filepath) === false
) {
continue;
}
$className = preg_replace('/.php/', '', $file);
include_once $filepath;
if (class_exists($className) === true) {
$instance = new $className();
$elements[$className] = $instance;
}
} catch (Exception $e) {
}
}
return $elements;
}
/**
* Render funcion for print the html.
*
* @return void
*/
public function render():void
{
$data = [];
$data['javascript'] = $this->javascript();
$data = array_merge($data, $this->elements);
View::render(
'tacticalView/view',
$data
);
}
/**
* Function for print js embedded in html.
*
* @return string
*/
public function javascript():string
{
$js = '<script>';
foreach ($this->elements as $key => $element) {
if ($element->interval > 0) {
foreach ($element->refreshConfig as $key => $conf) {
$js .= 'autoRefresh('.$element->interval.',"'.$conf['id'].'", "'.$conf['method'].'", "'.$element->nameClass().'");';
}
}
}
$js .= '</script>';
return $js;
}
/**
* Return the welcome message.
*
* @return string
*/
private function getWelcomeMessage():string
{
global $config;
$user = users_get_user_by_id($config['id_user']);
if (is_array($user) === true && count($user) > 0) {
$name = $user['fullname'];
} else {
$name = '';
}
if (empty($name) === true) {
$message = __('Welcome back! 👋');
} else {
$message = __('Welcome back %s! 👋', $name);
}
return html_print_div(
[
'content' => $message,
'class' => 'message-welcome',
],
true
);
}
}

View File

@ -0,0 +1,446 @@
<?php
/**
* Agents element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Agents, this class contain all logic for this section.
*/
class Agents extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Agents');
$this->ajaxMethods = ['getGroups'];
}
/**
* Get total number of agents.
*
* @return string
*/
public function getTotalAgents():string
{
$agents = agents_get_agents();
if (is_array($agents) === true) {
$total = count($agents);
} else {
$total = 0;
}
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Get total alerts of agents.
*
* @return string
*/
public function getAlerts():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$group_query = ' AND (
t3.id_grupo IN ('.$id_groups.')
OR tasg.id_group IN ('.$id_groups.')
)';
$sql = 'SELECT count(t0.id)
FROM talert_template_modules t0
INNER JOIN talert_templates t1
ON t0.id_alert_template = t1.id
INNER JOIN tagente_modulo t2
ON t0.id_agent_module = t2.id_agente_modulo
INNER JOIN tagente t3
ON t2.id_agente = t3.id_agente
LEFT JOIN tagent_secondary_group tasg
ON tasg.id_agent = t3.id_agente
WHERE last_fired >=UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY) '.$group_query;
$total = db_get_value_sql($sql);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Get a datatable with the top groups with more agents.
*
* @return string
*/
public function getDataTableGroups():string
{
$columns = [
'nombre',
'total',
];
$columnNames = [
__('Group alias'),
__('Agents'),
];
return ui_print_datatable(
[
'id' => 'list_groups',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'no_sortable_columns' => [
0,
1,
],
'ajax_data' => [
'method' => 'getGroups',
'class' => static::class,
],
'order' => [
'field' => 'title',
'direction' => 'asc',
],
'default_pagination' => 8,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return top 20 groups with more agents for ajax datatable.
*
* @return string
*/
public function getGroups():string
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$pagination = '';
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
try {
ob_start();
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$sql = sprintf(
'SELECT gr.nombre, count(*) +
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
INNER JOIN(
SELECT gr.id_grupo, count(*) AS total
FROM tagente a LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo ORDER BY total DESC LIMIT 20
) top_groups ON top_groups.id_grupo = gr.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC
%s',
$pagination
);
$rows = db_process_sql($sql);
$sql_count = 'SELECT gr.nombre,
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
INNER JOIN(
SELECT gr.id_grupo, count(*) AS total
FROM tagente a LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo ORDER BY total DESC LIMIT 20
) top_groups ON top_groups.id_grupo = gr.id_grupo
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC';
$total = db_get_num_rows($sql_count);
// Capture output.
$response = ob_get_clean();
return json_encode(
[
'data' => $rows,
'recordsTotal' => $total,
'recordsFiltered' => $total,
]
);
} catch (Exception $e) {
return json_encode(['error' => $e->getMessage()]);
}
return json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
return $response;
} else {
return json_encode(
[
'success' => false,
'error' => $response,
]
);
}
}
/**
* Return the html graph of number agents by os.
*
* @return string
*/
public function getOperatingSystemGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT name, count(*) AS total
FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
LEFT JOIN tconfig_os os ON os.id_os = a.id_os
WHERE a.id_grupo IN ('.$id_groups.') OR g.id_group IN ('.$id_groups.')
GROUP BY a.id_os
ORDER BY total DESC';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of number agents by status.
*
* @return string
*/
public function getStatusGraph():string
{
$agents = agents_get_agents(
false,
[
'id_agente',
'id_grupo',
'nombre',
'alias',
'id_os',
'ultimo_contacto',
'intervalo',
'comentarios description',
'quiet',
'normal_count',
'warning_count',
'critical_count',
'unknown_count',
'notinit_count',
'total_count',
'fired_count',
'ultimo_contacto_remoto',
'remote',
'agent_version',
]
);
$labels = [
__('No Monitors'),
__('CRITICAL'),
__('WARNING'),
__('UKNOWN'),
__('NORMAL'),
];
$totals = [
'no_monitors' => 0,
'critical' => 0,
'warning' => 0,
'unknown' => 0,
'ok' => 0,
];
$colors = [
COL_NOTINIT,
COL_CRITICAL,
COL_WARNING,
COL_UNKNOWN,
COL_NORMAL,
];
foreach ($agents as $key => $agent) {
if ($agent['total_count'] == 0 || $agent['total_count'] == $agent['notinit_count']) {
$totals['no_monitors']++;
}
if ($agent['critical_count'] > 0) {
$totals['critical']++;
} else if ($agent['warning_count'] > 0) {
$totals['warning']++;
} else if ($agent['unknown_count'] > 0) {
$totals['unknown']++;
} else {
$totals['ok']++;
}
}
foreach ($totals as $key => $total) {
$data[] = $total;
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '80%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
}

View File

@ -0,0 +1,274 @@
<?php
/**
* Alerts element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Alerts, this class contain all logic for this section.
*/
class Alerts extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Alerts');
$this->ajaxMethods = ['getUsers'];
$this->ajaxMethods = [
'getUsers',
'getCurrentlyTriggered',
'getActiveAlerts',
];
$this->interval = 300000;
$this->refreshConfig = [
'triggered' => [
'id' => 'currently-triggered',
'method' => 'getCurrentlyTriggered',
],
'active-correlation' => [
'id' => 'active-correlation',
'method' => 'getActiveAlerts',
],
];
}
/**
* Returns the html of currently triggered.
*
* @return string
*/
public function getCurrentlyTriggered():string
{
$total = alerts_get_alerts(0, '', 'fired', -1, 'AR', true);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'id' => 'currently-triggered',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of active correlation.
*
* @return string
*/
public function getActiveAlerts():string
{
$total = alerts_get_alerts(0, '', 'all', -1, 'AR', true);
return html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l',
'id' => 'active-correlation',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Return a datatable with de users lists.
*
* @return string
*/
public function getDataTableUsers():string
{
$columns = [
'id_user',
'is_admin',
'last_connect',
];
$columnNames = [
__('User'),
__('Role'),
__('Last seen'),
];
return ui_print_datatable(
[
'id' => 'list_users',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'ajax_data' => [
'method' => 'getUsers',
'class' => static::class,
],
'order' => [
'field' => 'title',
'direction' => 'asc',
],
'default_pagination' => 10,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return all users for ajax.
*
* @return string
*/
public function getUsers():string
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$orderDatatable = get_datatable_order(true);
$pagination = '';
$order = '';
try {
ob_start();
if (isset($orderDatatable)) {
$order = sprintf(
' ORDER BY %s %s',
$orderDatatable['field'],
$orderDatatable['direction']
);
}
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$sql = sprintf(
'SELECT DISTINCT id_user, is_admin ,last_connect
FROM tusuario u
LEFT JOIN tusuario_perfil p ON p.id_usuario = u.id_user
WHERE id_grupo IN ('.$id_groups.')
GROUP BY id_user
%s %s',
$order,
$pagination
);
$rows = db_process_sql($sql);
foreach ($rows as $key => $row) {
$rows[$key]['id_user'] = '<a href="index.php?sec=gusuarios&sec2=godmode/users/configure_user&edit_user=1&pure=0&id_user='.$row['id_user'].'">'.$row['id_user'].'</a>';
if ((bool) $row['is_admin'] === true) {
$rows[$key]['is_admin'] = '<span class="admin">'.__('Admin').'</span>';
} else {
$rows[$key]['is_admin'] = '<span class="user">'.__('User').'</span>';
}
if ($row['last_connect'] > 0) {
$rows[$key]['last_connect'] = ui_print_timestamp($row['last_connect'], true, ['prominent' => 'compact']);
} else {
$rows[$key]['last_connect'] = __('Unknown');
}
}
$sql_count = sprintf(
'SELECT DISTINCT id_user, count(*) as total
FROM tusuario u
LEFT JOIN tusuario_perfil p ON p.id_usuario = u.id_user
WHERE id_grupo IN ('.$id_groups.')
%s',
$order,
);
$total = db_process_sql($sql_count);
// Capture output.
$response = ob_get_clean();
return json_encode(
[
'data' => $rows,
'recordsTotal' => $total[0]['total'],
'recordsFiltered' => $total[0]['total'],
]
);
} catch (Exception $e) {
return json_encode(['error' => $e->getMessage()]);
}
json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
return $response;
} else {
return json_encode(
[
'success' => false,
'error' => $response,
]
);
}
}
/**
* Check if user can manager users.
*
* @return boolean
*/
public function checkAclUserList():bool
{
global $config;
$user_m = (bool) check_acl($config['id_user'], 0, 'UM');
return $user_m;
}
}

View File

@ -0,0 +1,252 @@
<?php
/**
* Configurations element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Configurations, this class contain all logic for this section.
*/
class Configurations extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Configurations');
}
/**
* Get total groups from automonitorization.
*
* @return string
*/
public function getTotalGroups():string
{
$value = $this->valueMonitoring('total_groups');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Groups.svg', true);
$text = '<span class="subtitle">'.__('Groups').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total modules from automonitorization.
*
* @return string
*/
public function getTotalModules():string
{
$value = $this->valueMonitoring('total_modules');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Modules.svg', true);
$text = '<span class="subtitle">'.__('Modules').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total policies from automonitorization.
*
* @return string
*/
public function getTotalPolicies():string
{
$totalPolicies = db_get_value(
'count(*)',
'tpolicies'
);
$image = html_print_image('images/Tactical_Policies.svg', true);
$text = '<span class="subtitle">'.__('Policies').'</span>';
$number = html_print_div(
[
'content' => format_numeric($totalPolicies, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total remote plugins from automonitorization.
*
* @return string
*/
public function getTotalRemotePlugins():string
{
$totalPLugins = db_get_value(
'count(*)',
'tplugin',
'plugin_type',
1,
);
$sql = 'SELECT count(*) AS total FROM tplugin WHERE plugin_type = 1;';
$rows = db_process_sql($sql);
$totalPLugins = 0;
if (is_array($rows) === true && count($rows) > 0) {
$totalPLugins = $rows[0]['total'];
}
$image = html_print_image('images/Tactical_Plugins.svg', true);
$text = '<span class="subtitle">'.__('Remote plugins').'</span>';
$number = html_print_div(
[
'content' => format_numeric($totalPLugins, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total module templates from automonitorization.
*
* @return string
*/
public function getTotalModuleTemplate():string
{
$countModuleTemplates = db_get_value(
'count(*)',
'tnetwork_profile'
);
$image = html_print_image('images/Tactical_Module_template.svg', true);
$text = '<span class="subtitle">'.__('Module templates').'</span>';
$number = html_print_div(
[
'content' => format_numeric($countModuleTemplates, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total not unit modules from automonitorization.
*
* @return string
*/
public function getNotInitModules():string
{
$value = $this->valueMonitoring('total_notinit');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Not_init_module.svg', true);
$text = '<span class="subtitle">'.__('Not-init modules').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Get total unknow agents from automonitorization.
*
* @return string
*/
public function getTotalUnknowAgents():string
{
$value = $this->valueMonitoring('total_unknown');
$total = round($value[0]['datos']);
$image = html_print_image('images/Tactical_Unknown_agent.svg', true);
$text = '<span class="subtitle">'.__('Unknown agents').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
/**
* Returns the html of total events.
*
* @return string
*/
public function getTotalEvents():string
{
$data = $this->valueMonitoring('last_events_24h');
$total = $data[0]['datos'];
$image = html_print_image('images/system_event.svg', true);
$text = '<span class="subtitle">'.__('Events in last 24 hrs').'</span>';
$number = html_print_div(
[
'content' => format_numeric($total, 0),
'class' => 'text-l text_center',
'style' => '',
],
true
);
$output = $image.$text.$number;
return $output;
}
}

View File

@ -0,0 +1,348 @@
<?php
/**
* Database element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Database, this class contain all logic for this section.
*/
class Database extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Database');
$this->ajaxMethods = [
'getStatus',
'getDataRecords',
'getEvents',
'getStringRecords',
'getReadsGraph',
'getWritesGraph',
];
$this->interval = 300000;
$this->refreshConfig = [
'status' => [
'id' => 'status-database',
'method' => 'getStatus',
],
'records' => [
'id' => 'data-records',
'method' => 'getDataRecords',
],
'events' => [
'id' => 'total-events',
'method' => 'getEvents',
],
'totalRecords' => [
'id' => 'total-records',
'method' => 'getStringRecords',
],
'reads' => [
'id' => 'database-reads',
'method' => 'getReadsGraph',
],
'writes' => [
'id' => 'database-writes',
'method' => 'getWritesGraph',
],
];
}
/**
* Returns the html status of database.
*
* @return string
*/
public function getStatus():string
{
// TODO connect to automonitorization.
$status = true;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'flex_center margin-top-5',
'id' => 'status-database',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html records data of database.
*
* @return string
*/
public function getDataRecords():string
{
$data = $this->valueMonitoring('mysql_size_of_data');
$value = format_numeric($data[0]['datos'], 2).' MB';
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'data-records',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total events.
*
* @return string
*/
public function getEvents():string
{
$data = $this->valueMonitoring('last_events_24h');
$value = format_numeric($data[0]['datos']);
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'total-events',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total records.
*
* @return string
*/
public function getStringRecords():string
{
$data = $this->valueMonitoring('total_string_data');
$value = format_numeric($data[0]['datos']);
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'id' => 'total-records',
'style' => 'margin: 0px 10px 10px 10px;',
],
true
);
}
/**
* Returns the html of total reads database in a graph.
*
* @return string
*/
public function getReadsGraph():string
{
$dateInit = (time() - 86400);
$reads = $this->valueMonitoring('mysql_questions_reads', $dateInit, time());
$dates = [];
$string_reads = [];
$total = 0;
foreach ($reads as $key => $read) {
$dates[] = date('d-m-Y H:i:s', $read['utimestamp']);
$string_reads[] = $read['datos'];
$total += $read['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#EC7176',
'borderColor' => '#EC7176',
'pointBackgroundColor' => '#EC7176',
'pointHoverBorderColor' => '#EC7176',
'data' => $string_reads,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'w100p h100p centered',
'style' => 'max-height: 83px; max-width: 93%; margin-bottom: 10px;',
],
true
);
$total = html_print_div(
[
'content' => format_numeric($total),
'class' => 'text-xl',
],
true
);
$output = html_print_div(
[
'content' => $total.$graph_area,
'id' => 'database-reads',
],
true
);
return $output;
}
/**
* Returns the html of total writes database in a graph.
*
* @return string
*/
public function getWritesGraph():string
{
$dateInit = (time() - 86400);
$writes = $this->valueMonitoring('mysql_questions_writes', $dateInit, time());
$dates = [];
$string_writes = [];
$total = 0;
foreach ($writes as $key => $write) {
$dates[] = date('d-m-Y H:i:s', $write['utimestamp']);
$string_writes[] = $write['datos'];
$total += $write['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#009D9E',
'borderColor' => '#009D9E',
'pointBackgroundColor' => '#009D9E',
'pointHoverBorderColor' => '#009D9E',
'data' => $string_writes,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'w100p h100p centered',
'style' => 'max-height: 83px; max-width: 93%; margin-bottom: 10px;',
],
true
);
$total = html_print_div(
[
'content' => format_numeric($total),
'class' => 'text-xl',
],
true
);
$output = html_print_div(
[
'content' => $total.$graph_area,
'id' => 'database-writes',
],
true
);
return $output;
}
/**
* Check if user can manage database
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$db_m = (bool) check_acl($config['id_user'], 0, 'DM');
return $db_m;
}
}

View File

@ -0,0 +1,485 @@
<?php
/**
* Events element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Events, this class contain all logic for this section.
*/
class Events extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Events');
$this->ajaxMethods = [
'getEventsGraph',
'getEventsCriticalityGraph',
'getEventsStatusValidateGraph',
'getEventsStatusGraph',
];
}
/**
* Return the html graph of events in last 24h.
*
* @return string
*/
public function getEventsGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT utimestamp from tevento WHERE utimestamp >= '.$intervalh.' ORDER BY utimestamp DESC;';
$rows = db_process_sql($sql);
$cut_seconds = ($time_events / 24);
$now = (time() - 300);
$cuts_intervals = [];
for ($i = 0; $i < 24; $i++) {
$cuts_intervals[$now] = 0;
$now -= $cut_seconds;
}
foreach ($rows as $key => $row) {
foreach ($cuts_intervals as $time => $count) {
if ($row['utimestamp'] > $time) {
$cuts_intervals[$time]++;
break;
}
}
}
$cuts_intervals = array_reverse($cuts_intervals, true);
$graph_values = [];
$colors = [];
$max_value = 0;
foreach ($cuts_intervals as $utimestamp => $count) {
if ($max_value < $count) {
$max_value = $count;
}
$graph_values[] = [
'y' => $count,
'x' => date('d-m-Y H:i:s', $utimestamp),
];
}
$danger = $max_value;
$ok = ($max_value / 3);
foreach ($graph_values as $key => $value) {
if ($value['y'] >= $danger) {
$colors[] = '#EC7176';
}
if ($value['y'] >= $ok && $value['y'] < $danger) {
$colors[] = '#FCAB10';
}
if ($value['y'] < $ok) {
$colors[] = '#82B92E';
}
}
$options = [
'height' => 237,
'legend' => ['display' => false],
'scales' => [
'x' => [
'bounds' => 'data',
'grid' => ['display' => false],
'display' => false,
],
'y' => [
'grid' => ['display' => false],
],
],
'colors' => $colors,
'borderColors' => ['#ffffff'],
];
$bar = vbar_graph($graph_values, $options);
$output = html_print_div(
[
'content' => $bar,
'class' => 'margin-top-5 w100p relative',
'style' => 'max-height: 250px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by criticity.
*
* @return string
*/
public function getEventsCriticalityGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT criticity, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by criticity';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
$colors = [];
foreach ($rows as $key => $row) {
switch ($row['criticity']) {
case EVENT_CRIT_CRITICAL:
$label = __('CRITICAL');
$colors[] = COL_CRITICAL;
break;
case EVENT_CRIT_MAINTENANCE:
$label = __('MAINTENANCE');
$colors[] = COL_MAINTENANCE;
break;
case EVENT_CRIT_INFORMATIONAL:
$label = __('INFORMATIONAL');
$colors[] = COL_INFORMATIONAL;
break;
case EVENT_CRIT_MAJOR:
$label = __('MAJOR');
$colors[] = COL_MAJOR;
break;
case EVENT_CRIT_MINOR:
$label = __('MINOR');
$colors[] = COL_MINOR;
break;
case EVENT_CRIT_NORMAL:
$label = __('NORMAL');
$colors[] = COL_NORMAL;
break;
case EVENT_CRIT_WARNING:
$label = __('WARNING');
$colors[] = COL_WARNING;
break;
default:
$colors[] = COL_UNKNOWN;
$label = __('UNKNOWN');
break;
}
$labels[] = $this->controlSizeText($label);
$data[] = $row['total'];
}
$options = [
'waterMark' => false,
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by status validate.
*
* @return string
*/
public function getEventsStatusValidateGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT estado, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by estado';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
switch ($row['estado']) {
case '2':
$label = _('In process');
break;
case '0':
$label = _('New events');
break;
case '3':
$label = _('Not validated');
break;
case '1':
$label = _('Validated events');
break;
default:
$label = __('Unknow');
break;
}
$labels[] = $label;
$data[] = $row['total'];
}
$options = [
'waterMark' => false,
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the html graph of events in last 8h grouped by status.
*
* @return string
*/
public function getEventsStatusGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
if (users_can_manage_group_all() === true) {
$id_groups[] = 0;
}
$id_groups = implode(',', $id_groups);
$event_view_h = (int) ($config['event_view_hr'] > 24) ? 24 : $config['event_view_hr'];
$time_events = ($event_view_h * 3600);
$intervalh = (time() - $time_events);
$sql = 'SELECT criticity, count(*) AS total
FROM tevento
WHERE utimestamp >= '.$intervalh.' AND id_grupo IN ('.$id_groups.')
group by criticity';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
$colors = [];
foreach ($rows as $key => $row) {
switch ($row['criticity']) {
case EVENT_CRIT_CRITICAL:
$label = __('CRITICAL');
$colors[] = COL_CRITICAL;
break;
case EVENT_CRIT_NORMAL:
$label = __('NORMAL');
$colors[] = COL_NORMAL;
break;
case EVENT_CRIT_WARNING:
$label = __('WARNING');
$colors[] = COL_WARNING;
break;
default:
$colors[] = COL_UNKNOWN;
$label = __('UNKNOWN');
break;
}
$labels[] = $this->controlSizeText($label);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => ['display' => false],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
'colors' => $colors,
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Return the datatable events in last 8 hours.
*
* @return string
*/
public function getDataTableEvents()
{
$column_names = [
__('S'),
__('Event'),
__('Date'),
];
$fields = [
'mini_severity',
'evento',
'timestamp',
];
return ui_print_datatable(
[
'id' => 'datatable_events',
'class' => 'info_table events',
'style' => 'width: 90%;',
'ajax_url' => 'operation/events/events',
'ajax_data' => [
'get_events' => 1,
'compact_date' => 1,
'external_url' => 1,
],
'order' => [
'field' => 'timestamp',
'direction' => 'desc',
],
'column_names' => $column_names,
'columns' => $fields,
'ajax_return_operation' => 'buffers',
'ajax_return_operation_function' => 'process_buffers',
'return' => true,
'csv' => 0,
'dom_elements' => 'tfp',
'default_pagination' => 8,
]
);
}
/**
* Check permission user for view events section.
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$event_a = (bool) check_acl($config['id_user'], 0, 'ER');
return $event_a;
}
}

View File

@ -0,0 +1,563 @@
<?php
/**
* Groups element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Groups, this class contain all logic for this section.
*/
class Groups extends Element
{
/**
* Total groups.
*
* @var integer
*/
public $total;
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
include_once $config['homedir'].'/include/functions_users.php';
include_once $config['homedir'].'/include/functions_groupview.php';
$this->ajaxMethods = ['getStatusHeatMap'];
ui_require_css_file('heatmap');
$this->title = __('Groups');
$this->total = $this->calculateTotalGroups();
}
/**
* Return the total groups.
*
* @return integer
*/
public function calculateTotalGroups():int
{
$total = db_get_value_sql('SELECT count(*) FROM tgrupo');
return $total;
}
/**
* Return the status groups in heat map.
*
* @return string
*/
public function getStatusHeatMap():string
{
global $config;
$groups = users_get_groups($config['id_group'], 'AR', false);
if (is_array($groups) === true && count($groups) >= 10) {
return $this->getStatusHeatMapGroup();
}
$agents = agents_get_agents();
if (is_array($agents) === true && count($agents) >= 10) {
$this->title = __('My monitored agents');
return $this->getStatusHeatMapAgents().'<span id="heatmap-title">'.$this->title.'</span>';
}
$this->title = __('My monitored modules');
return $this->getStatusHeatMapModules().'<span id="heatmap-title">'.$this->title.'</span>';
}
/**
* Return the status modules in heatmap.
*
* @return string
*/
public function getStatusHeatMapModules():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$modules = modules_get_modules_in_group($id_groups);
$total_groups = count($modules);
if ($total_groups === 0) {
return graph_nodata_image(['width' => '400']);
}
$groups = $modules;
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_groups) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($groups as $key => $value) {
$module_id = $value['id_agente_modulo'];
$db_status = modules_get_agentmodule_status($module_id);
$module_value = modules_get_last_value($module_id);
$status = '';
$title = '';
modules_get_status($module_id, $db_status, $module_value, $status, $title);
switch ($status) {
case STATUS_MODULE_NO_DATA:
// Not init status.
$status = 'notinit';
break;
case STATUS_MODULE_CRITICAL:
// Critical status.
$status = 'critical';
break;
case STATUS_MODULE_WARNING:
// Warning status.
$status = 'warning';
break;
case STATUS_MODULE_OK:
// Normal status.
$status = 'normal';
break;
case 3:
case -1:
default:
// Unknown status.
$status = 'unknown';
break;
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_groups = "'.$total_groups.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_groups);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_groups / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
/**
* Return the status agents in heat map.
*
* @return string
*/
public function getStatusHeatMapAgents():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT * FROM tagente a
LEFT JOIN tagent_secondary_group g ON g.id_agent = a.id_agente
WHERE g.id_group IN ('.$id_groups.') OR a.id_grupo IN ('.$id_groups.')';
$all_agents = db_get_all_rows_sql($sql);
if (empty($all_agents)) {
return null;
}
$total_agents = count($all_agents);
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_agents) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($all_agents as $key => $value) {
// Colour by status.
$status = agents_get_status_from_counts($value);
switch ($status) {
case 5:
// Not init status.
$status = 'notinit';
break;
case 1:
// Critical status.
$status = 'critical';
break;
case 2:
// Warning status.
$status = 'warning';
break;
case 0:
// Normal status.
$status = 'normal';
break;
case 3:
case -1:
default:
// Unknown status.
$status = 'unknown';
break;
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_agents = "'.$total_agents.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_agents);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_agents / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
/**
* Return the status groups in heat map.
*
* @return string
*/
public function getStatusHeatMapGroup():string
{
global $config;
$width = get_parameter('width', 350);
$height = get_parameter('height', 275);
// ACL Check.
$agent_a = check_acl($config['id_user'], 0, 'AR');
$agent_w = check_acl($config['id_user'], 0, 'AW');
$groups_list = groupview_get_groups_list(
$config['id_user'],
($agent_a == true) ? 'AR' : (($agent_w == true) ? 'AW' : 'AR'),
true
);
$total_groups = $groups_list['counter'];
$groups = $groups_list['groups'];
// Best square.
$high = (float) max($width, $height);
$low = 0.0;
while (abs($high - $low) > 0.000001) {
$mid = (($high + $low) / 2.0);
$midval = (floor($width / $mid) * floor($height / $mid));
if ($midval >= $total_groups) {
$low = $mid;
} else {
$high = $mid;
}
}
$square_length = min(($width / floor($width / $low)), ($height / floor($height / $low)));
// Print starmap.
$heatmap = sprintf(
'<svg id="svg" style="width: %spx; height: %spx;">',
$width,
$height
);
$heatmap .= '<g>';
$row = 0;
$column = 0;
$x = 0;
$y = 0;
$cont = 1;
foreach ($groups as $key => $value) {
if ($value['_name_'] === 'All') {
continue;
}
if ($value['_monitors_critical_'] > 0) {
$status = 'critical';
} else if ($value['_monitors_warning_'] > 0) {
$status = 'warning';
} else if (($value['_monitors_unknown_'] > 0) || ($value['_agents_unknown_'] > 0)) {
$status = 'unknown';
} else if ($value['_monitors_ok_'] > 0) {
$status = 'normal';
} else {
$status = 'unknown';
}
$heatmap .= sprintf(
'<rect id="%s" x="%s" style="stroke-width:1;stroke:#ffffff" y="%s" row="%s" rx="3" ry="3" col="%s" width="%s" height="%s" class="scuare-status %s_%s"></rect>',
'rect_'.$cont,
$x,
$y,
$row,
$column,
$square_length,
$square_length,
$status,
random_int(1, 10)
);
$y += $square_length;
$row++;
if ((int) ($y + $square_length) > (int) $height) {
$y = 0;
$x += $square_length;
$row = 0;
$column++;
}
if ((int) ($x + $square_length) > (int) $width) {
$x = 0;
$y += $square_length;
$column = 0;
$row++;
}
$cont++;
}
$heatmap .= '<script type="text/javascript">
$(document).ready(function() {
const total_groups = "'.$total_groups.'";
function getRandomInteger(min, max) {
return Math.floor(Math.random() * max) + min;
}
function oneSquare(solid, time) {
var randomPoint = getRandomInteger(1, total_groups);
let target = $(`#rect_${randomPoint}`);
let class_name = target.attr("class");
class_name = class_name.split("_")[0];
setTimeout(function() {
target.removeClass();
target.addClass(`${class_name}_${solid}`);
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
}, time);
}
let cont = 0;
while (cont < Math.ceil(total_groups / 3)) {
oneSquare(getRandomInteger(1, 10), getRandomInteger(100, 900));
cont ++;
}
});
</script>';
$heatmap .= '</g>';
$heatmap .= '</svg>';
return html_print_div(
[
'content' => $heatmap,
'style' => 'margin: 0 auto; width: fit-content; min-height: 285px;',
],
true
);
}
}

View File

@ -0,0 +1,219 @@
<?php
/**
* LogStorage element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* LogStorage, this class contain all logic for this section.
*/
class LogStorage extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('Log storage');
$this->ajaxMethods = [
'getStatus',
'getTotalSources',
'getStoredData',
'getAgeOfStoredData',
];
$this->interval = 300000;
$this->refreshConfig = [
'status' => [
'id' => 'status-log-storage',
'method' => 'getStatus',
],
'total-source' => [
'id' => 'total-source-log-storage',
'method' => 'getTotalSources',
],
'total-lines' => [
'id' => 'total-lines-log-storage',
'method' => 'getStoredData',
],
'age' => [
'id' => 'age-of-stored',
'method' => 'getAgeOfStoredData',
],
];
}
/**
* Check if log storage module exist.
*
* @return boolean
*/
public function isEnabled():bool
{
global $config;
if ((bool) $config['log_collector'] === true) {
return true;
} else {
return false;
}
}
/**
* Returns the html status of log storage.
*
* @return string
*/
public function getStatus():string
{
$classDisabled = '';
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('Log server connection');
$status = ((int) $value[0]['datos'] === 1) ? true : false;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
} else {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
$classDisabled = 'alpha50';
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'flex_center margin-top-5 '.$classDisabled,
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'status-log-storage',
],
true
);
}
/**
* Returns the html of total sources in log storage.
*
* @return string
*/
public function getTotalSources():string
{
if ($this->isEnabled() === true) {
$data = $this->valueMonitoring('Total sources');
$value = format_numeric($data[0]['datos']);
} else {
$value = __('N/A');
}
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'total-source-log-storage',
],
true
);
}
/**
* Returns the html of lines in log storage.
*
* @return string
*/
public function getStoredData():string
{
if ($this->isEnabled() === true) {
$data = $this->valueMonitoring('Total lines of data');
$value = format_numeric($data[0]['datos']);
} else {
$value = __('N/A');
}
return html_print_div(
[
'content' => $value,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'total-lines-log-storage',
],
true
);
}
/**
* Returns the html of age of stored data.
*
* @return string
*/
public function getAgeOfStoredData():string
{
$data = $this->valueMonitoring('Longest data archived');
$date = $data[0]['datos'];
if ($date > 0 && $this->isEnabled() === true) {
$interval = (time() - strtotime($date));
$days = format_numeric(($interval / 86400), 0);
} else {
$days = 'N/A';
}
return html_print_div(
[
'content' => $days,
'class' => 'text-l',
'style' => 'margin: 0px 10px 0px 10px;',
'id' => 'age-of-stored',
],
true
);
}
}

View File

@ -0,0 +1,246 @@
<?php
/**
* MonitoringElements element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* MonitoringElements, this class contain all logic for this section.
*/
class MonitoringElements extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
include_once $config['homedir'].'/include/graphs/fgraph.php';
include_once $config['homedir'].'/include/functions_graph.php';
$this->title = __('Monitoring elements');
}
/**
* Returns the html of the tags grouped by modules.
*
* @return string
*/
public function getTagsGraph():string
{
$sql = 'SELECT name, count(*) AS total
FROM ttag_module t
LEFT JOIN ttag ta ON ta.id_tag = t.id_tag
GROUP BY t.id_tag
ORDER BY total DESC
LIMIT 10;';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of the groups grouped by modules.
*
* @return string
*/
public function getModuleGroupGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT name, count(*) AS total
FROM tagente_modulo m
LEFT JOIN tagente a on a.id_agente = m.id_agente
LEFT JOIN tagent_secondary_group gs ON gs.id_agent = a.id_agente
LEFT JOIN tmodule_group g ON g.id_mg = m.id_module_group
WHERE name <> "" AND (a.id_grupo IN ('.$id_groups.') OR gs.id_group IN ('.$id_groups.'))
GROUP BY m.id_module_group
ORDER BY total DESC
LIMIT 10';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['name']) === true) {
continue;
}
$labels[] = $this->controlSizeText($row['name']);
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of the agent grouped by modules.
*
* @return string
*/
public function getAgentGroupsGraph():string
{
global $config;
$id_groups = array_keys(users_get_groups($config['id_user'], 'AR', false));
if (in_array(0, $id_groups) === false) {
foreach ($id_groups as $key => $id_group) {
if ((bool) check_acl_restricted_all($config['id_user'], $id_group, 'AR') === false) {
unset($id_groups[$key]);
}
}
}
$id_groups = implode(',', $id_groups);
$sql = 'SELECT gr.nombre, count(*) +
IFNULL((SELECT count(*) AS total
FROM tagente second_a
LEFT JOIN tagent_secondary_group second_g ON second_g.id_agent = second_a.id_agente
WHERE a.id_grupo = second_g.id_group AND second_g.id_group IN ('.$id_groups.')
GROUP BY second_g.id_group
), 0) AS total
FROM tagente a
LEFT JOIN tgrupo gr ON gr.id_grupo = a.id_grupo
WHERE a.id_grupo IN ('.$id_groups.')
GROUP BY a.id_grupo
ORDER BY total DESC
LIMIT 10';
$rows = db_process_sql($sql);
$labels = [];
$data = [];
foreach ($rows as $key => $row) {
if (empty($row['nombre']) === true) {
continue;
}
$labels[] = $this->controlSizeText(io_safe_output($row['nombre']));
$data[] = $row['total'];
}
$options = [
'labels' => $labels,
'legend' => [
'position' => 'bottom',
'align' => 'right',
'display' => false,
],
'cutout' => 80,
'nodata_image' => ['width' => '100%'],
];
$pie = ring_graph($data, $options);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
/**
* Returns the html of monitoring by status.
*
* @return string
*/
public function getMonitoringStatusGraph():string
{
$pie = graph_agent_status(false, '', '', true, true, false, true);
$output = html_print_div(
[
'content' => $pie,
'style' => 'margin: 0 auto; max-width: 80%; max-height: 220px;',
],
true
);
return $output;
}
}

View File

@ -0,0 +1,124 @@
<?php
/**
* NewsBoard element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* NewsBoard, this class contain all logic for this section.
*/
class NewsBoard extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
ui_require_css_file('news');
include_once 'general/news_dialog.php';
$this->title = __('News Board');
}
/**
* Returns the html of the latest news.
*
* @return string
*/
public function getNews():string
{
global $config;
$options = [];
$options['id_user'] = $config['id_user'];
$options['modal'] = false;
$options['limit'] = 7;
$news = get_news($options);
if (!empty($news)) {
$output = '<div id="news-board" class="new">';
foreach ($news as $article) {
$default = false;
if ($article['text'] == '&amp;lt;p&#x20;style=&quot;text-align:&#x20;center;&#x20;font-size:&#x20;13px;&quot;&amp;gt;Hello,&#x20;congratulations,&#x20;if&#x20;you&apos;ve&#x20;arrived&#x20;here&#x20;you&#x20;already&#x20;have&#x20;an&#x20;operational&#x20;monitoring&#x20;console.&#x20;Remember&#x20;that&#x20;our&#x20;forums&#x20;and&#x20;online&#x20;documentation&#x20;are&#x20;available&#x20;24x7&#x20;to&#x20;get&#x20;you&#x20;out&#x20;of&#x20;any&#x20;trouble.&#x20;You&#x20;can&#x20;replace&#x20;this&#x20;message&#x20;with&#x20;a&#x20;personalized&#x20;one&#x20;at&#x20;Admin&#x20;tools&#x20;-&amp;amp;gt;&#x20;Site&#x20;news.&amp;lt;/p&amp;gt;&#x20;') {
$article['subject'] = __('Welcome to Pandora FMS Console');
$default = true;
}
$text_bbdd = io_safe_output($article['text']);
$text = html_entity_decode($text_bbdd);
$output .= '<div class="new-board">';
$output .= '<div class="new-board-header">';
$output .= '<span class="new-board-title">'.$article['subject'].'</span>';
$output .= '<span class="new-board-author">'.__('By').' '.$article['author'].' '.ui_print_timestamp($article['timestamp'], true).'</span>';
$output .= '</div>';
$output .= '<div class="new content">';
if ($default) {
$output .= '<div class="default-new">';
$output .= '<div class="default-image-new">';
$output .= '<img src="./images/welcome_image.svg" alt="img colabora con nosotros - Support">';
$output .= '</div><div class="default-text-new">';
$output .= '
<p>'.__('Welcome to our monitoring tool so grand,').'
<br>'.__('Where data insights are at your command.').'
<br>'.__('Sales, marketing, operations too,').'
<br>'.__("Customer support, we've got you.").'
</p>
<p>'.__('Our interface is user-friendly,').'
<br>'.__("Customize your dashboard, it's easy.").'
<br>'.__('Set up alerts and gain insights so keen,').'
<br>'.__("Optimize your data, like you've never seen.").'
</p>
<p>'.__('Unleash its power now, and join the pro league,').'
<br>'.__('Unlock the potential of your data to intrigue.').'
<br>'.__('Monitoring made simple, efficient and fun,').'
<br>'.__('Discover a whole new way to get things done.').'
</p>
<p>'.__('And take control of your IT once and for all.').'</p>
<span>'.__('You can replace this message with a personalized one at Admin tools -> Site news.').'</span>
';
$output .= '</div></div>';
} else {
$text = str_replace('<script', '&lt;script', $text);
$text = str_replace('</script', '&lt;/script', $text);
$output .= nl2br($text);
}
$output .= '</div></div>';
}
$output .= '</div>';
return $output;
}
}
}

View File

@ -0,0 +1,345 @@
<?php
/**
* Overview element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* Overview, this class contain all logic for this section.
*/
class Overview extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
if (is_ajax() === true) {
include_once $config['homedir'].'/include/functions_servers.php';
}
$this->title = __('General overview');
$this->ajaxMethods = [
'getLogSizeStatus',
'getServerStatus',
'getCPULoadGraph',
];
$this->interval = 300000;
$this->refreshConfig = [
'logSizeStatus' => [
'id' => 'status-log-size',
'method' => 'getLogSizeStatus',
],
'ServerStatus' => [
'id' => 'status-servers',
'method' => 'getServerStatus',
],
'cpuStatus' => [
'id' => 'status-cpu',
'method' => 'getCPULoadGraph',
],
];
}
/**
* Return the html log size status.
*
* @return string
*/
public function getLogSizeStatus():string
{
$size = $this->valueMonitoring('console_log_size');
$status = ($size[0]['datos'] < 1000) ? true : false;
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Too size log size'),
'class' => 'status-text',
],
true
);
}
$output = $image_status.$text;
return html_print_div(
[
'content' => $output,
'class' => 'margin-top-5 flex_center',
'id' => 'status-log-size',
],
true
);
}
/**
* Return the html Servers status.
*
* @return string
*/
public function getServerStatus():string
{
$status = check_all_servers_up();
if ($status === true) {
$image_status = html_print_image('images/status_check@svg.svg', true);
$text = html_print_div(
[
'content' => __('Everythings OK!'),
'class' => 'status-text',
],
true
);
} else {
$image_status = html_print_image('images/status_error@svg.svg', true);
$text = html_print_div(
[
'content' => __('Somethings wrong'),
'class' => 'status-text',
],
true
);
}
$output = '<a href="index.php?sec=gservers&sec2=godmode/servers/modificar_server" class="flex_center">'.$image_status.$text.'</a>';
return html_print_div(
[
'content' => $output,
'class' => 'margin-top-5',
'id' => 'status-servers',
],
true
);
}
/**
* Returns the html of the used licenses.
*
* @return string
*/
public function getLicenseUsageGraph():string
{
if (enterprise_installed() === true) {
$info = license_get_info();
if ($info['limit'] > $info['count']) {
$used = round(($info['count'] / $info['limit']) * 100);
$free = (100 - $used);
} else {
$free = 100;
$used = 0;
}
$data = [
'agents_used' => [
'label' => __('% Agents used'),
'perc' => $used,
'color' => '#1C4E6B',
],
'free_agents' => [
'label' => __('% Free agents'),
'perc' => $free,
'color' => '#5C63A2',
],
];
} else {
$agents = agents_get_agents();
$enabled_agents = agents_get_agents(
false,
false,
'AR',
[
'field' => 'nombre',
'order' => 'ASC',
],
false,
1
);
if (is_array($agents) === true) {
$total = count($agents);
} else {
$total = 0;
}
if ($total > 0 && is_array($enabled_agents) === true) {
$total_disabled_agents = round((($total - count($enabled_agents)) * 100) / $total);
$total_enabled_agents = round((count($enabled_agents) * 100) / $total);
} else {
$total_disabled_agents = 0;
$total_enabled_agents = 100;
}
$data = [
'agents_enabled' => [
'label' => __('% Agents enabled'),
'perc' => $total_enabled_agents,
'color' => '#1C4E6B',
],
'agents_disabled' => [
'label' => __('% Agents disabled'),
'perc' => $total_disabled_agents,
'color' => '#5C63A2',
],
];
}
$bar = $this->printHorizontalBar($data);
$output = html_print_div(
[
'content' => $bar,
'style' => 'margin: 0 auto;',
],
true
);
return $output;
}
/**
* Print horizontal bar divided by percentage.
*
* @param array $data Required [perc, color, label].
*
* @return string
*/
private function printHorizontalBar(array $data):string
{
$output = '<div id="horizontalBar">';
$output .= '<div class="labels">';
foreach ($data as $key => $value) {
$output .= html_print_div(
[
'content' => '<div style="background: '.$value['color'].'"></div><span>'.$value['label'].'</span>',
'class' => 'label',
],
true
);
}
$output .= '</div>';
$output .= '<div class="bar">';
foreach ($data as $key => $value) {
$output .= html_print_div(
[
'content' => $value['perc'].' %',
'style' => 'width: '.$value['perc'].'%; background-color: '.$value['color'].';',
],
true
);
}
$output .= '</div>';
$output .= '
<div class="marks">
<div class="mark"><div class="line mark0"></div><span class="number">0 %</span></div>
<div class="mark"><div class="line mark20"></div><span class="number number20">20 %</span></div>
<div class="mark"><div class="line mark40"></div><span class="number number40">40 %</span></div>
<div class="mark"><div class="line mark60"></div><span class="number number60">60 %</span></div>
<div class="mark"><div class="line mark80"></div><span class="number number80">80 %</span></div>
<div class="mark"><div class="line mark100"></div><span class="number number100">100 %</span></div>
</div>';
$output .= '</div>';
return $output;
}
/**
* Returns the html of a graph with the cpu load.
*
* @return string
*/
public function getCPULoadGraph():string
{
$data_last24h = $this->valueMonitoring('CPU Load', (time() - 86400), time());
$dates = [];
$cpu_load = [];
foreach ($data_last24h as $key => $raw_data) {
$dates[] = date('H:m:s', $raw_data['utimestamp']);
$cpu_load[] = $raw_data['datos'];
}
$options = [
'labels' => $dates,
'legend' => [ 'display' => false ],
'tooltips' => [ 'display' => false ],
'scales' => [
'y' => [
'grid' => ['display' => false],
'ticks' => ['display' => false],
'display' => false,
],
'x' => [
'grid' => ['display' => false],
'display' => false,
],
],
'elements' => [ 'point' => [ 'radius' => 0 ] ],
];
$data = [
[
'backgroundColor' => '#009D9E',
'borderColor' => '#009D9E',
'pointBackgroundColor' => '#009D9E',
'pointHoverBorderColor' => '#009D9E',
'data' => $cpu_load,
],
];
$graph_area = html_print_div(
[
'content' => line_graph($data, $options),
'class' => 'margin-top-5 w100p h100p',
'style' => 'max-height: 50px;',
'id' => 'status-cpu',
],
true
);
$output = $graph_area;
return $output;
}
}

View File

@ -0,0 +1,270 @@
<?php
/**
* ScheduledDowntime element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* ScheduledDowntime, this class contain all logic for this section.
*/
class ScheduledDowntime extends Element
{
/**
* Constructor
*/
public function __construct()
{
global $config;
parent::__construct();
ui_require_javascript_file('pandora_planned_downtimes');
include_once $config['homedir'].'/include/functions_reporting.php';
$this->title = __('Scheduled Downtime');
$this->ajaxMethods = ['getScheduleDowntime'];
}
/**
* List all schedule downtime.
*
* @return string
*/
public function list():string
{
$columns = [
'name',
'configuration',
'running',
'affected',
];
$columnNames = [
__('Name #Ag.'),
__('Configuration'),
__('Running'),
__('Affected'),
];
return ui_print_datatable(
[
'id' => 'list_downtime',
'class' => 'info_table',
'style' => 'width: 90%',
'dom_elements' => 'tfp',
'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_url' => $this->ajaxController,
'no_sortable_columns' => [
1,
2,
],
'ajax_data' => [
'method' => 'getScheduleDowntime',
'class' => static::class,
],
'order' => [
'field' => 'name',
'direction' => 'asc',
],
'default_pagination' => 5,
'search_button_class' => 'sub filter float-right',
'return' => true,
]
);
}
/**
* Return the schedule downtime for datatable by ajax.
*
* @return void
*/
public function getScheduleDowntime():void
{
global $config;
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$orderDatatable = get_datatable_order(true);
$pagination = '';
$order = '';
try {
ob_start();
if (isset($orderDatatable)) {
$order = sprintf(
' ORDER BY %s %s',
$orderDatatable['field'],
$orderDatatable['direction']
);
}
if (isset($length) && $length > 0
&& isset($start) && $start >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$length,
$start
);
}
$columns = [
'id',
'name',
'description',
'date_from',
'date_to',
'executed',
'id_group',
'only_alerts',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
'periodically_time_from',
'periodically_time_to',
'periodically_day_from',
'periodically_day_to',
'type_downtime',
'type_execution',
'type_periodicity',
'id_user',
'cron_interval_from',
'cron_interval_to',
];
$columns_str = implode(',', $columns);
$sql = sprintf(
'SELECT %s
FROM tplanned_downtime
%s %s',
$columns_str,
$order,
$pagination,
);
$sql_count = 'SELECT COUNT(id) AS num
FROM tplanned_downtime';
$downtimes = db_get_all_rows_sql($sql);
foreach ($downtimes as $key => $downtime) {
if ((int) $downtime['executed'] === 0) {
$downtimes[$key]['running'] = html_print_div(
[
'content' => '',
'class' => 'square stop',
'title' => 'Not running',
],
true
);
} else {
$downtimes[$key]['running'] = html_print_div(
[
'content' => '',
'class' => 'square running',
'title' => 'Running',
],
true
);
}
$downtimes[$key]['configuration'] = reporting_format_planned_downtime_dates($downtime);
$settings = [
'url' => ui_get_full_url('ajax.php', false, false, false),
'loadingText' => __('Loading, this operation might take several minutes...'),
'title' => __('Elements affected'),
'id' => $downtime['id'],
];
$downtimes[$key]['affected'] = '<a style="margin-left: 22px;" href="javascript:" onclick=\'dialogAgentModulesAffected('.json_encode($settings).')\'>';
$downtimes[$key]['affected'] .= html_print_image(
'images/details.svg',
true,
[
'title' => __('Agents and modules affected'),
'class' => 'main_menu_icon invert_filter',
]
);
$downtimes[$key]['affected'] .= '</a>';
}
$downtimes_number_res = db_get_all_rows_sql($sql_count);
$downtimes_number = ($downtimes_number_res !== false) ? $downtimes_number_res[0]['num'] : 0;
if (empty($downtimes) === true) {
$downtimes = [];
}
echo json_encode(
[
'data' => $downtimes,
'recordsTotal' => $downtimes_number,
'recordsFiltered' => $downtimes_number,
]
);
// Capture output.
$response = ob_get_clean();
} catch (Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
exit;
}
json_decode($response);
if (json_last_error() === JSON_ERROR_NONE) {
echo $response;
} else {
echo json_encode(
[
'success' => false,
'error' => $response,
]
);
}
exit;
}
/**
* Check permission acl for this section.
*
* @return boolean
*/
public function checkAcl():bool
{
global $config;
$read_permisson = (bool) check_acl($config['id_user'], 0, 'AR');
if ($read_permisson === true) {
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,129 @@
<?php
/**
* SnmpTraps element for tactical view.
*
* @category General
* @package Pandora FMS
* @subpackage TacticalView
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2023 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
use PandoraFMS\TacticalView\Element;
/**
* SnmpTraps, this class contain all logic for this section.
*/
class SnmpTraps extends Element
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->title = __('SNMP Traps');
$this->ajaxMethods = [
'getQueues',
'getTotalSources',
];
$this->interval = 300000;
$this->refreshConfig = [
'queues' => [
'id' => 'total-queues',
'method' => 'getQueues',
],
'total-snmp' => [
'id' => 'total-snmp',
'method' => 'getTotalSources',
],
];
}
/**
* Check if snmp traps module exist.
*
* @return boolean
*/
public function isEnabled():bool
{
if (empty($this->monitoringAgent) === true) {
return false;
}
$existModule = modules_get_agentmodule_id(io_safe_input('snmp_trap_queue'), $this->monitoringAgent['id_agente']);
if ($existModule === false) {
return false;
} else {
return true;
}
}
/**
* Returns the html of queues traps.
*
* @return string
*/
public function getQueues():string
{
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('snmp_trap_queue');
$total = round($value[0]['data']);
} else {
$total = __('N/A');
}
return html_print_div(
[
'content' => $total,
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'total-queues',
],
true
);
}
/**
* Returns the html of total sources traps.
*
* @return string
*/
public function getTotalSources():string
{
if ($this->isEnabled() === true) {
$value = $this->valueMonitoring('total_trap');
$total = round($value[0]['data']);
} else {
$total = __('N/A');
}
return html_print_div(
[
'content' => $total,
'class' => 'text-l',
'style' => 'margin: 0px 10px 10px 10px;',
'id' => 'total-snmp',
],
true
);
}
}

View File

@ -3,7 +3,7 @@
}
.query_result_editor_container {
width: 30%;
width: 40%;
}
.query_result_editor_container p {
@ -26,7 +26,7 @@
}
.query_result_view_container {
width: 70%;
width: 60%;
margin-left: 30px;
}
@ -51,3 +51,12 @@
margin-top: 10px;
margin-bottom: 10px;
}
.ace_editor,
.ace_editor * {
font-family: "Monaco", "Menlo", "Ubuntu Mono", "Droid Sans Mono", "Consolas",
monospace !important;
font-size: 14px !important;
font-weight: 400 !important;
letter-spacing: 0 !important;
}

View File

@ -0,0 +1,363 @@
#welcome-message {
margin-bottom: 30px;
}
.message-welcome {
color: #161628;
font-size: 32px;
line-height: 38px;
text-align: left;
font-weight: 700;
}
.subtitle-welcome-message {
color: #8a96a6;
font-size: 15px;
line-height: 20px;
text-align: left;
margin-left: 5px;
}
.row {
display: flex;
width: 100%;
align-items: stretch;
}
.col-12 {
width: 100%;
}
.col-6,
.col-xl-6 {
width: 50%;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
}
.col-7 {
width: 58%;
}
.col-8 {
width: 66.6%;
}
.col-4 {
width: 33%;
}
.col-5 {
width: 42%;
}
.col-3,
.col-md-3 {
width: 25%;
}
.col-9,
.col-md-9 {
width: 75%;
}
.container {
background-color: white;
border: 1px solid #e5e9ed;
border-radius: 10px;
height: 100%;
max-width: 100%;
}
.br-l {
border-left: 1px solid #e5e9ed;
}
.br-t {
border-top: 1px solid #e5e9ed;
}
.br-r {
border-right: 1px solid #e5e9ed;
}
.br-b {
border-bottom: 1px solid #e5e9ed;
}
.title {
font-size: 18px !important;
color: #161628;
text-align: center !important;
font-weight: bold !important;
padding: 15px 0px !important;
}
.subtitle {
font-size: 13px;
color: #161628;
padding-bottom: 5px;
padding-top: 5px;
}
.subtitle.link {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.subtitle.link a {
color: #14524f;
font-size: 13px;
font-weight: 800;
}
.absolute-link::after {
content: "→";
}
.status-text {
color: #6e7079;
font-size: 13px;
margin-left: 6px;
}
.text-xl {
font-size: 40px;
color: #6c7587;
font-weight: bold;
padding-left: 8px;
margin-bottom: 8px;
line-height: initial;
}
.text-l {
font-size: 27px;
color: #6c7587;
font-weight: bold;
margin-bottom: 8px;
line-height: initial;
}
#news-board {
min-width: 530px;
width: 100%;
max-height: 639px;
overflow-y: auto;
}
#database .subtitle,
#logStorage .subtitle,
#SNMPTraps .subtitle,
#Alerts .subtitle,
#Agents .subtitle {
padding: 10px 10px 5px 10px;
}
#Agents > .row {
min-height: 550px;
}
#horizontalBar {
margin: 0px 20px;
position: relative;
}
#horizontalBar .bar {
display: flex;
color: white;
height: 43px;
justify-content: space-between;
}
#horizontalBar .bar div {
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.marks {
display: flex;
margin-top: 20px;
}
.marks .line {
height: 76px;
background: #00000033;
width: 1px;
position: absolute;
top: 24px;
}
.mark {
min-height: 30px;
}
.mark .number {
position: absolute;
}
.mark0 {
left: 0%;
}
.mark20 {
left: 20%;
}
.mark40 {
left: 40%;
}
.mark60 {
left: 60%;
}
.mark80 {
left: 80%;
}
.mark100 {
left: 100%;
}
.number20 {
left: 19%;
}
.number40 {
left: 39%;
}
.number60 {
left: 59%;
}
.number80 {
left: 79%;
}
.number100 {
left: 95%;
}
.mark:nth-child(1) {
text-align: left;
}
.labels {
display: flex;
margin-bottom: 19px;
}
.label {
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.label div {
width: 10px;
height: 10px;
border-radius: 2px;
margin-right: 3px;
}
.indicative-text {
color: #6e7079;
font-size: 12px;
line-height: 13px;
text-align: left;
padding: 0px 10px 10px 10px;
}
.dataTables_paginate a {
background: none !important;
border: 0px;
font-size: 13px;
}
.pandora_pagination.next,
.pandora_pagination.previous {
border-right: 0px !important;
border-left: 0px !important;
}
a.pandora_pagination {
border-radius: 3px;
padding: 6px;
}
.info_table > tbody > tr:nth-child(even) {
background-color: #f9f9f9;
}
.pandora_pagination.current {
background-color: #1d7874 !important;
}
a.pandora_pagination:first-child {
border-left: 0px !important;
}
.info_table {
border: 1px solid #c0ccdc;
border-bottom: 1px solid #c0ccdc !important;
border-collapse: collapse;
}
.info_table td:nth-child(1) {
border-top: 0px;
}
.info_table td {
border-top: 1px solid #c0ccdc !important;
}
.info_table th {
border: 0px !important;
}
.admin {
color: #ec7176;
}
.user {
color: #8a96a6;
}
.mini-criticity {
width: 6px !important;
min-width: auto !important;
max-width: auto !important;
height: 28px !important;
border-radius: 9px !important;
margin-left: 7px !important;
}
#datatable_events .datatables_thead_tr th:nth-child(1) {
width: 10.3333px !important;
padding: 20px 0px 20px 15px !important;
}
.info_table td {
font-size: 13px !important;
}
table.dataTable thead th {
padding: 0px 18px !important;
}
#list_downtime_wrapper {
margin: 28px 0px;
}
.square {
width: 20px;
height: 20px;
margin-left: 20px;
}
.running {
background-color: #82b92e;
}
.stop {
background-color: #ec7176;
}
@media (max-width: 1636px) {
.col-xl-6 {
width: 100%;
}
.col-6 {
width: 49%;
}
.col-3 {
width: 21%;
}
.col-4 {
width: 33%;
}
.row {
flex-wrap: wrap;
}
.col-7 {
width: 56%;
}
.col-5 {
width: 41%;
}
.flex-nowrap {
flex-wrap: nowrap !important;
}
.col-md-9,
.col-md-3 {
width: 100%;
}
}
@media (max-width: 1300px) {
.col-6 {
width: 49%;
}
}

View File

@ -1,7 +1,7 @@
.new-board {
background-color: #ffffff;
border: 1px solid #e5e9ed;
border-radius: 4px;
border-top: 1px solid #e5e9ed;
border-bottom: 1px solid #e5e9ed;
margin-bottom: 15px;
}
@ -36,12 +36,12 @@
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
align-items: flex-start;
}
.default-new > div > img {
width: 100%;
max-width: 430px;
max-width: 268px;
height: auto;
}

View File

@ -12090,6 +12090,10 @@ span.help_icon_15px > img {
border-radius: 50%;
}
.spinner-fixed.inherit {
position: inherit;
}
@keyframes animate {
0% {
transform: rotate(0deg);

View File

@ -1858,3 +1858,16 @@ a.pandora_pagination,
#modal_help::before {
border-bottom: 8px solid #222222;
}
#general-tactical-view .message-welcome,
#general-tactical-view .subtitle,
#general-tactical-view .text-l,
#general-tactical-view .text-xl,
#general-tactical-view .status-text {
color: white !important;
}
#general-tactical-view .marks .line {
background-color: #ffffff33;
}
#general-tactical-view #horizontalBar .labels .label span {
color: black;
}

View File

@ -131,7 +131,7 @@
<div style='padding-bottom: 50px'>
<?php
$version = '7.0NG.773.3';
$build = '231020';
$build = '231024';
$banner = "v$version Build $build";
error_reporting(0);

View File

@ -3320,3 +3320,9 @@ div.visual-console-container-dashboard fieldset {
.ui-page-theme-a div.visual-console-container-dashboard a {
color: inherit !important;
}
h1.dialog_title {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

View File

@ -27,14 +27,9 @@
*/
// Begin.
use PandoraFMS\TacticalView\GeneralTacticalView;
global $config;
require_once 'include/functions_events.php';
require_once 'include/functions_servers.php';
require_once 'include/functions_reporting.php';
require_once 'include/functions_tactical.php';
require_once $config['homedir'].'/include/functions_graph.php';
check_login();
if (! check_acl($config['id_user'], 0, 'AR') && ! check_acl($config['id_user'], 0, 'AW')) {
@ -46,267 +41,5 @@ if (! check_acl($config['id_user'], 0, 'AR') && ! check_acl($config['id_user'],
return;
}
ui_require_css_file('tactical');
$is_admin = check_acl($config['id_user'], 0, 'PM');
$user_strict = (bool) db_get_value('strict_acl', 'tusuario', 'id_user', $config['id_user']);
$force_refresh = get_parameter('force_refresh', '');
$refresh = get_parameter('refr', 0);
if ($force_refresh == 1) {
db_process_sql('UPDATE tgroup_stat SET utimestamp = 0');
}
$updated_time = '';
if ($config['realtimestats'] == 0) {
$updated_time = "<a href='index.php?sec=estado&sec2=operation/agentes/tactical&force_refresh=1'>";
$updated_time .= __('Last update').' : '.ui_print_timestamp(db_get_sql('SELECT min(utimestamp) FROM tgroup_stat'), true);
$updated_time .= '</a>';
} else {
// $updated_info = __("Updated at realtime");
$updated_info = '';
}
// Header.
ui_print_standard_header(
__('Tactical view'),
'',
false,
'',
false,
(array) $updated_time,
[
[
'link' => '',
'label' => __('Monitoring'),
],
[
'link' => '',
'label' => __('Views'),
],
]
);
// Currently this function makes loading this page is impossible. Change
// and create new function.
$all_data = tactical_status_modules_agents($config['id_user'], false, 'AR');
$data = [];
$data['monitor_not_init'] = (int) $all_data['_monitors_not_init_'];
$data['monitor_unknown'] = (int) $all_data['_monitors_unknown_'];
$data['monitor_ok'] = (int) $all_data['_monitors_ok_'];
$data['monitor_warning'] = (int) $all_data['_monitors_warning_'];
$data['monitor_critical'] = (int) $all_data['_monitors_critical_'];
$data['monitor_not_normal'] = (int) $all_data['_monitor_not_normal_'];
$data['monitor_alerts'] = (int) $all_data['_monitors_alerts_'];
$data['monitor_alerts_fired'] = (int) $all_data['_monitors_alerts_fired_'];
$data['monitor_total'] = (int) $all_data['_monitor_total_'];
$data['total_agents'] = (int) $all_data['_total_agents_'];
$data['monitor_checks'] = (int) $all_data['_monitor_checks_'];
// Percentages
if (!empty($all_data)) {
if ($data['monitor_not_normal'] > 0 && $data['monitor_checks'] > 0) {
$data['monitor_health'] = format_numeric((100 - ($data['monitor_not_normal'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['monitor_health'] = 100;
}
if ($data['monitor_not_init'] > 0 && $data['monitor_checks'] > 0) {
$data['module_sanity'] = format_numeric((100 - ($data['monitor_not_init'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['module_sanity'] = 100;
}
if (isset($data['alerts'])) {
if ($data['monitor_alerts_fired'] > 0 && $data['alerts'] > 0) {
$data['alert_level'] = format_numeric((100 - ($data['monitor_alerts_fired'] / ($data['alerts'] / 100))), 1);
} else {
$data['alert_level'] = 100;
}
} else {
$data['alert_level'] = 100;
$data['alerts'] = 0;
}
$data['monitor_bad'] = ($data['monitor_critical'] + $data['monitor_warning']);
if ($data['monitor_bad'] > 0 && $data['monitor_checks'] > 0) {
$data['global_health'] = format_numeric((100 - ($data['monitor_bad'] / ($data['monitor_checks'] / 100))), 1);
} else {
$data['global_health'] = 100;
}
$data['server_sanity'] = format_numeric((100 - $data['module_sanity']), 1);
}
echo '<table border=0 class="w100p"><tr>';
echo '<td class="tactical_left_column" id="leftcolumn">';
// ---------------------------------------------------------------------
// The status horizontal bars (Global health, Monitor sanity...
// ---------------------------------------------------------------------
$bg_color = 'background-color: #222';
if ($config['style'] !== 'pandora_black' && !is_metaconsole()) {
$bg_color = 'background-color: #fff';
}
$table = new stdClass();
$table->width = '100%';
$table->class = 'info_table no-td-borders';
$table->cellpadding = 2;
$table->cellspacing = 2;
$table->border = 0;
$table->head = [];
$table->data = [];
$table->style = [$bg_color];
$stats = reporting_get_stats_indicators($data, 120, 10, false);
$statusTacticalTable = new stdClass();
$statusTacticalTable->width = '100%';
$statusTacticalTable->id = 'statusTacticalTable';
$statusTacticalTable->class = 'status_tactical tactical_table bg_white';
$statusTacticalTable->data = [];
foreach ($stats as $key => $stat) {
$statusTacticalTable->cellstyle['line_'.$key][0] = 'width: 40%;';
$statusTacticalTable->style['line_'.$key][1] = 'width: 60%;';
$statusTacticalTable->data['line_'.$key][0] = '<span>'.$stat['title'].'</span>';
$statusTacticalTable->data['line_'.$key][1] = $stat['graph'];
}
$status = html_print_table($statusTacticalTable, true);
$table->rowclass = [];
$table->rowclass[0] = 'w100p';
$table->rowclass[1] = 'w100p';
$table->rowclass[2] = 'w100p';
$table->rowclass[3] = 'w100p';
$table->rowclass[4] = 'w100p';
$table->data[0][0] = $status;
// ---------------------------------------------------------------------
// Monitor checks
// ---------------------------------------------------------------------
$data_agents = [
__('Critical') => $data['monitor_critical'],
__('Warning') => $data['monitor_warning'],
__('Normal') => $data['monitor_ok'],
__('Unknown') => $data['monitor_unknown'],
__('Not init') => $data['monitor_not_init'],
];
$table->data[1][0] = reporting_get_stats_alerts($data);
$table->rowclass[1] = 'w100p';
$table->data[2][0] = reporting_get_stats_modules_status($data, 180, 100, false, $data_agents);
$table->data[3][0] = reporting_get_stats_agents_monitors($data);
$table->rowclass[] = '';
// ---------------------------------------------------------------------
// Server performance
// ---------------------------------------------------------------------
if ($is_admin) {
$table->data[4][0] = reporting_get_stats_servers();
$table->rowclass[] = '';
}
ui_toggle(
html_print_table($table, true),
__('Report of State'),
'',
'',
false
);
echo '</td>';
// Left column
echo '<td class="w75p pdd_t_0px" id="rightcolumn">';
// ---------------------------------------------------------------------
// Last events information
// ---------------------------------------------------------------------
if (check_acl($config['id_user'], 0, 'ER')) {
$tags_condition = tags_get_acl_tags(false, 0, 'ER', 'event_condition');
$event_filter = 'estado<>1';
if (!empty($tags_condition)) {
$event_filter .= " AND ($tags_condition)";
}
if ($config['event_view_hr']) {
$event_filter .= ' AND utimestamp > (UNIX_TIMESTAMP(NOW()) - '.($config['event_view_hr'] * SECONDS_1HOUR).')';
}
$events = events_print_event_table($event_filter, 10, '100%', true, 0, true);
ui_toggle(
$events,
__('Latest events'),
'',
'',
false
);
}
// ---------------------------------------------------------------------
// Server information
// ---------------------------------------------------------------------
if ($is_admin) {
$tiny = true;
include $config['homedir'].'/godmode/servers/servers.build_table.php';
}
$out = '<table cellpadding=0 cellspacing=0 class="databox pies" width=100%><tr><td style="width:50%;">';
$out .= '<fieldset class="databox tactical_set" id="total_event_graph">';
$out .= '<legend>'.__('Event graph').'</legend>';
$out .= html_print_image('images/spinner.gif', true, ['id' => 'spinner_total_event_graph']);
$out .= '</fieldset>';
$out .= '</td><td style="width:50%;">';
$out .= '<fieldset class="databox tactical_set" id="graphic_event_group">
<legend>'.__('Event graph by agent').'</legend>'.html_print_image('images/spinner.gif', true, ['id' => 'spinner_graphic_event_group']).'</fieldset>';
$out .= '</td></tr></table>';
ui_toggle(
$out,
__('Event graphs'),
'',
'',
false
);
echo '</td>';
echo '</tr></table>';
?>
<script type="text/javascript">
$(document).ready(function () {
var parameters = {};
parameters["page"] = "include/ajax/events";
parameters["total_event_graph"] = 1;
$.ajax({type: "GET",url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",data: parameters,
success: function(data) {
$("#spinner_total_event_graph").hide();
$("#total_event_graph").append(data);
}
});
delete parameters["total_event_graph"];
parameters["graphic_event_group"] = 1;
$.ajax({type: "GET",url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",data: parameters,
success: function(data) {
$("#spinner_graphic_event_group").hide();
$("#graphic_event_group").append(data);
}
});
});
$('.tactical_table .alert_module_background_state').replaceWith(function(){
return $("<div />").addClass($(this).attr('class')).data($(this).data());
});
</script>
$tacticalView = new GeneralTacticalView();
$tacticalView->render();

View File

@ -338,8 +338,10 @@ if (is_metaconsole() === true
// Ajax responses.
if (is_ajax() === true) {
$get_events = (int) get_parameter('get_events', 0);
$external_url = (bool) get_parameter('external_url', 0);
$table_id = get_parameter('table_id', '');
$groupRecursion = (bool) get_parameter('groupRecursion', false);
$compact_date = (int) get_parameter('compact_date', 0);
// Datatables offset, limit.
$start = (int) get_parameter('start', 0);
@ -469,7 +471,7 @@ if (is_ajax() === true) {
$data = array_reduce(
$events,
function ($carry, $item) use ($table_id, &$redirection_form_id, $filter) {
function ($carry, $item) use ($table_id, &$redirection_form_id, $filter, $compact_date, $external_url) {
global $config;
$tmp = (object) $item;
@ -610,6 +612,12 @@ if (is_ajax() === true) {
);
$user_timezone = users_get_user_by_id($_SESSION['id_usuario'])['timezone'];
if ($compact_date === 1) {
$options = ['prominent' => 'compact'];
} else {
$options = [];
}
if (empty($user_timezone) === true) {
if (date_default_timezone_get() !== $config['timezone']) {
$timezone = timezone_open(date_default_timezone_get());
@ -624,16 +632,16 @@ if (is_ajax() === true) {
$total_sec = strtotime($tmp->timestamp);
$total_sec += $dif;
$last_contact = date($config['date_format'], $total_sec);
$last_contact_value = ui_print_timestamp($last_contact, true);
$last_contact_value = ui_print_timestamp($last_contact, true, $options);
} else {
$title = date($config['date_format'], strtotime($tmp->timestamp));
$value = ui_print_timestamp(strtotime($tmp->timestamp), true);
$value = ui_print_timestamp(strtotime($tmp->timestamp), true, $options);
$last_contact_value = '<span title="'.$title.'">'.$value.'</span>';
}
} else {
date_default_timezone_set($user_timezone);
$title = date($config['date_format'], strtotime($tmp->timestamp));
$value = ui_print_timestamp(strtotime($tmp->timestamp), true);
$value = ui_print_timestamp(strtotime($tmp->timestamp), true, $options);
$last_contact_value = '<span title="'.$title.'">'.$value.'</span>';
}
@ -734,8 +742,13 @@ if (is_ajax() === true) {
$criticity .= $color.'" data-title="'.$text.'" data-use_title_for_force_title="1">'.$text.'</div>';
$tmp->criticity = $criticity;
// Add event severity to end of text.
$evn = '<a href="javascript:" onclick="show_event_dialog(\''.$tmp->b64.'\')">';
if (isset($external_url) === true && $external_url === true) {
$url = ui_get_full_url('index.php?sec=eventos&sec2=operation/events/events');
$evn = '<a href="'.$url.'&show_event_dialog='.$tmp->b64.'">';
} else {
// Add event severity to end of text.
$evn = '<a href="javascript:" onclick="show_event_dialog(\''.$tmp->b64.'\')">';
}
// Grouped events.
if ((int) $filter['group_rep'] === EVENT_GROUP_REP_EXTRAIDS) {
@ -3562,7 +3575,7 @@ function show_event_dialo(event, dialog_page) {
// History mode flag
var history = $("#hidden-history").val();
console.log(event);
jQuery.post(
ajax_file,
{
@ -3580,7 +3593,7 @@ function show_event_dialo(event, dialog_page) {
.empty()
.append(data)
.dialog({
title: event.evento,
title: event.event_title,
resizable: true,
draggable: true,
modal: true,

View File

@ -6,7 +6,7 @@
%define debug_package %{nil}
%define name pandorafms_console
%define version 7.0NG.773.3
%define release 231020
%define release 231024
# User and Group under which Apache is running
%define httpd_name httpd

View File

@ -6,7 +6,7 @@
%define debug_package %{nil}
%define name pandorafms_console
%define version 7.0NG.773.3
%define release 231020
%define release 231024
# 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.773.3
%define release 231020
%define release 231024
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2

View File

@ -276,6 +276,7 @@ CREATE TABLE IF NOT EXISTS `tagente_modulo` (
`warning_time` INT UNSIGNED DEFAULT 0,
`quiet_by_downtime` TINYINT NOT NULL DEFAULT 0,
`disabled_by_downtime` TINYINT NOT NULL DEFAULT 0,
`last_compact` TIMESTAMP NOT NULL DEFAULT 0,
`made_enabled` TINYINT UNSIGNED DEFAULT 0,
PRIMARY KEY (`id_agente_modulo`),
KEY `main_idx` (`id_agente_modulo`,`id_agente`),
@ -3133,6 +3134,110 @@ CREATE TABLE IF NOT EXISTS `tevent_alert_action` (
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- -----------------------------------------------------
-- Table `tlog_alert`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tlog_alert` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT ,
`description` MEDIUMTEXT,
`order` INT UNSIGNED DEFAULT 0,
`mode` ENUM('PASS','DROP'),
`field1` TEXT ,
`field2` TEXT ,
`field3` TEXT ,
`field4` TEXT ,
`field5` TEXT ,
`field6` TEXT ,
`field7` TEXT ,
`field8` TEXT ,
`field9` TEXT ,
`field10` TEXT ,
`time_threshold` INT NOT NULL DEFAULT 86400,
`max_alerts` INT UNSIGNED NOT NULL DEFAULT 1,
`min_alerts` INT UNSIGNED NOT NULL DEFAULT 0,
`time_from` time DEFAULT '00:00:00',
`time_to` time DEFAULT '00:00:00',
`monday` TINYINT DEFAULT 1,
`tuesday` TINYINT DEFAULT 1,
`wednesday` TINYINT DEFAULT 1,
`thursday` TINYINT DEFAULT 1,
`friday` TINYINT DEFAULT 1,
`saturday` TINYINT DEFAULT 1,
`sunday` TINYINT DEFAULT 1,
`recovery_notify` TINYINT DEFAULT 0,
`field1_recovery` TEXT,
`field2_recovery` TEXT,
`field3_recovery` TEXT,
`field4_recovery` TEXT,
`field5_recovery` TEXT,
`field6_recovery` TEXT,
`field7_recovery` TEXT,
`field8_recovery` TEXT,
`field9_recovery` TEXT,
`field10_recovery` TEXT,
`id_group` MEDIUMINT UNSIGNED NULL DEFAULT 0,
`internal_counter` INT DEFAULT 0,
`last_fired` BIGINT NOT NULL DEFAULT 0,
`last_reference` BIGINT NOT NULL DEFAULT 0,
`times_fired` INT NOT NULL DEFAULT 0,
`disabled` TINYINT DEFAULT 0,
`standby` TINYINT DEFAULT 0,
`priority` TINYINT DEFAULT 0,
`force_execution` TINYINT DEFAULT 0,
`group_by` enum ('','id_agente','id_agentmodule','id_alert_am','id_grupo') DEFAULT '',
`special_days` TINYINT DEFAULT 0,
`disable_event` TINYINT DEFAULT 0,
`id_template_conditions` INT UNSIGNED NOT NULL DEFAULT 0,
`id_template_fields` INT UNSIGNED NOT NULL DEFAULT 0,
`last_evaluation` BIGINT NOT NULL DEFAULT 0,
`pool_occurrences` INT UNSIGNED NOT NULL DEFAULT 0,
`schedule` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- -----------------------------------------------------
-- Table `tlog_rule`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tlog_rule` (
`id_log_rule` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_log_alert` INT UNSIGNED NOT NULL,
`operation` ENUM('NOP', 'AND','OR','XOR','NAND','NOR','NXOR'),
`order` INT UNSIGNED DEFAULT 0,
`window` INT NOT NULL DEFAULT 0,
`count` INT NOT NULL DEFAULT 1,
`name` TEXT,
`log_content` TEXT,
`log_source` TEXT,
`log_agent` TEXT,
`operator_log_content` TEXT COMMENT 'Operator for log_content',
`operator_log_source` TEXT COMMENT 'Operator for log_source',
`operator_log_agent` TEXT COMMENT 'Operator for log_agent',
PRIMARY KEY (`id_log_rule`),
KEY `idx_id_log_alert` (`id_log_alert`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- -----------------------------------------------------
-- Table `tevent_alert_action`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `tlog_alert_action` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_log_alert` INT UNSIGNED NOT NULL,
`id_alert_action` INT UNSIGNED NOT NULL,
`fires_min` INT UNSIGNED DEFAULT 0,
`fires_max` INT UNSIGNED DEFAULT 0,
`module_action_threshold` INT NOT NULL DEFAULT 0,
`last_execution` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_log_alert`) REFERENCES tlog_alert(`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`id_alert_action`) REFERENCES talert_actions(`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- -----------------------------------------------------
-- Table `tmodule_synth`
-- -----------------------------------------------------

View File

@ -120,10 +120,10 @@ INSERT INTO `tconfig` (`token`, `value`) VALUES
('custom_report_front_logo', 'images/pandora_logo_white.jpg'),
('custom_report_front_header', ''),
('custom_report_front_footer', ''),
('MR', 65),
('MR', 66),
('identification_reminder', 1),
('identification_reminder_timestamp', 0),
('current_package', 773),
('current_package', 774),
('post_process_custom_values', '{"0.00000038580247":"Seconds&#x20;to&#x20;months","0.00000165343915":"Seconds&#x20;to&#x20;weeks","0.00001157407407":"Seconds&#x20;to&#x20;days","0.01666666666667":"Seconds&#x20;to&#x20;minutes","0.00000000093132":"Bytes&#x20;to&#x20;Gigabytes","0.00000095367432":"Bytes&#x20;to&#x20;Megabytes","0.00097656250000":"Bytes&#x20;to&#x20;Kilobytes","0.00000001653439":"Timeticks&#x20;to&#x20;weeks","0.00000011574074":"Timeticks&#x20;to&#x20;days"}'),
('custom_docs_logo', 'default_docs.png'),
('custom_support_logo', 'default_support.png'),

View File

@ -0,0 +1,391 @@
<?php global $config; ?>
<div id="general-tactical-view">
<div id="welcome-message">
<?php echo $welcome; ?>
<span class="subtitle-welcome-message"><?php echo __('This is the latest data in your tactical view'); ?></span>
</div>
<div class="row">
<div class="col-xl-6">
<div id="general-overview" class="pdd_5px">
<div class="container">
<div class="title">
<?php echo $Overview->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-12">
<div class="row">
<div class="col-4">
<div class="padding10">
<span class="subtitle">
<?php echo __('Pandora FMS log size'); ?>
</span>
<?php echo $Overview->getLogSizeStatus(); ?>
</div>
</div>
<div class="col-4 br-l">
<div class="padding10">
<span class="subtitle">
<?php echo __('Server status'); ?>
</span>
<?php echo $Overview->getServerStatus(); ?>
</div>
</div>
<div class="col-4 br-l">
<div class="padding10">
<span class="subtitle">
<?php echo __('System CPU Load'); ?>
</span>
<?php echo $Overview->getCPULoadGraph(); ?>
</div>
</div>
</div>
<div class="br-t">
<div class="padding10">
<span class="subtitle">
<?php echo __('License usage'); ?>
</span>
<?php echo $Overview->getLicenseUsageGraph(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row flex-nowrap">
<div class="col-7 pdd_5px">
<div class="container">
<div class="title">
<?php echo $MonitoringElements->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 Tags'); ?> <a href="index.php?sec=gusuarios&sec2=godmode/tag/tag"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getTagsGraph(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 module groups'); ?> <a href="index.php?sec=view&sec2=extensions/module_groups"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getModuleGroupGraph(); ?>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="subtitle link padding10 padding2">
<?php echo __('Status'); ?> <a href="index.php?sec=view&sec2=operation/agentes/estado_agente"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getMonitoringStatusGraph(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle link padding10 padding2">
<?php echo __('Top-10 Groups'); ?> <a href="index.php?sec=view&sec2=operation/agentes/group_view"><?php echo __('Info'); ?></a>
</div>
<?php echo $MonitoringElements->getAgentGroupsGraph(); ?>
</div>
</div>
</div>
</div>
</div>
<div class="col-5 pdd_5px">
<div class="container" id="database">
<div class="title">
<?php echo $Database->title; ?>
</div>
<div class="content br-t">
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle">
<?php echo __('Database status'); ?>
</div>
<?php echo $Database->getStatus(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle">
<?php echo __('Data records'); ?>
</div>
<?php echo $Database->getDataRecords(); ?>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="subtitle">
<?php echo __('String records'); ?>
</div>
<?php echo $Database->getStringRecords(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle">
<?php echo __('Events'); ?>
</div>
<?php echo $Database->getEvents(); ?>
</div>
</div>
<div class="br-t">
<div class="subtitle padding10 padding2">
<?php echo __('Reads (last 24 hrs)'); ?>
</div>
<?php echo $Database->getReadsGraph(); ?>
</div>
<div class="br-t">
<div class="subtitle padding10 padding2">
<?php echo __('Writes (last 24 hrs)'); ?>
</div>
<?php echo $Database->getWritesGraph(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="container mrgn_5px">
<div class="title">
<?php echo $NewsBoard->title; ?>
</div>
<?php echo $NewsBoard->getNews(); ?>
</div>
<div class="row">
<div class="col-6 pdd_5px">
<div class="container">
<div class="title br-b" id="heatmap-title">
<?php echo $Groups->title; ?>
</div>
<div class="subtitle link padding10 padding2">
<?php echo __('Status'); ?> <a href="index.php?sec=view&sec2=operation/agentes/group_view"><?php echo __('Info'); ?></a>
</div>
<div id="heatmap-group">
<?php echo $Groups->loading(); ?>
</div>
</div>
</div>
<div class="col-6">
<div class="container mrgn_5px" id="logStorage">
<div class="title br-b">
<?php echo $LogStorage->title; ?>
</div>
<div class="row">
<div class="col-6 br-r br-b">
<div class="subtitle">
<?php echo __('Log storage status'); ?>
</div>
<?php echo $LogStorage->getStatus(); ?>
</div>
<div class="col-6 br-b">
<div class="subtitle">
<?php echo __('Total sources'); ?>
</div>
<?php echo $LogStorage->getTotalSources(); ?>
</div>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Stored data'); ?>
</div>
<?php echo $LogStorage->getStoredData(); ?>
<span class="indicative-text"><?php echo __('Lines'); ?></span>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Age of stored data'); ?>
</div>
<?php echo $LogStorage->getAgeOfStoredData(); ?>
<span class="indicative-text"><?php echo __('Days'); ?></span>
</div>
</div>
</div>
<div class="container mrgn_5px" id="SNMPTraps">
<div class="title br-b">
<?php echo $SnmpTraps->title; ?>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Trap queues'); ?>
</div>
<?php echo $SnmpTraps->getQueues(); ?>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Total sources'); ?>
</div>
<?php echo $SnmpTraps->getTotalSources(); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="<?php echo (($Events->checkAcl() === true)) ? 'col-md-3 pdd_5px' : 'col-12 pdd_5px'; ?>">
<div class="container" id="Alerts">
<div class="title br-b">
<?php echo $Alerts->title; ?>
</div>
<div class="row br-b">
<div class="col-6">
<div class="subtitle">
<?php echo __('Currently triggered'); ?>
</div>
<?php echo $Alerts->getCurrentlyTriggered(); ?>
</div>
<div class="col-6 br-l">
<div class="subtitle">
<?php echo __('Active alerts'); ?>
</div>
<?php echo $Alerts->getActiveAlerts(); ?>
</div>
</div>
<?php if ($Alerts->checkAclUserList() === true) : ?>
<div id="list-users">
<div class="subtitle link padding10 padding2">
<b><?php echo __('Logged in users (24 hrs)'); ?></b> <a href="index.php?sec=gusuarios&sec2=godmode/users/user_list"><?php echo __('More details'); ?></a>
</div>
<?php echo $Alerts->getDataTableUsers(); ?>
</div>
<?php endif; ?>
</div>
</div>
<?php if ($Events->checkAcl() === true) : ?>
<div class="col-md-9 pdd_5px">
<div class="container overflow_hidden" id="Events">
<div class="title br-b">
<?php echo $Events->title; ?>
</div>
<div class="row">
<div class="col-8 br-r">
<div class="subtitle link padding10 padding2">
<?php echo __('Number of events per hour ('.$config['event_view_hr'].' hrs)'); ?></b> <a href="index.php?sec=eventos&sec2=operation/events/events&filter[event_view_hr]=24&filter[tag_with]=WyIwIl0=&filter[tag_without]=WyIwIl0="><?php echo __('Info'); ?></a>
</div>
<div id="events-last-24"><?php echo $Events->loading(); ?></div>
<div class="row br-t h100p">
<div class="col-4 br-r">
<div class="subtitle padding10 padding2">
<?php echo __('Criticality'); ?></b>
</div>
<div id="events-criticality"><?php echo $Events->loading(); ?></div>
</div>
<div class="col-4 br-r">
<div class="subtitle padding10 padding2">
<?php echo __('Status'); ?></b>
</div>
<div id="events-status-validate"><?php echo $Events->loading(); ?></div>
</div>
<div class="col-4">
<div class="subtitle padding10 padding2">
<?php echo __('Pending validation'); ?></b>
</div>
<div id="events-status-pending-validate"><?php echo $Events->loading(); ?></div>
</div>
</div>
</div>
<div class="col-4">
<div class="subtitle link padding10 padding2">
<?php echo __('Active events ('.$config['event_view_hr'].' hrs)'); ?></b> <a href="index.php?sec=eventos&sec2=operation/events/events"><?php echo __('Info'); ?></a>
</div>
<?php echo $Events->getDataTableEvents(); ?>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
<div class="row">
<div class="col-xl-6 pdd_5px">
<div class="container" id="Agents">
<div class="title br-b">
<?php echo $Agents->title; ?>
</div>
<div class="row">
<div class="col-6 br-r">
<div class="row br-b">
<div class="col-6 br-r">
<div class="subtitle">
<?php echo __('Total agents'); ?>
</div>
<?php echo $Agents->getTotalAgents(); ?>
</div>
<div class="col-6">
<div class="subtitle">
<?php echo __('Alerts (24hrs)'); ?>
</div>
<?php echo $Agents->getAlerts(); ?>
</div>
</div>
<div class="subtitle link padding10 padding2">
<?php echo __('Top 20 groups'); ?></b> <a href="index.php?sec=view&sec2=operation/agentes/estado_agente"><?php echo __('More details'); ?></a>
</div>
<?php echo $Agents->getDataTableGroups(); ?>
</div>
<div class="col-6">
<div class="subtitle padding10 padding2">
<?php echo __('Operating system'); ?></b>
</div>
<?php echo $Agents->getOperatingSystemGraph(); ?>
<div class="subtitle padding10 padding2 br-t">
<?php echo __('Status'); ?></b>
</div>
<?php echo $Agents->getStatusGraph(); ?>
</div>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="container mrgn_5px">
<div class="title br-b">
<?php echo $Configurations->title; ?>
</div>
<div class="row br-b flex-nowrap">
<a href="index.php?sec=view&sec2=operation/agentes/group_view" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalGroups(); ?>
</a>
<a href="index.php?sec=view&sec2=extensions/agents_modules" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalModules(); ?>
</a>
<?php if (enterprise_installed() === true) : ?>
<a href="index.php?sec=gmodules&sec2=enterprise/godmode/policies/policies" class="col-3 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalPolicies(); ?>
</a>
<?php endif; ?>
<a href="index.php?sec=gservers&sec2=godmode/servers/plugin" class="col-3 flex flex-column center pdd_20px">
<?php echo $Configurations->getTotalRemotePlugins(); ?>
</a>
</div>
<div class="row flex-nowrap br-b">
<a href="index.php?sec=templates&sec2=godmode/modules/manage_module_templates" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalModuleTemplate(); ?>
</a>
<a href="index.php?sec=view&sec2=operation/agentes/estado_agente&status=5" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getNotInitModules(); ?>
</a>
<a href="index.php?sec=view&sec2=operation/agentes/estado_agente&status=3" class="col-4 flex flex-column center pdd_20px br-r">
<?php echo $Configurations->getTotalUnknowAgents(); ?>
</a>
<a href="index.php?sec=eventos&sec2=operation/events/events" class="col-4 flex flex-column center pdd_20px">
<?php echo $Configurations->getTotalEvents(); ?>
</a>
</div>
</div>
<?php if ($ScheduledDowntime->checkAcl() === true) : ?>
<div class="container mrgn_5px">
<div class="title br-b">
<?php echo $ScheduledDowntime->title; ?>
</div>
<?php echo $ScheduledDowntime->list(); ?>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
echo $javascript;

View File

@ -1,5 +1,5 @@
package: pandorafms-server
Version: 7.0NG.773.3-231020
Version: 7.0NG.773.3-231024
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.773.3-231020"
pandora_version="7.0NG.773.3-231024"
package_cpan=0
package_pandora=1

View File

@ -477,26 +477,30 @@ export_threads 1
eventserver 0
# Enable (1) or disable (0) Pandora FMS Correlation Server (PANDORA FMS ENTERPRISE ONLY).
# Number of threads for the Event Server (PANDORA FMS ENTERPRISE ONLY).
correlationserver 0
eventserver_threads 1
# Time in seconds to re-evaluate correlation alerts pool (PANDORA FMS ENTERPRISE ONLY).
correlation_threshold 30
# Correlated alerts, event window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
# Event alerts, event window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
event_window 3600
# Correlated Alerts, log window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
# Enable (1) or disable (0) Pandora FMS Log Server (PANDORA FMS ENTERPRISE ONLY).
logserver 0
# Number of threads for the Log Server (PANDORA FMS ENTERPRISE ONLY).
logserver_threads 1
# Event alerts, log window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
log_window 3600
# Pre-load windows on start with available information. (PANDORA FMS ENTERPRISE ONLY).
#preload_windows 0
# Correlated Alerts, group cache ttl (in seconds). Set to 0 to disable. (PANDORA FMS ENTERPRISE ONLY).
# Event alerts, group cache ttl (in seconds). Set to 0 to disable. (PANDORA FMS ENTERPRISE ONLY).
#event_server_cache_ttl 10
# Log retrieving, items per request. (High values could make elasticsearch crash)
@ -776,6 +780,9 @@ netflowserver 0
# Number of threads for the Pandora FMS Netflow Server (PANDORA FMS ENTERPRISE ONLY).
netflowserver_threads 1
# Enable (1) or disable (0) the verification of SSL certificates (set to 0 when using self-signed certificates).
ssl_verify 0
# Enable (1) or disable (0) the Monitoring Anomaly Detection Engine (PANDORA FMS ENTERPRISE ONLY).
madeserver 0

View File

@ -470,26 +470,30 @@ export_threads 1
eventserver 0
# Enable (1) or disable (0) Pandora FMS Correlation Server (PANDORA FMS ENTERPRISE ONLY).
# Number of threads for the Event Server (PANDORA FMS ENTERPRISE ONLY).
correlationserver 0
eventserver_threads 1
# Time in seconds to re-evaluate correlation alerts pool (PANDORA FMS ENTERPRISE ONLY).
correlation_threshold 30
# Correlated alerts, event window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
# Event alerts, event window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
event_window 3600
# Correlated Alerts, log window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
# Enable (1) or disable (0) Pandora FMS Log Server (PANDORA FMS ENTERPRISE ONLY).
logserver 0
# Number of threads for the Log Server (PANDORA FMS ENTERPRISE ONLY).
logserver_threads 1
# Log alerts, log window in seconds (3600 by default) (PANDORA FMS ENTERPRISE ONLY).
log_window 3600
# Pre-load windows on start with available information. (PANDORA FMS ENTERPRISE ONLY).
#preload_windows 0
# Correlated Alerts, group cache ttl (in seconds). Set to 0 to disable. (PANDORA FMS ENTERPRISE ONLY).
# Event alerts, group cache ttl (in seconds). Set to 0 to disable. (PANDORA FMS ENTERPRISE ONLY).
#event_server_cache_ttl 10
# Log retrieving, items per request. (High values could make elasticsearch crash)

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.773.3";
my $pandora_build = "231020";
my $pandora_build = "231024";
our $VERSION = $pandora_version." ".$pandora_build;
# Setup hash
@ -297,8 +297,9 @@ sub pandora_load_config {
$pa_config->{"google_maps_description"} = 0;
$pa_config->{'openstreetmaps_description'} = 0;
$pa_config->{"eventserver"} = 1; # 4.0
$pa_config->{"correlationserver"} = 0; # 757
$pa_config->{"correlation_threshold"} = 30; # 757
$pa_config->{"eventserver_threads"} = 1; # 4.0
$pa_config->{"logserver"} = 1; # 7.774
$pa_config->{"logserver_threads"} = 1; # 7.774
$pa_config->{"event_window"} = 3600; # 4.0
$pa_config->{"log_window"} = 3600; # 7.741
$pa_config->{"elastic_query_size"} = 10; # 7.754 Elements per request (ELK)
@ -580,6 +581,8 @@ sub pandora_load_config {
$pa_config->{"repl_dbuser"} = undef; # 7.0.770
$pa_config->{"repl_dbpass"} = undef; # 7.0.770
$pa_config->{"ssl_verify"} = 0; # 7.0 774
$pa_config->{"madeserver"} = 0; # 774.
# Check for UID0
@ -803,14 +806,17 @@ sub pandora_load_config {
$pa_config->{"transactional_pool"} = $pa_config->{"incomingdir"} . "/" . $tbuf;
}
}
elsif ($parametro =~ m/^eventserver\s+([0-9]*)/i) {
elsif ($parametro =~ m/^eventserver\s+([0-1])/i) {
$pa_config->{'eventserver'}= clean_blank($1);
}
elsif ($parametro =~ m/^correlationserver\s+([0-9]*)/i) {
$pa_config->{'correlationserver'}= clean_blank($1);
elsif ($parametro =~ m/^eventserver_threads\s+([0-9]*)/i) {
$pa_config->{'eventserver_threads'}= clean_blank($1);
}
elsif ($parametro =~ m/^correlation_threshold\s+([0-9]*)/i) {
$pa_config->{'correlation_threshold'}= clean_blank($1);
elsif ($parametro =~ m/^logserver\s+([0-1])/i) {
$pa_config->{'logserver'}= clean_blank($1);
}
elsif ($parametro =~ m/^logserver_threads\s+([0-9]*)/i) {
$pa_config->{'logserver_threads'}= clean_blank($1);
}
elsif ($parametro =~ m/^icmpserver\s+([0-9]*)/i) {
$pa_config->{'icmpserver'}= clean_blank($1);
@ -1393,6 +1399,9 @@ sub pandora_load_config {
elsif ($parametro =~ m/^repl_dbpass\s(.*)/i) {
$pa_config->{'repl_dbpass'} = clean_blank($1);
}
elsif ($parametro =~ m/^ssl_verify\s+([0-1])/i) {
$pa_config->{'ssl_verify'} = clean_blank($1);
}
elsif ($parametro =~ m/^madeserver\s+([0-1])/i){
$pa_config->{'madeserver'}= clean_blank($1);
}

View File

@ -313,6 +313,7 @@ our @ServerTypes = qw (
icmpserver
snmpserver
satelliteserver
transactionalserver
mfserver
syncserver
wuxserver
@ -324,6 +325,7 @@ our @ServerTypes = qw (
ncmserver
netflowserver
logserver
logserver
madeserver
);
our @AlertStatus = ('Execute the alert', 'Do not execute the alert', 'Do not execute the alert, but increment its internal counter', 'Cease the alert', 'Recover the alert', 'Reset internal counter');
@ -806,9 +808,9 @@ Process an alert given the status returned by pandora_evaluate_alert.
=cut
##########################################################################
sub pandora_process_alert ($$$$$$$$;$$) {
sub pandora_process_alert ($$$$$$$$;$) {
my ($pa_config, $data, $agent, $module, $alert, $rc, $dbh, $timestamp,
$extra_macros, $is_correlated_alert) = @_;
$extra_macros) = @_;
if (defined ($agent)) {
logger ($pa_config, "Processing alert '" . safe_output($alert->{'name'}) . "' for agent '" . safe_output($agent->{'nombre'}) . "': " . (defined ($AlertStatus[$rc]) ? $AlertStatus[$rc] : 'Unknown status') . ".", 10);
@ -816,15 +818,21 @@ sub pandora_process_alert ($$$$$$$$;$$) {
else {
logger ($pa_config, "Processing alert '" . safe_output($alert->{'name'}) . "': " . (defined ($AlertStatus[$rc]) ? $AlertStatus[$rc] : 'Unknown status') . ".", 10);
}
# Simple or event alert?
my ($id, $table) = (undef, undef);
if (defined ($alert->{'id_template_module'})) {
$id = $alert->{'id_template_module'};
$table = 'talert_template_modules';
} else {
} elsif (defined ($alert->{'_log_alert'})) {
$id = $alert->{'id'};
$table = 'tlog_alert';
} elsif (defined ($alert->{'_event_alert'})) {
$id = $alert->{'id'};
$table = 'tevent_alert';
} else {
logger($pa_config, "pandora_process_alert received invalid data", 10);
return;
}
# Do not execute
@ -876,10 +884,10 @@ sub pandora_process_alert ($$$$$$$$;$$) {
if ($pa_config->{'alertserver'} == 1 || $pa_config->{'alertserver_queue'} == 1) {
pandora_queue_alert($pa_config, $dbh, [$data, $agent, $module,
$alert, 0, $timestamp, 0, $extra_macros, $is_correlated_alert]);
$alert, 0, $timestamp, 0, $extra_macros]);
} else {
pandora_execute_alert ($pa_config, $data, $agent, $module, $alert, 0, $dbh,
$timestamp, 0, $extra_macros, $is_correlated_alert);
$timestamp, 0, $extra_macros);
}
return;
}
@ -922,10 +930,10 @@ sub pandora_process_alert ($$$$$$$$;$$) {
if ($pa_config->{'alertserver'} == 1 || $pa_config->{'alertserver_queue'} == 1) {
pandora_queue_alert($pa_config, $dbh, [$data, $agent, $module,
$alert, 1, $timestamp, 0, $extra_macros, $is_correlated_alert]);
$alert, 1, $timestamp, 0, $extra_macros]);
} else {
pandora_execute_alert ($pa_config, $data, $agent, $module, $alert, 1,
$dbh, $timestamp, 0, $extra_macros, $is_correlated_alert);
$dbh, $timestamp, 0, $extra_macros);
}
return;
}
@ -941,7 +949,7 @@ Execute the given alert.
sub pandora_execute_alert {
my ($pa_config, $data, $agent, $module,
$alert, $alert_mode, $dbh, $timestamp, $forced_alert,
$extra_macros, $is_correlated_alert) = @_;
$extra_macros) = @_;
# 'in-process' events can inhibit alers too.
if ($pa_config->{'event_inhibit_alerts'} == 1 && $alert_mode != RECOVERED_ALERT) {
@ -1031,7 +1039,7 @@ sub pandora_execute_alert {
}
}
# Event alert
else {
elsif (defined($alert->{'_event_alert'})) {
if ($alert_mode == RECOVERED_ALERT) {
@actions = get_db_rows ($dbh, 'SELECT talert_actions.name as action_name, tevent_alert_action.*, talert_actions.*, talert_commands.*
FROM tevent_alert_action, talert_actions, talert_commands
@ -1062,6 +1070,38 @@ sub pandora_execute_alert {
$alert->{'id_alert_action'});
}
}
# Log alert.
elsif (defined($alert->{'_log_alert'})) {
if ($alert_mode == RECOVERED_ALERT) {
@actions = get_db_rows ($dbh, 'SELECT talert_actions.name as action_name, tlog_alert_action.*, talert_actions.*, talert_commands.*
FROM tlog_alert_action, talert_actions, talert_commands
WHERE tlog_alert_action.id_alert_action = talert_actions.id
AND talert_actions.id_alert_command = talert_commands.id
AND tlog_alert_action.id_log_alert = ?
AND ((fires_min = 0 AND fires_max = 0)
OR ? >= fires_min)',
$alert->{'id'}, $alert->{'times_fired'});
} else {
@actions = get_db_rows ($dbh, 'SELECT talert_actions.name as action_name, tlog_alert_action.*, talert_actions.*, talert_commands.*
FROM tlog_alert_action, talert_actions, talert_commands
WHERE tlog_alert_action.id_alert_action = talert_actions.id
AND talert_actions.id_alert_command = talert_commands.id
AND tlog_alert_action.id_log_alert = ?
AND ((fires_min = 0 AND fires_max = 0)
OR (fires_min <= fires_max AND ? >= fires_min AND ? <= fires_max)
OR (fires_min > fires_max AND ? >= fires_min))',
$alert->{'id'}, $alert->{'times_fired'}, $alert->{'times_fired'}, $alert->{'times_fired'});
}
# Get default action
if ($#actions < 0) {
@actions = get_db_rows ($dbh, 'SELECT talert_actions.name as action_name, talert_actions.*, talert_commands.*
FROM talert_actions, talert_commands
WHERE talert_actions.id = ?
AND talert_actions.id_alert_command = talert_commands.id',
$alert->{'id_alert_action'});
}
}
# No actions defined
if ($#actions < 0) {
@ -1150,8 +1190,33 @@ sub pandora_execute_alert {
#If we've spotted an alert recovered, we set the new event's severity to 2 (NORMAL), otherwise the original value is maintained.
my ($text, $event, $severity) = ($alert_mode == RECOVERED_ALERT) ? ('recovered', 'alert_recovered', 2) : ('fired', 'alert_fired', $alert->{'priority'});
if (defined($is_correlated_alert) && $is_correlated_alert == 1) {
$text = "Correlated alert $text";
if (defined($alert->{'_event_alert'})) {
$text = "Event alert $text";
pandora_event (
$pa_config,
"$text (" . safe_output($alert->{'name'}) . ") ",
(defined ($agent) ? $agent->{'id_grupo'} : 0),
# id agent.
0,
$severity,
(defined ($alert->{'id_template_module'}) ? $alert->{'id_template_module'} : 0),
# id agent module.
0,
$event,
0,
$dbh,
'monitoring_server',
'',
'',
'',
'',
$critical_instructions,
$warning_instructions,
$unknown_instructions,
p_encode_json($pa_config, $custom_data)
);
} elsif (defined($alert->{'_log_alert'})) {
$text = "Log alert $text";
pandora_event (
$pa_config,
"$text (" . safe_output($alert->{'name'}) . ") ",

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.773.3";
my $pandora_build = "231020";
my $pandora_build = "231024";
our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] );

View File

@ -67,7 +67,6 @@ our @EXPORT = qw(
INVENTORYSERVER
WEBSERVER
EVENTSERVER
CORRELATIONSERVER
ICMPSERVER
SNMPSERVER
SATELLITESERVER
@ -80,6 +79,7 @@ our @EXPORT = qw(
NCMSERVER
NETFLOWSERVER
LOGSERVER
LOGSERVER
MADESERVER
METACONSOLE_LICENSE
OFFLINE_LICENSE

View File

@ -7,7 +7,7 @@
%define debug_package %{nil}
%define name pandorafms_server
%define version 7.0NG.773.3
%define release 231020
%define release 231024
Summary: Pandora FMS Server
Name: %{name}

View File

@ -4,7 +4,7 @@
%global __os_install_post %{nil}
%define name pandorafms_server
%define version 7.0NG.773.3
%define release 231020
%define release 231024
Summary: Pandora FMS Server
Name: %{name}

View File

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

View File

@ -26,6 +26,9 @@ use POSIX qw(strftime);
use File::Path qw(rmtree);
use Time::HiRes qw(usleep);
use List::Util qw(min);
use List::Util qw(sum);
# Default lib dir for RPM and DEB packages
BEGIN { push @INC, '/usr/lib/perl5'; }
@ -35,7 +38,7 @@ use PandoraFMS::Config;
use PandoraFMS::DB;
# version: define current version
my $version = "7.0NG.773.3 Build 231020";
my $version = "7.0NG.773.3 Build 231024";
# Pandora server configuration
my %conf;
@ -443,116 +446,187 @@ sub pandora_purgedb ($$$) {
###############################################################################
# Compact agent data.
###############################################################################
sub pandora_compactdb ($$$) {
my ($conf, $dbh, $dbh_conf) = @_;
sub pandora_compactdb {
my ($conf, $dbh, $dbh_conf) = @_;
my $total_modules = get_db_value($dbh, "SELECT COUNT(id_agente_modulo) FROM tagente_modulo");
# Interval in hours to compact.
my $compaction_interval = 24;
my $compaction_factor = (3600 * $compaction_interval) / 300;
# Number of agents to be proceced on this execution
my $agents_limit = int($total_modules / $compaction_factor);
my $last_compact_offset = pandora_get_config_value($dbh, "last_compact_offset");
unless ($last_compact_offset) {
db_do($dbh, "INSERT INTO tconfig (token, value) VALUES ('last_compact_offset', '0')");
$last_compact_offset = 0;
}
# Obtain a group of modules to compact.
my @module_groups = get_db_rows(
$dbh,
'SELECT id_agente_modulo, id_tipo_modulo, UNIX_TIMESTAMP(last_compact) as last_compact FROM tagente_modulo WHERE id_agente_modulo > ? LIMIT ?',
$last_compact_offset,
$agents_limit
);
# Compact the group of modules.
my $starting_time = time();
pandora_compact_modules($dbh, $conf, @module_groups);
my $ending_time = time();
log_message('COMPACT', "Time taken: " . ($ending_time - $starting_time) . " seconds.");
# Add the offset.
$last_compact_offset += $agents_limit;
# If the offset is higher than the max module start again
$last_compact_offset = 0 if ($last_compact_offset >= $total_modules);
# Save the new offset
db_do($dbh, "UPDATE tconfig SET value = ? WHERE token = 'last_compact_offset'", $last_compact_offset);
}
sub pandora_compact_modules {
my ($dbh, $conf, @module_groups) = @_;
# Obtain the minimun last compact from the block
my $min_compact = min(map { $_->{"last_compact"} } @module_groups);
# if the min has not been setted
if($min_compact == 0){
$min_compact = get_db_value(
$dbh,
'SELECT MIN(td.utimestamp)
FROM tagente_datos td, tagente_modulo tm
WHERE td.id_agente_modulo = tm.id_agente_modulo
AND tm.id_tipo_modulo not in (2, 6, 9, 18, 21, 31, 35, 100)
AND td.id_agente_modulo BETWEEN ? AND ?',
$module_groups[0]->{"id_agente_modulo"}, $module_groups[-1]->{"id_agente_modulo"}
);
}
# One week of data of data as max from the last min compact.
my $max_compact = $min_compact + (60 * 60 * 24 * 7);
# If the last compact is on the future set the current time as max.
$max_compact = time() if($max_compact > time());
log_message('COMPACT', "Compacting data of agents agents $module_groups[0]->{'id_agente_modulo'} to $module_groups[-1]->{'id_agente_modulo'}, data between " . strftime('%Y-%m-%d %H:%M:%S', localtime($min_compact)) . " and " . strftime('%Y-%m-%d %H:%M:%S', localtime($max_compact)));
# Obtain all the data from the interval to avoid multiple requests
# Avoid pull data from modules that should be skipped.
my @data = get_db_rows (
$dbh,
'SELECT td.id_agente_modulo, td.datos, td.utimestamp
FROM tagente_datos td, tagente_modulo tm
WHERE td.id_agente_modulo = tm.id_agente_modulo
AND tm.id_tipo_modulo not in (2, 6, 9, 18, 21, 31, 35, 100)
AND td.utimestamp < ? AND td.utimestamp >= ?
AND td.id_agente_modulo BETWEEN ? AND ?
',
$max_compact, $min_compact, $module_groups[0]->{"id_agente_modulo"}, $module_groups[-1]->{"id_agente_modulo"}
);
my $total_data = scalar(@data);
my $proceced_total_data = 0;
my $progress = 0;
my $compactations = 0;
my %count_hash;
my %id_agent_hash;
my %value_hash;
my %module_proc_hash;
return if ($conf->{'_days_compact'} == 0 || $conf->{'_step_compact'} < 1);
# Convert compact interval length from hours to seconds
my $step = $conf->{'_step_compact'} * 3600;
# The oldest timestamp will be the lower limit
my $limit_utime = get_db_value ($dbh, 'SELECT min(utimestamp) as min FROM tagente_datos');
return unless (defined ($limit_utime) && $limit_utime > 0);
# Max. 168 steps or 7 days in one hour steps.
# This avoids blocking of old modules without last compact
my $step_limit = 24 * 7;
# Calculate the start date
my $start_utime = time() - $conf->{'_days_compact'} * 24 * 60 * 60;
my $last_compact = $start_utime;
my $stop_utime;
# Compact the modules in this block
foreach my $module (@module_groups) {
$progress = $total_data == 0 ? 0 : ($proceced_total_data / $total_data) * 100;
printf(strftime("\r" . "%H:%M:%S", localtime()) . ' [COMPACT] ' . "Progress: %.2f%%", $progress);
my $id = $module->{"id_agente_modulo"};
my $module_type = $module->{"id_tipo_modulo"};
# Do not compact the same data twice!
if (defined ($conf->{'_last_compact'}) && $conf->{'_last_compact'} > $limit_utime) {
$limit_utime = $conf->{'_last_compact'};
}
if ($start_utime <= $limit_utime || ( defined ($conf->{'_last_compact'}) && (($conf->{'_last_compact'} + 24 * 60 * 60) > $start_utime))) {
log_message ('COMPACT', "Data already compacted.");
return;
}
log_message ('COMPACT', "Compacting data from " . strftime ("%Y-%m-%d %H:%M:%S", localtime($limit_utime)) . " to " . strftime ("%Y-%m-%d %H:%M:%S", localtime($start_utime)) . '.', '');
next unless defined ($module_type);
next if ($module_type == 2 || $module_type == 6 || $module_type == 9 || $module_type == 18 || $module_type == 21 || $module_type == 31 || $module_type == 35 || $module_type == 100);
# Prepare the query to retrieve data from an interval
while (1) {
# Obtain the data just for this module
my @module_data = grep { $_->{"id_agente_modulo"} == $id } @data;
my $total_elements = scalar(@module_data);
# Calculate the stop date for the interval
$stop_utime = $start_utime - $step;
# No data for this module.
next if ($total_elements == 0);
# Out of limits
last if ($start_utime < $limit_utime);
# Obtain the last compact of this module to avoid compact something previously compacted
my $last_compact = $module ->{"last_compact"};
# Mark the progress
log_message ('', ".");
# In case that the last compact has not been defined take the minimun data as last compact
$last_compact = min(map { $_->{"utimestamp"} } @module_data)-1 if($last_compact == 0);
# Create an array to store INSERT commands
my @insert_commands;
my $insert_command = 'INSERT INTO tagente_datos (id_agente_modulo, datos, utimestamp) VALUES (?, ?, ?)';
my $step_number = 0;
my $first_compact = $last_compact;
# Compact using the steps
while($step_number < $step_limit){
my $next_compact = $last_compact + $step;
my @data = get_db_rows ($dbh, 'SELECT * FROM tagente_datos WHERE utimestamp < ? AND utimestamp >= ?', $start_utime, $stop_utime);
# No data, move to the next interval
if ($#data == 0) {
$start_utime = $stop_utime;
last if($next_compact > time());
# Obtain the data between the last compact and the next step.
my @data_in_range = grep { $_->{"utimestamp"} > $last_compact && $_->{"utimestamp"} <= $next_compact } @module_data;
my $total_range_elements = scalar(@data_in_range);
# Nothing to compress, skip this step.
if($total_range_elements == 0){
$last_compact = $next_compact;
next;
}
# Get interval data
foreach my $data (@data) {
my $id_module = $data->{'id_agente_modulo'};
if (! defined($module_proc_hash{$id_module})) {
my $module_type = get_db_value ($dbh, 'SELECT id_tipo_modulo FROM tagente_modulo WHERE id_agente_modulo = ?', $id_module);
next unless defined ($module_type);
my $total_data = sum(map { $_->{"datos"} } @data_in_range);
# Mark proc modules.
if ($module_type == 2 || $module_type == 6 || $module_type == 9 || $module_type == 18 || $module_type == 21 || $module_type == 31 || $module_type == 35 || $module_type == 100) {
$module_proc_hash{$id_module} = 1;
}
else {
$module_proc_hash{$id_module} = 0;
}
}
my $avg = $total_data / $total_range_elements;
# Skip proc modules!
next if ($module_proc_hash{$id_module} == 1);
$proceced_total_data += $total_range_elements;
push @insert_commands, [$insert_command, $id, $avg, int($last_compact + ($step / 2))];
if (! defined($value_hash{$id_module})) {
$value_hash{$id_module} = 0;
$count_hash{$id_module} = 0;
$last_compact = $next_compact;
$step_number +=1;
# Small sleep to don't burn the DB
usleep (1000);
}
if (! defined($id_agent_hash{$id_module})) {
$id_agent_hash{$id_module} = $data->{'id_agente'};
}
}
$dbh->begin_work;
$value_hash{$id_module} += $data->{'datos'};
$count_hash{$id_module}++;
}
db_do ($dbh, 'DELETE FROM tagente_datos WHERE utimestamp > ? AND utimestamp <= ? AND id_agente_modulo = ?', $first_compact, $last_compact, $id);
# Delete interval from the database
db_do ($dbh, 'DELETE ad FROM tagente_datos ad
INNER JOIN tagente_modulo am ON ad.id_agente_modulo = am.id_agente_modulo AND am.id_tipo_modulo NOT IN (2,6,9,18,21,31,35,100)
WHERE ad.utimestamp < ? AND ad.utimestamp >= ?', $start_utime, $stop_utime);
# Execute the INSERT commands
foreach my $command (@insert_commands) {
my ($sql, @params) = @$command;
db_do($dbh, $sql, @params);
}
# Insert interval average value
foreach my $key (keys(%value_hash)) {
$value_hash{$key} /= $count_hash{$key};
db_do ($dbh, 'INSERT INTO tagente_datos (id_agente_modulo, datos, utimestamp) VALUES (?, ?, ?)', $key, $value_hash{$key}, $stop_utime);
delete($value_hash{$key});
delete($count_hash{$key});
}
usleep (1000); # Very small usleep, just to don't burn the DB
# Move to the next interval
$start_utime = $stop_utime;
$dbh->commit;
# Update the last compacted timestamp.
db_do($dbh, "UPDATE tagente_modulo SET last_compact = FROM_UNIXTIME(?) WHERE id_agente_modulo = ?", $last_compact, $module ->{"id_agente_modulo"});
$compactations += $step_number;
}
log_message ('', "\n");
# Mark the last compact date
if (defined ($conf->{'_last_compact'})) {
db_do ($dbh_conf, 'UPDATE tconfig SET value=? WHERE token=?', $last_compact, 'last_compact');
} else {
db_do ($dbh_conf, 'INSERT INTO tconfig (value, token) VALUES (?, ?)', $last_compact, 'last_compact');
}
printf(strftime("\r" . "%H:%M:%S", localtime()) . ' [COMPACT] ' . "Progress: %.2f%%", 100);
print("\n");
log_message('COMPACT', "A total of $proceced_total_data elements has been compacted into $compactations elements");
}
########################################################################
@ -1234,9 +1308,8 @@ sub pandoradb_main {
# Only active database should be compacted. Disabled for historical database.
# Compact on if enable and DaysCompact are below DaysPurge
if (($conf->{'_onlypurge'} == 0)
&& ($conf->{'_days_compact'} < $conf->{'_days_purge'})
) {
pandora_compactdb ($conf, defined ($history_dbh) ? $history_dbh : $dbh, $dbh);
pandora_compactdb ($conf, $dbh, $dbh);
}
# Update tconfig with last time of database maintance time (now)

View File

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