diff options
author | Kristian Lyngstol <kly@kly.no> | 2016-02-21 18:59:40 +0000 |
---|---|---|
committer | Kristian Lyngstol <kly@kly.no> | 2016-02-21 18:59:40 +0000 |
commit | 1a448d0d7c53d25c87d31bd3b175f5b75644f618 (patch) | |
tree | ac91a62ff0928ede012c0c114eeacdc2f43dbbc8 | |
parent | 47e4039f8fae192f268a13b08e64424d835edb83 (diff) |
nms: Refactoring work
Moving SNMP into a separate module reduces startup time for all the stuff
that doesn't need it.
Currently comments are broken because the js hasn't been updated.
-rwxr-xr-x | include/nms.pm | 80 | ||||
-rw-r--r-- | include/nms/snmp.pm | 89 | ||||
-rwxr-xr-x | include/nms/web.pm | 23 | ||||
-rwxr-xr-x | web/nms.gathering.org/comment-change.pl | 22 | ||||
-rwxr-xr-x | web/nms.gathering.org/comment.pl | 3 | ||||
-rwxr-xr-x | web/nms.gathering.org/port-state.pl | 109 |
6 files changed, 140 insertions, 186 deletions
diff --git a/include/nms.pm b/include/nms.pm index 4012cc6..6a9598e 100755 --- a/include/nms.pm +++ b/include/nms.pm @@ -6,7 +6,6 @@ use Net::OpenSSH; use Net::Telnet; use Data::Dumper; use FileHandle; -use SNMP; use JSON; package nms; @@ -18,22 +17,9 @@ BEGIN { eval { require "config.local.pm"; }; - - # $SNMP::debugging = 1; - - # sudo mkdir /usr/share/mibs/site - # cd /usr/share/mibs/site - # wget -O- ftp://ftp.cisco.com/pub/mibs/v2/v2.tar.gz | sudo tar --strip-components=3 -zxvvf - - SNMP::initMib(); - SNMP::addMibDirs("../mibs"); - SNMP::loadModules('SNMPv2-MIB'); - SNMP::loadModules('ENTITY-MIB'); - SNMP::loadModules('IF-MIB'); - SNMP::loadModules('LLDP-MIB'); - SNMP::loadModules('IP-MIB'); - SNMP::loadModules('IP-FORWARD-MIB'); } + sub db_connect { my $connstr = "dbi:Pg:dbname=" . $nms::config::db_name; $connstr .= ";host=" . $nms::config::db_host unless (!defined($nms::config::db_host)); @@ -157,70 +143,6 @@ sub switch_disconnect($) { waitpid($struct->{pid}, 0); } } - -sub snmp_open_session { - my ($ip, $community, $async) = @_; - - $async //= 0; - - my %options = (UseEnums => 1); - if ($ip =~ /:/) { - $options{'DestHost'} = "udp6:$ip"; - } else { - $options{'DestHost'} = "udp:$ip"; - } - - if ($community =~ /^snmpv3:(.*)$/) { - my ($username, $authprotocol, $authpassword, $privprotocol, $privpassword) = split /\//, $1; - - $options{'SecName'} = $username; - $options{'SecLevel'} = 'authNoPriv'; - $options{'AuthProto'} = $authprotocol; - $options{'AuthPass'} = $authpassword; - - if (defined($privprotocol) && defined($privpassword)) { - $options{'SecLevel'} = 'authPriv'; - $options{'PrivProto'} = $privprotocol; - $options{'PrivPass'} = $privpassword; - } - - $options{'Version'} = 3; - } else { - $options{'Community'} = $community; - $options{'Version'} = 2; - } - - my $session = SNMP::Session->new(%options); - if (defined($session) && ($async || defined($session->getnext('sysDescr')))) { - return $session; - } else { - die 'Could not open SNMP session to ' . $ip; - } -} - -# Not currently in use; kept around for reference. -sub fetch_multi_snmp { - my ($session, @oids) = @_; - - my %results = (); - - # Do bulk reads of 40 and 40; seems to be about the right size for 1500-byte packets. - for (my $i = 0; $i < scalar @oids; $i += 40) { - my $end = $i + 39; - $end = $#oids if ($end > $#oids); - my @oid_slice = @oids[$i..$end]; - - my $localresults = $session->get_request(-varbindlist => \@oid_slice); - return undef if (!defined($localresults)); - - while (my ($key, $value) = each %$localresults) { - $results{$key} = $value; - } - } - - return \%results; -} - # A few utilities to convert from SNMP binary address format to human-readable. sub convert_mac { diff --git a/include/nms/snmp.pm b/include/nms/snmp.pm new file mode 100644 index 0000000..b1354ae --- /dev/null +++ b/include/nms/snmp.pm @@ -0,0 +1,89 @@ +#! /usr/bin/perl +use strict; +use warnings; +use SNMP; +use nms; +package nms::snmp; + +use base 'Exporter'; +our @EXPORT = qw(); + +BEGIN { + # $SNMP::debugging = 1; + + # sudo mkdir /usr/share/mibs/site + # cd /usr/share/mibs/site + # wget -O- ftp://ftp.cisco.com/pub/mibs/v2/v2.tar.gz | sudo tar --strip-components=3 -zxvvf - + SNMP::initMib(); + SNMP::addMibDirs("../mibs"); + SNMP::loadModules('SNMPv2-MIB'); + SNMP::loadModules('ENTITY-MIB'); + SNMP::loadModules('IF-MIB'); + SNMP::loadModules('LLDP-MIB'); + SNMP::loadModules('IP-MIB'); + SNMP::loadModules('IP-FORWARD-MIB'); +} + +sub snmp_open_session { + my ($ip, $community, $async) = @_; + + $async //= 0; + + my %options = (UseEnums => 1); + if ($ip =~ /:/) { + $options{'DestHost'} = "udp6:$ip"; + } else { + $options{'DestHost'} = "udp:$ip"; + } + + if ($community =~ /^snmpv3:(.*)$/) { + my ($username, $authprotocol, $authpassword, $privprotocol, $privpassword) = split /\//, $1; + + $options{'SecName'} = $username; + $options{'SecLevel'} = 'authNoPriv'; + $options{'AuthProto'} = $authprotocol; + $options{'AuthPass'} = $authpassword; + + if (defined($privprotocol) && defined($privpassword)) { + $options{'SecLevel'} = 'authPriv'; + $options{'PrivProto'} = $privprotocol; + $options{'PrivPass'} = $privpassword; + } + + $options{'Version'} = 3; + } else { + $options{'Community'} = $community; + $options{'Version'} = 2; + } + + my $session = SNMP::Session->new(%options); + if (defined($session) && ($async || defined($session->getnext('sysDescr')))) { + return $session; + } else { + die 'Could not open SNMP session to ' . $ip; + } +} + +# Not currently in use; kept around for reference. +sub fetch_multi_snmp { + my ($session, @oids) = @_; + + my %results = (); + + # Do bulk reads of 40 and 40; seems to be about the right size for 1500-byte packets. + for (my $i = 0; $i < scalar @oids; $i += 40) { + my $end = $i + 39; + $end = $#oids if ($end > $#oids); + my @oid_slice = @oids[$i..$end]; + + my $localresults = $session->get_request(-varbindlist => \@oid_slice); + return undef if (!defined($localresults)); + + while (my ($key, $value) = each %$localresults) { + $results{$key} = $value; + } + } + + return \%results; +} + diff --git a/include/nms/web.pm b/include/nms/web.pm index b768104..b13fa9a 100755 --- a/include/nms/web.pm +++ b/include/nms/web.pm @@ -1,6 +1,8 @@ #! /usr/bin/perl +# vim:ts=8:sw=8 use strict; use warnings; +use utf8; use CGI qw(fatalsToBrowser); use DBI; use Data::Dumper; @@ -9,14 +11,14 @@ use nms; package nms::web; use base 'Exporter'; -our @EXPORT = qw(finalize_output json cgi dbh); +our @EXPORT = qw(finalize_output json cgi dbh db_safe_quote); our $cgi; -our %json = (); +our %json; our $dbh; our $now; our $when; our $ifname; -our %cc = (); +our %cc; # Print cache-control from %cc sub printcc { @@ -29,13 +31,26 @@ sub printcc { print 'Cache-Control: ' . $line . "\n"; } +sub db_safe_quote { + my $word = $_[0]; + my $term = $cgi->param($word); + if (!defined($term)) { + if(defined($_[1])) { + $term = $_[1]; + } else { + die "Missing CGI param $word"; + } + } + return $dbh->quote($term) || die; +} + # returns a valid $when statement # Also sets cache-control headers if time is overridden sub setwhen { my $when; $now = "now()"; if (defined($cgi->param('now'))) { - $now = "'" . $cgi->param('now') . "'::timestamp "; + $now = db_safe_quote('now') . "::timestamp "; $cc{'max-age'} = "3600"; } $when = " time > " . $now . " - '5m'::interval and time < " . $now . " "; diff --git a/web/nms.gathering.org/comment-change.pl b/web/nms.gathering.org/comment-change.pl index 13ed058..d860777 100755 --- a/web/nms.gathering.org/comment-change.pl +++ b/web/nms.gathering.org/comment-change.pl @@ -1,24 +1,20 @@ #! /usr/bin/perl -use CGI qw(fatalsToBrowser); -use DBI; +# vim:ts=8:sw=8 use lib '../../include'; use utf8; use nms; +use nms::web; use strict; use warnings; -use Data::Dumper; -my $cgi = CGI->new; +my $id = db_safe_quote('comment'); +my $state = db_safe_quote('state'); -my $dbh = nms::db_connect(); - -my $id = $dbh->quote($cgi->param('comment') || die ); -my $state= $dbh->quote($cgi->param('state') || die); - - -my $q = $dbh->prepare("UPDATE switch_comments SET state = " . $state . " WHERE id = " . $id . ";"); +my $q = $nms::web::dbh->prepare("UPDATE switch_comments SET state = " . $state . " WHERE id = " . $id . ";"); $q->execute(); -print $cgi->header(-type=>'text/json; charset=utf-8'); -print "{ 'state': 'ok' }"; +$nms::web::cc{'max-age'} = '0'; +$nms::web::cc{'stale-while-revalidate'} = '0'; +$nms::web::json{'state'} = 'ok'; +finalize_output(); diff --git a/web/nms.gathering.org/comment.pl b/web/nms.gathering.org/comment.pl index d22dcdc..7a45d76 100755 --- a/web/nms.gathering.org/comment.pl +++ b/web/nms.gathering.org/comment.pl @@ -5,9 +5,8 @@ use lib '../../include'; use nms::web; use strict; use warnings; -use Data::Dumper; -my $query = $nms::web::dbh->prepare('select sysname,extract(epoch from date_trunc(\'second\',time)) as time,state,username,id,comment from switch_comments natural join switches where state != \'delete\' order by time desc limit 1'); +my $query = $nms::web::dbh->prepare('select sysname,extract(epoch from date_trunc(\'second\',time)) as time,state,username,id,comment from switch_comments natural join switches where state != \'delete\' order by time desc'); $query->execute(); while (my $ref = $query->fetchrow_hashref()) { push @{$nms::web::json{'comments'}{$ref->{'sysname'}}{'comments'}},$ref; diff --git a/web/nms.gathering.org/port-state.pl b/web/nms.gathering.org/port-state.pl index e3dc24a..e48e23a 100755 --- a/web/nms.gathering.org/port-state.pl +++ b/web/nms.gathering.org/port-state.pl @@ -5,119 +5,52 @@ use CGI qw(fatalsToBrowser); use DBI; use lib '../../include'; use nms; +use nms::web; use strict; use warnings; use Data::Dumper; -my $cgi = CGI->new; - -my %cc = (); -$cc{'stale-while-revalidate'} = "3600"; -$cc{'max-age'} = "5"; - -# Print cache-control from %cc -sub printcc { - my $line = ""; - my $first = ""; - foreach my $tmp (keys(%cc)) { - $line .= $first . $tmp . "=" . $cc{$tmp}; - $first = ", "; - } - print 'Cache-Control: ' . $line . "\n"; -} - -# FIXME: Shouldn't be magic. -# Only used for setting time in result from DB time. -# FIXME: Clarification, this _has_ to be set before setwhen is run, -# since it secretly overrides it. -my $now; - -# returns a valid $when statement -# Also sets cache-control headers if time is overridden -sub setwhen { - my $when; - $now = "now()"; - if (defined($cgi->param('now'))) { - $now = "'" . $cgi->param('now') . "'::timestamp "; - $cc{'max-age'} = "3600"; - } - $when = " time > " . $now . " - '5m'::interval and time < " . $now . " "; - return $when; -} - -# Sets the ifname. If we are logged in, it's simply set to "ifname", otherwise -# it's hashed for anonymization. -sub obfuscateifname { - my $ifname = "ifname"; - if (defined($cgi->param('public'))) { - $ifname = "regexp_replace(ifname, 'ge-0/0/(([0-3][0-9])|(4[0-3])|([0-9]))\$',concat('ge-participant',sha1_hmac(ifname::bytea,'".$nms::config::nms_hash."'::bytea))) as ifname"; - } - return $ifname; -} - - -my %json = (); -my $dbh = nms::db_connect(); -my $when = setwhen; -my $ifname = obfuscateifname; - -my $query = 'select sysname,extract(epoch from date_trunc(\'second\',time)) as time, '.$ifname.',ifhighspeed,ifhcinoctets,ifhcoutoctets from polls natural join switches where time in (select max(time) from polls where ' . $when . ' group by switch,ifname);'; -my $q = $dbh->prepare($query); +my $query = 'select sysname,extract(epoch from date_trunc(\'second\',time)) as time, '.$nms::web::ifname.',ifhighspeed,ifhcinoctets,ifhcoutoctets from polls natural join switches where time in (select max(time) from polls where ' . $nms::web::when . ' group by switch,ifname);'; +my $q = $nms::web::dbh->prepare($query); $q->execute(); while (my $ref = $q->fetchrow_hashref()) { my @fields = ('ifhighspeed','ifhcoutoctets','ifhcinoctets'); foreach my $val (@fields) { - $json{'switches'}{$ref->{'sysname'}}{'ports'}{$ref->{'ifname'}}{$val} = $ref->{$val}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'ports'}{$ref->{'ifname'}}{$val} = $ref->{$val}; } - $json{'switches'}{$ref->{'sysname'}}{'ports'}{$ref->{'ifname'}}{'time'} = $ref->{'time'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'ports'}{$ref->{'ifname'}}{'time'} = $ref->{'time'}; } -my $q2 = $dbh->prepare('select switch,sysname,placement,ip,switchtype,poll_frequency,community,last_updated from switches natural join placements'); -my $q3 = $dbh->prepare('select distinct on (switch) switch,temp,time,sysname from switch_temp natural join switches where ' . $when . ' order by switch,time desc'); +my $q2 = $nms::web::dbh->prepare('select switch,sysname,placement,ip,switchtype,poll_frequency,community,last_updated from switches natural join placements'); +my $q3 = $nms::web::dbh->prepare('select distinct on (switch) switch,temp,time,sysname from switch_temp natural join switches where ' . $nms::web::when . ' order by switch,time desc'); $q2->execute(); while (my $ref = $q2->fetchrow_hashref()) { $ref->{'placement'} =~ /\((-?\d+),(-?\d+)\),\((-?\d+),(-?\d+)\)/; my ($x1, $y1, $x2, $y2) = ($1, $2, $3, $4); my $sysname = $ref->{'sysname'}; - $json{'switches'}{$ref->{'sysname'}}{'switchtype'} = $ref->{'switchtype'}; - $json{'switches'}{$ref->{'sysname'}}{'management'}{'ip'} = $ref->{'ip'}; - $json{'switches'}{$ref->{'sysname'}}{'management'}{'poll_frequency'} = $ref->{'poll_frequency'}; - $json{'switches'}{$ref->{'sysname'}}{'management'}{'community'} = $ref->{'community'}; - $json{'switches'}{$ref->{'sysname'}}{'management'}{'last_updated'} = $ref->{'last_updated'}; - $json{'switches'}{$ref->{'sysname'}}{'placement'}{'x'} = $x2; - $json{'switches'}{$ref->{'sysname'}}{'placement'}{'y'} = $y2; - $json{'switches'}{$ref->{'sysname'}}{'placement'}{'width'} = $x1 - $x2; - $json{'switches'}{$ref->{'sysname'}}{'placement'}{'height'} = $y1 - $y2; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'switchtype'} = $ref->{'switchtype'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'management'}{'ip'} = $ref->{'ip'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'management'}{'poll_frequency'} = $ref->{'poll_frequency'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'management'}{'community'} = $ref->{'community'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'management'}{'last_updated'} = $ref->{'last_updated'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'placement'}{'x'} = $x2; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'placement'}{'y'} = $y2; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'placement'}{'width'} = $x1 - $x2; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'placement'}{'height'} = $y1 - $y2; } $q3->execute(); while (my $ref = $q3->fetchrow_hashref()) { my $sysname = $ref->{'sysname'}; - $json{'switches'}{$ref->{'sysname'}}{'temp'} = $ref->{'temp'}; - $json{'switches'}{$ref->{'sysname'}}{'temp_time'} = $ref->{'time'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'temp'} = $ref->{'temp'}; + $nms::web::json{'switches'}{$ref->{'sysname'}}{'temp_time'} = $ref->{'time'}; } -my $q4 = $dbh->prepare(' select linknet, (select sysname from switches where switch = switch1) as sysname1, addr1, (select sysname from switches where switch = switch2) as sysname2,addr2 from linknets'); +my $q4 = $nms::web::dbh->prepare(' select linknet, (select sysname from switches where switch = switch1) as sysname1, addr1, (select sysname from switches where switch = switch2) as sysname2,addr2 from linknets'); $q4->execute(); while (my $ref = $q4->fetchrow_hashref()) { - $json{'linknets'}{$ref->{'linknet'}} = $ref; -# push @{$json{'linknets'}}, $ref; + $nms::web::json{'linknets'}{$ref->{'linknet'}} = $ref; } -my $q5; -$q5 = $dbh->prepare ('select ' . $now . ' as time;'); -$q5->execute(); -$json{'time'} = $q5->fetchrow_hashref()->{'time'}; - -my $q6 = $dbh->prepare('select sysname,extract(epoch from date_trunc(\'second\',time)) as time,state,username,id,comment from switch_comments natural join switches where state != \'delete\' order by time desc'); -$q6->execute(); -while (my $ref = $q6->fetchrow_hashref()) { - push @{$json{'switches'}{$ref->{'sysname'}}{'comments'}},$ref; -} - -$json{'username'} = $cgi->remote_user(); -printcc; - -print $cgi->header(-type=>'text/json; charset=utf-8'); -print JSON::XS::encode_json(\%json); +finalize_output(); |