Created
January 17, 2021 14:47
-
-
Save viliampucik/b346f7c865facbfdb81dffb8cb16daa0 to your computer and use it in GitHub Desktop.
Replay NNMi key incidents
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use strict; | |
use warnings; | |
use DBD::Pg; | |
use DBI; | |
use Getopt::Long qw( :config no_ignore_case bundling ); | |
use Net::Domain 'hostfqdn'; | |
use Net::SNMP ':asn1'; | |
use Pod::Usage; | |
use POSIX 'strftime'; | |
use constant CLOSED => 4; | |
sub varbind { | |
my ( $type, $name ) = @_; | |
return ( $type, $name ) if defined $name; | |
return ( NULL, undef ); | |
} | |
my $fqdn = hostfqdn(); | |
my $offset = strftime( '%z', localtime() ); | |
my $options = { | |
'snmp-host' => $fqdn, | |
'snmp-community' => 'public', | |
'snmp-port' => 5162, | |
'url' => "http://$fqdn:80/nnm", | |
}; | |
GetOptions( | |
'help|h|?' => \$options->{'help'}, | |
'open|o' => \$options->{'open'}, | |
'closed|c' => \$options->{'closed'}, | |
'from|f=s' => \$options->{'from'}, | |
'to|t=s' => \$options->{'to'}, | |
'node|n=s' => \$options->{'node'}, | |
'tenant=s' => \$options->{'tenant'}, | |
'uuid|u=s' => \$options->{'uuid'}, | |
'snmp-host=s' => \$options->{'snmp-host'}, | |
'snmp-community=s' => \$options->{'snmp-community'}, | |
'snmp-port=i' => \$options->{'snmp-port'}, | |
'url=s' => \$options->{'url'}, | |
'verbose|v' => \$options->{'verbose'}, | |
'version|V' => \$options->{'version'}, | |
'changelog' => \$options->{'changelog'}, # hidden option | |
'author' => \$options->{'author'}, # hidden option | |
) | |
or pod2usage( -verbose => 0 ); | |
pod2usage( -verbose => 1 ) if $options->{'help'}; | |
pod2usage( -verbose => 99, -sections => 'VERSION' ) if $options->{'version'}; | |
pod2usage( -verbose => 99, -sections => 'CHANGELOG' ) if $options->{'changelog'}; | |
pod2usage( -verbose => 99, -sections => 'AUTHOR' ) if $options->{'author'}; | |
my $conditions = ''; | |
my @bindings; | |
if ( defined $options->{'uuid'} ) { | |
$conditions .= "AND i.uuid = ?\n"; | |
push @bindings, $options->{'uuid'}; | |
} | |
else { | |
my @lifecycles; | |
if ( defined $options->{'closed'} ) { | |
push @lifecycles, 'Closed'; | |
} | |
if ( defined $options->{'open'} || ! scalar @lifecycles ) { # open incidents are enabled by default | |
push @lifecycles, 'Registered', 'In Progress', 'Completed'; | |
} | |
$conditions .= "AND s.label IN ( " . join( ', ', map '?', @lifecycles ) . " )\n"; | |
push @bindings, @lifecycles; | |
if ( defined $options->{'from'} ) { | |
$conditions .= "AND i.time_origin >= ?\n"; | |
push @bindings, $options->{'from'}; | |
} | |
if ( defined $options->{'to'} ) { | |
$conditions .= "AND i.time_origin <= ?\n"; | |
push @bindings, $options->{'to'}; | |
} | |
if ( defined $options->{'node'} ) { | |
$conditions .= "AND n.long_name = ?\n"; | |
push @bindings, $options->{'node'}; | |
} | |
if ( defined $options->{'tenant'} ) { | |
$conditions .= "AND t.name = ?\n"; | |
push @bindings, $options->{'tenant'}; | |
} | |
} | |
my ( $snmp, $error ) = Net::SNMP->session( | |
-hostname => $options->{'snmp-host'}, | |
-community => $options->{'snmp-community'}, | |
-port => $options->{'snmp-port'}, | |
-version => 2, | |
-maxmsgsize => 65535, | |
); | |
unless ( defined $snmp ) { | |
print "Unable to start SNMP session: $error\n"; | |
exit 1; | |
} | |
printf "SNMP destination: %s, community: %s, port: %s\n", | |
$options->{'snmp-host'}, | |
$options->{'snmp-community'}, | |
$options->{'snmp-port'}, | |
if $options->{'verbose'}; | |
my $db = DBI->connect( | |
'DBI:Pg:host=localhost;dbname=nnm', | |
'postgres', | |
exists $ENV{'PGPASSWORD'} ? $ENV{'PGPASSWORD'} : 'nnmP0stgr3S', | |
{ 'AutoCommit' => 0, 'RaiseError' => 1, 'PrintError' => 0 }, | |
); | |
my $query = $db->prepare( qq{ | |
SELECT | |
ec.oid as snmptrapoid, | |
i.name as nnmiincidentname, | |
i.uuid as nnmiincidentuuid, | |
c.value as nnmiincidentcategory, | |
f.value as nnmiincidentfamily, | |
CASE i.origin | |
WHEN 0 THEN 'MANAGEMENTSOFTWARE' | |
WHEN 3 THEN 'SNMPTRAP' | |
ELSE 'N/A' | |
END as nnmiincidentorigin, | |
i.nature + 1 as nnmiincidentnature, | |
i.formatted_message as nnmiincidentfmtmessage, | |
i.severity + 1 as nnmiincidentseverity, | |
CASE p.label | |
WHEN 'None' THEN 5 | |
WHEN 'Low' THEN 4 | |
WHEN 'Medium' THEN 3 | |
WHEN 'High' THEN 2 | |
WHEN 'Top' THEN 1 | |
ELSE 0 | |
END as nnmiincidentpriority, | |
CASE s.label | |
WHEN 'Registered' THEN 1 | |
WHEN 'In Progress' THEN 2 | |
WHEN 'Completed' THEN 3 | |
WHEN 'Closed' THEN 4 | |
WHEN 'Dampened' THEN 5 | |
ELSE 0 | |
END as nnmiincidentlifecyclestate, | |
TO_CHAR(i.time_origin, 'YYYYMMDDHH24MISSMS') as nnmiincidentorigintime, | |
TO_CHAR(i.reg_created, 'YYYYMMDDHH24MISSMS') as nnmiincidentdbcreatetime, | |
TO_CHAR(i.reg_modified, 'YYYYMMDDHH24MISSMS') as nnmiincidentdbmodifiedtime, | |
i.dup_count as nnmiincidentdupcount, | |
i.assign as nnmiincidentassignedto, | |
n.long_name as nnmiincidentsourcenodehostname, | |
i.node_uuid as nnmiincidentsourcenodeuuid, | |
i.source_name as nnmiincidentsourcename, | |
i.src_type as nnmiincidentsourcetype, | |
i.src_uuid as nnmiincidentsourceuuid, | |
GET_BYTE( a.active_addr, 12 ) || '.' || | |
GET_BYTE( a.active_addr, 13 ) || '.' || | |
GET_BYTE( a.active_addr, 14 ) || '.' || | |
GET_BYTE( a.active_addr, 15 ) as nnmiincidentsourcenodemgmtaddr, | |
cia.value as nnmiincidentclosedreason | |
FROM nms_incidents i | |
JOIN nms_incident_config ic ON ic.name = i.name | |
JOIN nms_mgmtevent_config ec ON ec.id = ic.id | |
JOIN nms_incident_category c ON c.id = i.category | |
JOIN nms_incident_family f ON f.id = i.family | |
JOIN nms_priority p ON p.id = i.priority | |
JOIN nms_incident_lifecycle_state s ON s.id = i.lifecyclestate | |
JOIN nms_node n ON n.uuid = i.node_uuid | |
JOIN nms_tenant t ON t.id = n.tenant | |
LEFT OUTER JOIN nms_snmp_agent_settings a ON a.id = n.snmp_agent | |
LEFT OUTER JOIN nms_inc_cia cia ON cia.incident = i.id AND cia.name = 'cia.reasonClosed' | |
WHERE i.nature = 0 | |
AND i.name <> 'StackWithNoSlave' | |
$conditions | |
ORDER BY i.time_origin | |
} ); | |
$query->execute( @bindings ); | |
# select nms_iface.* | |
# from nms_node, nms_connection, nms_iface | |
# where nms_connection.id = nms_iface.l2_connection | |
# and nms_connection.uuid = 'ac1ceb83-3b0e-4f13-b21d-b00668f83ad6' -- nnmiincidentsourceuuid | |
# and nms_node.id = nms_iface.hosted_on | |
# and nms_node.uuid = '64d661c5-1700-4a0a-89cc-a338229aeacf'; -- nnmiincidentsourcenodeuuid | |
my $count = 0; | |
while ( my $row = $query->fetchrow_hashref() ) { | |
$count++; | |
printf "%4i. %s %s %s %-37s %s\n", | |
$count, | |
$row->{'nnmiincidentuuid'}, | |
$row->{'nnmiincidentorigintime'}, | |
$row->{'nnmiincidentlifecyclestate'} == CLOSED ? 'closed' : 'open ', | |
$row->{'nnmiincidentname'}, | |
$row->{'nnmiincidentsourcenodehostname'} | |
if $options->{'verbose'}; | |
if ( defined $row->{'nnmiincidentsourcetype'} && | |
defined $row->{'nnmiincidentsourcenodeuuid'} && | |
defined $row->{'nnmiincidentsourceuuid'} | |
) { | |
my $tmp; | |
if ( $row->{'nnmiincidentsourcetype'} eq 'com.hp.ov.nms.model.core.Interface' ) { | |
$tmp = $db->selectrow_hashref( q{ | |
SELECT i.ifname as nnmiincidentsourceifname, | |
i.ifalias as nnmiincidentsourceifalias, | |
i.ifdesc as nnmiincidentsourceifdesc, | |
i.ifindex as nnmiincidentsourceifindex | |
FROM nms_iface i | |
JOIN nms_node n ON n.id = i.hosted_on | |
WHERE n.uuid = ? | |
AND i.uuid = ? | |
}, undef, $row->{'nnmiincidentsourcenodeuuid'}, $row->{'nnmiincidentsourceuuid'} ); | |
} | |
elsif ( $row->{'nnmiincidentsourcetype'} eq 'com.hp.ov.nms.model.layer2.L2Connection' ) { | |
$tmp = $db->selectrow_hashref( q{ | |
SELECT i.ifname as nnmiincidentsourceifname, | |
i.ifalias as nnmiincidentsourceifalias, | |
i.ifdesc as nnmiincidentsourceifdesc, | |
i.ifindex as nnmiincidentsourceifindex | |
FROM nms_iface i | |
JOIN nms_node n ON n.id = i.hosted_on | |
JOIN nms_connection c ON c.id = i.l2_connection | |
WHERE n.uuid = ? | |
AND c.uuid = ? | |
}, undef, $row->{'nnmiincidentsourcenodeuuid'}, $row->{'nnmiincidentsourceuuid'} ); | |
} | |
$row = { %$row, %$tmp } if defined $tmp; | |
} | |
my $result; | |
# Open root cause incident | |
if ( $row->{'nnmiincidentlifecyclestate'} != CLOSED ) { | |
$result = $snmp->snmpv2_trap( -varbindlist => [ | |
( '1.3.6.1.2.1.1.3.0', TIMETICKS, 0 ), | |
( '1.3.6.1.6.3.1.1.4.1.0', OBJECT_IDENTIFIER, $row->{'snmptrapoid'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.1', OCTET_STRING, 'NNMi' ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.2', OCTET_STRING, $options->{'url'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.3', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.4', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.5', OCTET_STRING, $row->{'nnmiincidentname'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.6', OCTET_STRING, $row->{'nnmiincidentuuid'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.7', OCTET_STRING, $row->{'nnmiincidentcategory'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.8', OCTET_STRING, $row->{'nnmiincidentfamily'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.9', OCTET_STRING, $row->{'nnmiincidentorigin'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.10', INTEGER32, $row->{'nnmiincidentnature'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.11', OCTET_STRING, $row->{'nnmiincidentfmtmessage'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.12', INTEGER32, $row->{'nnmiincidentseverity'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.13', INTEGER32, $row->{'nnmiincidentpriority'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.14', INTEGER32, $row->{'nnmiincidentlifecyclestate'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.15', OCTET_STRING, $row->{'nnmiincidentorigintime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.16', OCTET_STRING, $row->{'nnmiincidentdbcreatetime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.17', OCTET_STRING, $row->{'nnmiincidentdbmodifiedtime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.18', INTEGER32, $row->{'nnmiincidentdupcount'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.19', varbind( OCTET_STRING, $row->{'nnmiincidentassignedto'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.20', OCTET_STRING, '' ), # TODO | |
( '1.3.6.1.4.1.11.2.17.19.2.2.21', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodehostname'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.22', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodeuuid'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.23', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.24', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodemgmtaddr'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.25', OCTET_STRING, $row->{'nnmiincidentsourcename'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.26', OCTET_STRING, $row->{'nnmiincidentsourcetype'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.27', OCTET_STRING, $row->{'nnmiincidentsourceuuid'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.28', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.29', varbind( OCTET_STRING, $row->{'nnmiincidentsourceifname'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.30', varbind( OCTET_STRING, $row->{'nnmiincidentsourceifalias'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.31', varbind( OCTET_STRING, $row->{'nnmiincidentsourceifdesc'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.32', varbind( OCTET_STRING, $row->{'nnmiincidentsourceifindex'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.33', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.34', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.35', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.36', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.37', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.38', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.39', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.40', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.41', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.42', NULL, undef ), | |
]); | |
} | |
# Closed root cause incident | |
else { | |
$result = $snmp->snmpv2_trap( -varbindlist => [ | |
( '1.3.6.1.2.1.1.3.0', TIMETICKS, 0 ), | |
( '1.3.6.1.6.3.1.1.4.1.0', OBJECT_IDENTIFIER, '1.3.6.1.4.1.11.2.17.19.2.0.1000' ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.1', OCTET_STRING, 'NNMi' ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.2', OCTET_STRING, $options->{'url'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.3', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.4', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.5', OCTET_STRING, $row->{'nnmiincidentname'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.6', OCTET_STRING, $row->{'nnmiincidentuuid'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.7', OCTET_STRING, $row->{'nnmiincidentcategory'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.8', OCTET_STRING, $row->{'nnmiincidentfamily'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.9', OCTET_STRING, $row->{'nnmiincidentorigin'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.10', INTEGER32, $row->{'nnmiincidentnature'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.11', OCTET_STRING, $row->{'nnmiincidentfmtmessage'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.12', INTEGER32, $row->{'nnmiincidentseverity'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.13', INTEGER32, $row->{'nnmiincidentpriority'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.14', INTEGER32, $row->{'nnmiincidentlifecyclestate'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.15', OCTET_STRING, $row->{'nnmiincidentorigintime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.16', OCTET_STRING, $row->{'nnmiincidentdbcreatetime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.17', OCTET_STRING, $row->{'nnmiincidentdbmodifiedtime'} . $offset ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.18', INTEGER32, $row->{'nnmiincidentdupcount'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.19', varbind( OCTET_STRING, $row->{'nnmiincidentassignedto'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.20', OCTET_STRING, '' ), # TODO | |
( '1.3.6.1.4.1.11.2.17.19.2.2.21', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodehostname'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.22', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodeuuid'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.23', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.24', varbind( OCTET_STRING, $row->{'nnmiincidentsourcenodemgmtaddr'} ) ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.25', OCTET_STRING, $row->{'nnmiincidentsourcename'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.26', OCTET_STRING, $row->{'nnmiincidentsourcetype'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.27', OCTET_STRING, $row->{'nnmiincidentsourceuuid'} ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.28', NULL, undef ), | |
( '1.3.6.1.4.1.11.2.17.19.2.2.43', varbind( OCTET_STRING, $row->{'nnmiincidentclosedreason'} ) ), | |
]); | |
} | |
unless ( defined $result ) { | |
print 'Cannot sent SNMP trap: ' . $snmp->error() . "\n"; | |
$snmp->close(); | |
$db->disconnect(); | |
exit 1; | |
} | |
} | |
$db->disconnect(); | |
$snmp->close(); | |
print "$count alarms replayed\n"; | |
__END__ | |
=head1 NAME | |
nnmreplay - Replay NNMi key incidents | |
=head1 SYNOPSIS | |
nnmreplay | |
nnmreplay -c -f '2013-09-14 10:00:00' -t '2013-09-15 00:00:00' | |
nnmreplay -o -c -n foo.bar.com | |
nnmreplay -u 1a4dc0f5-44f8-4ac9-a24e-6be939f122d5 | |
=head1 OPTIONS | |
=over 8 | |
=item B<-o, --open> | |
Replay open root cause incidents, enabled by default. | |
=item B<-c, --closed> | |
Replay closed root cause incidents. | |
=item B<-f, --from> | |
Replay incidents that occurred after the given time, including. | |
=item B<-t, --to> | |
Replay incidents that occurred until the given date, including. | |
=item B<-n, --node> | |
Replay incidents associated with the given source node. | |
=item B<--tenant> | |
Replay incidents associated with the given tenant. | |
=item B<-u, --uuid> | |
Replay only one specific incident, other options are automatically ignored. | |
=item B<--snmp-host> | |
Destination of SNMP traps, default is the current host. | |
=item B<--snmp-community> | |
SNMP traps community, default is public. | |
=item B<--snmp-port> | |
SNMP traps port, default is 5162. | |
=item B<--url> | |
NNMi URL embedded in SNMP traps, default is http://<FQDN>:80/nnm | |
=item B<-h, --help> | |
Print a brief help message. | |
=item B<-V, --version> | |
Display the current version. | |
=back | |
=head1 DESCRIPTION | |
=head1 VERSION | |
0.1 | |
=head1 CHANGELOG | |
=over 8 | |
=item * B<1.1.0> [2016-10-19] | |
Added tenant support. | |
=item * B<1.0.0> [2016-10-12] | |
Initial release. | |
=back | |
=head1 AUTHOR | |
Viliam Pucik <[email protected]> | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment