Merge remote-tracking branch 'origin/develop' into ent-9554-nuevas-graficas-de-tarta-que-reemplazar-a-las-actuales-3

This commit is contained in:
daniel 2022-12-21 12:51:18 +01:00
commit 47c503bdab
65 changed files with 7105 additions and 1461 deletions

View File

@ -1,5 +1,5 @@
package: pandorafms-agent-unix
Version: 7.0NG.767-221219
Version: 7.0NG.767-221221
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.767-221219"
pandora_version="7.0NG.767-221221"
echo "Test if you has the tools for to make the packages."
whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null

View File

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

View File

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

View File

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

View File

@ -10,7 +10,7 @@
# **********************************************************************
PI_VERSION="7.0NG.767"
PI_BUILD="221219"
PI_BUILD="221221"
OS_NAME=`uname -s`
FORCE=0

View File

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

View File

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

View File

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

View File

@ -1666,6 +1666,14 @@ godmode/um_client/vendor/sebastian/object-enumerator
godmode/um_client/vendor/sebastian
godmode/um_client/vendor
update_manager_client/resources/styles/pandora.css
enterprise/views/cluster/edit.php
enterprise/views/cluster/list.php
enterprise/views/cluster/view.php
enterprise/include/lib/Cluster.php
enterprise/include/lib/ClusterModule.php
enterprise/include/lib/ClusterViewer/ClusterManager.php
enterprise/include/lib/ClusterViewer/ClusterWizard.php
enterprise/operation/cluster/cluster.php
enterprise/meta/general/upload_head_image.php
general/first_task/transactional_list.php
enterprise/include/ajax/transactional.ajax.php

File diff suppressed because one or more lines are too long

View File

