pandorafms/pandora_console/include/class/Diagnostics.class.php

2262 lines
69 KiB
PHP

<?php
/**
* Extension to self monitor Pandora FMS Console
*
* @category Console Class
* @package Pandora FMS
* @subpackage Diagnostics
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org 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.
* ============================================================================
*/
global $config;
require_once $config['homedir'].'/include/functions_db.php';
require_once $config['homedir'].'/include/functions_io.php';
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
/**
* Base class Diagnostics.
*/
class Diagnostics extends Wizard
{
/**
* Ajax controller page.
*
* @var string
*/
public $ajaxController;
/**
* Print Html or Pdf view.
*
* @var boolean
*/
public $pdf;
/**
* Constructor.
*
* @param string $page Page.
* @param boolean $pdf PDF View.
*/
public function __construct(
string $page='tools/diagnostics',
bool $pdf=false
) {
global $config;
// Check access.
check_login();
$this->url = ui_get_full_url(
'index.php?sec=gextensions&sec2=tools/diagnostics'
);
$this->ajaxController = $page;
$this->pdf = $pdf;
$this->product_name = io_safe_output(get_product_name());
}
/**
* Allowed methods to be called using AJAX request.
*
* @var array
*/
public $AJAXMethods = [
'getStatusInfo',
'getPHPSetup',
'getDatabaseSizeStats',
'getDatabaseHealthStatus',
'getDatabaseStatusInfo',
'getSystemInfo',
'getMySQLPerformanceMetrics',
'getTablesFragmentation',
'getPandoraFMSLogsDates',
'getLicenceInformation',
'getAttachmentFolder',
'getInfoTagenteDatos',
'getServerThreads',
'getShowEngine',
'datatablesDraw',
'getChartAjax',
'formFeedback',
'createdScheduleFeedbackTask',
];
/**
* Checks if target method is available to be called using AJAX.
*
* @param string $method Target method.
*
* @return boolean True allowed, false not.
*/
public function ajaxMethod(string $method):bool
{
return in_array($method, $this->AJAXMethods);
}
/**
* Show view diagnostics.
*
* @return void
*/
public function run()
{
global $config;
if ($this->pdf === true) {
$this->exportPDF();
exit;
}
ui_require_css_file('diagnostics');
$pdf_url = $this->url.'&pdf=true';
$pdf_img = html_print_image(
'images/pdf.png',
true,
[
'title' => __('Export to PDF'),
'class' => 'invert_filter',
]
);
$header_buttons = [
'csv' => [
'active' => false,
'text' => '<a target="_new" href="'.$pdf_url.'">'.$pdf_img.'</a>',
],
];
// Header.
ui_print_page_header(
__('%s Diagnostic tool', $this->product_name),
'images/gm_massive_operations.png',
false,
'',
true,
$header_buttons
);
// Print all Methods Diagnostic Info.
echo $this->printMethodsDiagnostigsInfo();
// Print all charts Monitoring.
echo $this->printCharts();
echo '<div class="footer-self-monitoring">';
echo $this->checkPandoraDB();
echo '</div>';
}
/**
* Print Methods:
* Info status pandoraFms.
* PHP setup.
* Database size stats.
* Database health status.
* Database status info.
* System Info.
* MySQL Performance metrics.
* Tables fragmentation in the Pandora FMS database.
* Pandora FMS logs dates.
* Pandora FMS Licence Information.
* Status of the attachment folder.
* Information from the tagente_datos table.
* Pandora FMS server threads.
*
* @return string Html.
*/
public function printMethodsDiagnostigsInfo():string
{
$infoMethods = [
'getStatusInfo',
'getPHPSetup',
'getDatabaseSizeStats',
'getDatabaseHealthStatus',
'getDatabaseStatusInfo',
'getSystemInfo',
'getMySQLPerformanceMetrics',
'getTablesFragmentation',
'getPandoraFMSLogsDates',
'getLicenceInformation',
'getAttachmentFolder',
'getInfoTagenteDatos',
'getServerThreads',
];
if ($this->pdf === true) {
$infoMethods[] = 'getShowEngine';
}
$return = '';
foreach ($infoMethods as $key => $method) {
switch ($method) {
case 'getStatusInfo':
$title = __('Info status %s', $this->product_name);
break;
case 'getPHPSetup':
$title = __('PHP setup');
break;
case 'getDatabaseSizeStats':
$title = __('Database size stats');
break;
case 'getDatabaseHealthStatus':
$title = __('Database health status');
break;
case 'getDatabaseStatusInfo':
$title = __('Database status info');
break;
case 'getSystemInfo':
$title = __('System Info');
break;
case 'getMySQLPerformanceMetrics':
$title = __('MySQL Performance metrics');
break;
case 'getTablesFragmentation':
$title = __(
'Tables fragmentation in the %s database',
$this->product_name
);
break;
case 'getPandoraFMSLogsDates':
$title = __('%s logs dates', $this->product_name);
break;
case 'getLicenceInformation':
$title = __('%s Licence Information', $this->product_name);
break;
case 'getAttachmentFolder':
$title = __('Status of the attachment folder');
break;
case 'getInfoTagenteDatos':
$title = __('Information from the tagente_datos table');
break;
case 'getServerThreads':
$title = __('%s server threads', $this->product_name);
break;
case 'getShowEngine':
$title = __('SQL show engine innodb status');
break;
default:
// Not possible.
$title = '';
break;
}
$return .= '<div class="mrgn_btn_30px">';
$return .= $this->printData($method, $title);
$return .= '</div>';
}
return false;
}
/**
* Print table graps:
* Graph of the Agents Unknown module.
* Graph of the Database Maintenance module.
* Graph of the Free Disk Spool Dir module.
* Graph of the Free RAM module.
* Graph of the Queued Modules module.
* Graph of the Status module.
* Graph of the System Load AVG module.
* Graph of the Execution Time module.
*
* @return string
*/
public function printCharts()
{
/*
* Agent id with name Master Server.
*/
$agentIdMasterServer = $this->getAgentIdMasterServer();
$result = '';
if ($agentIdMasterServer !== 0) {
$agentMonitoring = [
'chartAgentsUnknown' => [
'title' => __(
'Graph of the Agents Unknown module.'
),
'nameModule' => 'Agents_Unknown',
'idAgent' => $agentIdMasterServer,
],
'chartDatabaseMain' => [
'title' => __(
'Graph of the Database Maintenance module.'
),
'nameModule' => 'Database&#x20;Maintenance',
'idAgent' => $agentIdMasterServer,
],
'chartFreeDiskSpoolDir' => [
'title' => __(
'Graph of the Free Disk Spool Dir module.'
),
'nameModule' => 'FreeDisk_SpoolDir',
'idAgent' => $agentIdMasterServer,
],
'chartFreeRAM' => [
'title' => __('Graph of the Free RAM module.'),
'nameModule' => 'Free_RAM',
'idAgent' => $agentIdMasterServer,
],
'chartQueuedModules' => [
'title' => __(
'Graph of the Queued Modules module.'
),
'nameModule' => 'Queued_Modules',
'idAgent' => $agentIdMasterServer,
],
'chartStatus' => [
'title' => __('Graph of the Status module.'),
'nameModule' => 'Status',
'idAgent' => $agentIdMasterServer,
],
'chartSystemLoadAVG' => [
'title' => __(
'Graph of the System Load AVG module.'
),
'nameModule' => 'System_Load_AVG',
'idAgent' => $agentIdMasterServer,
],
'chartExecutionTime' => [
'title' => __(
'Graph of the Execution Time module.'
),
'nameModule' => 'Execution_time',
'idAgent' => $agentIdMasterServer,
],
];
$return .= '<div class="title-self-monitoring">';
$return .= __(
'Graphs modules that represent the self-monitoring system'
);
$return .= '</div>';
$return .= '<div class="container-self-monitoring">';
foreach ($agentMonitoring as $key => $value) {
$return .= $this->printDataCharts($value);
}
$return .= '</div>';
}
return $return;
}
/**
* Info status pandoraFms.
*
* @return string
*/
public function getStatusInfo(): string
{
global $config;
global $build_version;
global $pandora_version;
$sql = sprintf(
"SELECT `key`, `value`
FROM `tupdate_settings`
WHERE `key` = '%s'
OR `key` = '%s'
OR `key` = '%s'",
'current_update',
'customer_key',
'updating_code_path'
);
$values_key = db_get_all_rows_sql($sql);
$values_key = array_reduce(
$values_key,
function ($carry, $item) {
if ($item['key'] === 'customer_key') {
$customer = substr($item['value'], 0, 5);
$customer .= '...';
$customer .= substr($item['value'], -5);
$item['value'] = $customer;
}
$carry[$item['key']] = $item['value'];
return $carry;
}
);
$result = [
'error' => false,
'data' => [
'buildVersion' => [
'name' => __('%s Build', $this->product_name),
'value' => $build_version,
],
'version' => [
'name' => __('%s Version', $this->product_name),
'value' => $pandora_version,
],
'mr' => [
'name' => __('Minor Release'),
'value' => $config['MR'],
],
'homeDir' => [
'name' => __('Homedir'),
'value' => $config['homedir'],
],
'homeUrl' => [
'name' => __('HomeUrl'),
'value' => $config['homeurl'],
],
'isEnterprise' => [
'name' => __('Enterprise installed'),
'value' => (enterprise_installed()) ? __('true') : __('false'),
],
'customerKey' => [
'name' => __('Update Key'),
'value' => $values_key['customer_key'],
],
'updatingCode' => [
'name' => __('Updating code path'),
'value' => $values_key['updating_code_path'],
],
'currentUpdate' => [
'name' => __('Current Update #'),
'value' => $values_key['current_update'],
],
],
];
return json_encode($result);
}
/**
* PHP Status.
*
* @return string
*/
public function getPHPSetup(): string
{
global $config;
$result = [
'error' => false,
'data' => [
'phpVersion' => [
'name' => __('PHP Version'),
'value' => phpversion(),
],
'maxExecutionTime' => [
'name' => __('PHP Max execution time'),
'value' => ini_get('max_execution_time'),
],
'maxInputTime' => [
'name' => __('PHP Max input time'),
'value' => ini_get('max_input_time'),
],
'memoryLimit' => [
'name' => __('PHP Memory limit'),
'value' => ini_get('memory_limit'),
],
'sessionLifetime' => [
'name' => __('Session cookie lifetime'),
'value' => ini_get('session.cookie_lifetime'),
],
],
];
return json_encode($result);
}
/**
* Database size stats.
*
* @return string
*/
public function getDatabaseSizeStats(): string
{
global $config;
$countAgents = db_get_value_sql('SELECT COUNT(*) FROM tagente');
$countModules = db_get_value_sql('SELECT COUNT(*) FROM tagente_modulo');
$countGroups = db_get_value_sql('SELECT COUNT(*) FROM tgrupo');
$countModuleData = db_get_value_sql(
'SELECT COUNT(*) FROM tagente_datos'
);
$countAgentAccess = db_get_value_sql(
'SELECT COUNT(*) FROM tagent_access'
);
$countEvents = db_get_value_sql('SELECT COUNT(*) FROM tevento');
if (enterprise_installed() === true) {
$countTraps = db_get_value_sql('SELECT COUNT(*) FROM ttrap');
}
$countUsers = db_get_value_sql('SELECT COUNT(*) FROM tusuario');
$countSessions = db_get_value_sql('SELECT COUNT(*) FROM tsesion');
$result = [
'error' => false,
'data' => [
'countAgents' => [
'name' => __('Total agents'),
'value' => $countAgents,
],
'countModules' => [
'name' => __('Total modules'),
'value' => $countModules,
],
'countGroups' => [
'name' => __('Total groups'),
'value' => $countGroups,
],
'countModuleData' => [
'name' => __('Total module data records'),
'value' => $countModuleData,
],
'countAgentAccess' => [
'name' => __('Total agent access record'),
'value' => $countAgentAccess,
],
'countEvents' => [
'name' => __('Total events'),
'value' => $countEvents,
],
'countTraps' => [
'name' => __('Total traps'),
'value' => $countTraps,
],
'countUsers' => [
'name' => __('Total users'),
'value' => $countUsers,
],
'countSessions' => [
'name' => __('Total sessions'),
'value' => $countSessions,
],
],
];
return json_encode($result);
}
/**
* Database health status.
*
* @return string
*/
public function getDatabaseHealthStatus(): string
{
global $config;
// Count agents unknowns.
$sqlUnknownAgents = 'SELECT COUNT( DISTINCT tagente.id_agente)
FROM tagente_estado, tagente, tagente_modulo
WHERE tagente.disabled = 0
AND tagente_modulo.id_agente_modulo = tagente_estado.id_agente_modulo
AND tagente_modulo.disabled = 0
AND tagente_estado.id_agente = tagente.id_agente
AND tagente_estado.estado = 3';
$unknownAgents = db_get_sql($sqlUnknownAgents);
// Count modules not initialize.
$sqlNotInitAgents = 'SELECT COUNT(tagente_estado.estado)
FROM tagente_estado
WHERE tagente_estado.estado = 4';
$notInitAgents = db_get_sql($sqlNotInitAgents);
$dateDbMantenaince = $config['db_maintance'];
$currentTime = time();
$pandoraDbLastRun = __('Pandora DB has never been executed');
if ($dateDbMantenaince !== false) {
$difference = ($currentTime - $dateDbMantenaince);
$pandoraDbLastRun = human_time_description_raw(
$difference,
true
);
$pandoraDbLastRun .= ' '.__('Ago');
}
$result = [
'error' => false,
'data' => [
'unknownAgents' => [
'name' => __('Total unknown agents'),
'value' => $unknownAgents,
],
'notInitAgents' => [
'name' => __('Total not-init modules'),
'value' => $notInitAgents,
],
'pandoraDbLastRun' => [
'name' => __('Pandora DB Last run'),
'value' => $pandoraDbLastRun,
],
],
];
return json_encode($result);
}
/**
* Database status info.
*
* @return string
*/
public function getDatabaseStatusInfo(): string
{
global $config;
// Size BBDD.
$dbSizeSql = db_get_value_sql(
'SELECT ROUND(SUM(data_length+index_length)/1024/1024,3)
FROM information_schema.TABLES'
);
// Add unit size.
$dbSize = $dbSizeSql.' M';
$result = [
'error' => false,
'data' => [
'dbSchemeFirstVersion' => [
'name' => __('DB Schema Version (first installed)'),
'value' => $config['db_scheme_first_version'],
],
'dbSchemeVersion' => [
'name' => __('DB Schema Version (actual)'),
'value' => $config['db_scheme_version'],
],
'dbSchemeBuild' => [
'name' => __('DB Schema Build'),
'value' => $config['db_scheme_build'],
],
'dbSize' => [
'name' => __('DB Size'),
'value' => $dbSize,
],
],
];
return json_encode($result);
}
/**
* Database status info.
*
* @return string
*/
public function getSystemInfo(): string
{
global $config;
$result = [];
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$cpuModelName = 'cat /proc/cpuinfo | grep "model name" | tail -1 | cut -f 2 -d ":"';
$cpuProcessor = 'cat /proc/cpuinfo | grep "processor" | wc -l';
$ramMemTotal = 'cat /proc/meminfo | grep "MemTotal"';
exec(
"ifconfig | awk '{ print $2}' | grep -E -o '([0-9]{1,3}[\.]){3}[0-9]{1,3}'",
$output
);
$ips = implode(', ', $output);
$result = [
'error' => false,
'data' => [
'cpuInfo' => [
'name' => __('CPU'),
'value' => exec($cpuModelName).' x '.exec($cpuProcessor),
],
'ramInfo' => [
'name' => __('RAM'),
'value' => exec($ramMemTotal),
],
'osInfo' => [
'name' => __('Os'),
'value' => exec('uname -a'),
],
'hostnameInfo' => [
'name' => __('Hostname'),
'value' => exec('hostname'),
],
'ipInfo' => [
'name' => __('Ip'),
'value' => $ips,
],
],
];
} else {
$result = [
'error' => false,
'data' => [
'osInfo' => [
'name' => __('OS'),
'value' => exec('ver'),
],
'hostnameInfo' => [
'name' => __('Hostname'),
'value' => exec('hostname'),
],
'ipInfo' => [
'name' => __('Ip'),
'value' => exec('ipconfig | findstr IPv4'),
],
],
];
}
return json_encode($result);
}
/**
* MySQL Performance metrics.
*
* @return string
*/
public function getMySQLPerformanceMetrics(): string
{
global $config;
$variablesMsql = db_get_all_rows_sql('SHOW VARIABLES');
$variablesMsql = array_reduce(
$variablesMsql,
function ($carry, $item) {
$bytes = 1048576;
$mega = 1024;
switch ($item['Variable_name']) {
case 'innodb_buffer_pool_size':
$name = __('InnoDB buffer pool size');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 250) ? 1 : 0;
$message = __(
'It has to be 40% of the server memory not recommended to be greater or less'
);
break;
case 'innodb_file_per_table':
$name = __('InnoDB file per table');
$value = $item['Value'];
$status = ($item['Value'] === 'ON') ? 1 : 0;
$message = __('Recommended ON');
break;
case 'innodb_flush_log_at_trx_commit':
$name = __('InnoDB flush log at trx-commit');
$value = $item['Value'];
$status = ($item['Value'] == 2) ? 1 : 0;
$message = __('Recommended Value').' 2';
break;
case 'innodb_lock_wait_timeout':
$name = __('InnoDB lock wait timeout');
$value = $item['Value'];
$status = ($item['Value'] >= 90) ? 1 : 0;
$message = __('Min. Recommended Value').' 90s';
break;
case 'innodb_log_buffer_size':
$name = __('InnoDB log buffer size');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 16) ? 1 : 0;
$message = __('Min. Recommended Value').' 16M';
break;
case 'innodb_log_file_size':
$name = __('InnoDB log file size');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 64) ? 1 : 0;
$message = __('Min. Recommended Value').' 64M';
break;
case 'max_allowed_packet':
$name = __('Maximun allowed packet');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 32) ? 1 : 0;
$message = __('Min. Recommended Value').' 32M';
break;
case 'max_connections':
$name = __('Maximun connections');
$value = $item['Value'];
$status = (($item['Value']) >= 90) ? 1 : 0;
$message = __('Min. Recommended Value');
$message .= ' 90 ';
$message .= __('conections');
break;
case 'query_cache_limit':
$name = __('Query cache limit');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 8) ? 1 : 0;
$message = __('Min. Recommended Value').' 8M';
break;
case 'query_cache_min_res_unit':
$name = __('Query cache min-res-unit');
$value = ($item['Value'] / $mega);
$status = (($item['Value'] / $mega) >= 2) ? 1 : 0;
$message = __('Min. Recommended Value').' 2M';
break;
case 'query_cache_size':
$name = __('Query cache size');
$value = ($item['Value'] / $bytes);
$status = (($item['Value'] / $bytes) >= 32) ? 1 : 0;
$message = __('Min. Recommended Value').' 32M';
break;
case 'query_cache_type':
$name = __('Query cache type');
$value = $item['Value'];
$status = ($item['Value'] === 'ON') ? 1 : 0;
$message = __('Recommended ON');
break;
case 'read_buffer_size':
$name = __('Read buffer size');
$value = ($item['Value'] / $mega);
$status = (($item['Value'] / $mega) >= 32) ? 1 : 0;
$message = __('Min. Recommended Value').' 32K';
break;
case 'read_rnd_buffer_size':
$name = __('Read rnd-buffer size');
$value = ($item['Value'] / $mega);
$status = (($item['Value'] / $mega) >= 32) ? 1 : 0;
$message = __('Min. Recommended Value').' 32K';
break;
case 'sort_buffer_size':
$name = __('Sort buffer size');
$value = ($item['Value'] / $mega);
$status = (($item['Value'] / $mega) >= 32) ? 1 : 0;
$message = __('Min. Recommended Value').' 32K';
break;
case 'sql_mode':
$name = __('Sql mode');
$value = ($item['Value']);
$status = (empty($item['Value']) === true) ? 1 : 0;
$message = __('Must be empty');
break;
case 'thread_cache_size':
$name = __('Thread cache size');
$value = $item['Value'];
$status = ($item['Value'] >= 8) ? 1 : 0;
$message = __('Min. Recommended Value').' 8';
break;
case 'thread_stack':
$name = __('Thread stack');
$value = ($item['Value'] / $mega);
$status = (($item['Value'] / $mega) >= 256) ? 1 : 0;
$message = __('Min. Recommended Value').' 256';
break;
default:
$name = '';
$value = 0;
break;
}
if (empty($name) !== true) {
$carry[$item['Variable_name']] = [
'name' => $name,
'value' => $value,
'status' => $status,
'message' => $message,
];
}
return $carry;
},
[]
);
$result = [
'error' => false,
'data' => $variablesMsql,
];
return json_encode($result);
}
/**
* Tables fragmentation in the Pandora FMS database.
*
* @return string
*/
public function getTablesFragmentation(): string
{
global $config;
// Estimated fragmentation percentage as maximum.
$tFragmentationMax = 10;
// Extract the fragmentation value.
$tFragmentationValue = db_get_sql(
sprintf(
"SELECT (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
AND table_name='tagente_datos'
AND table_schema='%s'",
$config['dbname']
)
);
// Check if it meets the fragmentation value.
$status_tables_frag = '';
if ($tFragmentationValue > $tFragmentationMax) {
$tFragmentationMsg = __(
'Table fragmentation is higher than recommended. They should be defragmented.'
);
$tFragmentationStatus = 0;
} else {
$tFragmentationMsg = __('Table fragmentation is correct.');
$tFragmentationStatus = 1;
}
$result = [
'error' => false,
'data' => [
'tablesFragmentationMax' => [
'name' => __(
'Tables fragmentation (maximum recommended value)'
),
'value' => $tFragmentationMax.'%',
],
'tablesFragmentationValue' => [
'name' => __('Tables fragmentation (current value)'),
'value' => number_format($tFragmentationValue, 2).'%',
],
'tablesFragmentationStatus' => [
'name' => __('Table fragmentation status'),
'value' => $status_tables_frag,
'status' => $tFragmentationStatus,
],
],
];
return json_encode($result);
}
/**
* Pandora FMS logs dates.
*
* @return string
*/
public function getPandoraFMSLogsDates(): string
{
global $config;
$unit = 'M';
$pathServerLogs = '/var/log/pandora/pandora_server.log';
$servers = $this->getLogInfo($pathServerLogs);
$pathErrLogs = '/var/log/pandora/pandora_server.error';
$errors = $this->getLogInfo($pathErrLogs);
$pathConsoleLogs = $config['homedir'].'/log/console.log';
$console = $this->getLogInfo($pathConsoleLogs);
$result = [
'error' => false,
'data' => [
'sizeServerLog' => [
'name' => __('Size server logs (current value)'),
'value' => $servers['value'].' '.$unit,
],
'statusServerLog' => [
'name' => __('Status server logs'),
'value' => $servers['message'],
'status' => $servers['status'],
],
'sizeErrorLog' => [
'name' => __('Size error logs (current value)'),
'value' => $errors['value'].' '.$unit,
],
'statusErrorLog' => [
'name' => __('Status error logs'),
'value' => $errors['message'],
'status' => $errors['status'],
],
'sizeConsoleLog' => [
'name' => __('Size console logs (current value)'),
'value' => $console['value'].' '.$unit,
],
'statusConsoleLog' => [
'name' => __('Status console logs'),
'value' => $console['message'],
'status' => $console['status'],
],
],
];
return json_encode($result);
}
/**
* Pandora FMS Licence Information.
*
* @return string
*/
public function getLicenceInformation(): string
{
global $config;
// Extract customer key.
$sql = sprintf(
"SELECT `value`
FROM `tupdate_settings`
WHERE `key` = '%s'",
'customer_key'
);
$customerKey = db_get_value_sql($sql);
// Extract Info license.
enterprise_include_once('include/functions_license.php');
$license = enterprise_hook('license_get_info');
// Agent Capacity.
$agentCount = db_get_value_sql('SELECT count(*) FROM tagente');
$agentsCapacity = __('License capacity is less than 90 percent');
$agentsCapacitySt = 1;
if ($agentCount > ($license['limit'] * 90 / 100)) {
$agentsCapacity = __('License capacity exceeds 90 percent');
$agentsCapacitySt = 0;
}
// Modules average.
$modulesCount = db_get_value_sql('SELECT count(*) FROM tagente_modulo');
$average = ($modulesCount / $agentCount);
$averageMsg = __(
'The average of modules per agent is more than 40. You can have performance problems'
);
$averageSt = 0;
if ($average <= 40) {
$averageMsg = __(
'The average of modules per agent is less than 40'
);
$averageSt = 1;
}
// Modules Networks average.
$totalNetworkModules = db_get_value_sql(
'SELECT count(*)
FROM tagente_modulo
WHERE id_tipo_modulo
BETWEEN 6 AND 18'
);
$totalModuleIntervalTime = db_get_value_sql(
'SELECT SUM(module_interval)
FROM tagente_modulo
WHERE id_tipo_modulo
BETWEEN 6 AND 18'
);
$averageTime = 0;
if ($totalModuleIntervalTime !== false) {
$averageTime = number_format(
((int) $totalNetworkModules / (int) $totalModuleIntervalTime),
3
);
}
$moduleNetworkmsg = __(
sprintf(
'The system is not overloaded (average time %f)',
$averageTime
)
);
$moduleNetworkst = 1;
if ($averageTime === 0) {
$moduleNetworkmsg = __('The system has no load');
$moduleNetworkst = 0;
} else if ($averageTime > 180) {
$moduleNetworkmsg = __(
sprintf(
'The system is overloaded (average time %f) and a very fine configuration is required',
$averageTime
)
);
$moduleNetworkst = 0;
}
$result = [
'error' => false,
'data' => [
'customerKey' => [
'name' => __('Customer key'),
'value' => $customerKey,
],
'customerExpires' => [
'name' => __('Support expires'),
'value' => $license['expiry_date'],
],
'customerLimit' => [
'name' => __('Platform Limit'),
'value' => $license['limit'].' '.__('Agents'),
],
'customerPfCount' => [
'name' => __('Current Platform Count'),
'value' => $license['count'].' '.__('Agents'),
],
'customerPfCountEnabled' => [
'name' => __('Current Platform Count (enabled: items)'),
'value' => $license['count_enabled'].' '.__('Agents'),
],
'customerPfCountDisabled' => [
'name' => __('Current Platform Count (disabled: items)'),
'value' => $license['count_disabled'].' '.__('Agents'),
],
'customerMode' => [
'name' => __('License Mode'),
'value' => $license['license_mode'],
],
'customerNMS' => [
'name' => __('Network Management System'),
'value' => ($license['nms'] > 0) ? __('On') : __('Off'),
],
'customerSatellite' => [
'name' => __('Satellite'),
'value' => ($license['dhpm'] > 0) ? __('On') : __('Off'),
],
'customerLicenseTo' => [
'name' => __('Licensed to'),
'value' => $license['licensed_to'],
],
'customerCapacity' => [
'name' => __('Status of agents capacity'),
'value' => $agentsCapacity,
'status' => $agentsCapacitySt,
],
'customerAverage' => [
'name' => __('Status of average modules per agent'),
'value' => $averageMsg,
'status' => $averageSt,
],
'customerAverageNetwork' => [
'name' => __('Interval average of the network modules'),
'value' => $moduleNetworkmsg,
'status' => $moduleNetworkst,
],
],
];
return json_encode($result);
}
/**
* Status of the attachment folder.
*
* @return string
*/
public function getAttachmentFolder(): string
{
global $config;
// Count files in attachment.
$attachmentFiles = count(
glob(
$config['homedir'].'/attachment/{*.*}',
GLOB_BRACE
)
);
// Check status attachment.
$attachmentMsg = __(
'The attached folder contains more than 700 files.'
);
$attachmentSt = 0;
if ($attachmentFiles <= 700) {
$attachmentMsg = __(
'The attached folder contains less than 700 files.'
);
$attachmentSt = 1;
}
$result = [
'error' => false,
'data' => [
'attachFiles' => [
'name' => __('Total files in the attached folder'),
'value' => $attachmentFiles,
],
'attachStatus' => [
'name' => __('Status of the attachment folder'),
'value' => $attachmentMsg,
'status' => $attachmentSt,
],
],
];
return json_encode($result);
}
/**
* Information from the tagente_datos table.
*
* @return string
*/
public function getInfoTagenteDatos(): string
{
global $config;
$agentDataCount = db_get_value_sql(
'SELECT COUNT(*)
FROM tagente_datos'
);
$taMsg = __(
'The tagente_datos table contains too much data. A historical database is recommended.'
);
$taStatus = 0;
if ($agentDataCount <= 3000000) {
$taMsg = __(
'The tagente_datos table contains an acceptable amount of data.'
);
$taStatus = 1;
}
$result = [
'error' => false,
'data' => [
'agentDataCount' => [
'name' => __('Total data in tagente_datos table'),
'value' => $agentDataCount,
],
'agentDataStatus' => [
'name' => __('Tagente_datos table status'),
'value' => $taMsg,
'status' => $taStatus,
],
],
];
return json_encode($result);
}
/**
* Pandora FMS server threads.
*
* @return string
*/
public function getServerThreads(): string
{
global $config;
$result = [];
$totalServerThreads = 0;
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$totalServerThreads = shell_exec(
'ps -T aux | grep pandora_server | grep -v grep | wc -l'
);
}
include_once $config['homedir'].'/include/functions_servers.php';
$sql = 'SELECT `name`, server_type, threads FROM tserver';
$servers = db_get_all_rows_sql($sql);
if (isset($servers) === true && is_array($servers) === true) {
$sum_threads = 0;
foreach ($servers as $key => $value) {
$result['data']['threads_server_'.$value['server_type']] = [
'name' => __('Threads').' '.\servers_get_server_string_name(
$value['server_type']
),
'value' => $value['threads'],
];
$sum_threads += $value['threads'];
}
$result['data']['total_threads'] = [
'name' => __('Total threads'),
'value' => $sum_threads,
'status' => ($sum_threads < $totalServerThreads) ? 2 : 1,
];
if ($sum_threads < $totalServerThreads) {
$result['data']['total_threads']['message'] = __(
'Current pandora_server running threads'
);
} else {
__(
'There\'s more pandora_server threads than configured, are you running multiple servers simultaneusly?.'
);
}
}
return json_encode($result);
}
/**
* SQL show engine innodb status.
*
* @return string
*/
public function getShowEngine(): string
{
global $config;
try {
// Trick to avoid showing error in case
// you don't have enough permissions.
$backup = error_reporting();
error_reporting(0);
$innodb = db_get_all_rows_sql('show engine innodb status');
error_reporting($backup);
} catch (Exception $e) {
$innodb['Status'] = $e->getMessage();
}
$result = [];
if (isset($innodb[0]['Status']) === true
&& $innodb[0]['Status'] !== false
) {
$lenght = strlen($innodb[0]['Status']);
$data = [];
for ($i = 0; $i < $lenght; $i = ($i + 300)) {
$str = substr($innodb[0]['Status'], $i, ($i + 300));
$data['showEngine-'.$i] = [
'name' => '',
'value' => '<pre>'.$str.'</pre>',
];
}
$result = [
'error' => false,
'data' => $data,
'id' => 'showEngine',
];
}
return json_encode($result);
}
/**
* Agent Id whit name is equal to Server Name.
*
* @return integer Id agent module.
*/
public function getAgentIdMasterServer(): int
{
global $config;
$serverName = db_get_value_sql(
'SELECT `name`
FROM tserver
WHERE `name` IS NOT NULL
AND `master` > 0
ORDER BY `master` DESC'
);
$agentId = (int) db_get_value_sql(
sprintf(
'SELECT id_agente
FROM tagente
WHERE nombre = "%s"',
$serverName
)
);
if (isset($agentId) === false || is_numeric($agentId) === false) {
$agentId = 0;
}
return $agentId;
}
/**
* Graph.
*
* @param integer $id Id agent.
* @param string $name Name module.
* @param boolean $image Chart interactive or only image.
* @param boolean $base64 Image or base64.
*
* @return string
*/
public function getChart(
int $id,
string $name,
bool $image=false,
bool $base64=false
): string {
global $config;
include_once $config['homedir'].'/include/functions_graph.php';
$data = modules_get_agentmodule_id($name, $id);
$params = [
'agent_module_id' => $data['id_agente_modulo'],
'period' => SECONDS_1MONTH,
'date' => time(),
'height' => '200',
'only_image' => $image,
'return_img_base_64' => $base64,
];
return grafico_modulo_sparse($params);
}
/**
* Check pandoradb installed.
*
* @return string
*/
public function checkPandoraDB(): string
{
global $config;
$result = '';
if (isset($config['db_maintenance']) === false) {
$result .= '(*) ';
$result .= __(
'Please check your Pandora Server setup and make sure that the database maintenance daemon is running.'
);
$result .= ' ';
$result .= __(
'It\' is very important to keep the database up-to-date to get the best performance and results in Pandora'
);
}
return $result;
}
/**
* Draw table.
*
* @param string $method Method.
* @param string $title Title.
*
* @return string Return html.
*/
public function printData(string $method, string $title): string
{
global $config;
if (is_ajax()) {
// TODO: Call method.
$result = $method;
} else {
// Datatables list.
try {
$columns = [
[
'class' => 'datatables-td-title',
'text' => 'name',
],
[
'class' => 'datatables-td-max',
'text' => 'value',
],
'message',
];
$columnNames = [
[
'style' => 'display:none;',
'text' => '',
],
[
'style' => 'display:none',
'text' => '',
],
[
'style' => 'display:none',
'text' => '',
],
];
$tableId = $method.'_'.uniqid();
// Load datatables user interface.
if ($this->pdf === false) {
$result = ui_print_datatable(
[
'id' => $tableId,
'class' => 'info_table caption_table',
'style' => 'width: 100%',
'columns' => $columns,
'column_names' => $columnNames,
'ajax_data' => [
'method' => 'datatablesDraw',
'name' => $method,
],
'ajax_url' => $this->ajaxController,
'paging' => 0,
'no_sortable_columns' => [-1],
'caption' => $title,
'print' => true,
]
);
} else {
$data = json_decode(
$this->datatablesDraw($method, true),
true
);
$table = new stdClass();
$table->width = '100%';
$table->class = 'pdf-report';
$table->style = [];
$table->style[0] = 'font-weight: bolder;';
// FIX tables break content.
if ($data['idTable'] === 'showEngine') {
$table->styleTable = 'page-break-inside: auto;';
} else {
$table->autosize = 1;
}
$table->head = [];
$table->head_colspan[0] = 3;
$table->head[0] = $title;
$table->data = [];
if (isset($data) === true
&& is_array($data) === true
&& count($data) > 0
) {
$i = 0;
foreach ($data['data'] as $key => $value) {
$table->data[$i][0] = $value['name'];
$table->data[$i][1] = $value['value'];
$table->data[$i][2] = $value['message'];
$i++;
}
}
$result = html_print_table($table, true);
}
} catch (Exception $e) {
$result = $e->getMessage();
}
}
return true;
}
/**
* Prepare params for getCarts.
*
* @return void
*/
public function getChartAjax():void
{
global $config;
$params = json_decode(
io_safe_output(get_parameter('params', '')),
true
);
$return = '';
if (isset($params['idAgent']) === true
&& empty($params['idAgent']) === false
&& isset($params['nameModule'])
&& empty($params['nameModule']) === false
) {
$return = $this->getChart(
$params['idAgent'],
$params['nameModule']
);
}
exit($return);
}
/**
* Paint table with charts.
*
* @param array $params Info charts.
*
* @return string Html.
*/
public function printDataCharts(array $params): string
{
global $config;
if (!$params) {
$params = get_parameter('params');
}
if (is_ajax()) {
// TODO: Call method.
$return = $method;
} else {
// Datatables list.
try {
$id = str_replace(
' ',
'',
io_safe_output($params['nameModule'])
);
if ($this->pdf === false) {
$return = '<div id="'.$id.'" class="element-self-monitoring"></div>';
$settings = [
'type' => 'POST',
'dataType' => 'html',
'url' => ui_get_full_url(
'ajax.php',
false,
false,
false
),
'data' => [
'page' => $this->ajaxController,
'method' => 'getChartAjax',
'params' => json_encode($params),
],
];
?>
<script type="text/javascript">
ajaxRequest(
'<?php echo $id; ?>',
<?php echo json_encode($settings); ?>
);
</script>
<?php
} else {
$table = new stdClass();
$table->width = '100%';
$table->class = 'pdf-report';
$table->style = [];
$table->style[0] = 'font-weight: bolder;';
$table->autosize = 1;
$table->head = [];
$table->head[0] = $params['nameModule'];
$table->data = [];
$table->data[0] = $this->getChart(
$params['idAgent'],
$params['nameModule'],
true,
false
);
$return = html_print_table($table, true);
}
} catch (Exception $e) {
$return = $e->getMessage();
}
}
return $return;
}
/**
* Private function for Info size path.
*
* @param string $path Route file.
*
* @return array With values size file and message and status.
*/
private function getLogInfo(string $path): array
{
global $config;
// Vars.
$mega = 1048576;
$tenMega = 10485760;
$result = [
'value' => 0,
'message' => '',
'status' => 0,
];
if (file_exists($path) === true) {
$fileSize = filesize($path);
$sizeServerLog = number_format($fileSize);
$sizeServerLog = (0 + str_replace(',', '', $sizeServerLog));
$value = number_format(($fileSize / $mega), 3);
$message = __('You have more than 10 MB of logs');
$status = 0;
if ($sizeServerLog <= $tenMega) {
$message = __('You have less than 10 MB of logs');
$status = 1;
}
$result = [
'value' => $value,
'message' => $message,
'status' => $status,
];
}
return $result;
}
/**
* Undocumented function
*
* @param string|null $method Method data requested.
* @param boolean $return Type return.
*
* @return string|null
*/
public function datatablesDraw(
?string $method=null,
bool $return=false
):?string {
if (isset($method) === false) {
$method = get_parameter('name', '');
}
if (method_exists($this, $method) === true) {
$data = json_decode($this->{$method}(), true);
}
$result = [];
if (isset($data) === true
&& is_array($data) === true
&& count($data) > 0
) {
$items = $data['data'];
$dataReduce = array_reduce(
array_keys($data['data']),
function ($carry, $key) use ($items) {
// Transforms array of arrays $data into an array
// of objects, making a post-process of certain fields.
if (isset($items[$key]['status']) === true) {
$acumValue = $items[$key]['value'];
if ($items[$key]['status'] === 2) {
$items[$key]['value'] = html_print_image(
'images/icono-warning.png',
true,
[
'title' => __('Warning'),
'style' => 'width:15px;',
]
);
} else if ($items[$key]['status'] === 1) {
$items[$key]['value'] = html_print_image(
'images/exito.png',
true,
[
'title' => __('Succesfuly'),
'style' => 'width:15px;',
]
);
} else {
$items[$key]['value'] = html_print_image(
'images/error_1.png',
true,
[
'title' => __('Error'),
'style' => 'width:15px;',
]
);
}
$items[$key]['value'] .= ' '.$acumValue;
}
// FIX for customer key.
if ($key === 'customerKey') {
$customerKey = ui_print_truncate_text(
$items[$key]['value'],
30,
false,
true,
false
);
$spanValue = '<span>'.$customerKey.'</span>';
$items[$key]['value'] = $spanValue;
}
if (isset($items[$key]['message']) === false) {
$items[$key]['message'] = '';
}
$carry[] = (object) $items[$key];
return $carry;
}
);
$result = [
'data' => $dataReduce,
'recordsTotal' => count($dataReduce),
'recordsFiltered' => count($dataReduce),
'idTable' => (isset($data['id']) === true) ? $data['id'] : '',
];
}
// Datatables format: RecordsTotal && recordsfiltered.
if ($return === false) {
echo json_encode($result);
return null;
} else {
return json_encode($result);
}
}
/**
* Print Diagnostics Form feedback.
*
* @return void
*/
public function formFeedback(): void
{
$form = [
'action' => '#',
'id' => 'modal_form_feedback',
'onsubmit' => 'return false;',
'class' => 'modal',
'extra' => 'novalidate',
];
$inputs = [];
$inputs[] = [
'label' => __('What happened?'),
'id' => 'div-what-happened',
'class' => 'flex-row',
'arguments' => [
'name' => 'what-happened',
'type' => 'textarea',
'value' => '',
'return' => true,
'rows' => 1,
'columns' => 1,
'size' => 25,
'attributes' => 'required="required"',
],
];
$inputs[] = [
'label' => __('Your email'),
'class' => 'flex-row-baseline',
'arguments' => [
'name' => 'email',
'id' => 'email',
'type' => 'email',
'size' => 42,
'required' => 'required',
],
];
$inputs[] = [
'label' => __('Include installation data'),
'class' => 'flex-row-vcenter',
'arguments' => [
'name' => 'include_installation_data',
'id' => 'include_installation_data',
'type' => 'switch',
'value' => 1,
],
];
exit(
$this->printForm(
[
'form' => $form,
'inputs' => $inputs,
],
true
)
);
}
/**
* Create cron task form feedback.
*
* @return void Json result AJAX request.
*/
public function createdScheduleFeedbackTask():void
{
global $config;
$mail_feedback = 'feedback@artica.es';
$email = $mail_feedback;
$subject = $this->product_name.' Report '.$config['pandora_uid'];
$text = get_parameter('what-happened', '');
$attachment = get_parameter_switch('include_installation_data', 0);
$email_from = get_parameter_switch('email', '');
$title = __('Hello Feedback-Men');
$product_name = io_safe_output(get_product_name());
if (check_acl($config['id_user'], 0, 'PM') !== 1) {
$email = get_mail_admin();
$name_admin = get_name_admin();
$subject = __('Feedback').' '.$product_name.' '.$config['pandora_uid'];
$title = __('Hello').' '.$name_admin;
}
$p1 = __(
'User %s is reporting an issue in its %s experience',
$email_from,
$product_name
);
$p1 .= ':';
$p2 = $text;
if ($attachment === 1) {
$msg_attch = __('Find some files attached to this mail');
$msg_attch .= '. ';
$msg_attch .= __(
'PDF is the diagnostic information retrieved at report time'
);
$msg_attch .= '. ';
$msg_attch .= __('CSV contains the statuses of every product file');
$msg_attch .= '. ';
}
$p3 = __(
'If you think this report must be escalated, feel free to forward this mail to "%s"',
$mail_feedback
);
$legal = __('LEGAL WARNING');
$legal1 = __(
'The information contained in this transmission is privileged and confidential information intended only for the use of the individual or entity named above'
);
$legal1 .= '. ';
$legal2 = __(
'If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited'
);
$legal2 .= '. ';
$legal3 = __(
'If you have received this transmission in error, do not read it'
);
$legal3 .= '. ';
$legal4 = __(
'Please immediately reply to the sender that you have received this communication in error and then delete it'
);
$legal4 .= '.';
$patterns = [
'/__title__/',
'/__p1__/',
'/__p2__/',
'/__attachment__/',
'/__p3__/',
'/__legal__/',
'/__legal1__/',
'/__legal2__/',
'/__legal3__/',
'/__legal4__/',
];
$substitutions = [
$title,
$p1,
$p2,
$msg_attch,
$p3,
$legal,
$legal1,
$legal2,
$legal3,
$legal4,
];
$html_template = file_get_contents(
$config['homedir'].'/include/templates/feedback_send_mail.html'
);
$text = preg_replace($patterns, $substitutions, $html_template);
$idUserTask = db_get_value(
'id',
'tuser_task',
'function_name',
'cron_task_feedback_send_mail'
);
// Params for send mail with cron.
$parameters = [
0 => '0',
1 => $email,
2 => $subject,
3 => $text,
4 => $attachment,
'first_execution' => strtotime('now'),
];
// Values insert task cron.
$values = [
'id_usuario' => $config['id_user'],
'id_user_task' => $idUserTask,
'args' => serialize($parameters),
'scheduled' => 'no',
'id_grupo' => 0,
];
$result = db_process_sql_insert(
'tuser_task_scheduled',
$values
);
$error = 1;
if ($result === false) {
$error = 0;
}
$return = [
'error' => $error,
'title' => [
__('Failed'),
__('Success'),
],
'text' => [
ui_print_error_message(__('Invalid cron task'), '', true),
ui_print_success_message(__('Sending of information has been processed'), '', true),
],
];
exit(json_encode($return));
}
/**
* Print Diagnostics PDF report.
*
* @param string|null $filename Filename.
*
* @return mixed
*/
public function exportPDF(?string $filename=null)
{
global $config;
$this->pdf = true;
enterprise_include_once('/include/class/Pdf.class.php');
$mpdf = new Pdf([]);
// Ignore pending HTML outputs.
while (@ob_end_clean()) {
$ignore_me;
}
// ADD style.
$mpdf->addStyle($config['homedir'].'/include/styles/diagnostics.css');
// ADD Metadata.
$product_name = io_safe_output(get_product_name());
$mpdf->setMetadata(
__('Diagnostics Info'),
$product_name.' Enteprise',
$product_name,
__(
'Automated %s report for user defined report',
$product_name
)
);
// ADD Header.
$mpdf->setHeaderHTML(__('Diagnostics Info'));
// ADD content to report.
$mpdf->addHTML(
$this->printMethodsDiagnostigsInfo()
);
$mpdf->addHTML(
$this->printCharts()
);
// ADD Footer.
$mpdf->setFooterHTML();
// Write html filename.
$mpdf->writePDFfile($filename);
return;
}
/**
* Send Csv md5 files.
*
* @return string
*/
public function csvMd5Files():string
{
global $config;
// Extract files.
$files = $this->recursiveDirValidation($config['homedir']);
// Type divider.
$divider = html_entity_decode($config['csv_divider']);
// BOM.
$result = pack('C*', 0xEF, 0xBB, 0xBF);
$result .= __('Path').$divider.__('MD5')."\n";
foreach ($files as $key => $value) {
$result .= $key.$divider.$value."\n";
}
return $result;
}
/**
* Function to return array with name file -> MD%.
*
* @param string $dir Directory.
*
* @return array Result all files in directory recursively.
*/
private function recursiveDirValidation(string $dir):array
{
$result = [];
$dir_content = scandir($dir);
// Dont check attachment.
if (strpos($dir, $config['homedir'].'/attachment') === false) {
if (is_array($dir_content) === true) {
foreach (scandir($dir) as $file) {
if ('.' === $file || '..' === $file) {
continue;
}
if (is_dir($dir.'/'.$file) === true) {
$result += $this->recursiveDirValidation(
$dir.'/'.$file
);
} else {
$result[$dir.'/'.$file] = md5_file($dir.'/'.$file);
}
}
}
}
return $result;
}
/**
* Send PHP info in report.
*
* @param string $filename Download dir report.
*
* @return void
*/
public function phpInfoReports(string $filename)
{
global $config;
$this->pdf = true;
// Extract info PHP.
ob_start();
phpinfo();
$php_info = ob_get_clean();
enterprise_include_once('/include/class/Pdf.class.php');
$mpdf = new Pdf([]);
// ADD Metadata.
$product_name = io_safe_output(get_product_name());
$mpdf->setMetadata(
__('PHP Info'),
$product_name.' Enteprise',
$product_name,
__(
'Automated %s report for user defined report',
$product_name
)
);
// ADD Header.
$mpdf->setHeaderHTML(__('PHP Info'));
// ADD content to report.
$mpdf->addHTML($php_info);
// ADD Footer.
$mpdf->setFooterHTML();
// Write html filename.
$mpdf->writePDFfile($filename);
}
}