Skip to content

Instantly share code, notes, and snippets.

@viliampucik
Created January 17, 2021 14:47
Show Gist options
  • Save viliampucik/b346f7c865facbfdb81dffb8cb16daa0 to your computer and use it in GitHub Desktop.
Save viliampucik/b346f7c865facbfdb81dffb8cb16daa0 to your computer and use it in GitHub Desktop.
Replay NNMi key incidents
#!/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 <viliam.pucik@hpe.com>
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment