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 package: pandorafms-agent-unix
Version: 7.0NG.767-221219 Version: 7.0NG.767-221221
Architecture: all Architecture: all
Priority: optional Priority: optional
Section: admin Section: admin

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -186,7 +186,7 @@ UpgradeApplicationID
{} {}
Version Version
{221219} {221221}
ViewReadme ViewReadme
{Yes} {Yes}

View File

@ -30,7 +30,7 @@ using namespace Pandora;
using namespace Pandora_Strutils; using namespace Pandora_Strutils;
#define PATH_SIZE _MAX_PATH+1 #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_path;
string pandora_dir; string pandora_dir;

View File

@ -11,7 +11,7 @@ BEGIN
VALUE "LegalCopyright", "Artica ST" VALUE "LegalCopyright", "Artica ST"
VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "OriginalFilename", "PandoraAgent.exe"
VALUE "ProductName", "Pandora FMS Windows Agent" 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" VALUE "FileVersion", "1.0.0.0"
END END
END END

View File

@ -1,5 +1,5 @@
package: pandorafms-console package: pandorafms-console
Version: 7.0NG.767-221219 Version: 7.0NG.767-221221
Architecture: all Architecture: all
Priority: optional Priority: optional
Section: admin Section: admin

View File

@ -14,7 +14,7 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
pandora_version="7.0NG.767-221219" pandora_version="7.0NG.767-221221"
package_pear=0 package_pear=0
package_pandora=1 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/sebastian
godmode/um_client/vendor godmode/um_client/vendor
update_manager_client/resources/styles/pandora.css 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 enterprise/meta/general/upload_head_image.php
general/first_task/transactional_list.php general/first_task/transactional_list.php
enterprise/include/ajax/transactional.ajax.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')) { 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'); ?>" /> <input type="submit" class="button_task ui_toggle" value="<?php echo __('Create Cluster'); ?>" />
</form> </form>
@ -76,4 +76,4 @@ ui_print_info_message(['no_close' => true, 'message' => __('There are no cluster
} }
?> ?>
</div> </div>
</div> </div>

View File

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

View File

@ -2118,6 +2118,9 @@ if ($delete_module) {
exit; 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. // Also call base function to delete modules.
modules_delete_agent_module($id_borrar_modulo); modules_delete_agent_module($id_borrar_modulo);

View File

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

View File

@ -247,6 +247,8 @@ if ($module_action === 'delete') {
$print_result_msg = true; $print_result_msg = true;
$count_correct_delete_modules = 0; $count_correct_delete_modules = 0;
foreach ($id_agent_modules_delete as $id_agent_module_del) { 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); $id_grupo = (int) agents_get_agent_group($id_agente);
$all_groups = agents_get_all_groups_agent($id_agente, $id_grupo); $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 != '') { 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') { if ($status_alert === 'disabled') {

View File

@ -200,14 +200,14 @@ if ($access_console_node === true) {
$sub['gmassive']['type'] = 'direct'; $sub['gmassive']['type'] = 'direct';
$sub['gmassive']['subtype'] = 'nolink'; $sub['gmassive']['subtype'] = 'nolink';
$sub2 = []; $sub2 = [];
$sub2['godmode/massive/massive_operations&amp;tab=massive_agents']['text'] = __('Agents operations'); $sub2['godmode/massive/massive_operations&tab=massive_agents']['text'] = __('Agents operations');
$sub2['godmode/massive/massive_operations&amp;tab=massive_modules']['text'] = __('Modules operations'); $sub2['godmode/massive/massive_operations&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_plugins']['text'] = __('Plugins operations');
if ((bool) check_acl($config['id_user'], 0, 'UM') === true) { 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('massivepolicies_submenu');
enterprise_hook('massivesnmp_submenu'); enterprise_hook('massivesnmp_submenu');
enterprise_hook('massivesatellite_submenu'); enterprise_hook('massivesatellite_submenu');

View File

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

View File

@ -77,6 +77,7 @@ if (is_ajax()) {
true true
).'&nbsp;&nbsp;'; ).'&nbsp;&nbsp;';
$table->data['autocreate_remote_users'] = $row; $table->data['autocreate_remote_users'] = $row;
$table->data['csrf_token'] = html_print_csrf_hidden();
add_enterprise_auth_autocreate_profiles($table, $type_auth); 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_input_hidden('hash_save_config', md5('save'.$config['dbpass']));
} }
html_print_csrf_hidden();
html_print_table($table); html_print_table($table);
echo '<div id="table_auth_result"></div>'; echo '<div id="table_auth_result"></div>';
echo '<div class="action-buttons" style="width: '.$table->width.'">'; 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']; $idGroup = $filter_alert['ag_group'];
$tag_filter = $filter_alert['tag_filter']; $tag_filter = $filter_alert['tag'];
$action_filter = $filter_alert['action']; $action_filter = $filter_alert['action'];
try { try {

View File

@ -26,6 +26,8 @@
* ============================================================================ * ============================================================================
*/ */
use PandoraFMS\Enterprise\Metaconsole\Node;
// Begin. // Begin.
if (check_login()) { if (check_login()) {
global $config; global $config;
@ -59,6 +61,11 @@ if (check_login()) {
0 0
); );
$get_data_dataMatrix = (bool) get_parameter(
'get_data_dataMatrix',
0
);
if ($get_agent_modules_json_by_name === true) { if ($get_agent_modules_json_by_name === true) {
$agent_name = get_parameter('agent_name'); $agent_name = get_parameter('agent_name');
@ -1436,4 +1443,190 @@ if (check_login()) {
return; 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 * Pandora build version and version
*/ */
$build_version = 'PC221219'; $build_version = 'PC221221';
$pandora_version = 'v7.0NG.767'; $pandora_version = 'v7.0NG.767';
// Do not overwrite default timezone set if defined. // Do not overwrite default timezone set if defined.

View File

@ -62,7 +62,7 @@ enterprise_include_once('include/functions_cron.php');
// Clases. // Clases.
use PandoraFMS\Agent; use PandoraFMS\Agent;
use PandoraFMS\Module; use PandoraFMS\Module;
use PandoraFMS\Enterprise\Cluster; use PandoraFMS\Cluster;
use PandoraFMS\Enterprise\Metaconsole\Node; use PandoraFMS\Enterprise\Metaconsole\Node;
use PandoraFMS\Event; use PandoraFMS\Event;
use PandoraFMS\SpecialDay; use PandoraFMS\SpecialDay;
@ -10157,6 +10157,8 @@ function api_set_delete_module($id, $id2, $other, $trash1)
} }
if (!$simulate) { 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); $return = modules_delete_agent_module($idAgentModule);
} else { } else {
$return = true; $return = true;
@ -10182,6 +10184,8 @@ function api_set_delete_module($id, $id2, $other, $trash1)
} }
if (!$simulate) { 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); $return = modules_delete_agent_module($idAgentModule);
} else { } else {
$return = true; $return = true;

View File

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

View File

@ -757,7 +757,8 @@ function db_uncompress_module_data(
$id_agente_modulo, $id_agente_modulo,
$tstart=false, $tstart=false,
$tend=false, $tend=false,
$slice_size=false $slice_size=false,
$force_slice_not_data=false
) { ) {
global $config; global $config;
@ -860,7 +861,10 @@ function db_uncompress_module_data(
$module_interval = modules_get_interval($id_agente_modulo); $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. // No data.
return false; return false;
} }
@ -2313,7 +2317,13 @@ function db_get_lock(string $lockname, int $expiration_time=86400) :?int
} }
if ($lock_status === false) { if ($lock_status === false) {
return null; db_pandora_audit(
AUDIT_LOG_SYSTEM,
'Issue in Database Lock',
'system'
);
return (int) null;
} }
return (int) $lock_status; 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 * @brief Get the button with the link to open realtime stats into a new window
* Only to native (not satellite discovered) snmp modules. * Only to native (not satellite discovered) snmp modules.
@ -4336,3 +4411,129 @@ function modules_get_regex(
return $result; 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 ($agent['source_data'] == -2) {
if (empty($parent) === true) { if (empty($parent) === true) {
$option = json_decode($agent, true); if (is_array($agent) === false) {
$option = json_decode($agent, true);
}
if ($option['networkmap'] == 0) { if ($option['networkmap'] == 0) {
$status = 0; $status = 0;
} else { } 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">'; $go_to_agent = '<div style="text-align: right">';
if ($agent['id_os'] == CLUSTER_OS_ID) { if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) { $cluster = PandoraFMS\Cluster::loadFromAgentId(
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId( $agent['id_agente']
$agent['id_agente'] );
); $url = 'index.php?sec=reporting&sec2=';
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR; $url .= 'operation/cluster/cluster';
$url .= '/operation/cluster/cluster'; $url = ui_get_full_url(
$url = ui_get_full_url( $url.'&op=update&id='.$cluster->id()
$url.'&op=update&id='.$cluster->id() );
); $go_to_agent .= '<a target="_blank" href="'.$url.'">';
$go_to_agent .= '<a target="_blank" href="'.$url.'">'; $go_to_agent .= html_print_submit_button(__('Edit cluster'), 'upd_button', false, 'class="sub config"', true);
$go_to_agent .= html_print_submit_button(__('Edit cluster'), 'upd_button', false, 'class="sub config"', true);
}
} else { } 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 .= '<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); $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.stopPropagation();
d3.event.preventDefault();
} }
function clear_selection() { function clear_selection() {
@ -4020,8 +4019,10 @@ function draw_elements_graph() {
font_size + font_size +
"px !important; text-align:center; text-anchor:middle; fill:#000000" "px !important; text-align:center; text-anchor:middle; fill:#000000"
) )
.text(function(d) { .html(function(d) {
return ellipsize(get_node_name_ov(d), 30); d.text = ellipsize(d.text, 30);
return get_node_name_ov(d, true, font_size);
}) })
.classed("dragable_node fill_fff", true) //own dragable .classed("dragable_node fill_fff", true) //own dragable
.on("click", selected_node) .on("click", selected_node)
@ -4030,7 +4031,7 @@ function draw_elements_graph() {
}); });
node_temp.append("title").text(function(d) { node_temp.append("title").text(function(d) {
return get_node_name_ov(d); return get_node_name_ov(d, false);
}); });
node.exit().remove(); node.exit().remove();
@ -4040,9 +4041,19 @@ function is_central_node(data) {
return data.type == 0 && data.id_agent == 0; 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 // 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() { 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 = ''; $sql_search = '';
if (empty($search) === false) { if (empty($search) === false) {
$sql_search = 'AND description LIKE "%'.$search.'%" '; $sql_search = 'AND description LIKE "%'.addslashes($search).'%" ';
} }
// User admin view all dashboards. // User admin view all dashboards.
@ -419,6 +419,7 @@ class Widget
case 'GroupedMeterGraphs': case 'GroupedMeterGraphs':
case 'ColorModuleTabs': case 'ColorModuleTabs':
case 'BlockHistogram': case 'BlockHistogram':
case 'DataMatrix':
$className .= '\\'.$name; $className .= '\\'.$name;
break; 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 { .tag-editor .tag-editor-delete:hover i:before {
color: #ccc !important; 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'> <div style='height: 10px'>
<?php <?php
$version = '7.0NG.767'; $version = '7.0NG.767';
$build = '221219'; $build = '221221';
$banner = "v$version Build $build"; $banner = "v$version Build $build";
error_reporting(0); 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;">'; $data[0] .= '<div class="agentleft_'.$agent['id_agente'].'" style="visibility: hidden; clear: left;">';
if ($agent['id_os'] == CLUSTER_OS_ID) { if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) { $cluster = PandoraFMS\Cluster::loadFromAgentId(
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId( $agent['id_agente']
$agent['id_agente'] );
); $url = 'index.php?sec=reporting&sec2=';
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR; $url .= 'operation/cluster/cluster';
$url .= '/operation/cluster/cluster'; $url = ui_get_full_url(
$url = ui_get_full_url( $url.'&op=view&id='.$cluster->id()
$url.'&op=view&id='.$cluster->id() );
); $data[0] .= '<a href="'.$url.'">'.__('View').'</a>';
$data[0] .= '<a href="'.$url.'">'.__('View').'</a>';
}
} else { } else {
$data[0] .= '<a href="index.php?sec=estado&sec2=operation/agentes/ver_agente&id_agente='.$agent['id_agente'].'">'.__('View').'</a>'; $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] .= ' | '; $data[0] .= ' | ';
if ($agent['id_os'] == CLUSTER_OS_ID) { if ($agent['id_os'] == CLUSTER_OS_ID) {
if (enterprise_installed()) { $cluster = PandoraFMS\Cluster::loadFromAgentId(
$cluster = PandoraFMS\Enterprise\Cluster::loadFromAgentId( $agent['id_agente']
$agent['id_agente'] );
); $url = 'index.php?sec=reporting&sec2=';
$url = 'index.php?sec=reporting&sec2='.ENTERPRISE_DIR; $url .= 'operation/cluster/cluster';
$url .= '/operation/cluster/cluster'; $url = ui_get_full_url(
$url = ui_get_full_url( $url.'&op=update&id='.$cluster->id()
$url.'&op=update&id='.$cluster->id() );
); $data[0] .= '<a href="'.$url.'">'.__('Edit').'</a>';
$data[0] .= '<a href="'.$url.'">'.__('Edit').'</a>';
}
} else { } else {
$data[0] .= '<a href="index.php?sec=gagente&amp;sec2=godmode/agentes/configurar_agente&amp;id_agente='.$agent['id_agente'].'">'.__('Edit').'</a>'; $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( $id_group = get_parameter(
'filter[id_group]', 'filter[id_group]',
($filter['id_group'] ?? '') ($filter['id_group'] ?? $id_group_filter)
); );
$event_type = get_parameter( $event_type = get_parameter(
'filter[event_type]', 'filter[event_type]',
($filter['event_type'] ?? '') ($filter['event_type'] ?? '')
@ -183,7 +189,7 @@ $search_secondary_groups = get_parameter(
); );
$search_recursive_groups = get_parameter( $search_recursive_groups = get_parameter(
'filter[search_recursive_groups]', 'filter[search_recursive_groups]',
0 ($filter['search_recursive_groups'] ?? '')
); );
$id_group_filter = get_parameter( $id_group_filter = get_parameter(
'filter[id_group_filter]', 'filter[id_group_filter]',

View File

@ -147,7 +147,12 @@ if ($access_console_node === true) {
$sub['snmpconsole']['subtype'] = 'nolink'; $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('aws_menu');
enterprise_hook('SAP_view'); 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 name pandorafms_console
%define version 7.0NG.767 %define version 7.0NG.767
%define release 221219 %define release 221221
# User and Group under which Apache is running # User and Group under which Apache is running
%define httpd_name httpd %define httpd_name httpd

View File

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

View File

@ -3,7 +3,7 @@
# #
%define name pandorafms_console %define name pandorafms_console
%define version 7.0NG.767 %define version 7.0NG.767
%define release 221219 %define release 221221
%define httpd_name httpd %define httpd_name httpd
# User and Group under which Apache is running # User and Group under which Apache is running
%define httpd_name apache2 %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 package: pandorafms-server
Version: 7.0NG.767-221219 Version: 7.0NG.767-221221
Architecture: all Architecture: all
Priority: optional Priority: optional
Section: admin Section: admin

View File

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

View File

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

View File

@ -280,6 +280,9 @@ our @EXPORT = qw(
notification_set_targets notification_set_targets
notification_get_users notification_get_users
notification_get_groups notification_get_groups
exec_cluster_aa_module
exec_cluster_ap_module
exec_cluster_status_module
); );
# Some global variables # 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 function declaration
# End of defined Code # 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 # version: Defines actual version of Pandora Server for this module only
my $pandora_version = "7.0NG.767"; my $pandora_version = "7.0NG.767";
my $pandora_build = "221219"; my $pandora_build = "221221";
our $VERSION = $pandora_version." ".$pandora_build; our $VERSION = $pandora_version." ".$pandora_build;
our %EXPORT_TAGS = ( 'all' => [ qw() ] ); our %EXPORT_TAGS = ( 'all' => [ qw() ] );

View File

@ -207,21 +207,21 @@ sub exec_prediction_module ($$$$) {
# Cluster status module. # Cluster status module.
if ($agent_module->{'prediction_module'} == 5) { if ($agent_module->{'prediction_module'} == 5) {
logger ($pa_config, "Executing cluster status module " . $agent_module->{'nombre'}, 10); 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; return;
} }
# Cluster active-active module. # Cluster active-active module.
if ($agent_module->{'prediction_module'} == 6) { if ($agent_module->{'prediction_module'} == 6) {
logger ($pa_config, "Executing cluster active-active module " . $agent_module->{'nombre'}, 10); 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; return;
} }
# Cluster active-passive module. # Cluster active-passive module.
if ($agent_module->{'prediction_module'} == 7) { if ($agent_module->{'prediction_module'} == 7) {
logger ($pa_config, "Executing cluster active-passive module " . $agent_module->{'nombre'}, 10); 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; return;
} }

View File

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

View File

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

View File

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

View File

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

View File

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