pandorafms/pandora_plugins/intel_dcm/intel_dcm_discovery.pl

421 lines
15 KiB
Perl
Raw Normal View History

2017-11-14 15:17:27 +01:00
#!/usr/bin/perl
# (c) Dario Rodriguez 2011 <dario.rodriguez@artica.es>
# Intel DCM Discovery
use POSIX qw(setsid strftime strftime ceil);
use strict;
use warnings;
use IO::Socket::INET;
use NetAddr::IP;
# Default lib dir for RPM and DEB packages
BEGIN { push @INC, '/usr/lib/perl5'; }
2017-11-14 15:17:27 +01:00
use PandoraFMS::Tools;
use PandoraFMS::DB;
use PandoraFMS::Core;
use PandoraFMS::Config;
sub getParam($) {
my $param = shift;
$param = "--".$param;
my $value_aux = undef;
my $i;
for($i=0; $i<$#ARGV; $i++) {
if ($param eq $ARGV[$i]) {
$value_aux = $ARGV[$i+1];
}
}
return $value_aux;
}
##########################################################################
# Global variables so set behaviour here:
my $target_timeout = 5; # Fixed to 5 secs by default
##########################################################################
# Code begins here, do not touch
##########################################################################
my $pandora_conf = "/etc/pandora/pandora_server.conf";
my $task_id = $ARGV[0]; # Passed automatically by the server
my $target_group = $ARGV[1]; # Defined by user
my $create_incident = $ARGV[2]; # Defined by user
# Used Custom Fields in this script
my $target_network = getParam("net"); # Filed1 defined by user
my $username = getParam("ipmi_user"); # Field2 defined by user
my $password = getParam("ipmi_pass"); # Field3 defined by user
my $dcm_server = getParam("dcm_server");
my $dcm_port = getParam("dcm_port");
my $derated_power = getParam("derated_power");
##########################################################################
# Update recon task status.
##########################################################################
sub update_recon_task ($$$) {
my ($dbh, $id_task, $status) = @_;
db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task);
}
##########################################################################
# Show help
##########################################################################
sub show_help {
print "\nSpecific Pandora FMS Intel DCM Discovery\n";
print "(c) Artica ST 2011 <info\@artica.es>\n\n";
print "Usage:\n\n";
print " $0 <task_id> <group_id> <create_incident_flag> more params, see doc\n\n";
exit;
}
sub ipmi_ping ($$$$) {
my ($conf, $addr, $user, $pass) = @_;
my $cmd = "ipmiping $addr -c 3";
my $res = `$cmd`;
if ($res =~ /100\.0% packet loss/) {
return 0;
}
#If we have credentials we must check it
if (defined($user) && defined($pass) && $user && $pass) {
# Check if the credentials are valid
$cmd = "bmc-info -h $addr -u $user -p $pass 2>&1";
$res = `$cmd`;
if ($? != 0) {
logger ($conf, "[Intel DCM Discovery] Host $addr reports a BMC error", 1);
return 0;
}
}
return 1;
}
sub create_custom_fields ($) {
my $dbh = shift;
my $id_entity = get_db_value($dbh, 'SELECT id_field FROM tagent_custom_fields WHERE name = "DCM_Entity_Id"');
if (!$id_entity) {
db_insert ($dbh, 'id_field', 'INSERT INTO tagent_custom_fields (name, display_on_front) VALUES ("DCM_Entity_Id", 0)');
}
my $id_derated = get_db_value($dbh, 'SELECT id_field FROM tagent_custom_fields WHERE name = "DCM_Entity_Derated_Power"');
if (!$id_derated) {
db_insert ($dbh, 'id_field', 'INSERT INTO tagent_custom_fields (name, display_on_front) VALUES ("DCM_Entity_Derated_Power", 0)');
}
($id_derated, $id_entity)
}
sub set_dcm_derated_power ($$$$) {
my ($dbh, $id_agent, $id_field, $derated_power) = @_;
db_insert ($dbh, 'id_field', 'INSERT INTO tagent_custom_data (id_field, id_agent, description) VALUES (?, ? ,?)', $id_field, $id_agent, $derated_power);
}
sub set_dcm_id ($$$$) {
my ($dbh, $id_agent, $id_field, $dcm_id) = @_;
db_insert ($dbh, 'id_field', 'INSERT INTO tagent_custom_data (id_field, id_agent, description) VALUES (?, ? ,?)', $id_field, $id_agent, $dcm_id);
}
sub create_dcm_entity ($$$$$$$$) {
my ($dbh, $dcm_server, $dcm_port, $agent_name, $agent_address, $derated_power, $bmc_user, $bmc_pass)= @_;
my $plugin_command = get_db_value($dbh, 'SELECT execute FROM tplugin WHERE name = "'.safe_input("Intel DCM Plugin").'"');
my $command = safe_output($plugin_command)." --server \"".$dcm_server."\" --port ".$dcm_port;
$command .= " --action 'add_entity' --type 'NODE' --value '$agent_name'";
$command .= " --address '$agent_address' --derated_power '$derated_power'";
$command .= " --connector 'com.intel.dcm.plugin.Nm15Plugin'";
$command .= " --bmc_user '$bmc_user' --bmc_pass '$bmc_pass'";
my $res = `$command`;
return $res;
}
sub create_metric_modules($$$$$$) {
my ($conf, $dbh, $id_agent, $dcm_id, $dcm_server, $dcm_port) = @_;
my @modules_array = (
{"name" => "Managed Nodes Energy",
"desc" => "The total energy consumed by all managed nodes in the specified entity, in Wh",
"value" => "mnged_nodes_energy"},
{"name" => "Managed Nodes Energy Bill",
"desc" => "The total power bill for all energy consumed by all managed nodes in the specified entity",
"value" => "mnged_nodes_energy_bill"},
{"name" => "IT Equipment Energy",
"desc" => "The total energy consumed by IT equipment, including managed nodes, unmanaged nodes and other IT equipment in the selected entity, in Wh",
"value" => "it_eqpmnt_energy"},
{"name" => "IT Equipment Energy Bill",
"desc" => "The calculated power bill for IT equipment, including managed nodes, unmanaged nodes and other IT equipment in the selected entity",
"value" => "it_eqpmnt_energy_bill"},
{"name" => "Calculated Cooling Energy",
"desc" => "The energy needed to cool the selected entity, in Wh",
"value" => "calc_cooling_energy"},
{"name" => "Calculated Cooling Energy Bill",
"desc" => "The calculated power bill for the energy needed to cool the selected entity",
"value" => "calc_cooling_energy_bill"},
{"name" => "Managed Nodes Power",
"desc" => "The total average power consumption by the managed nodes in the selected entity, in watts",
"value" => "mnged_nodes_pwr"},
{"name" => "IT Equipment Power",
"desc" => "Provides the total average power consumption by IT equipment, including managed nodes, unmanaged nodes and other IT equipment in the selected entity in watts",
"value" => "it_eqpmnt_pwr"},
{"name" => "Calculated Cooling Power",
"desc" => "Provides the average cooling power based on the IT_EQPMNT_PWR multiplied by COOLING_MULT in watts",
"value" => "calc_cooling_pwr"},
{"name" => "Avg. Power Per Dimension",
"desc" => "The average power consumption per dimension",
"value" => "avg_pwr_per_dimension"},
{"name" => "Derated power",
"desc" => "Adds the de-rated values of all the nodes in the entity to the nameplate power value of all unmanaged nodes and equipment associated with the entity, as defined by NAMEPLATE_PWR_UNMNGD_EQPMNT",
"value" => "derated_pwr"},
{"name" => "Inlet Temperature Span",
"desc" => "The average inlet temperature differential between the highest and lowest node temperature in a group (degC/degF)",
"value" => "inlet_temperature_span"});
my $plugin_action = "--action \'metric_data\' --entity_id \'".$dcm_id."\'";
my $id_plugin = get_db_value($dbh, 'SELECT id FROM tplugin WHERE name = "'.safe_input("Intel DCM Plugin").'"');
foreach my $mod (@modules_array) {
my %aux_mod = %{$mod};
my $aux_params = $plugin_action." --value \'".$aux_mod{'value'}."\'";
my %parameters;
$parameters{"nombre"} = safe_input($aux_mod{'name'});
$parameters{"id_tipo_modulo"} = 1;
$parameters{"id_agente"} = $id_agent;
$parameters{"id_plugin"} = $id_plugin;
$parameters{"ip_target"} = $dcm_server;
$parameters{"tcp_port"} = $dcm_port;
$parameters{"id_modulo"} = 4;
$parameters{"max_timeout"} = 300;
$parameters{"descripcion"} = $aux_mod{'desc'};
$parameters{"plugin_parameter"} = $aux_params;
pandora_create_module_from_hash ($conf, \%parameters, $dbh);
}
}
sub create_query_modules($$$$$$) {
my ($conf, $dbh, $id_agent, $dcm_id, $dcm_server, $dcm_port) = @_;
my @modules_array = (
{"name" => "Max. Power",
"desc" => "The maximum power consumed by any single node/enclosure",
"value" => "max_pwr"},
{"name" => "Avg. Power",
"desc" => "The average power consumption across all nodes/enclosures",
"value" => "avg_pwr"},
{"name" => "Min. Power",
"desc" => "The minimum power consumed by any single node/enclosure",
"value" => "min_pwr"},
{"name" => "Max. Avg. Power",
"desc" => "The maximum of group sampling (in a monitoring cycle) power in specified aggregation period for the sum of average power measurement in a group of nodes/enclosures within the specified entity",
"value" => "max_avg_pwr"},
{"name" => "Total Max. Power",
"desc" => "The maximum of group sampling (in a monitoring cycle) power in specified aggregation period for sum of maximum power measurement in a group of nodes/enclosures within the specified entity",
"value" => "total_max_pwr"},
{"name" => "Total Avg. Power",
"desc" => "The average (in specified aggregation period) of group power for sum of average power measurement in a group of nodes/enclosures within the specified entity",
"value" => "total_avg_pwr"},
{"name" => "Max. Avg. Power Capping",
"desc" => "The maximum of group sampling (in a monitoring cycle) power in specified aggregation period for the sum of average power measurement in a group of nodes/enclosures with power capping capability",
"value" => "max_avg_pwr_cap"},
{"name" => "Total Max. Power Capping",
"desc" => "The maximum group sampling (in a monitoring cycle) power in specified aggregation period for sum of maximum power measurement in a group of nodes/enclosures with power capping capability",
"value" => "total_max_pwr_cap"},
{"name" => "Total Avg. Power Capping",
"desc" => "The average (in specified aggregation period) of group power for sum of average power measurement in a group of nodes/enclosures with power capping capability",
"value" => "total_avg_pwr_cap"},
{"name" => "Total Min. Power",
"desc" => "The minimal group sampling (in a monitoring cycle) power in specified aggregation period for sum of minimum power measurement in a group of nodes/enclosures within the specified entity",
"value" => "total_min_pwr"},
{"name" => "Min. Avg. Power",
"desc" => "The minimal group sampling (in a monitoring cycle) power in specified aggregation period for sum of average power measurement in a group of nodes/enclosures within the specified entity",
"value" => "min_avg_pwr"},
{"name" => "Max. Inlet Temperature",
"desc" => "The maximum temperature for any single node within the specified entity",
"value" => "max_inlet_temp"},
{"name" => "Avg. Inlet Temperature",
"desc" => "The average temperature for any single node within the specified entity",
"value" => "avg_inlet_temp"},
{"name" => "Min. Inlet Temperature",
"desc" => "The minimum temperature for any single node within the specified entity",
"value" => "min_inlet_temp"},
{"name" => "Instantaneous Power",
"desc" => "The instantaneous power consumption of a specified node/enclosure or the sum of the instantaneous power of the nodes/enclosures within the specified entity",
"value" => "ins_pwr"});
my $plugin_action = "--action \'query_data\' --entity_id \'".$dcm_id."\'";
my $id_plugin = get_db_value($dbh, 'SELECT id FROM tplugin WHERE name = "'.safe_input("Intel DCM Plugin").'"');
foreach my $mod (@modules_array) {
my %aux_mod = %{$mod};
my $aux_params = $plugin_action." --value \'".$aux_mod{'value'}."\'";
my %parameters;
$parameters{"nombre"} = safe_input($aux_mod{'name'});
$parameters{"id_tipo_modulo"} = 1;
$parameters{"id_agente"} = $id_agent;
$parameters{"id_plugin"} = $id_plugin;
$parameters{"ip_target"} = $dcm_server;
$parameters{"tcp_port"} = $dcm_port;
$parameters{"id_modulo"} = 4;
$parameters{"max_timeout"} = 300;
$parameters{"descripcion"} = $aux_mod{'desc'};
$parameters{"plugin_parameter"} = $aux_params;
pandora_create_module_from_hash ($conf, \%parameters, $dbh);
}
}
##########################################################################
##########################################################################
# M A I N C O D E
##########################################################################
##########################################################################
if ($#ARGV == -1){
show_help();
}
# Pandora server configuration
my %conf;
$conf{"quiet"} = 0;
$conf{"verbosity"} = 1; # Verbose 1 by default
$conf{"daemon"}=0; # Daemon 0 by default
$conf{'PID'}=""; # PID file not exist by default
$conf{'pandora_path'} = $pandora_conf;
# Read config file
pandora_load_config (\%conf);
# Connect to the DB
my $dbh = db_connect ('mysql', $conf{'dbname'}, $conf{'dbhost'}, '3306', $conf{'dbuser'}, $conf{'dbpass'});
# Start the network sweep
# Get a NetAddr::IP object for the target network
my $net_addr = new NetAddr::IP ($target_network);
if (! defined ($net_addr)) {
logger (\%conf, "Invalid network " . $target_network . " for Intel DCM Discovery task", 1);
update_recon_task ($dbh, $task_id, -1);
return -1;
}
#Get id of custom fields
my ($id_derated_cf, $id_entity_cf) = create_custom_fields($dbh);
# Scan the network for hosts
my ($total_hosts, $hosts_found, $addr_found) = ($net_addr->num, 0, '');
my $last = 0;
for (my $i = 1; $net_addr <= $net_addr->broadcast; $i++, $net_addr++) {
if($last == 1) {
last;
}
my $net_addr_temp = $net_addr + 1;
if($net_addr eq $net_addr_temp) {
$last = 1;
}
if ($net_addr =~ /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.(\d{1,3})\b/) {
if($1 eq '0' || $1 eq '255') {
next;
}
}
my $addr = (split(/\//, $net_addr))[0];
$hosts_found ++;
# Update the recon task
update_recon_task ($dbh, $task_id, ceil ($i / ($total_hosts / 100)));
my $alive = 0;
if (ipmi_ping (\%conf, $addr, $username, $password) == 1) {
$alive = 1;
}
next unless ($alive > 0);
# Resolve the address
my $host_name = gethostbyaddr(inet_aton($addr), AF_INET);
$host_name = $addr unless defined ($host_name);
logger(\%conf, "Intel DCM Device found host $host_name.", 10);
# Check if the agent exists
my $agent_id = get_agent_id($dbh, $host_name);
# If the agent exists go for the next
if($agent_id != -1) {
next;
}
# Create DCM Entity
my $dcm_id = create_dcm_entity ($dbh, $dcm_server, $dcm_port, $host_name, $addr, $derated_power, $username, $password);
# Create a new agent
$agent_id = pandora_create_agent (\%conf, $conf{'servername'}, $host_name, $addr, $target_group, 0, 11, 'Created by Intel DCM Discovery', 300, $dbh);
# Create modules
create_query_modules(\%conf, $dbh, $agent_id, $dcm_id, $dcm_server, $dcm_port);
create_metric_modules(\%conf, $dbh, $agent_id, $dcm_id, $dcm_server, $dcm_port);
# Set custom fields
set_dcm_derated_power ($dbh, $agent_id, $id_derated_cf, $derated_power);
set_dcm_id ($dbh, $agent_id, $id_entity_cf, $dcm_id);
# Generate an event
pandora_event (\%conf, "[RECON] New Intel DCM host [$host_name] detected on network [" . $target_network . ']', $target_group, $agent_id, 2, 0, 0, 'recon_host_detected', 0, $dbh);
}
# Mark recon task as done
update_recon_task ($dbh, $task_id, -1);
# End of code