@ -68,7 +68,7 @@ ui_print_info_message(['no_close' => true, 'message' => __('There are no cluster
if (check_acl($config['id_user'], 0, 'AW')) {
?>
<form action='index.php?sec=estado&sec2=enterprise/operation/cluster/cluster&op=new' method="post">
<form action='index.php?sec=estado&sec2=operation/cluster/cluster&op=new' method="post">
<input type="submit" class="button_task ui_toggle" value="<?php echo __('Create Cluster'); ?>" />
</form>
@ -76,4 +76,4 @@ ui_print_info_message(['no_close' => true, 'message' => __('There are no cluster
}
?>
</div>
</div>
</div>

View File

@ -59,6 +59,7 @@ ui_print_warning_message(
]
);
$table = new StdClass();
$table->width = '100%';
$table->class = 'databox filters';
$table->data = [];

View File

@ -2118,6 +2118,9 @@ if ($delete_module) {
exit;
}
// Before delete the main module, check and delete the childrens from the original module.
module_check_childrens_and_delete($id_borrar_modulo);
// Also call base function to delete modules.
modules_delete_agent_module($id_borrar_modulo);

View File

@ -732,17 +732,15 @@ if ($agents !== false) {
}
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.ui_print_truncate_text($agent['alias'], 'agent_medium').'</a>';
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.ui_print_truncate_text($agent['alias'], 'agent_medium').'</a>';
} else {
echo '<a alt ='.$agent['nombre']." href='index.php?sec=gagente&
sec2=godmode/agentes/configurar_agente&tab=$main_tab&
@ -792,18 +790,16 @@ if ($agents !== false) {
echo '</span><div class="left actions clear_left" style=" visibility: hidden">';
if ($check_aw) {
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.__('Edit').'</a>';
echo ' | ';
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.__('Edit').'</a>';
echo ' | ';
} else {
echo '<a href="index.php?sec=gagente&
sec2=godmode/agentes/configurar_agente&tab=main&
@ -825,17 +821,15 @@ if ($agents !== false) {
echo ' | ';
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=view&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.__('View').'</a>';
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=view&id='.$cluster->id()
);
echo '<a href="'.$url.'">'.__('View').'</a>';
} else {
echo '<a href="index.php?sec=estado
&sec2=operation/agentes/ver_agente

View File

@ -247,6 +247,8 @@ if ($module_action === 'delete') {
$print_result_msg = true;
$count_correct_delete_modules = 0;
foreach ($id_agent_modules_delete as $id_agent_module_del) {
// Before delete the main module, check and delete the childrens from the original module.
module_check_childrens_and_delete($id_agent_module_del);
$id_grupo = (int) agents_get_agent_group($id_agente);
$all_groups = agents_get_all_groups_agent($id_agente, $id_grupo);

View File

@ -231,7 +231,7 @@ if (strlen(trim($agentName)) > 0) {
}
if ($actionID != -1 && $actionID != '') {
$where .= ' AND talert_template_modules.id IN (SELECT id_alert_template_module FROM talert_template_module_actions WHERE id_alert_action = '.$actionID.') OR talert_template_modules.id IN (SELECT id FROM talert_template_modules ttm WHERE ttm.id_alert_template IN (SELECT tat.id FROM talert_templates tat WHERE tat.id_alert_action = '.$actionID.'))';
$where .= ' AND (talert_template_modules.id IN (SELECT id_alert_template_module FROM talert_template_module_actions WHERE id_alert_action = '.$actionID.') OR talert_template_modules.id IN (SELECT id FROM talert_template_modules ttm WHERE ttm.id_alert_template IN (SELECT tat.id FROM talert_templates tat WHERE tat.id_alert_action = '.$actionID.')))';
}
if ($status_alert === 'disabled') {

View File

@ -200,14 +200,14 @@ if ($access_console_node === true) {
$sub['gmassive']['type'] = 'direct';
$sub['gmassive']['subtype'] = 'nolink';
$sub2 = [];
$sub2['godmode/massive/massive_operations&amp;tab=massive_agents']['text'] = __('Agents operations');
$sub2['godmode/massive/massive_operations&amp;tab=massive_modules']['text'] = __('Modules operations');
$sub2['godmode/massive/massive_operations&amp;tab=massive_plugins']['text'] = __('Plugins operations');
$sub2['godmode/massive/massive_operations&tab=massive_agents']['text'] = __('Agents operations');
$sub2['godmode/massive/massive_operations&tab=massive_modules']['text'] = __('Modules operations');
$sub2['godmode/massive/massive_operations&tab=massive_plugins']['text'] = __('Plugins operations');
if ((bool) check_acl($config['id_user'], 0, 'UM') === true) {
$sub2['godmode/massive/massive_operations&amp;tab=massive_users']['text'] = __('Users operations');
$sub2['godmode/massive/massive_operations&tab=massive_users']['text'] = __('Users operations');
}
$sub2['godmode/massive/massive_operations&amp;tab=massive_alerts']['text'] = __('Alerts operations');
$sub2['godmode/massive/massive_operations&tab=massive_alerts']['text'] = __('Alerts operations');
enterprise_hook('massivepolicies_submenu');
enterprise_hook('massivesnmp_submenu');
enterprise_hook('massivesatellite_submenu');

View File

@ -2182,6 +2182,8 @@ switch ($action) {
'historical_db_check'
);
$values['top_n_value'] = get_parameter('max_items');
$values['server_name'] = get_parameter('combo_server');
} else if ($values['type'] == 'url') {
$values['external_source'] = get_parameter('url');
} else if ($values['type'] == 'event_report_group') {

View File

@ -77,6 +77,7 @@ if (is_ajax()) {
true
).'&nbsp;&nbsp;';
$table->data['autocreate_remote_users'] = $row;
$table->data['csrf_token'] = html_print_csrf_hidden();
add_enterprise_auth_autocreate_profiles($table, $type_auth);
}
@ -475,6 +476,8 @@ if (!is_metaconsole()) {
html_print_input_hidden('hash_save_config', md5('save'.$config['dbpass']));
}
html_print_csrf_hidden();
html_print_table($table);
echo '<div id="table_auth_result"></div>';
echo '<div class="action-buttons" style="width: '.$table->width.'">';

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -654,7 +654,7 @@ if ($get_agent_alerts_datatable === true) {
}
$idGroup = $filter_alert['ag_group'];
$tag_filter = $filter_alert['tag_filter'];
$tag_filter = $filter_alert['tag'];
$action_filter = $filter_alert['action'];
try {

View File

@ -26,6 +26,8 @@
* ============================================================================
*/
use PandoraFMS\Enterprise\Metaconsole\Node;
// Begin.
if (check_login()) {
global $config;
@ -59,6 +61,11 @@ if (check_login()) {
0
);
$get_data_dataMatrix = (bool) get_parameter(
'get_data_dataMatrix',
0
);
if ($get_agent_modules_json_by_name === true) {
$agent_name = get_parameter('agent_name');
@ -1436,4 +1443,190 @@ if (check_login()) {
return;
}
if ($get_data_dataMatrix === true) {
global $config;
$table_id = get_parameter('table_id', '');
$modules = json_decode(
io_safe_output(
get_parameter('modules', '')
),
true
);
$period = get_parameter('period', 0);
$slice = get_parameter('slice', 0);
// Datatables offset, limit.
$start = get_parameter('start', 0);
$formatData = (bool) get_parameter('formatData', 0);
$length = get_parameter(
'length',
$config['block_size']
);
$order = get_datatable_order(true);
// Total time per page.
$time_all_box = ($length * $slice);
// Total number of boxes.
$total_box = ceil($period / $slice);
if ($start > 0) {
$start = ($start / $length);
}
// Uncompress.
try {
ob_start();
$dateNow = get_system_time();
$final = ($dateNow - $period);
$date = ($dateNow - ($time_all_box * $start));
if (($date - $time_all_box) > $final) {
$datelimit = ($date - $time_all_box);
} else {
$datelimit = $final;
}
foreach ($modules as $key => $value) {
if (is_metaconsole() === true) {
try {
$node = new Node((int) $value['id_node']);
$node->connect();
} catch (\Exception $e) {
// Unexistent agent.
$node->disconnect();
}
}
$value['thresholds'] = [
'min_critical' => (empty($value['c_min']) === true) ? null : $value['c_min'],
'max_critical' => (empty($value['c_max']) === true) ? null : $value['c_max'],
'min_warning' => (empty($value['w_min']) === true) ? null : $value['w_min'],
'max_warning' => (empty($value['w_max']) === true) ? null : $value['w_max'],
];
$module_data = db_uncompress_module_data(
$value['id'],
$datelimit,
$date,
$slice,
true
);
$uncompressData[] = array_reduce(
$module_data,
function ($carry, $item) use ($value, $config, $formatData) {
// Last value.
$vdata = null;
if (is_array($item['data']) === true) {
foreach ($item['data'] as $v) {
$vdata = $v['datos'];
}
}
$status = get_status_data_modules(
$value['id'],
$vdata,
$value['thresholds']
);
$resultData = '<span style="color:'.$status['color'].'">';
if ($vdata !== null && $vdata !== '' && $vdata !== false) {
if (isset($formatData) === true
&& (bool) $formatData === true
) {
$resultData .= format_for_graph(
$vdata,
$config['graph_precision']
);
} else {
$resultData .= sla_truncate(
$vdata,
$config['graph_precision']
);
}
$resultData .= ' '.$value['unit'];
} else {
$resultData .= '--';
}
$resultData .= '</span>';
$carry[] = [
'utimestamp' => $item['utimestamp'],
'Column-'.$value['id'] => $resultData,
];
return $carry;
},
[]
);
if (is_metaconsole() === true) {
$node->disconnect();
}
}
if (empty($uncompressData) === false) {
$data = array_reduce(
$uncompressData,
function ($carry, $item) {
foreach ($item as $data_module) {
foreach ($data_module as $key => $value) {
if ($key === 'utimestamp') {
$carry[$data_module['utimestamp']]['date'] = date('Y-m-d H:i', (int) $value);
} else {
$carry[$data_module['utimestamp']][$key] = $value;
}
}
}
return $carry;
}
);
}
if (empty($data) === false) {
$data = array_reverse(array_values($data));
} else {
$data = [];
}
// RecordsTotal && recordsfiltered resultados totales.
echo json_encode(
[
'data' => $data,
'recordsTotal' => $total_box,
'recordsFiltered' => $total_box,
]
);
$response = ob_get_clean();
// Clean output buffer.
while (ob_get_level() !== 0) {
ob_end_clean();
}
} catch (Exception $e) {
echo json_encode(
['error' => $e->getMessage()]
);
}
// If not valid it will throw an exception.
json_decode($response);
if (json_last_error() == JSON_ERROR_NONE) {
// If valid dump.
echo $response;
} else {
echo json_encode(
['error' => $response]
);
}
return;
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -62,7 +62,7 @@ enterprise_include_once('include/functions_cron.php');
// Clases.
use PandoraFMS\Agent;
use PandoraFMS\Module;
use PandoraFMS\Enterprise\Cluster;
use PandoraFMS\Cluster;
use PandoraFMS\Enterprise\Metaconsole\Node;
use PandoraFMS\Event;
use PandoraFMS\SpecialDay;
@ -10157,6 +10157,8 @@ function api_set_delete_module($id, $id2, $other, $trash1)
}
if (!$simulate) {
// Before delete the main module, check and delete the childrens from the original module.
module_check_childrens_and_delete($idAgentModule);
$return = modules_delete_agent_module($idAgentModule);
} else {
$return = true;
@ -10182,6 +10184,8 @@ function api_set_delete_module($id, $id2, $other, $trash1)
}
if (!$simulate) {
// Before delete the main module, check and delete the childrens from the original module.
module_check_childrens_and_delete($idAgentModule);
$return = modules_delete_agent_module($idAgentModule);
} else {
$return = true;

View File

@ -523,6 +523,15 @@ function config_update_config()
break;
case 'auth':
$validatedCSRF = validate_csrf_code();
// CSRF Validation.
if ($validatedCSRF === false) {
include_once 'general/login_page.php';
// Finish the execution.
exit('</html>');
}
// AUTHENTICATION SETUP.
if (config_update_value('auth', get_parameter('auth'), true) === false) {
$error_update[] = __('Authentication method');

View File

@ -757,7 +757,8 @@ function db_uncompress_module_data(
$id_agente_modulo,
$tstart=false,
$tend=false,
$slice_size=false
$slice_size=false,
$force_slice_not_data=false
) {
global $config;
@ -860,7 +861,10 @@ function db_uncompress_module_data(
$module_interval = modules_get_interval($id_agente_modulo);
if (($raw_data === false) && ( $first_utimestamp === false )) {
if (($force_slice_not_data === false)
&& ($raw_data === false)
&& ( $first_utimestamp === false )
) {
// No data.
return false;
}
@ -2313,7 +2317,13 @@ function db_get_lock(string $lockname, int $expiration_time=86400) :?int
}
if ($lock_status === false) {
return null;
db_pandora_audit(
AUDIT_LOG_SYSTEM,
'Issue in Database Lock',
'system'
);
return (int) null;
}
return (int) $lock_status;

View File

@ -3982,6 +3982,81 @@ function recursive_get_dt_from_modules_tree(&$f_modules, $modules, $deep)
}
/**
* Get the module data from a children
*
* @param integer $id_module Id module
* @return array Children module data
*/
function get_children_module($id_module)
{
$children_module_data = db_get_all_rows_sql(
'SELECT *
FROM tagente_modulo
WHERE parent_module_id = '.$id_module
);
return $children_module_data;
}
/**
* Find and delete the childers modules from the $id_module
*
* @param mixed $id_module
* @return void
*/
function module_check_childrens_and_delete($id_module)
{
$children_data = get_children_module($id_module);
// Check if exist have a childer
if ($children_data) {
// If have more than 1 children
if (is_array($children_data)) {
foreach ($children_data as $children_module_data) {
if ($children_module_data['parent_module_id']) {
// Search children and delete this module
// Before delete, lets check if exist (Just for cases it's already deleted)
if (modules_check_agentmodule_exists($children_module_data['parent_module_id'])) {
modules_delete_agent_module($children_module_data['parent_module_id']);
}
module_check_childrens_and_delete($children_module_data['id_agente_modulo']);
} else {
// If haven't children just delete
// Before delete, lets check if exist (Just for cases it's already deleted)
if (modules_check_agentmodule_exists($children_module_data['id_agente_modulo'])) {
modules_delete_agent_module($children_module_data['id_agente_modulo']);
}
}
}
} else {
// If just have 1 children
if ($children_data['parent_module_id']) {
// Before delete, lets check if exist (Just for cases it's already deleted)
if (modules_check_agentmodule_exists($children_data['parent_module_id'])) {
modules_delete_agent_module($children_data['parent_module_id']);
}
module_check_childrens_and_delete($children_data['id_agente_modulo']);
} else {
// If haven't children just delete
// Before delete, lets check if exist (Just for cases it's already deleted)
if (modules_check_agentmodule_exists($children_data['id_agente_modulo'])) {
modules_delete_agent_module($children_data['id_agente_modulo']);
}
}
}
} else {
// Haven't childrens, so delete
// Before delete, lets check if exist (Just for cases it's already deleted)
if (modules_check_agentmodule_exists($id_module)) {
modules_delete_agent_module($id_module);
}
}
}
/**
* @brief Get the button with the link to open realtime stats into a new window
* Only to native (not satellite discovered) snmp modules.
@ -4336,3 +4411,129 @@ function modules_get_regex(
return $result;
}
/**
* Status for data thresholds modules.
*
* @param integer $id_module Module ID.
* @param mixed $data Data int, bool, null, etc.
* @param array $thresholds Array thresholds.
*
* @return array
*/
function get_status_data_modules(int $id_module, $data, $thresholds)
{
// Check not init.
if ($data === false) {
return ['color' => COL_NOTINIT];
}
// Check boolean.
$is_bolean = modules_is_boolean($id_module);
if ($is_bolean === true) {
if ($data > 0) {
return ['color' => COL_CRITICAL];
} else {
return ['color' => COL_NORMAL];
}
}
$thresholds = calculateThreshold($thresholds);
foreach (getStatuses() as $status) {
if ($thresholds[$status]['min'] === null
&& $thresholds[$status]['max'] === null
) {
continue;
}
if (($thresholds[$status]['min'] === null
&& $thresholds[$status]['max'] >= $data)
|| ($thresholds[$status]['max'] === null
&& $thresholds[$status]['min'] <= $data)
|| ($thresholds[$status]['min'] <= $data
&& $thresholds[$status]['max'] >= $data)
) {
if ($status === 'critical') {
return ['color' => COL_CRITICAL];
} else if ($status === 'warning') {
return ['color' => COL_WARNING];
} else {
return ['color' => COL_NORMAL];
}
}
}
return ['color' => COL_NORMAL];
}
/**
* Calculate thresholds.
*
* @param array $thresholds_array
*
* @return array
*/
function calculateThreshold(array $thresholds_array)
{
$nMax = null;
if ($thresholds_array['min_warning'] !== null) {
$nMax = $thresholds_array['min_warning'];
} else if ($thresholds_array['min_critical'] !== null) {
$nMax = $thresholds_array['min_critical'];
}
$wMin = null;
if ($thresholds_array['min_warning'] !== null) {
$wMin = $thresholds_array['min_warning'];
}
$wMax = null;
if ($thresholds_array['max_warning'] !== null) {
$wMax = $thresholds_array['max_warning'];
}
$cMin = null;
if ($thresholds_array['min_critical'] !== null) {
$cMin = $thresholds_array['min_critical'];
}
$cMax = null;
if ($thresholds_array['max_critical'] !== null) {
$cMax = $thresholds_array['max_critical'];
}
$thresholds = [
'normal' => [
'min' => null,
'max' => $nMax,
],
'warning' => [
'min' => $wMin,
'max' => $wMax,
],
'critical' => [
'min' => $cMin,
'max' => $cMax,
],
];
return $thresholds;
}
/**
* Get status.
*
* @return array
*/
function getStatuses()
{
return [
'critical',
'warning',
'normal',
];
}

View File

@ -3399,7 +3399,10 @@ function get_status_color_networkmap_fictional_point($id_networkmap, $parent='')
if ($agent['source_data'] == -2) {
if (empty($parent) === true) {
$option = json_decode($agent, true);
if (is_array($agent) === false) {
$option = json_decode($agent, true);
}
if ($option['networkmap'] == 0) {
$status = 0;
} else {

View File

@ -690,18 +690,16 @@ function treeview_printTable($id_agente, $server_data=[], $no_head=false)
$go_to_agent = '<div style="text-align: right">';
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
$go_to_agent .= '<a target="_blank" href="'.$url.'">';
$go_to_agent .= html_print_submit_button(__('Edit cluster'), 'upd_button', false, 'class="sub config"', true);
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
$go_to_agent .= '<a target="_blank" href="'.$url.'">';
$go_to_agent .= html_print_submit_button(__('Edit cluster'), 'upd_button', false, 'class="sub config"', true);
} else {
$go_to_agent .= '<a target=_blank href="'.$console_url.'index.php?sec=gagente&sec2=godmode/agentes/configurar_agente&id_agente='.$id_agente.$ent.'">';
$go_to_agent .= html_print_submit_button(__('Go to agent edition'), 'upd_button', false, 'class="sub config"', true);

View File

@ -1699,7 +1699,6 @@ function selected_node(d, selected_param, hold_other_selections) {
);
d3.event.stopPropagation();
d3.event.preventDefault();
}
function clear_selection() {
@ -4020,8 +4019,10 @@ function draw_elements_graph() {
font_size +
"px !important; text-align:center; text-anchor:middle; fill:#000000"
)
.text(function(d) {
return ellipsize(get_node_name_ov(d), 30);
.html(function(d) {
d.text = ellipsize(d.text, 30);
return get_node_name_ov(d, true, font_size);
})
.classed("dragable_node fill_fff", true) //own dragable
.on("click", selected_node)
@ -4030,7 +4031,7 @@ function draw_elements_graph() {
});
node_temp.append("title").text(function(d) {
return get_node_name_ov(d);
return get_node_name_ov(d, false);
});
node.exit().remove();
@ -4040,9 +4041,19 @@ function is_central_node(data) {
return data.type == 0 && data.id_agent == 0;
}
function get_node_name_ov(data) {
function get_node_name_ov(data, generate_link, font_size) {
font_size = font_size || 20;
generate_link = generate_link || false;
var data_text = data.text;
if (generate_link === true && data.networkmap_id > 0) {
data_text = `<a href="index.php?sec=network&amp;sec2=operation/agentes/pandora_networkmap&amp;tab=view&amp;id_networkmap=
${data.networkmap_id}" style="font-size: ${font_size}px;">${data.text}</a>`;
}
// Node central name should be the product name
return is_central_node(data) ? $("#hidden-product_name").val() : data.text;
return is_central_node(data) ? $("#hidden-product_name").val() : data_text;
}
function choose_group_for_show_agents() {

View File

@ -0,0 +1,906 @@
<?php
/**
* Cluster entity class.
*
* @category Class
* @package Pandora FMS
* @subpackage Community
* @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.
* ============================================================================
*/
// Begin.
namespace PandoraFMS;
use PandoraFMS\Entity;
use PandoraFMS\Agent;
use PandoraFMS\Module;
use PandoraFMS\Group;
/**
* PandoraFMS Cluster entity.
*/
class Cluster extends Entity
{
/**
* References cluster status Module.
*
* @var PandoraFMS\Module
*/
private $clusterStatus;
/**
* Array of PandoraFMS\Agents members of this cluster.
*
* @var array
*/
private $members = [];
/**
* AA modules.
*
* @var array
*/
private $aaModules = [];
/**
* AP modules.
*
* @var array
*/
private $apModules = [];
/**
* Removed items.
*
* @var array
*/
private $removedItems = [];
/**
* Loads a cluster definition from target agent (rel 1-1).
*
* @param integer $id_agent Agent id.
* @param boolean $load_members Load members or not.
*
* @return PandoraFMS\Cluster Object.
*/
public static function loadFromAgentId(
int $id_agent,
?bool $load_members=true
) {
if (is_numeric($id_agent) === true
&& $id_agent > 0
) {
$cluster_id = db_get_value(
'id',
'tcluster',
'id_agent',
$id_agent
);
return new self($cluster_id, $load_members);
}
return null;
}
/**
* Builds a PandoraFMS\ClusterViewer\Cluster object from a cluster id.
*
* @param integer $id_cluster Cluster Id.
* @param boolean $load_members Load members or not.
*
* @throws \Exception On error.
*/
public function __construct(?int $id_cluster=null, ?bool $load_members=true)
{
if (is_numeric($id_cluster) === true
&& $id_cluster > 0
) {
try {
parent::__construct('tcluster', ['id' => $id_cluster]);
} catch (\Exception $e) {
throw new \Exception('Cluster id not found.');
}
if ($load_members === true) {
// Retrieve members.
$data = \db_get_all_rows_filter(
'tcluster_agent',
['id_cluster' => $id_cluster]
);
if (is_array($data) === true) {
foreach ($data as $row) {
$this->addMember($row['id_agent']);
}
}
}
// Retrieve items.
$data = \db_get_all_rows_filter(
'tcluster_item',
['id_cluster' => $id_cluster]
);
if (is_array($data) === true) {
foreach ($data as $row) {
if ($row['item_type'] === 'AA') {
$this->aaModules[$row['name']] = new ClusterModule(
$row['id']
);
} else if ($row['item_type'] === 'AP') {
$this->apModules[$row['name']] = new ClusterModule(
$row['id']
);
}
}
}
} else {
parent::__construct('tcluster');
}
// Customize certain fields.
try {
$this->fields['group'] = new Group($this->group());
} catch (\Exception $e) {
$this->fields['group'] = new Group();
}
if ($this->id_agent() !== null) {
try {
$this->fields['agent'] = new Agent($this->id_agent(), true);
} catch (\Exception $e) {
$this->fields['agent'] = new Agent();
}
} else {
$this->fields['agent'] = new Agent();
}
if ($this->id_agent() !== null) {
$this->clusterStatus = Module::search(
[
'nombre' => io_safe_input('Cluster status'),
'id_agente' => $this->id_agent(),
],
1
);
}
}
/**
* Return an array of PandoraFMS\Agents as members of current cluster.
*
* @return array Of agents.
*/
public function getMembers()
{
if (is_array($this->members) === true) {
return $this->members;
}
return [];
}
/**
* Cleans members from cluster object.
*
* @return void
*/
public function cleanMembers()
{
unset($this->members);
}
/**
* Register a new agent in the cluster.
*
* @param integer $id_agent New id_agent to be added.
*
* @return mixed
* @throws \Exception On error.
*/
public function addMember(int $id_agent)
{
if (isset($this->members[$id_agent]) === true) {
// Already joining.
return;
}
try {
$agent = new Agent($id_agent);
} catch (\Exception $e) {
return;
}
if ($agent->id_agente() === null) {
throw new \Exception('Invalid agent id.');
}
$this->members[$agent->id_agente()] = $agent;
return $agent;
}
/**
* Remove an agent from the cluster.
*
* @param integer $id_agent New id_agent to be removed.
*
* @return void
* @throws \Exception On error.
*/
public function removeMember(int $id_agent)
{
if (isset($this->members[$id_agent]) === false) {
return;
}
unset($this->members[$id_agent]);
$rs = \db_process_sql_delete(
'tcluster_agent',
[
'id_cluster' => $this->fields['id'],
'id_agent' => $id_agent,
]
);
return true;
}
/**
* Return AA modules associated to current cluster.
*
* @param integer $type AA or AP (use constants)
* MODULE_PREDICTION_CLUSTER_AA
* MODULE_PREDICTION_CLUSTER_AP.
*
* @return array Of items.
*/
public function getItems(?int $type=null)
{
$items = [];
if ($type === MODULE_PREDICTION_CLUSTER_AA) {
if (is_array($this->aaModules) === true) {
return $this->aaModules;
}
}
if ($type === MODULE_PREDICTION_CLUSTER_AP) {
if (is_array($this->apModules) === true) {
return $this->apModules;
}
}
if (is_array($this->apModules) === true
) {
$items = array_merge($items, $this->apModules);
}
if (is_array($this->aaModules) === true
) {
$items = array_merge($items, $this->aaModules);
}
return $items;
}
/**
* Retrieve AA modules.
*
* @return array Of ClusterItem definition.
*/
public function getAAModules()
{
return $this->getItems(MODULE_PREDICTION_CLUSTER_AA);
}
/**
* Retrieve AP modules.
*
* @return array Of ClusterItem definition.
*/
public function getAPModules()
{
return $this->getItems(MODULE_PREDICTION_CLUSTER_AP);
}
/**
* Retrieves module definition from current members matching name.
*
* @param string $name Target name to retrieve.
*
* @return array Module fields.
* @throws \Exception On error.
*/
public function getModuleSkel(string $name)
{
foreach ($this->members as $member) {
$module = $member->searchModules(
['nombre' => $name]
);
if ($module !== null && empty($module) === false) {
if (count($module) > 1) {
$msg = __METHOD__.' error: Multiple occurrences of "';
$msg .= $name.'", please remove duplicates from agent "';
$msg .= $member->alias().'".';
throw new \Exception(
$msg
);
}
// Method searchModules returns multiple occurrences.
$module = $module[0];
$module = $module->toArray();
break;
}
}
// Remove specific fields.
unset($module['id_agente_modulo']);
unset($module['id_agente']);
return $module;
}
/**
* Add an item to the cluster.
*
* @param string $name Target name.
* @param integer $type Item type.
* @param array $definition Module definition.
*
* @return ClusterModule Created module.
* @throws \Exception On error.
*/
public function addItem(string $name, int $type, array $definition)
{
$item = new ClusterModule();
$item->name($name);
$item->id_cluster($this->id());
// Skel values.
$module_skel = $this->getModuleSkel($name);
// Customize definition.
$definition = array_merge($module_skel, $definition);
// Store in cluster agent.
$definition['id_agente'] = $this->id_agent();
if ($type === MODULE_PREDICTION_CLUSTER_AA) {
$item->item_type('AA');
} else if ($type === MODULE_PREDICTION_CLUSTER_AP) {
$item->item_type('AP');
} else {
throw new \Exception(__METHOD__.' error: Invalid item type');
}
// Set module definition.
$item->setModule($definition);
// Default values.
$item->critical_limit(0);
$item->warning_limit(0);
$item->is_critical(0);
return $item;
}
/**
* Add AA module to the cluster.
*
* @param string $name Target name.
*
* @return void
*/
public function addAAModule(string $name)
{
if (empty($this->aaModules[$name]) === true) {
$main_id = $this->clusterStatus->id_agente_modulo();
// Register module in agent.
// id_modulo = 0,
// tcp_port = 1,
// prediction_moddule = 6.
// Set thresholds while updating.
$this->aaModules[$name] = $this->addItem(
$name,
MODULE_PREDICTION_CLUSTER_AA,
[
'nombre' => $name,
'id_modulo' => 0,
'prediction_module' => 6,
'tcp_port' => 1,
'id_tipo_modulo' => 1,
'custom_integer_1' => $this->id(),
'parent_module_id' => $main_id,
]
);
\db_pandora_audit(
AUDIT_LOG_AGENT_MANAGEMENT,
'Module '.io_safe_output(
$name
).' added to cluster'.io_safe_output(
$this->fields['name']
).' as Active-Active module'
);
}
}
/**
* Add AP module to the cluster.
*
* @param string $name Target name.
*
* @return void
*/
public function addAPModule(string $name)
{
if (empty($this->apModules[$name]) === true) {
$main_id = $this->clusterStatus->id_agente_modulo();
$type = db_get_value(
'id_tipo_modulo',
'tagente_modulo',
'nombre',
$name
);
if (empty($type) === true) {
$type = 1;
}
// Register module in agent.
// id_modulo = 5,
// tcp_port = 1,
// prediction_moddule = 7.
// Set thresholds while updating.
$this->apModules[$name] = $this->addItem(
$name,
MODULE_PREDICTION_CLUSTER_AP,
[
'nombre' => $name,
'id_modulo' => 5,
'prediction_module' => 7,
'tcp_port' => 1,
'id_tipo_modulo' => $type,
'custom_integer_1' => $this->id(),
'parent_module_id' => $main_id,
]
);
\db_pandora_audit(
AUDIT_LOG_AGENT_MANAGEMENT,
'Module '.io_safe_output(
$name
).' added to cluster'.io_safe_output(
$this->fields['name']
).' as Active-Passive module'
);
}
}
/**
* Removes AA module from the cluster.
*
* @param string $name Target name.
*
* @return void
*/
public function removeAAModule(string $name)
{
if (empty($this->aaModules[$name]) === false) {
// Mark item for db elimination.
$this->removedItems[] = [
'id' => $this->aaModules[$name]->id(),
'item_type' => $this->aaModules[$name]->item_type(),
];
$this->aaModules[$name]->delete();
unset($this->aaModules[$name]);
}
}
/**
* Removes AP module from the cluster.
*
* @param string $name Target name.
*
* @return void
*/
public function removeAPModule(string $name)
{
if (empty($this->apModules[$name]) === false) {
// Mark item for db elimination.
$this->removedItems[] = [
'id' => $this->apModules[$name]->id(),
'item_type' => $this->apModules[$name]->item_type(),
];
$this->apModules[$name]->delete();
unset($this->apModules[$name]);
}
}
/**
* Return found cluster definitions.
*
* @param array $filter Conditions.
*
* @return mixed Array or false.
*/
public static function search(array $filter)
{
return \db_get_all_rows_filter(
'tcluster',
$filter
);
}
/**
* Operates with group.
*
* @param integer|null $id_group Target group to update. Retrieve group obj
* if null.
*
* @return mixed Void if set, PandoraFMS\Group if argument is null.
*/
public function group(?int $id_group=null)
{
if (is_numeric($id_group) === true && $id_group > 0) {
$this->fields['group'] = new Group($id_group);
} else {
return $this->fields['group'];
}
}
/**
* Returns AA modules as nodes for a map if any, if not, retrieves members.
*
* @return array Of PandoraFMS\Networkmap nodes.
*/
public function getNodes()
{
// Parse agents.
$nodes = [];
$node_count = 0;
$parent = $node_count;
$id_node = $node_count++;
$status = \agents_get_status_from_counts($this->agent()->toArray());
$image = 'images/networkmap/'.os_get_icon($this->agent()->id_os());
if (empty($this->aaModules) === true) {
// No AA modules, use members.
$parent = $this->agent()->id_agente();
// Add node.
foreach ($this->members as $agent) {
$node = [];
foreach ($agent->toArray() as $k => $v) {
$node[$k] = $v;
}
$node['id_agente'] = $agent->id_agente();
$node['id_parent'] = $parent;
$node['id_node'] = $node_count;
$node['image'] = 'images/networkmap/'.os_get_icon(
$agent->id_os()
);
$node['status'] = \agents_get_status_from_counts(
$agent->toArray()
);
$nodes[$node_count++] = $node;
}
} else {
foreach ($this->aaModules as $cl_item) {
$cl_module = $cl_item->getModule();
if ($cl_module === null) {
continue;
}
foreach ($this->members as $agent) {
$module = $agent->searchModules(
['nombre' => $cl_module->nombre()]
);
if (empty($module) === true) {
// AA Module not found in member.
continue;
}
// Transform multi array to get first occurrence.
// Warning. Here must only be 1 result.
$module = array_shift($module);
$node = [];
$node['type'] = NODE_GENERIC;
$node['label'] = $agent->alias().' &raquo; ';
$node['label'] .= $module->nombre();
$node['id_agente'] = $module->id_agente();
$node['id_agente_modulo'] = $module->id_agente_modulo();
$node['id_parent'] = $parent;
$node['id_node'] = $node_count;
$node['image'] = 'images/networkmap/'.os_get_icon(
$agent->id_os()
);
$node['status'] = $module->getStatus()->last_known_status();
$nodes[$node_count++] = $node;
}
}
}
$nodes[$parent] = $this->agent()->toArray();
$nodes[$parent] = ($nodes[$parent] + [
'id_parent' => $parent,
'id_node' => $id_node,
'status' => $status,
'id_agente' => $this->agent()->id_agente(),
'image' => $image,
]);
return $nodes;
}
/**
* Saves current group definition to database.
*
* @return mixed Affected rows of false in case of error.
* @throws \Exception On error.
*/
public function save()
{
$values = $this->fields;
unset($values['agent']);
$values['group'] = $this->group()->id_grupo();
if (isset($values['id']) === true && $values['id'] > 0) {
// Update.
$rs = \db_process_sql_update(
'tcluster',
$values,
['id' => $this->fields['id']]
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
\db_pandora_audit(
AUDIT_LOG_AGENT_MANAGEMENT,
'Cluster '.io_safe_output($this->fields['name']).' modified'
);
} else {
// New.
$rs = \db_process_sql_insert(
'tcluster',
$values
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
$this->fields['id'] = $rs;
\db_pandora_audit(
AUDIT_LOG_AGENT_MANAGEMENT,
'Cluster '.io_safe_output($this->fields['name']).' created'
);
}
$this->saveMembers();
$this->saveItems();
return true;
}
/**
* Updates entries in tcluster_agent.
*
* @return void
* @throws \Exception On error.
*/
public function saveMembers()
{
$err = __METHOD__.' error: ';
$values = [];
foreach ($this->members as $agent) {
$values[$agent->id_agente()] = [
'id_cluster' => $this->fields['id'],
'id_agent' => $agent->id_agente(),
];
}
if (empty($values) === true) {
return;
}
// Clean previous relationships.
$rs = \db_process_sql_delete(
'tcluster_agent',
[ 'id_cluster' => $this->fields['id'] ]
);
foreach ($values as $set) {
// Add current relationships.
$rs = \db_process_sql_insert(
'tcluster_agent',
$set
);
if ($rs === false) {
global $config;
throw new \Exception(
$err.$config['dbconnection']->error
);
}
}
}
/**
* Undocumented function
*
* @return void
*/
public function saveItems()
{
$items = $this->getItems();
foreach ($this->removedItems as $item) {
\db_process_sql_delete(
'tcluster_item',
$item
);
}
// Save cluster modules.
foreach ($items as $item) {
$item->save();
}
}
/**
* Force cluster status module to be executed.
*
* @param boolean $get_informed Throw exception if clusterStatus is null.
*
* @return void
* @throws \Exception On error.
*/
public function force(?bool $get_informed=true)
{
if ($this->clusterStatus === null) {
if ($get_informed === true) {
throw new \Exception(
__METHOD__.' error: Cluster status module does not exist'
);
}
} else {
$this->clusterStatus->flag(1);
$this->clusterStatus->save();
}
}
/**
* Delete cluster from db.
*
* @return void
* @throws \Exception On error.
*/
public function delete()
{
global $config;
if ($this->agent() !== null) {
// Delete agent and modules.
$this->agent()->delete();
}
// Remove entries from db.
// Table tcluster_agent.
$rs = \db_process_sql_delete(
'tcluster_agent',
['id_cluster' => $this->fields['id']]
);
if ($rs === false) {
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
// Table tcluster_item.
$rs = \db_process_sql_delete(
'tcluster_item',
['id_cluster' => $this->fields['id']]
);
if ($rs === false) {
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
// Table tcluster.
$rs = \db_process_sql_delete(
'tcluster',
['id' => $this->fields['id']]
);
if ($rs === false) {
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
\db_pandora_audit(
AUDIT_LOG_AGENT_MANAGEMENT,
'Cluster '.io_safe_output($this->fields['name']).' deleted'
);
unset($this->aaModules);
unset($this->apModules);
unset($this->fields);
}
}

View File

@ -0,0 +1,268 @@
<?php
// phpcs:disable Squiz.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Cluster module entity class.
*
* @category Class
* @package Pandora FMS
* @subpackage Community
* @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.
* ============================================================================
*/
// Begin.
namespace PandoraFMS;
use PandoraFMS\Entity;
use PandoraFMS\Module;
/**
* Represents AA and AP modules entity from a cluster.
*/
class ClusterModule extends Entity
{
/**
* Associated module.
*
* @var PandoraFMS\Module
*/
private $module;
/**
* Builds a PandoraFMS\ClusterViewer\ClusterModule object from a id.
*
* @param integer $id ClusterModule Id.
*
* @throws \Exception On error.
*/
public function __construct(?int $id=null)
{
if (is_numeric($id) === true && $id > 0) {
try {
parent::__construct('tcluster_item', ['id' => $id]);
} catch (\Exception $e) {
throw new \Exception('ClusterModule id not found.');
}
// Get module.
$this->module = Module::search(
[
'nombre' => $this->name(),
'custom_integer_1' => $this->id_cluster(),
],
1
);
} else {
parent::__construct('tcluster_item');
$this->module = new Module();
}
}
/**
* Returns current object as array.
*
* @return array Of fields.
*/
public function toArray()
{
return $this->fields;
}
/**
* Associates a module to this clusterModule.
*
* @param array $params Module parameters.
*
* @return void
*/
public function setModule(array $params)
{
$this->module = new Module();
foreach ($params as $k => $v) {
$this->module->{$k}($v);
}
}
/**
* Associates a module to this clusterModule.
*
* @param PandoraFMS\Module $module Module definition.
*
* @return void
*/
public function setModuleObject(Module $module)
{
$this->module = $module;
}
/**
* Returns current module.
*
* @return PandoraFMS\Module Object.
*/
public function getModule()
{
return $this->module;
}
/**
* Saves or retrieves value of warning_limit.
*
* @param float|null $value Warning value.
*
* @return mixed Value or empty.
*/
public function warning_limit(?float $value=null)
{
if ($value !== null) {
$this->fields['warning_limit'] = $value;
if ($this->module !== null) {
$this->module->min_warning($value);
}
} else {
return $this->fields['warning_limit'];
}
}
/**
* Saves or retrieves value of critical_limit.
*
* @param float|null $value Critical value.
*
* @return mixed Value or empty.
*/
public function critical_limit(?float $value=null)
{
if ($value !== null) {
$this->fields['critical_limit'] = $value;
if ($this->module !== null) {
$this->module->min_critical($value);
}
} else {
return $this->fields['critical_limit'];
}
}
/**
* Save ClusterModule.
*
* @return boolean True if success, false if error.
* @throws \Exception On db error.
*/
public function save()
{
$values = $this->fields;
if ($this->module === null) {
return false;
}
if (method_exists($this->module, 'save') === false) {
throw new \Exception(
__METHOD__.' error: Cluster module "'.$this->name().'" invalid.'
);
}
if (isset($values['id']) === true && $values['id'] > 0) {
// Update.
$rs = \db_process_sql_update(
'tcluster_item',
$values,
['id' => $this->fields['id']]
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
if ($this->module === null) {
throw new \Exception(
__METHOD__.' error: Cluster module "'.$this->name().'" is not defined'
);
}
// Update reference.
$this->module->custom_integer_2($this->fields['id']);
// Update module.
$this->module->save();
return true;
} else {
// New.
$rs = \db_process_sql_insert(
'tcluster_item',
$values
);
if ($rs === false) {
global $config;
throw new \Exception(
__METHOD__.' error: '.$config['dbconnection']->error
);
}
$this->fields['id'] = $rs;
// Update reference.
$this->module->custom_integer_2($this->fields['id']);
// Update module.
$this->module->save();
return true;
}
return false;
}
/**
* Erases this object and its module.
*
* @return void
*/
public function delete()
{
if (method_exists($this->module, 'delete') === true) {
$this->module->delete();
}
unset($this->fields);
unset($this->module);
}
}

View File

@ -0,0 +1,767 @@
<?php
/**
* Cluster view main class.
*
* @category Class
* @package Pandora FMS
* @subpackage Community
* @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.
* ============================================================================
*/
// Begin.
namespace PandoraFMS\ClusterViewer;
use PandoraFMS\View;
use PandoraFMS\Group;
use PandoraFMS\Cluster;
/**
* Class to handle Cluster view operations.
*/
class ClusterManager
{
/**
* Url of controller.
*
* @var string
*/
public $ajaxController;
/**
* Url (main).
*
* @var string
*/
public $url;
/**
* Number of clusters defined.
*
* @var integer
*/
private static $count;
/**
* Constructor
*
* @param string $ajax_page Path to ajax controller.
* @param string $url Url.
*/
public function __construct(
string $ajax_page='operation/cluster/cluster',
string $url='index.php?sec=estado&sec2=operation/cluster/cluster'
) {
global $config;
check_login();
if (! check_acl($config['id_user'], 0, 'AR')
&& ! check_acl($config['id_user'], 0, 'AW')
) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to access cluster viewer'
);
if (is_ajax()) {
echo json_encode(['error' => 'noaccess']);
} else {
include 'general/noaccess.php';
}
exit;
}
$this->ajaxController = $ajax_page;
$this->url = $url;
}
/**
* Main program starts here.
*
* @return void
*/
public function run()
{
$operation = get_parameter('op', '');
switch ($operation) {
case 'new':
case 'update':
$this->showClusterEditor($operation);
break;
case 'view':
$this->showCluster();
break;
case 'delete':
$this->deleteCluster();
break;
case 'force':
$this->forceCluster();
break;
default:
$n_clusters = $this->getCount();
if ($n_clusters > 0) {
$this->showList();
} else {
$this->showWelcome();
}
break;
}
}
/**
* Prints error message
*
* @param string $msg Message.
*
* @return void
*/
public function error(string $msg)
{
if (is_ajax()) {
echo json_encode(
['error' => $msg]
);
} else {
ui_print_error_message($msg);
}
}
/**
* Loads view 'first tasks' for cluster view.
* Old style.
*
* @return void
*/
public function showWelcome()
{
global $config;
include_once $config['homedir'].'/general/first_task/cluster_builder.php';
}
/**
* Prepares available clusters definition for current users and loads view.
*
* @param string|null $msg Message (if any).
*
* @return void
*/
public function showList(?string $msg='')
{
global $config;
// Extract data.
$n_clusters = $this->getCount();
if ($n_clusters > 0) {
$clusters = $this->getAll();
} else {
$clusters = [];
}
View::render(
'cluster/list',
[
'message' => $msg,
'config' => $config,
'model' => $this,
'n_clusters' => $n_clusters,
'clusters' => $clusters,
]
);
}
/**
* Show cluster information.
*
* @param string|null $msg Message (if any).
*
* @return void
*/
public function showCluster(?string $msg=null)
{
global $config;
$err = '';
$id = get_parameter('id', null);
try {
$cluster = new Cluster($id);
} catch (\Exception $e) {
$err = ui_print_error_message(
__('Cluster not found: '.$e->getMessage()),
'',
true
);
}
if ($cluster->agent()->id_agente() === null) {
// Failed.
$err = ui_print_error_message(
__('Cluster agent not found: '),
'',
true
);
$critical = true;
}
View::render(
'cluster/view',
[
'message' => $msg,
'error' => $err,
'config' => $config,
'model' => $this,
'cluster' => $cluster,
'critical' => $critical,
]
);
}
/**
* Removes a cluster from db.
*
* @return void
*/
public function deleteCluster()
{
$msg = '';
$id = get_parameter('id', null);
try {
$cluster = new Cluster($id);
$cluster->delete();
unset($cluster);
} catch (\Exception $e) {
$msg = ui_print_error_message(
__('Error while deleting, reason: %s', $e->getMessage()),
'',
true
);
}
if (empty($msg) === true) {
$msg = ui_print_success_message(
__('Cluster successfully deleted.'),
'',
true
);
}
$this->showList($msg);
}
/**
* Force cluster execution.
*
* @return void
*/
public function forceCluster()
{
$msg = '';
$id = get_parameter('id', null);
try {
$cluster = new Cluster($id);
$cluster->force();
unset($cluster);
} catch (\Exception $e) {
$msg = ui_print_error_message(
__('Error while forcing, reason: %s', $e->getMessage()),
'',
true
);
}
if (empty($msg) === true) {
$msg = ui_print_success_message(
__('Cluster successfully forced.'),
'',
true
);
}
$this->showCluster($msg);
}
/**
* Shows editor for target cluster (or new one).
*
* @param string $operation Current operation.
*
* @return void
*/
public function showClusterEditor(string $operation)
{
global $config;
if (!check_acl($config['id_user'], 0, 'AW')) {
db_pandora_audit(
AUDIT_LOG_ACL_VIOLATION,
'Trying to create clusters'
);
include 'general/noaccess.php';
} else {
$wizard = new ClusterWizard(
$this->url,
$operation
);
$wizard->run();
}
}
/**
* Returns number of clusters registered.
*
* @return integer
*/
public function getCount()
{
if (isset($this->count) !== true) {
$this->count = $this->getAll('count');
}
return $this->count;
}
/**
* Return all cluster definitons matching given filters.
*
* @param mixed $fields Fields array or 'count' keyword to retrieve
* count, null or default to use default ones.
* @param array $filter Filters to be applied.
* @param integer $offset Offset (pagination).
* @param integer $limit Limit (pagination).
* @param string $order Sort order.
* @param string $sort_field Sort field.
*
* @return array With all results or false if error.
* @throws \Exception On error.
*/
public static function getAll(
$fields=null,
array $filter=[],
?int $offset=null,
?int $limit=null,
?string $order=null,
?string $sort_field=null
) {
$sql_filters = [];
$order_by = '';
$pagination = '';
global $config;
if (is_array($filter) === false) {
throw new \Exception('[ClusterManager::getAll] Filter must be an array.');
}
if (empty($filter['id_group']) === false
&& (int) $filter['id_group'] !== 0
) {
$sql_filters[] = sprintf(
' AND tc.`group` = %d',
$filter['id_group']
);
}
if (empty($filter['free_search']) === false) {
$topic = io_safe_input($filter['free_search']);
$sql_filters[] = sprintf(
' AND (lower(tc.name) like lower("%%%s%%")
OR lower(tc.description) like lower("%%%s%%") ) ',
$topic,
$topic
);
}
$count = false;
if (is_array($fields) === false && $fields === 'count') {
$fields = ['tc.*'];
$count = true;
} else if (is_array($fields) === false) {
// Default values.
$fields = [
'tc.*',
'(SELECT COUNT(*) FROM `tcluster_agent` WHERE `id_cluster` = tc.`id`) as `nodes`',
'tas.known_status',
];
}
if (isset($order) === true) {
$dir = 'asc';
if ($order === 'desc') {
$dir = 'desc';
};
if ($sort_field === 'type') {
$sort_field = 'cluster_type';
}
if (in_array(
$sort_field,
[
'name',
'description',
'group',
'cluster_type',
'nodes',
'known_status',
]
) === true
) {
$order_by = sprintf(
'ORDER BY `%s` %s',
$sort_field,
$dir
);
}
}
if (isset($limit) === true && $limit > 0
&& isset($offset) === true && $offset >= 0
) {
$pagination = sprintf(
' LIMIT %d OFFSET %d ',
$limit,
$offset
);
}
$sql = sprintf(
'SELECT %s
FROM tcluster tc
LEFT JOIN tagente ta
ON tc.id_agent = ta.id_agente
LEFT JOIN tagente_modulo tam
ON tam.id_agente = tc.id_agent
AND tam.nombre = "%s"
LEFT JOIN tagente_estado tas
ON tam.id_agente_modulo=tas.id_agente_modulo
WHERE 1=1
%s
%s
%s',
join(',', $fields),
io_safe_input('Cluster status'),
join(' ', $sql_filters),
$order_by,
$pagination
);
if ($count === true) {
$sql = sprintf('SELECT count(*) as n FROM ( %s ) tt', $sql);
// Counter.. All data.
return db_get_value_sql($sql);
}
return db_get_all_rows_sql($sql);
}
/**
* Return data for datatables painting.
*
* @return void
* @throws \Exception On Error.
*/
public function draw()
{
global $config;
// Datatables offset, limit and order.
$filter = get_parameter('filter', []);
$start = get_parameter('start', 0);
$length = get_parameter('length', $config['block_size']);
$order = get_datatable_order(true);
try {
ob_start();
$fields = [
'tc.*',
'(SELECT COUNT(*) FROM `tcluster_agent` WHERE `id_cluster` = tc.`id`) as `nodes`',
'tas.known_status',
];
// Retrieve data.
$data = self::getAll(
// Fields.
$fields,
// Filter.
$filter,
// Offset.
$start,
// Limit.
$length,
// Order.
$order['direction'],
// Sort field.
$order['field']
);
// Retrieve counter.
$count = self::getAll(
'count',
$filter
);
if ($data) {
$data = array_reduce(
$data,
function ($carry, $item) {
global $config;
// Transforms array of arrays $data into an array
// of objects, making a post-process of certain fields.
$tmp = (object) $item;
$manage = check_acl(
$config['id_user'],
$tmp->group,
'AW',
true
);
$tmp->name = '<b><a href="'.ui_get_full_url(
$this->url.'&op=view&id='.$tmp->id
).'">'.$tmp->name.'</a></b>';
if (empty($tmp->group) === true) {
$tmp->group = __('Not set');
} else {
$tmp->group = ui_print_group_icon(
$tmp->group,
true
);
}
// Type.
if ($tmp->cluster_type === 'AA') {
$tmp->type = __('Active-Active');
} else if ($tmp->cluster_type === 'AP') {
$tmp->type = __('Active-Passive');
} else {
$tmp->type = __('Unknown');
}
// Status.
$tmp->known_status = ui_print_module_status(
$tmp->known_status,
true
);
// Options. View.
$tmp->options = '<a href="';
$tmp->options .= ui_get_full_url(
$this->url.'&op=view&id='.$tmp->id
);
$tmp->options .= '">';
$tmp->options .= html_print_image(
'images/operation.png',
true,
[
'title' => __('View'),
'class' => 'invert_filter',
]
);
$tmp->options .= '</a>';
if ($manage) {
// Options. Edit.
$tmp->options .= '<a href="';
$tmp->options .= ui_get_full_url(
$this->url.'&op=update&id='.$tmp->id
);
$tmp->options .= '">';
$tmp->options .= html_print_image(
'images/config.png',
true,
[
'title' => __('Edit'),
'class' => 'invert_filter',
]
);
$tmp->options .= '</a>';
// Options. Delete.
$tmp->options .= '<a href="';
$tmp->options .= ui_get_full_url(
$this->url.'&op=delete&id='.$tmp->id
);
$tmp->options .= '">';
$tmp->options .= html_print_image(
'images/cross.png',
true,
[
'title' => __('Delete'),
'class' => 'invert_filter',
]
);
$tmp->options .= '</a>';
}
$carry[] = $tmp;
return $carry;
}
);
}
// Datatables format: RecordsTotal && recordsfiltered.
echo json_encode(
[
'data' => $data,
'recordsTotal' => $count,
'recordsFiltered' => $count,
]
);
// Capture output.
$response = ob_get_clean();
} catch (\Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
exit;
}
// If not valid, show error with issue.
json_decode($response);
if (json_last_error() == JSON_ERROR_NONE) {
// If valid dump.
echo $response;
} else {
echo json_encode(
['error' => $response]
);
}
}
/**
* Provides data for wizard. Ajax method.
*
* @return void
*/
public function getAgentsFromGroup()
{
$side = get_parameter('side', null);
$id = get_parameter('id', null);
$group_id = get_parameter('group_id', 0);
$group_recursion = (bool) get_parameter('group_recursion', 0);
$groups = [];
if ($group_recursion === true) {
$groups = groups_get_children_ids($group_id, true);
} else {
$groups = $group_id;
}
if ($side === 'left') {
// Available agents.
$agents = agents_get_agents(
[ 'id_grupo' => $groups ],
[
'id_agente',
'alias',
]
);
$agents = array_reduce(
$agents,
function ($carry, $item) {
$carry[$item['id_agente']] = io_safe_output($item['alias']);
return $carry;
}
);
} else if ($side === 'right') {
// Selected agents.
$cluster = new Cluster($id);
$agents = $cluster->getMembers();
$agents = array_reduce(
$agents,
function ($carry, $item) use ($groups) {
if (in_array($item->id_grupo(), $groups) === true) {
$carry[$item->id_agente()] = io_safe_output(
$item->alias()
);
}
return $carry;
}
);
}
if (empty($agents) === true) {
echo '[]';
} else {
// Dump response.
echo json_encode($agents);
}
}
/**
* Returns a goBack form structure.
*
* @return array Form structure.
*/
public function getGoBackForm()
{
$form['form']['action'] = $this->url;
$form['form']['method'] = 'POST';
$form['form']['id'] = 'go-back-form';
$form['inputs'] = [
[
'arguments' => [
'name' => 'submit',
'label' => __('Go back'),
'type' => 'submit',
'attributes' => 'class="sub cancel"',
'return' => true,
],
],
];
return $form;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -206,7 +206,7 @@ class Widget
$sql_search = '';
if (empty($search) === false) {
$sql_search = 'AND description LIKE "%'.$search.'%" ';
$sql_search = 'AND description LIKE "%'.addslashes($search).'%" ';
}
// User admin view all dashboards.
@ -419,6 +419,7 @@ class Widget
case 'GroupedMeterGraphs':
case 'ColorModuleTabs':
case 'BlockHistogram':
case 'DataMatrix':
$className .= '\\'.$name;
break;

View File

@ -0,0 +1,697 @@
<?php
/**
* Widget data matrix Pandora FMS Console
*
* @category Console Class
* @package Pandora FMS
* @subpackage Widget
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2022 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.
* ============================================================================
*/
namespace PandoraFMS\Dashboard;
use PandoraFMS\Enterprise\Metaconsole\Node;
global $config;
/**
* URL Widgets
*/
class DataMatrix extends Widget
{
private const MAX_MODULES = 10;
/**
* Name widget.
*
* @var string
*/
protected $name;
/**
* Title widget.
*
* @var string
*/
protected $title;
/**
* Page widget;
*
* @var string
*/
protected $page;
/**
* Class name widget.
*
* @var string
*/
protected $className;
/**
* Values options for each widget.
*
* @var array
*/
protected $values;
/**
* Configuration required.
*
* @var boolean
*/
protected $configurationRequired;
/**
* Error load widget.
*
* @var boolean
*/
protected $loadError;
/**
* Width.
*
* @var integer
*/
protected $width;
/**
* Heigth.
*
* @var integer
*/
protected $height;
/**
* Grid Width.
*
* @var integer
*/
protected $gridWidth;
/**
* Cell ID.
*
* @var integer
*/
protected $cellId;
/**
* Construct.
*
* @param integer $cellId Cell ID.
* @param integer $dashboardId Dashboard ID.
* @param integer $widgetId Widget ID.
* @param integer|null $width New width.
* @param integer|null $height New height.
* @param integer|null $gridWidth Grid width.
*/
public function __construct(
int $cellId,
int $dashboardId=0,
int $widgetId=0,
?int $width=0,
?int $height=0,
?int $gridWidth=0
) {
global $config;
// WARNING: Do not edit. This chunk must be in the constructor.
parent::__construct(
$cellId,
$dashboardId,
$widgetId
);
// Width.
$this->width = $width;
// Height.
$this->height = $height;
// Grid Width.
$this->gridWidth = $gridWidth;
// Cell Id.
$this->cellId = $cellId;
// Options.
$this->values = $this->decoders($this->getOptionsWidget());
// Positions.
$this->position = $this->getPositionWidget();
// Page.
$this->page = basename(__FILE__);
// ClassName.
$class = new \ReflectionClass($this);
$this->className = $class->getShortName();
// Title.
$this->title = __('Color tabs modules');
// Name.
if (empty($this->name) === true) {
$this->name = 'single_graph';
}
// This forces at least a first configuration.
$this->configurationRequired = false;
if (empty($this->values['moduleDataMatrix']) === true) {
$this->configurationRequired = true;
}
$this->overflow_scrollbars = false;
}
/**
* Decoders hack for retrocompability.
*
* @param array $decoder Values.
*
* @return array Returns the values with the correct key.
*/
public function decoders(array $decoder): array
{
$values = [];
// Retrieve global - common inputs.
$values = parent::decoders($decoder);
$values['agentsDataMatrix'] = [];
if (isset($decoder['agentsDataMatrix']) === true) {
if (isset($decoder['agentsDataMatrix'][0]) === true
&& empty($decoder['agentsDataMatrix']) === false
) {
$values['agentsDataMatrix'] = explode(
',',
$decoder['agentsDataMatrix'][0]
);
}
}
if (isset($decoder['selectionDataMatrix']) === true) {
$values['selectionDataMatrix'] = $decoder['selectionDataMatrix'];
}
$values['moduleDataMatrix'] = [];
if (isset($decoder['moduleDataMatrix']) === true) {
if (empty($decoder['moduleDataMatrix']) === false) {
$values['moduleDataMatrix'] = $decoder['moduleDataMatrix'];
}
}
if (isset($decoder['formatData']) === true) {
$values['formatData'] = $decoder['formatData'];
}
$values['label'] = 'module';
if (isset($decoder['label']) === true) {
$values['label'] = $decoder['label'];
}
if (isset($decoder['fontColor']) === true) {
$values['fontColor'] = $decoder['fontColor'];
}
if (isset($decoder['period']) === true) {
$values['period'] = $decoder['period'];
}
if (isset($decoder['slice']) === true) {
$values['slice'] = $decoder['slice'];
}
if (isset($decoder['limit']) === true) {
$values['limit'] = $decoder['limit'];
}
return $values;
}
/**
* Generates inputs for form (specific).
*
* @return array Of inputs.
*
* @throws Exception On error.
*/
public function getFormInputs(): array
{
global $config;
$values = $this->values;
// Retrieve global - common inputs.
$inputs = parent::getFormInputs();
$blocks = [
'row1',
'row2',
];
$inputs['blocks'] = $blocks;
foreach ($inputs as $kInput => $vInput) {
$inputs['inputs']['row1'][] = $vInput;
}
if (isset($values['formatData']) === false) {
$values['formatData'] = 1;
}
// Format Data.
$inputs['inputs']['row1'][] = [
'label' => __('Format Data'),
'arguments' => [
'name' => 'formatData',
'id' => 'formatData',
'type' => 'switch',
'value' => $values['formatData'],
],
];
if (isset($values['period']) === false) {
$values['period'] = SECONDS_1DAY;
}
$inputs['inputs']['row1'][] = [
'label' => __('Periodicity'),
'arguments' => [
'name' => 'period',
'type' => 'interval',
'value' => $values['period'],
'nothing' => __('None'),
'nothing_value' => 0,
'style_icon' => 'flex-grow: 0',
],
];
if (isset($values['slice']) === false) {
$values['slice'] = SECONDS_5MINUTES;
}
$inputs['inputs']['row1'][] = [
'label' => __('Interval'),
'arguments' => [
'name' => 'slice',
'type' => 'interval',
'value' => $values['slice'],
'nothing' => __('None'),
'nothing_value' => 0,
'style_icon' => 'flex-grow: 0',
],
];
if (isset($values['limit']) === false) {
$values['limit'] = $config['block_size'];
}
// Limit Default block_size.
$blockSizeD4 = \format_integer_round(($config['block_size'] / 4));
$blockSizeD2 = \format_integer_round(($config['block_size'] / 2));
$fields = [
$config['block_size'] => $config['block_size'],
$blockSizeD4 => $blockSizeD4,
$blockSizeD2 => $blockSizeD2,
($config['block_size'] * 2) => ($config['block_size'] * 2),
($config['block_size'] * 3) => ($config['block_size'] * 3),
];
$inputs['inputs']['row1'][] = [
'label' => \__('Limit'),
'arguments' => [
'type' => 'select',
'fields' => $fields,
'class' => 'event-widget-input',
'name' => 'limit',
'selected' => $values['limit'],
'return' => true,
],
];
// Type Label.
$fields = [
'module' => __('Module'),
'agent' => __('Agent'),
'agent_module' => __('Agent / module'),
];
$inputs['inputs']['row2'][] = [
'label' => __('Label'),
'arguments' => [
'type' => 'select',
'fields' => $fields,
'name' => 'label',
'selected' => $values['label'],
'return' => true,
],
];
$inputs['inputs']['row2'][] = [
'arguments' => [
'type' => 'select_multiple_modules_filtered_select2',
'agent_values' => agents_get_agents_selected(0),
'agent_name' => 'agentsDataMatrix[]',
'agent_ids' => $values['agentsDataMatrix'],
'selectionModules' => $values['selectionDataMatrix'],
'selectionModulesNameId' => 'selectionDataMatrix',
'modules_ids' => $values['moduleDataMatrix'],
'modules_name' => 'moduleDataMatrix[]',
'notStringModules' => true,
],
];
return $inputs;
}
/**
* Get Post for widget.
*
* @return array
*/
public function getPost():array
{
// Retrieve global - common inputs.
$values = parent::getPost();
$values['agentsDataMatrix'] = \get_parameter(
'agentsDataMatrix',
[]
);
$values['selectionDataMatrix'] = \get_parameter(
'selectionDataMatrix',
0
);
$values['moduleDataMatrix'] = \get_parameter(
'moduleDataMatrix'
);
$agColor = [];
if (isset($values['agentsDataMatrix'][0]) === true
&& empty($values['agentsDataMatrix'][0]) === false
) {
$agColor = explode(',', $values['agentsDataMatrix'][0]);
}
$agModule = [];
if (isset($values['moduleDataMatrix'][0]) === true
&& empty($values['moduleDataMatrix'][0]) === false
) {
$agModule = explode(',', $values['moduleDataMatrix'][0]);
}
$values['moduleDataMatrix'] = \get_same_modules_all(
$agColor,
$agModule
);
$values['formatData'] = \get_parameter_switch('formatData');
$values['fontColor'] = \get_parameter('fontColor', '#2c3e50');
$values['label'] = \get_parameter('label', 'module');
$values['period'] = \get_parameter('period', 0);
$values['slice'] = \get_parameter('slice', 0);
$values['limit'] = \get_parameter('limit', 20);
return $values;
}
/**
* Draw widget.
*
* @return string;
*/
public function load()
{
$this->size = parent::getSize();
$output = '';
if (count($this->values['moduleDataMatrix']) > self::MAX_MODULES) {
$output .= '<div class="container-center">';
$output .= \ui_print_info_message(
__(
'The maximum number of modules to display is %d, please reconfigure the widget.',
self::MAX_MODULES
),
'',
true
);
$output .= '</div>';
return $output;
}
if (is_metaconsole() === true) {
$modules_nodes = array_reduce(
$this->values['moduleDataMatrix'],
function ($carry, $item) {
$explode = explode('|', $item);
$carry[$explode[0]][] = $explode[1];
return $carry;
},
[]
);
$modules = [];
foreach ($modules_nodes as $n => $mod) {
try {
$node = new Node((int) $n);
$node->connect();
$node_mods = $this->getInfoModules($mod);
if (empty($node_mods) === false) {
foreach ($node_mods as $value) {
$value['id_node'] = $n;
$value['server_name'] = $node->toArray()['server_name'];
$modules[] = $value;
}
}
$node->disconnect();
} catch (\Exception $e) {
// Unexistent agent.
$node->disconnect();
}
}
} else {
$modules = $this->getInfoModules(
$this->values['moduleDataMatrix']
);
}
if ($modules !== false && empty($modules) === false) {
// Datatables list.
try {
$info_columns = $this->columns($modules);
$columns = $info_columns['columns'];
$column_names = $info_columns['column_names'];
$columns_sort = $info_columns['columns_sort'];
$tableId = 'dataMatrix_'.$this->dashboardId.'_'.$this->cellId;
// Load datatables user interface.
ui_print_datatable(
[
'id' => $tableId,
'class' => 'info_table',
'style' => 'width: 100%',
'columns' => $columns,
'column_names' => $column_names,
'ajax_url' => 'include/ajax/module',
'ajax_data' => [
'get_data_dataMatrix' => 1,
'table_id' => $tableId,
'period' => $this->values['period'],
'slice' => $this->values['slice'],
'formatData' => $this->values['formatData'],
'modules' => json_encode($modules),
],
'default_pagination' => $this->values['limit'],
'no_sortable_columns' => $columns_sort,
'order' => [
'field' => 'date',
'direction' => 'desc',
],
'csv' => 0,
]
);
} catch (\Exception $e) {
echo $e->getMessage();
}
} else {
$output = '';
$output .= '<div class="container-center">';
$output .= \ui_print_info_message(
__('Not found modules'),
'',
true
);
$output .= '</div>';
return $output;
}
}
/**
* Get info modules.
*
* @param array $modules Modules.
*
* @return array Data.
*/
private function getInfoModules(array $modules): array
{
$where = sprintf(
'tagente_modulo.id_agente_modulo IN (%s)
AND tagente_modulo.delete_pending = 0',
implode(',', $modules)
);
$sql = sprintf(
'SELECT tagente_modulo.id_agente_modulo AS `id`,
tagente_modulo.nombre AS `name`,
tagente_modulo.unit AS `unit`,
tagente_modulo.min_warning AS w_min,
tagente_modulo.max_warning AS w_max,
tagente_modulo.str_warning AS w_str,
tagente_modulo.min_critical AS c_min,
tagente_modulo.max_critical AS c_max,
tagente_modulo.str_critical AS c_str,
tagente_modulo.id_tipo_modulo AS type_module,
tagente_estado.datos AS `data`,
tagente_estado.timestamp AS `timestamp`,
tagente_estado.estado AS `status`,
tagente.alias
FROM tagente_modulo
LEFT JOIN tagente_estado
ON tagente_modulo.id_agente_modulo = tagente_estado.id_agente_modulo
LEFT JOIN tagente
ON tagente_modulo.id_agente = tagente.id_agente
WHERE %s',
$where
);
$modules = db_get_all_rows_sql($sql);
if ($modules === false) {
$modules = [];
}
return $modules;
}
/**
* Get columns.
*
* @param array $modules Info modules.
*
* @return array
*/
private function columns(array $modules)
{
$columns = [];
$columns[] = 'date';
$column_names = [];
$column_names[] = __('Date');
$columns_sort = [];
$columns_sort[] = 0;
foreach ($modules as $key => $module) {
$columns[] = 'Column-'.$module['id'];
// Module name.
$name = '';
switch ($this->values['label']) {
case 'agent':
$name = $module['alias'];
break;
case 'agent_module':
$name = $module['alias'].' / '.$module['name'];
break;
default:
case 'module':
$name = $module['name'];
break;
}
$columns_sort[] = ($key + 1);
$column_names[] = $name;
}
$data = [
'columns' => $columns,
'column_names' => $column_names,
'columns_sort' => $columns_sort,
];
return $data;
}
/**
* Get description.
*
* @return string.
*/
public static function getDescription()
{
return __('Data Matrix');
}
/**
* Get Name.
*
* @return string.
*/
public static function getName()
{
return 'DataMatrix';
}
/**
* Get size Modal Configuration.
*
* @return array
*/
public function getSizeModalConfiguration(): array
{
$size = [
'width' => (is_metaconsole() === true) ? 1000 : 900,
'height' => 480,
];
return $size;
}
}

View File

@ -9156,3 +9156,16 @@ div#err_msg_centralised {
.tag-editor .tag-editor-delete:hover i:before {
color: #ccc !important;
}
.snmp-td {
padding: 0 !important;
height: 0;
}
.snmp-div {
height: 100%;
display: flex;
align-items: center;
justify-content: start;
padding-left: 10px;
}

View File

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

View File

@ -846,17 +846,15 @@ foreach ($agents as $agent) {
$data[0] .= '<div class="agentleft_'.$agent['id_agente'].'" style="visibility: hidden; clear: left;">';
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=view&id='.$cluster->id()
);
$data[0] .= '<a href="'.$url.'">'.__('View').'</a>';
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=view&id='.$cluster->id()
);
$data[0] .= '<a href="'.$url.'">'.__('View').'</a>';
} else {
$data[0] .= '<a href="index.php?sec=estado&sec2=operation/agentes/ver_agente&id_agente='.$agent['id_agente'].'">'.__('View').'</a>';
}
@ -865,17 +863,15 @@ foreach ($agents as $agent) {
$data[0] .= ' | ';
if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) {
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR;
$url .= '/operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
$data[0] .= '<a href="'.$url.'">'.__('Edit').'</a>';
}
$cluster = PandoraFMS\Cluster::loadFromAgentId(
$agent['id_agente']
);
$url = 'index.php?sec=reporting&sec2=';
$url .= 'operation/cluster/cluster';
$url = ui_get_full_url(
$url.'&op=update&id='.$cluster->id()
);
$data[0] .= '<a href="'.$url.'">'.__('Edit').'</a>';
} else {
$data[0] .= '<a href="index.php?sec=gagente&amp;sec2=godmode/agentes/configurar_agente&amp;id_agente='.$agent['id_agente'].'">'.__('Edit').'</a>';
}

View File

@ -0,0 +1,70 @@
<?php
/**
* Cluster view entrypoint.
*
* @category View
* @package Pandora FMS
* @subpackage Community
* @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.
* ============================================================================
*/
// Begin.
global $config;
require 'vendor/autoload.php';
use PandoraFMS\ClusterViewer\ClusterManager;
$ajaxPage = 'operation/cluster/cluster';
// Control call flow.
try {
// User access and validation is being processed on class constructor.
$obj = new ClusterManager($ajaxPage);
} catch (Exception $e) {
if (is_ajax()) {
echo json_encode(['error' => '[ClusterManager]'.$e->getMessage() ]);
exit;
} else {
echo '[ClusterManager]'.$e->getMessage();
}
// Stop this execution, but continue 'globally'.
return;
}
// AJAX controller.
if (is_ajax()) {
$method = get_parameter('method');
if (method_exists($obj, $method) === true) {
$obj->{$method}();
} else {
$obj->error('Method not found. [ClusterManager::'.$method.']');
}
// Stop any execution.
exit;
} else {
// Run.
$obj->run();
}

View File

@ -102,10 +102,16 @@ if (isset($fb64) === true) {
);
}
$id_group_filter = get_parameter(
'filter[id_group_filter]',
($filter['id_group_filter'] ?? '')
);
$id_group = get_parameter(
'filter[id_group]',
($filter['id_group'] ?? '')
($filter['id_group'] ?? $id_group_filter)
);
$event_type = get_parameter(
'filter[event_type]',
($filter['event_type'] ?? '')
@ -183,7 +189,7 @@ $search_secondary_groups = get_parameter(
);
$search_recursive_groups = get_parameter(
'filter[search_recursive_groups]',
0
($filter['search_recursive_groups'] ?? '')
);
$id_group_filter = get_parameter(
'filter[id_group_filter]',

View File

@ -147,7 +147,12 @@ if ($access_console_node === true) {
$sub['snmpconsole']['subtype'] = 'nolink';
}
enterprise_hook('cluster_menu');
if (check_acl($config['id_user'], 0, 'AR')) {
$sub['operation/cluster/cluster']['text'] = __('Cluster View');
$sub['operation/cluster/cluster']['id'] = 'cluster';
$sub['operation/cluster/cluster']['refr'] = 0;
}
enterprise_hook('aws_menu');
enterprise_hook('SAP_view');

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
#
%define name pandorafms_console
%define version 7.0NG.767
%define release 221219
%define release 221221
# 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.767
%define release 221219
%define release 221221
# 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.767
%define release 221219
%define release 221221
%define httpd_name httpd
# User and Group under which Apache is running
%define httpd_name apache2

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,129 @@
<?php
/**
* Cluster View: Edit
*
* @category View
* @package Pandora FMS
* @subpackage Cluster View
* @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.
* ============================================================================
*/
// Begin.
// Prepare header and breadcrums.
$i = 0;
$bc = [];
$extra = '&op='.$wizard->operation;
if ($wizard->id !== null) {
$extra .= '&id='.$wizard->id;
}
$bc[] = [
'link' => $wizard->parentUrl,
'label' => __('Cluster list'),
'selected' => false,
];
$labels = $wizard->getLabels();
foreach ($labels as $key => $label) {
$bc[] = [
'link' => $wizard->url.(($key >= 0) ? $extra.'&page='.$key : ''),
'label' => __($label),
'selected' => ($wizard->page == $key),
];
}
$wizard->prepareBreadcrum($bc);
$header_str = __(ucfirst($wizard->getOperation())).' ';
$header_str .= (($cluster->name() !== null) ? $cluster->name() : __('cluster '));
$header_str .= ' &raquo; '.__($labels[$wizard->page]);
// Header.
$buttons = [];
$main_page = '<a href="'.$wizard->parentUrl.'">';
$main_page .= html_print_image(
'images/list.png',
true,
[
'title' => __('Cluster list'),
'class' => 'invert_filter',
]
);
$main_page .= '</a>';
$buttons = [
[
'active' => false,
'text' => $main_page,
],
];
if ($cluster !== null) {
if ($cluster->id() !== null) {
$view = '<a href="'.$wizard->parentUrl.'&op=view&id='.$cluster->id().'">';
$view .= html_print_image(
'images/operation.png',
true,
[
'title' => __('View this cluster'),
'class' => 'invert_filter',
]
);
$view .= '</a>';
$buttons[] = [
'active' => false,
'text' => $view,
];
}
}
ui_print_page_header(
$header_str,
'',
false,
'cluster_view',
true,
// Buttons.
$buttons,
false,
'',
GENERIC_SIZE_TEXT,
'',
$wizard->printHeader(true)
);
// Check if any error ocurred.
if (empty($wizard->errMessages) === false) {
foreach ($wizard->errMessages as $msg) {
ui_print_error_message(__($msg));
}
}
if (empty($form) === false) {
// Print form (prepared in ClusterWizard).
HTML::printForm($form, false, ($wizard->page < 6));
}
// Print always go back button.
HTML::printForm($wizard->getGoBackForm(), false);

View File

@ -0,0 +1,132 @@
<?php
/**
* Cluster View: List
*
* @category View
* @package Pandora FMS
* @subpackage Cluster View
* @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.
* ============================================================================
*/
// Header.
\ui_print_page_header(
__('Monitoring').' &raquo; '.__('Clusters'),
'images/chart.png',
false,
'',
false
);
if (empty($message) === false) {
echo $message;
}
// Datatables list.
try {
$columns = [
'name',
'description',
'group',
'type',
'nodes',
'known_status',
[
'text' => 'options',
'class' => 'action_buttons',
],
];
$column_names = [
__('Name'),
__('Description'),
__('Group'),
__('Type'),
__('Nodes'),
__('Status'),
__('Options'),
];
$tableId = 'clusters';
// Load datatables user interface.
ui_print_datatable(
[
'id' => $tableId,
'class' => 'info_table',
'style' => 'width: 100%',
'columns' => $columns,
'column_names' => $column_names,
'ajax_url' => $model->ajaxController,
'ajax_data' => ['method' => 'draw'],
'no_sortable_columns' => [-1],
'order' => [
'field' => 'known_status',
'direction' => 'asc',
],
'search_button_class' => 'sub filter float-right',
'form' => [
'inputs' => [
[
'label' => __('Filter group'),
'name' => 'id_group',
'returnAllGroup' => true,
'privilege' => 'AR',
'type' => 'select_groups',
'return' => true,
'size' => '250px',
],
[
'label' => __('Free search'),
'type' => 'text',
'class' => 'mw250px',
'id' => 'free_search',
'name' => 'free_search',
],
],
],
]
);
} catch (Exception $e) {
echo $e->getMessage();
}
if (check_acl($config['id_user'], 0, 'AW')) {
HTML::printForm(
[
'form' => [
'method' => 'POST',
'action' => ui_get_full_url($model->url.'&op=new'),
],
'inputs' => [
[
'class' => 'w100p',
'arguments' => [
'name' => 'submit',
'label' => __('New cluster'),
'type' => 'submit',
'attributes' => 'class="sub next"',
'return' => true,
],
],
],
]
);
}

View File

@ -0,0 +1,453 @@
<?php
/**
* Cluster View: View
*
* @category View
* @package Pandora FMS
* @subpackage Cluster View
* @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.
* ============================================================================
*/
ui_require_css_file('discovery');
ui_require_css_file('agent_view');
ui_require_css_file('cluster_view');
$html = new HTML();
// Begin.
// Prepare header and breadcrums.
$i = 0;
$bc = [];
$bc[] = [
'link' => $model->url,
'label' => __('Cluster list'),
'selected' => false,
];
$bc[] = [
'link' => $model->url.'&op=view&id='.$cluster->id(),
'label' => __('Cluster details'),
'selected' => true,
];
$html->prepareBreadcrum($bc);
// Header.
$main_page = '<a href="'.$model->url.'">';
$main_page .= html_print_image(
'images/list.png',
true,
[
'title' => __('Cluster list'),
'class' => 'invert_filter',
]
);
$main_page .= '</a>';
$edit = '<a href="'.$model->url.'&op=update&id='.$cluster->id().'">';
$edit .= html_print_image(
'images/setup.png',
true,
[
'title' => __('Edit this cluster'),
'class' => 'invert_filter',
]
);
$edit .= '</a>';
ui_print_page_header(
__('Cluster details').' &raquo; '.$cluster->name(),
'',
false,
// Help link.
'cluster_view',
true,
// Buttons.
[
[
'active' => false,
'text' => $main_page,
],[
'active' => false,
'text' => $edit,
],
],
false,
'',
GENERIC_SIZE_TEXT,
'',
$html->printHeader(true)
);
if (empty($error) === false) {
echo $error;
}
if (empty($message) === false) {
echo $message;
}
if ($critical === true) {
// Print always go back button.
HTML::printForm($model->getGoBackForm(), false);
return;
}
/*
*
* All this block has been retrieved from 'estado_generalagente.php' as
* described in issue #5755.
*
*/
/*
*
*
* CLUSTER AGENT DETAILS.
*
*/
// Prepare information for view.
$alive_animation = agents_get_status_animation(
agents_get_interval_status($cluster->agent()->toArray(), false)
);
$agent_name = ui_print_agent_name(
$cluster->agent()->id_agente(),
true,
500,
'font-size: medium;font-weight:bold',
true,
'',
'',
false,
false
);
$in_planned_downtime = db_get_sql(
'SELECT executed FROM tplanned_downtime
INNER JOIN tplanned_downtime_agents
ON tplanned_downtime.id = tplanned_downtime_agents.id_downtime
WHERE tplanned_downtime_agents.id_agent = '.$cluster->agent()->id_agente().' AND tplanned_downtime.executed = 1'
);
if ($cluster->agent()->disabled()) {
if ($in_planned_downtime) {
$agent_name = '<em>'.$agent_name.ui_print_help_tip(__('Disabled'), true);
} else {
$agent_name = '<em>'.$agent_name.'</em>'.ui_print_help_tip(__('Disabled'), true);
}
} else if ($cluster->agent()->quiet()) {
if ($in_planned_downtime) {
$agent_name = "<em'>".$agent_name.'&nbsp;'.html_print_image('images/dot_blue.png', true, ['border' => '0', 'title' => __('Quiet'), 'alt' => '']);
} else {
$agent_name = "<em'>".$agent_name.'&nbsp;'.html_print_image('images/dot_blue.png', true, ['border' => '0', 'title' => __('Quiet'), 'alt' => '']).'</em>';
}
} else {
$agent_name = $agent_name;
}
if ($in_planned_downtime && !$cluster->agent()->disabled() && !$cluster->agent()->quiet()) {
$agent_name .= '<em>&nbsp;'.ui_print_help_tip(
__('Agent in scheduled downtime'),
true,
'images/minireloj-16.png'
).'</em>';
} else if (($in_planned_downtime && !$cluster->agent()->disabled())
|| ($in_planned_downtime && !$cluster->agent()->quiet())
) {
$agent_name .= '&nbsp;'.ui_print_help_tip(
__('Agent in scheduled downtime'),
true,
'images/minireloj-16.png'
).'</em>';
}
$table_agent_header = '<div class="agent_details_agent_alias">';
$table_agent_header .= $agent_name;
$table_agent_header .= '</div>';
$table_agent_header .= '<div class="agent_details_agent_name">';
if (!$config['show_group_name']) {
$table_agent_header .= ui_print_group_icon(
$cluster->agent()->id_grupo(),
true,
'groups_small',
'padding-right: 6px;'
);
}
$table_agent_header .= '</div>';
$status_img = agents_detail_view_status_img(
$cluster->agent()->critical_count(),
$cluster->agent()->warning_count(),
$cluster->agent()->unknown_count(),
$cluster->agent()->total_count(),
$cluster->agent()->notinit_count()
);
$table_agent_header .= '<div class="icono_right">'.$status_img.'</div>';
$table_agent_header .= '&nbsp;&nbsp;';
$table_agent_header .= '<a href="'.$model->url.'&op=force&id='.$cluster->id();
$table_agent_header .= '">'.html_print_image(
'images/target.png',
true,
[
'title' => __('Force cluster status calculation'),
'alt' => '',
'class' => 'invert_filter',
]
).'</a>';
// Fixed width non interactive charts.
$status_chart_width = 180;
$graph_width = 180;
$table_agent_graph = '<div id="status_pie" style="width: '.$status_chart_width.'px;">';
$table_agent_graph .= graph_agent_status(
$cluster->agent()->id_agente(),
$graph_width,
$graph_width,
true,
false,
false,
true
);
$table_agent_graph .= '</div>';
$table_agent_os = '<p>'.ui_print_os_icon(
$cluster->agent()->id_os(),
false,
true,
true,
false,
false,
false,
['title' => __('OS').': '.get_os_name($cluster->agent()->id_os())]
);
$table_agent_os .= (empty($cluster->agent()->os_version()) === true) ? get_os_name((int) $cluster->agent()->id_os()) : $cluster->agent()->os_version().'</p>';
$addresses = agents_get_addresses($cluster->agent()->id_agente());
$address = agents_get_address($cluster->agent()->id_agente());
foreach ($addresses as $k => $add) {
if ($add == $address) {
unset($addresses[$k]);
}
}
if (empty($address) === false) {
$table_agent_ip = '<p>'.html_print_image(
'images/world.png',
true,
[
'title' => __('IP address'),
'class' => 'invert_filter',
]
);
$table_agent_ip .= '<span class="align-top inline">';
$table_agent_ip .= empty($address) ? '<em>'.__('N/A').'</em>' : $address;
$table_agent_ip .= '</span></p>';
}
$table_agent_description = '<p>'.html_print_image(
'images/list.png',
true,
[
'title' => __('Description'),
'class' => 'invert_filter',
]
);
$table_agent_description .= '<span class="align-top inline">';
$table_agent_description .= empty(
$cluster->description()
) ? '<em>'.__('N/A').'</em>' : $cluster->description();
$table_agent_description .= '</span></p>';
$table_agent_count_modules = reporting_tiny_stats(
$cluster->agent()->toArray(),
true,
'agent',
// Useless.
':',
true
);
$table_agent_version = '<p>'.html_print_image(
'images/version.png',
true,
[
'title' => __('Agent Version'),
'class' => 'invert_filter',
]
);
$table_agent_version .= '<span class="align-top inline">';
$table_agent_version .= empty($cluster->agent()->agent_version()) ? '<i>'.__('Cluster agent').'</i>' : $cluster->agent()->agent_version();
$table_agent_version .= '</span></p>';
/*
*
* MAP
*
*/
$nodes = $cluster->getNodes();
$font_size = 20;
$width = '45%';
$height = '500';
$node_radius = 40;
// Generate map.
$map_manager = new NetworkMap(
[
'nodes' => $nodes,
'no_pandora_node' => 1,
'pure' => 1,
'map_options' => [
'generation_method' => LAYOUT_SPRING1,
'font_size' => $font_size,
'node_radius' => $node_radius,
'height' => $height,
'width' => '100%',
'tooltip' => true,
'size_image' => 50,
'z_dash' => 0.5,
'map_filter' => [
'node_sep' => 7,
'node_radius' => 50,
'x_offs' => 130,
'y_offs' => -70,
],
],
]
);
/*
*
* EVENTS 24h
*
*/
$table_events = '<div class="white_table_graph" id="table_events">';
$table_events .= '<div class="white_table_graph_header">';
$table_events .= html_print_image(
'images/arrow_down_green.png',
true
);
$table_events .= '<span>';
$table_events .= __('Events (Last 24h)');
$table_events .= '</span>';
$table_events .= '</div>';
$table_events .= '<div class="white_table_graph_content white-table-graph-content">';
$table_events .= graph_graphic_agentevents(
$cluster->agent()->id_agente(),
95,
70,
SECONDS_1DAY,
'',
true,
true,
500
);
$table_events .= '</div>';
$table_events .= '</div>';
?>
<div id="agent_details_first_row" class="w100p cluster-agent-data">
<div class="box-shadow agent_details_col agent_details_col_left">
<div class="agent_details_header">
<?php echo $table_agent_header; ?>
</div>
<div class="agent_details_content">
<div class="agent_details_graph">
<?php echo $table_agent_graph; ?>
<div class="agent_details_bullets">
<?php echo $table_agent_count_modules; ?>
</div>
</div>
<div class="agent_details_info">
<?php
echo $alive_animation;
echo $table_agent_os;
echo $table_agent_ip;
echo $table_agent_version;
echo $table_agent_description;
?>
</div>
</div>
</div>
<div class="box-shadow agent_details_col agent_details_col_right">
<div class="cluster-map">
<?php $map_manager->printMap(); ?>
</div>
</div>
</div>
<div class="w100p cluster-events-graph">
<?php echo $table_events; ?>
</div>
<div id='cluster-modules' class="w100p modules">
<?php
$id_agente = $cluster->agent()->id_agente();
require_once $config['homedir'].'/operation/agentes/estado_monitores.php';
?>
</div>
<?php
HTML::printForm(
[
'form' => [
'action' => $model->url.'&op=view&id='.$cluster->id(),
'method' => 'POST',
],
'inputs' => [
[
'arguments' => [
'name' => 'submit',
'label' => __('Reload'),
'type' => 'submit',
'attributes' => 'class="sub cancel"',
'return' => true,
],
],
],
],
false
);
echo '<br/>';
// Print always go back button.
HTML::printForm($model->getGoBackForm(), false);

View File

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

View File

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

View File

@ -280,6 +280,9 @@ our @EXPORT = qw(
notification_set_targets
notification_get_users
notification_get_groups
exec_cluster_aa_module
exec_cluster_ap_module
exec_cluster_status_module
);
# Some global variables
@ -7275,6 +7278,175 @@ sub pandora_snmptrapd_still_working ($$) {
}
}
################################################################################
# Execute a cluster status module.
################################################################################
sub exec_cluster_status_module ($$$$) {
my ($pa_config, $module, $server_id, $dbh) = @_;
# Execute cluster modules.
my @modules = get_db_rows($dbh,
'SELECT *
FROM tagente_modulo
WHERE tagente_modulo.id_agente = ?
AND tagente_modulo.disabled != 1
AND tagente_modulo.tcp_port = 1',
$module->{'id_agente'});
foreach my $agent_module (@modules) {
# Cluster active-active module.
if ($agent_module->{'prediction_module'} == 6) {
logger ($pa_config, "Executing cluster active-active critical module " . $agent_module->{'nombre'}, 10);
exec_cluster_aa_module($pa_config, $agent_module, $server_id, $dbh);
}
# Cluster active-passive module.
elsif ($agent_module->{'prediction_module'} == 7) {
logger ($pa_config, "Executing cluster active-passive critical module " . $agent_module->{'nombre'}, 10);
exec_cluster_ap_module($pa_config, $agent_module, $server_id, $dbh);
}
}
# Get the status of cluster modules.
my $data = -1;
@modules = get_db_rows($dbh,
'SELECT tagente_modulo.id_agente_modulo, tagente_estado.estado
FROM tagente_estado, tagente_modulo
WHERE tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND tagente_modulo.disabled != 1
AND tagente_modulo.tcp_port = 1
AND tagente_modulo.id_agente = ?',
$module->{'id_agente'});
foreach my $cluster_module (@modules) {
next if ($cluster_module->{'id_agente_modulo'} == $module->{'id_agente_modulo'}); # Skip the current module.
# Critical.
if ($cluster_module->{'estado'} == MODULE_NORMAL && $data < 0) {
$data = 0;
} elsif ($cluster_module->{'estado'} == MODULE_WARNING && $data < 1) {
$data = 1;
} elsif (($cluster_module->{'estado'} == MODULE_CRITICAL || $cluster_module->{'estado'} == MODULE_UNKNOWN) && $data < 2) {
$data = 2;
}
}
# No data.
if ($data < 0) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Get the current timestamp.
my $utimestamp = time ();
my $timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
# Update the module.
pandora_process_module($pa_config, {'data' => $data}, '', $module, '', $timestamp, $utimestamp, $server_id, $dbh);
pandora_update_agent($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh);
}
################################################################################
# Execute a cluster active-active module.
################################################################################
sub exec_cluster_aa_module ($$$$) {
my ($pa_config, $module, $server_id, $dbh) = @_;
# Get the cluster item.
my $item = get_db_single_row($dbh, 'SELECT * FROM tcluster_item WHERE id=?', $module->{'custom_integer_2'});
if (!defined($item)) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Get cluster agents and compute the item status.
my ($not_normal, $total) = (0, 0);
my @agents = get_db_rows($dbh, 'SELECT id_agent FROM tcluster_agent WHERE id_cluster = ?', $module->{'custom_integer_1'});
foreach my $agent_id (@agents) {
my $item_status = get_db_value($dbh,
'SELECT estado
FROM tagente_estado, tagente_modulo
WHERE tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND tagente_modulo.id_agente = ?
AND tagente_modulo.nombre = ?',
$agent_id->{'id_agent'}, $item->{'name'});
# Count modules in a status other than normal.
if (!defined($item_status) || $item_status != MODULE_NORMAL) {
$not_normal += 1;
}
$total += 1;
}
# No data.
if ($total < 1) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Convert $not_normal to a percentage.
$not_normal = 100 * $not_normal / $total;
# Get the current timestamp.
my $utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
# Update module
pandora_process_module ($pa_config, {'data' => $not_normal}, '', $module, '', $timestamp, $utimestamp, $server_id, $dbh);
pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh);
}
################################################################################
# Execute a cluster active-pasive module.
################################################################################
sub exec_cluster_ap_module ($$$$) {
my ($pa_config, $module, $server_id, $dbh) = @_;
# Get the cluster item.
my $item = get_db_single_row($dbh, 'SELECT * FROM tcluster_item WHERE id=?', $module->{'custom_integer_2'});
if (!defined($item)) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Get cluster agents and compute the item status.
my $data = undef;
my $utimestamp = 0;
my @agents = get_db_rows($dbh, 'SELECT id_agent FROM tcluster_agent WHERE id_cluster = ?', $module->{'custom_integer_1'});
foreach my $agent_id (@agents) {
my $status = get_db_single_row($dbh,
'SELECT datos, estado, utimestamp
FROM tagente_estado, tagente_modulo
WHERE tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND tagente_modulo.id_agente = ?
AND tagente_modulo.nombre = ?',
$agent_id->{'id_agent'}, $item->{'name'});
# Get the most recent data.
if (defined($status) && $status->{'estado'} != MODULE_UNKNOWN && $status->{'utimestamp'} > $utimestamp) {
$utimestamp = $status->{'utimestamp'};
$data = $status->{'datos'};
}
}
# No data.
if ($utimestamp == 0) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
return;
}
# Get the current timestamp.
$utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
# Update the module.
pandora_process_module ($pa_config, {'data' => $data }, '', $module, '', $timestamp, $utimestamp, $server_id, $dbh);
# Update the agent.
pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh);
}
# End of function declaration
# End of defined Code

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

View File

@ -207,21 +207,21 @@ sub exec_prediction_module ($$$$) {
# Cluster status module.
if ($agent_module->{'prediction_module'} == 5) {
logger ($pa_config, "Executing cluster status module " . $agent_module->{'nombre'}, 10);
enterprise_hook ('exec_cluster_status_module', [$pa_config, $agent_module, $server_id, $dbh]);
exec_cluster_status_module($pa_config, $agent_module, $server_id, $dbh);
return;
}
# Cluster active-active module.
if ($agent_module->{'prediction_module'} == 6) {
logger ($pa_config, "Executing cluster active-active module " . $agent_module->{'nombre'}, 10);
enterprise_hook ('exec_cluster_aa_module', [$pa_config, $agent_module, $server_id, $dbh]);
exec_cluster_aa_module($pa_config, $agent_module, $server_id, $dbh);
return;
}
# Cluster active-passive module.
if ($agent_module->{'prediction_module'} == 7) {
logger ($pa_config, "Executing cluster active-passive module " . $agent_module->{'nombre'}, 10);
enterprise_hook ('exec_cluster_ap_module', [$pa_config, $agent_module, $server_id, $dbh]);
exec_cluster_ap_module($pa_config, $agent_module, $server_id, $dbh);
return;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ use Encode::Locale;
Encode::Locale::decode_argv;
# version: define current version
my $version = "7.0NG.767 Build 221219";
my $version = "7.0NG.767 Build 221221";
# save program name for logging
my $progname = basename($0);
@ -1296,7 +1296,6 @@ sub help_screen_line($$$){
sub check_values($) {
my ($check) = @_;
use experimental 'smartmatch';
my $arg_cont = 2;
my $cont = 0;
@ -1316,7 +1315,7 @@ sub check_values($) {
# Check values.
if (defined($check->[$cont]->{'values'})) {
if (!($args[$arg_cont] ~~ $check->[$cont]->{'values'})) {
if (!(is_in_array($check->[$cont]->{'values'}, $args[$arg_cont]))) {
print "\nError: value `$args[$arg_cont]` is not valid for $check->[$cont]->{'name'}\n";
print "\tAvailable options: \t$check->[$cont]->{'values'}->[0]";
if (defined($check->[$cont]->{'text_extra'}->[0])) {