From d6cfbb682b3492d24b6623fbf1345c5b2b95f230 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 29 Mar 2006 12:22:57 +0000 Subject: [PATCH] initial import (automatically generated log message) --- clients/dhcptail.pl | 40 ++ clients/makeplace.pl | 25 + clients/smanagrun.pl | 149 +++++ clients/snmp.sql | 24 + clients/snmpfetch.pl | 275 ++++++++ clients/switchfix.pl | 98 +++ clients/switchport.pl | 75 +++ web/dhcpkart.pl | 80 +++ web/index.html | 62 ++ web/make-switches.pl | 85 +++ web/mygraph.pl | 178 ++++++ web/nettkart-telnet.pl | 49 ++ web/nettkart-text.pl | 49 ++ web/nettkart-web.pl | 49 ++ web/nettkart.pl | 68 ++ web/nms.sql | 1369 ++++++++++++++++++++++++++++++++++++++++ web/overlay.pl | 160 +++++ web/portkart.pl | 71 +++ web/sendsms.pl | 55 ++ web/showswitch.pl | 215 +++++++ web/smanagement.pl | 273 ++++++++ web/snmp-bg.png | Bin 0 -> 54273 bytes web/ssendfile.pl | 91 +++ web/sshow.pl | 269 ++++++++ web/stemp-bg5.png | Bin 0 -> 3036 bytes web/stempmap-ptn.pl | 57 ++ web/stempmap.pl | 96 +++ web/streaming.pl | 25 + web/tempfetch.pl | 139 ++++ 29 files changed, 4126 insertions(+) create mode 100755 clients/dhcptail.pl create mode 100644 clients/makeplace.pl create mode 100755 clients/smanagrun.pl create mode 100644 clients/snmp.sql create mode 100755 clients/snmpfetch.pl create mode 100755 clients/switchfix.pl create mode 100755 clients/switchport.pl create mode 100755 web/dhcpkart.pl create mode 100644 web/index.html create mode 100644 web/make-switches.pl create mode 100755 web/mygraph.pl create mode 100755 web/nettkart-telnet.pl create mode 100755 web/nettkart-text.pl create mode 100755 web/nettkart-web.pl create mode 100755 web/nettkart.pl create mode 100644 web/nms.sql create mode 100755 web/overlay.pl create mode 100755 web/portkart.pl create mode 100755 web/sendsms.pl create mode 100755 web/showswitch.pl create mode 100755 web/smanagement.pl create mode 100644 web/snmp-bg.png create mode 100755 web/ssendfile.pl create mode 100755 web/sshow.pl create mode 100644 web/stemp-bg5.png create mode 100755 web/stempmap-ptn.pl create mode 100755 web/stempmap.pl create mode 100755 web/streaming.pl create mode 100644 web/tempfetch.pl diff --git a/clients/dhcptail.pl b/clients/dhcptail.pl new file mode 100755 index 0000000..044c817 --- /dev/null +++ b/clients/dhcptail.pl @@ -0,0 +1,40 @@ +#! /usr/bin/perl +use DBI; +use POSIX; +use strict; +use warnings; + +# WARNING: CHANGE THIS! :-P +my $year = 2005; + +my %months = ( + Jan => 1, + Feb => 2, + Mar => 3, + Apr => 4, + May => 5, + Jun => 6, + Jul => 7, + Aug => 8, + Sep => 9, + Oct => 10, + Nov => 11, + Dec => 12 +); + +my ($dbh, $q); +while (<>) { + /(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d+)\s+(\d+:\d+:\d+).*DHCPACK on (\d+\.\d+\.\d+\.\d+)/ or next; + my $date = $year . "-" . $months{$1} . "-" . $2 . " " . $3; + + if (!defined($dbh) || !$dbh->ping) { + $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + $q = $dbh->prepare("UPDATE dhcp SET last_ack=? WHERE inet ? << network AND ( last_ack < ? OR last_ack IS NULL )") + or die "Couldn't prepare query"; + } + + print STDERR "$date $4\n"; + $q->execute($date, $4, $date) + or die "Couldn't push $1 into database"; +} diff --git a/clients/makeplace.pl b/clients/makeplace.pl new file mode 100644 index 0000000..5c20d09 --- /dev/null +++ b/clients/makeplace.pl @@ -0,0 +1,25 @@ +#! /usr/bin/perl + +my $x = 308; +my $y = 385; +my $done = 0; + +while (<>) { + chomp (my $switch = $_); + print "DELETE FROM placements WHERE switch=$switch;\n"; + printf "INSERT INTO placements VALUES ( $switch, '(%u,%u,%u,%u)');\n", + $x, $y, $x + 14, $y + 51; + $y += 51; + if ($y > 500) { + $y = 385; + $x += 18; + if ($x > 410 && $done == 0) { + $x += 13; + $done = 1; + } + if ($x > 570 && $done == 1) { + $x += 12; + $done = 2; + } + } +} diff --git a/clients/smanagrun.pl b/clients/smanagrun.pl new file mode 100755 index 0000000..e66cfd2 --- /dev/null +++ b/clients/smanagrun.pl @@ -0,0 +1,149 @@ +#!/usr/bin/perl +# +# + +use warnings; +use strict; +use Net::Telnet; +use DBI; +use POSIX; + +# Tweak and check +my $password = 'removed'; +my $timeout = 15; +my $delaytime = 30; +my $poll_frequency = 60; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", + "snmpfetch", "removed") + or die "Couldn't connect to database"; +$dbh->{AutoCommit} = 0; + +my $spoll = $dbh->prepare(" +SELECT + addr, + sysname +FROM + squeue +WHERE + processed = 'f' AND + disabled = 'f' AND + (locked='f' OR now() - updated > '3 minutes'::interval) AND + (delay IS NULL OR delay - now() < 0) +ORDER BY + priority DESC, + added +LIMIT 1"); +my $sgetallpoll = $dbh->prepare(" +SELECT + id, + gid, + addr, + sysname, + cmd +FROM + squeue +WHERE + sysname = ? AND + disabled = 'f' AND + processed = 'f' +ORDER BY + priority DESC, + added"); + +my $slock = $dbh->prepare("UPDATE squeue SET locked = 't', updated=now() WHERE sysname = ?") + or die "Unable to prepare slock"; +my $sunlock = $dbh->prepare("UPDATE squeue SET locked = 'f', updated=now() WHERE sysname = ?") + or die "Unable to prepare sunlock"; +my $sresult = $dbh->prepare("UPDATE squeue SET updated = now(), result = ?, + processed = 't' WHERE id = ?") + or die "Unable to prepare sresult"; +my $sdelay = $dbh->prepare("UPDATE squeue SET delay = now() + delaytime, updated=now(), result = ? WHERE sysname = ?") + or die "Unable to prepae sdelay"; + +# Send a command to switch and return the data recvied from the switch +sub switch_exec($$) { + my ($cmd, $conn) = @_; + + # Send the command and get data from switch + my @data = $conn->cmd($cmd); + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push (@lines, $line); + } + + return @data; +} + +sub switch_connect($) { + my ($ip) = @_; + + my $conn = new Net::Telnet( Timeout => $timeout, + Dump_Log => '/tmp/dumplog-queue', + Errmode => 'return', + Prompt => '/es(\-)?3024|e\d+\-\dsw>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (undef); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login(»·Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + $conn->cmd($password); + # Get rid of banner + $conn->get; + return ($conn); +} + +sub mylog { + my $msg = shift; + my $time = POSIX::ctime(time); + $time =~ s/\n.*$//; + printf STDERR "[%s] %s\n", $time, $msg; +} + +while (1) { + $spoll->execute() or die "Could not execute spoll"; + my $switch = $spoll->fetchrow_hashref(); + if (!defined($switch)) { + $dbh->commit; + mylog("No available switches in pool, sleeping."); + sleep 60; + next; + } + $slock->execute($switch->{sysname}); + $dbh->commit(); + + if ($switch->{'locked'}) { + mylog("WARNING: Lock timed out on $switch->{'ip'}, breaking lock"); + } + + my $conn = switch_connect($switch->{addr}); + if (!defined($conn)) { + mylog("Could not connect to ".$switch->{sysname})."(".$switch->{addr}.")"; + $sdelay->execute("Could not connect to switch, delaying...", $switch->{sysname}); + $sunlock->execute($switch->{sysname}); + $dbh->commit(); + next; + } + my $error; + $error = $sgetallpoll->execute($switch->{sysname}); + if (!$error) { + print "Could not execute sgetallpoll\n".$dbh->errstr(); + $conn->close; + next; + } + while (my $row = $sgetallpoll->fetchrow_hashref()) { + print "sysname: ".$row->{sysname}." cmd: ".$row->{cmd}."\n"; + my @data = switch_exec($row->{cmd}, $conn); + my $result = join("\n", @data); + $sresult->execute($result, $row->{id}); + } + $conn->close(); + $sunlock->execute($switch->{sysname}); +} + diff --git a/clients/snmp.sql b/clients/snmp.sql new file mode 100644 index 0000000..47b4458 --- /dev/null +++ b/clients/snmp.sql @@ -0,0 +1,24 @@ +create table switchtypes ( + switchtype varchar not null primary key, + ports varchar not null +); + +create table switches ( + switch serial not null primary key, + ip inet not null, + sysname varchar not null, + switchtype varchar not null references switchtypes, + last_updated timestamp, + locked boolean not null default 'f' +); + +create table poll ( + time timestamp not null, + switch integer not null references switches, + port integer not null, + bytes_in bigint not null, + bytes_out bigint not null, + + primary key ( time, switch, port ) +); +create index poll_switch_port on poll ( switch, port ); diff --git a/clients/snmpfetch.pl b/clients/snmpfetch.pl new file mode 100755 index 0000000..fa50f60 --- /dev/null +++ b/clients/snmpfetch.pl @@ -0,0 +1,275 @@ +#! /usr/bin/perl +use BER; +use DBI; +use POSIX; +use Time::HiRes; +use Net::Telnet; +use strict; +use warnings; +require 'SNMP_Session.pm'; + +my $password = 'removed'; +my $timeout = 15; + +my $dbh = DBI->connect("dbi:Pg:dbname=nms;host=localhost", "nms", "nms") + or die "Couldn't connect to database"; +$dbh->{AutoCommit} = 0; + +# normal mode: fetch switches from the database +# instant mode: poll the switches specified on the command line +my $instant = (defined($ARGV[0])); +my $qualification; +if ($instant) { + $qualification = "sysname=?"; +} else { + $qualification = <<"EOF"; + (last_updated IS NULL OR now() - last_updated > poll_frequency) + AND (locked='f' OR now() - last_updated > '15 minutes'::interval) +EOF +} + +my $qswitch = $dbh->prepare(<<"EOF") +SELECT + *, + DATE_TRUNC('second', now() - last_updated - poll_frequency) AS overdue +FROM + switches + NATURAL LEFT JOIN switchtypes +WHERE $qualification +ORDER BY + priority DESC, + overdue DESC +LIMIT 1 +FOR UPDATE OF switches +EOF + or die "Couldn't prepare qswitch"; +my $qlock = $dbh->prepare("UPDATE switches SET locked='t', last_updated=now() WHERE switch=?") + or die "Couldn't prepare qlock"; +my $qunlock = $dbh->prepare("UPDATE switches SET locked='f', last_updated=now() WHERE switch=?") + or die "Couldn't prepare qunlock"; +my $qpoll = $dbh->prepare("INSERT INTO polls (time, switch, port, bytes_in, bytes_out) VALUES (timeofday()::timestamp,?,?,?,?)") + or die "Couldn't prepare qpoll"; +my $qtemppoll = $dbh->prepare("INSERT INTO temppoll (time, switch, temp) VALUES (timeofday()::timestamp,?::text::int,?::text::float)") + or die "Couldn't prepare qtemppoll"; +my $qcpupoll = $dbh->prepare("INSERT INTO cpuloadpoll (time, switch, entity, value) VALUES (timeofday()::timestamp,?::text::int,?,?)") + or die "Couldn't prepare qtemppoll"; + +while (1) { + my $sysname; + if ($instant) { + $sysname = shift @ARGV; + exit if (!defined($sysname)); + $qswitch->execute($sysname) + or die "Couldn't get switch"; + } else { + # Find a switch to grab + $qswitch->execute() + or die "Couldn't get switch"; + } + my $switch = $qswitch->fetchrow_hashref(); + + if (!defined($switch)) { + $dbh->commit; + + if ($instant) { + mylog("No such switch $sysname available, quitting."); + exit; + } else { + mylog("No available switches in pool, sleeping."); + sleep 60; + next; + } + } + + $qlock->execute($switch->{'switch'}) + or die "Couldn't lock switch"; + $dbh->commit; + + if ($switch->{'locked'}) { + mylog("WARNING: Lock timed out on $switch->{'ip'}, breaking lock"); + } + + my $msg; + if (defined($switch->{'overdue'})) { + $msg = sprintf "Polling ports %s on %s (%s), %s overdue.", + $switch->{'ports'}, $switch->{'ip'}, $switch->{'sysname'}, $switch->{'overdue'}; + } else { + $msg = sprintf "Polling ports %s on %s (%s), never polled before.", + $switch->{'ports'}, $switch->{'ip'}, $switch->{'sysname'}; + } + mylog($msg); + + my $ip = $switch->{'ip'}; + + if ($ip eq '127.0.0.1') { + mylog("Polling disabled for this switch, skipping."); + $qunlock->execute($switch->{'switch'}) + or die "Couldn't unlock switch"; + $dbh->commit; + next; + } + + my $community = $switch->{'community'}; + my $start = [Time::HiRes::gettimeofday]; + eval { + my $session; + if ($switch->{'wide_counters'}) { + $session = SNMPv2c_Session->open($ip, $community, 161) + or die "Couldn't talk to switch"; + } else { + $session = SNMP_Session->open($ip, $community, 161) + or die "Couldn't talk to switch"; + } + my @ports = expand_ports($switch->{'ports'}); + + for my $port (@ports) { + my $in = fetch_data($session, $port, 0, $switch->{'wide_counters'}); + my $out = fetch_data($session, $port, 1, $switch->{'wide_counters'}); + + $qpoll->execute($switch->{'switch'}, $port, $in, $out); + } + my $conn = switch_connect($ip); + if (!defined($conn)) { + print "Could not connect to switch ".$switch->{'switch'}."\n"; + } elsif ($switch->{'switchtype'} eq 'es3024') { + my @data = switch_exec('sys monitor status', $conn); + my @fields = split(/\s+/, $data[2]); + # The temp fields are 6, 7, 8 + print "$fields[7] + $fields[8] + $fields[9]\n"; + my $avgtemp = ($fields[7] + $fields[8] + $fields[9]) / 3; + print $avgtemp." avgtemp\n"; + $qtemppoll->execute($switch->{'switch'}, + $avgtemp) or die "Could not exec qtemppoll"; + } elsif ($switch->{'switchtype'} eq 'cisco6509') { + for my $i (1..5) { + # find the ID + my $oid = BER::encode_oid(1, 3, 6, 1, 4, 1, 9, 9, 109, 1, 1, 1, 1, 2, $i); + my $entity = fetch_snmp($session, $oid); + + next if (!defined($entity)); + + # last-minute load for the given entity + $oid = BER::encode_oid(1, 3, 6, 1, 4, 1, 9, 9, 109, 1, 1, 1, 1, 4, $i); + my $value = fetch_snmp($session, $oid); + + $qcpupoll->execute($switch->{'switch'}, $entity, $value) + or die "Could not exec qcpupoll"; + } + } + $session->close; + }; + if ($@) { + mylog("ERROR: $@ (during poll of $ip)"); + $dbh->rollback; + } + + my $elapsed = Time::HiRes::tv_interval($start); + $msg = sprintf "Polled $switch->{'ip'} in %5.3f seconds.", $elapsed; + mylog($msg); + + $qunlock->execute($switch->{'switch'}) + or die "Couldn't unlock switch"; + $dbh->commit; +} + +sub fetch_data { + my ($session, $port, $out, $wide_counters) = @_; + + my $oid; + if ($wide_counters) { + if ($out) { + $oid = BER::encode_oid(1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 10, $port); # interfaces.ifTable.ifEntry.ifHCOutOctets + } else { + $oid = BER::encode_oid(1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 6, $port); # interfaces.ifTable.ifEntry.ifHCInOctets + } + } else { + if ($out) { + $oid = BER::encode_oid(1, 3, 6, 1, 2, 1, 2, 2, 1, 16, $port); # interfaces.ifTable.ifEntry.ifOutOctets + } else { + $oid = BER::encode_oid(1, 3, 6, 1, 2, 1, 2, 2, 1, 10, $port); # interfaces.ifTable.ifEntry.ifInOctets + } + } + + return fetch_snmp($session, $oid); +} + +sub fetch_snmp { + my ($session, $oid) = @_; + + if ($session->get_request_response($oid)) { + my ($bindings) = $session->decode_get_response ($session->{pdu_buffer}); + my $binding; + while ($bindings ne '') { + ($binding,$bindings) = &decode_sequence ($bindings); + my ($oid,$value) = &decode_by_template ($binding, "%O%@"); + return BER::pretty_print($value); + } + } + die "Couldn't get info from switch"; +} + +sub expand_ports { + my $in = shift; + my @ranges = split /,/, $in; + my @ret = (); + + for my $range (@ranges) { + if ($range =~ /^\d+$/) { + push @ret, $range; + } elsif ($range =~ /^(\d+)-(\d+)$/) { + for my $i ($1..$2) { + push @ret, $i; + } + } else { + die "Couldn't understand '$range' in ports"; + } + } + + return (sort { $a <=> $b } @ret); +} + +sub mylog { + my $msg = shift; + my $time = POSIX::ctime(time); + $time =~ s/\n.*$//; + printf STDERR "[%s] %s\n", $time, $msg; +} + +sub switch_exec { + my ($cmd, $conn) = @_; + + # Send the command and get data from switch +# $conn->dump_log(*STDOUT); + my @data = $conn->cmd($cmd); + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push @lines, $line; + } + + return @lines; +} + +sub switch_connect { + my ($ip) = @_; + + my $conn = new Net::Telnet( Timeout => $timeout, + Dump_Log => '/tmp/dumplog-tempfetch', + Errmode => 'return', + Prompt => '/es-3024|e(\-)?\d+\-\dsw>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (0); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login( Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + my @data = $conn->cmd($password); + # Get rid of banner + $conn->get; + return $conn; +} + diff --git a/clients/switchfix.pl b/clients/switchfix.pl new file mode 100755 index 0000000..536e868 --- /dev/null +++ b/clients/switchfix.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl +use strict; +use warnings; +use DBI; +use Getopt::Long; +use LWP::UserAgent; +{ + package RequestAgent; + our @ISA = qw(LWP::UserAgent); + + sub new { + return LWP::UserAgent::new(@_); + } + + sub get_basic_credentials { + return ("admin", "removed"); + } +} + +# CONFIG +my $read = 0; +my $write = 0; +GetOptions ("read|r" => \$read, "write|w" => \$write); +my $target_mask = $ARGV[0] ? $ARGV[0] : 'e%-%sw'; + + +# ACTION +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", + "snmpfetch", "removed") + or die "Couldn't connect to database"; + +my $sth = $dbh->prepare("SELECT sysname,ip FROM switches WHERE sysname LIKE ? ORDER BY ip"); +$sth->execute($target_mask); + +while (my ($sysname,$ip) = $sth->fetchrow_array) { + my ($gw, $mgmnt); + + # Autodefine + if ($ip =~ /(\d+\.\d+\.\d*)(\d)\.\d+/) { + $gw = $1.$2.".1"; + $mgmnt = "90$2"; + } else { + print "$sysname\t($ip):\tAieeh! IP parsing fuckup!\n"; + next; + } + + # Define + my $url = "http://$ip/Forms/rpip_1"; + my %shit = ( + "rpip_RpgDHCP" => "1", + "rpip_IptIPAddr" => "$ip", + "rpip_IptSubnetMask" => "255.255.255.0", + "rpip_IptDefaultGateway" => "$gw", + "rpip_IptDNS" => "0.0.0.0", + "rpip_IptVID" => "$mgmnt", + "rpip_HidBtnNum" => "1" + ); + + # Check + my $found = 0; + open(NMAP, "nmap -p80 $ip|"); + while() { + if(/^80\/tcp\s+open/) { + $found = 1; + } + } + if(!$found) { + print "$sysname\t($ip):\tNo reply on port 80\n"; + next; + } + + # Read + if ($read) { + print "$sysname\t($ip):\t"; + + my $ua = RequestAgent->new; + my $res = $ua->get("http://$ip/rpip.html"); + if ($res->is_success) { + foreach (split("\n", $res->content)) { + if (/.*rpip_IptDefaultGateway" .* VALUE="([^"]+)">/) { + print "default route $1\n"; + } + } + } else { + print $res->status_line, "\n"; + } + } + + # Rape + if ($write) { + print "$sysname\t($ip):\t"; + + my $ua = RequestAgent->new; + my $res = $ua->post($url, \%shit); + + print $res->status_line, "\n"; + } +} diff --git a/clients/switchport.pl b/clients/switchport.pl new file mode 100755 index 0000000..3802509 --- /dev/null +++ b/clients/switchport.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl +# +# + +use warnings; +use strict; +use Net::Telnet; + +# Tweak and check +my $password = 'removed'; +my $timeout = 15; + +sub switch_exec($$) { + my ($cmd, $conn) = @_; + + # Send the command and get data from switch + my @data = $conn->cmd($cmd); + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push (@lines, $line); + } + + return @data; +} + +sub switch_connect($) { + my ($ip) = @_; + +# Errmode => 'return', + my $conn = new Net::Telnet( Timeout => $timeout, + Dump_Log => 'dumplog', + Prompt => '/es(\-)?3024|e(\-)?\d+\-\dsw>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (undef); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login(»·Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + $conn->cmd($password); + # Get rid of banner + $conn->get; + return ($conn); +} + +sub switch_get_arp($) { + my ($conn) = @_; + + my @data = switch_exec('ip arp status', $conn); + foreach (@data) { +# 81.162.241.1 Ethernet 300 00:e0:2b:e0:f3:00 41 swif0 swp24 + $_ =~ /(\d+\.\d+\.\d+\.\d+)\s+\w+\s+\d+\s+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)\s+\d+\s+\w+\s+(\w+)/; + next if (!defined($1)); + next if ($3 eq "NULL"); + print "$1 $2 $3\n"; + } + return @data; +} + +my $conn = switch_connect($ARGV[0]); +if (!defined($conn)) { + die "something went wrong!"; +} +my @data = switch_exec('sys monitor status', $conn); +my @fields = split(/\s+/, $data[2]); +# The temp fields are 6, 7, 8 +print "$fields[7] + $fields[8] + $fields[9]\n"; +my $avgtemp = ($fields[7] + $fields[8] + $fields[9]) / 3; +print $avgtemp." avgtemp\n"; +$conn->close(); + diff --git a/web/dhcpkart.pl b/web/dhcpkart.pl new file mode 100755 index 0000000..2558fb9 --- /dev/null +++ b/web/dhcpkart.pl @@ -0,0 +1,80 @@ +#! /usr/bin/perl +use CGI; +use GD; +use DBI; +my $cgi = CGI->new; + +my $greentimeout = 900; +my $maxtimeout = $greentimeout*9; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +GD::Image->trueColor(1); +$img = GD::Image->new('snmp-bg.png'); + +my $blk = $img->colorResolve(0, 0, 0); + +$img->string(gdMediumBoldFont,0,0,"TG05 - DHCP-lease status",$blk); +$img->string(gdSmallFont,0,20,"Last recieved DHCP-request",$blk); + +# first 1/5: green (<30 min) +# middle 3/5: yellow -> red (30 min - 6 hours) +# last 1/5: blue (>6 hours) +my $grn = $img->colorResolve(0, 255, 0); +my $blu = $img->colorResolve(0, 0, 255); + +my $l1 = 42 + (236 - 42)/5; +my $l2 = 236 - (236 - 42)/5; + +$img->filledRectangle(32, 42, 53, $l1, $grn); +$img->string(gdSmallFont,56,$l1-8,($greentimeout/60)." min",$blk); + +$img->filledRectangle(32, $l2, 53, 237, $blu); +$img->string(gdSmallFont,56,$l2-5,($maxtimeout/60)." min",$blk); + +for my $y ($l1..$l2) { + my $i = 1.0 - ($y - $l1) / ($l2 - $l1); + my $clr = get_color($i); + + $img->filledRectangle(32,$y,53,$y+1,$clr); +} + +my $q = $dbh->prepare('select switch,sysname,placement,EXTRACT(EPOCH FROM now() - last_ack) as age from switches natural join placements natural join dhcp'); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + my $age = $ref->{'age'}; + if (!defined($age) || $age > $maxtimeout) { + $clr = $img->colorResolve(0, 0, 255); + } elsif ($age < $greentimeout) { + $clr = $img->colorResolve(0, 255, 0); + } else { + # 30 minutes = 0.0 + # 6 hours = 1.0 + + my $intensity = log($age / $greentimeout) / log($maxtimeout/$greentimeout); + $clr = get_color(1.0 - $intensity); + } + + $_ = $ref->{'sysname'}; + if (!m/d0/i) { # don't draw distro-switches + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + $img->filledRectangle($3,$4,$1,$2,$clr); + $img->rectangle($3,$4,$1,$2,$blk); + + $img->stringUp(gdSmallFont,$3,$2-3,$ref->{'sysname'},$blk); + } +} +$dbh->disconnect; + +if (!defined($ARGV[0])) { + print $cgi->header(-type=>'image/png', + -refresh=>'10; http://nms.tg05.gathering.org/dhcpkart.pl'); +} +print $img->png; + +sub get_color { + my $intensity = shift; + my $gamma = 1.0/1.90; + return $img->colorResolve(255.0, 255.0 * ($intensity ** $gamma), 0); +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..5036d8c --- /dev/null +++ b/web/index.html @@ -0,0 +1,62 @@ + + + snmp + + +

tg light & magic. :-)

+ + + + diff --git a/web/make-switches.pl b/web/make-switches.pl new file mode 100644 index 0000000..a728ec2 --- /dev/null +++ b/web/make-switches.pl @@ -0,0 +1,85 @@ +#! /usr/bin/perl + +print "delete from temppoll;\n"; +print "delete from placements;\n"; +print "delete from dhcp;\n"; +print "delete from switches;\n"; +print "SELECT pg_catalog.setval('switches_switch_seq', 1, false);\n"; +print "SELECT pg_catalog.setval('polls_poll_seq', 1, false);\n"; + +my $cc = 241; +my $dd = 0; + +my $i = 1; +for $e (1..73) { + next if ($e % 2 == 0); + + for $s (1..6) { + next if ($s < 4 && $e < 5); + next if ($s >= 4 && $e > 72); + + next if ($e >= 69 && ($s == 1 || $s == 6)); + + my $x = int(285 + $e * 9.45); + my $y; + + $x += 7 if ($e >= 19); + $x += 14 if ($e >= 35); + $x += 9 if ($e >= 51); + $x += 9 if ($e >= 68 && $s < 4); + + my ($c, $d); + if ($s <= 3) { + $c = $e; + $d = ($s - 1) * 64; + + $y = 470 - $s * 48; + } else { + $c = $e + 1; + $d = ($s - 4) * 64; + + $y = 450 - $s * 48 - ($s - 3) * 2; + } + + my $xx = $x + 12; + my $yy = $y + (($s > 3) ? 50 : 48); + + $dk = $dd + 7 + ($cc - 241) * 42; + + # lasses magic-factor =) + $dk += 4; + if ($dk > 13) { + $dk += 3; + } + + print "insert into switches (ip, sysname, switchtype) values ('81.162.$cc.$dk', 'e$e-${s}sw', 'es3024');\n"; + print "insert into placements (switch, placement) values ($i, box '(($x,$y),($xx,$yy))');\n"; + print "insert into dhcp (switch, network) values ($i, '81.162.$c.$d/26');\n"; + $i++; + + $dd++; + if ($dd == 42) { + $cc++; + $dd = 0; + } + } +} + +my @k = qw( + 81.162.212.0/24|81.162.212.1|game|es3024|((1100,200),(1125,225)) + 81.162.250.0/24|81.162.250.1|noc|es3024|((630,520),(680,550)) + 81.162.252.0/24|81.162.252.1|presse|es3024|((560,520),(610,550)) + 81.162.203.0/24|81.162.203.1|info-desk|es3024|((270,350),(305,385)) + 81.162.213.0/24|81.162.213.1|logistics|es3024|((800,75),(900,100)) + 81.162.213.0/24|81.162.213.1|logistics|es3024|((800,75),(900,100)) + 81.162.200.0/24|81.162.200.1|vision|es3024|((170,240),(200,270)) + 81.162.202.0/24|81.162.202.1|vision-sponsor|es3024|((220,150),(250,180)) + ); + +for my $x (@k) { + my ($net,$mip,$sysname,$switchtype,$box) = split /\|/, $x; + print "insert into switches (ip, sysname, switchtype) values ('$mip', '$sysname', '$switchtype');\n"; + print "insert into placements (switch, placement) values ($i, box '$box');\n"; + print "insert into dhcp (switch, network) values ($i, '$net');\n"; + $i++; +} diff --git a/web/mygraph.pl b/web/mygraph.pl new file mode 100755 index 0000000..9861264 --- /dev/null +++ b/web/mygraph.pl @@ -0,0 +1,178 @@ +#! /usr/bin/perl -T +use strict; +use warnings; +use GD; +use POSIX; +use Time::Zone; + +sub blendpx { + my ($gd, $x, $y, $r, $g, $b, $frac) = @_; + my ($ro, $go, $bo) = $gd->rgb($gd->getPixel($x, $y)); + + # workaround for icky 256-color graphs + $frac = int($frac * 32) / 32; + + my $rn = $ro * (1.0 - $frac) + $r * $frac; + my $gn = $go * (1.0 - $frac) + $g * $frac; + my $bn = $bo * (1.0 - $frac) + $b * $frac; + + $gd->setPixel($x, $y, $gd->colorResolve($rn, $gn, $bn)); +} + +# Standard implementation of Wu's antialiased line algorithm. +sub wuline { + my ($gd, $x1, $y1, $x2, $y2, $r, $g, $b, $a) = @_; + $x1 = POSIX::floor($x1); + $x2 = POSIX::floor($x2); + $y1 = POSIX::floor($y1); + $y2 = POSIX::floor($y2); + + if (abs($x2 - $x1) > abs($y2 - $y1)) { + # x-directional + if ($y2 < $y1) { + ($x2, $y2, $x1, $y1) = ($x1, $y1, $x2, $y2); + } + + my $y = POSIX::floor($y1); + my $frac = $y1 - $y; + my $dx = ($x2 > $x1) ? 1 : -1; + my $dy = ($y2 - $y1) / abs($x2 - $x1); + + for (my $x = $x1; $x != $x2 + $dx; $x += $dx) { + blendpx($gd, $x, $y, $r, $g, $b, $a * (1.0 - $frac)); + blendpx($gd, $x, $y + 1, $r, $g, $b, $a * $frac); + $frac += $dy; + if ($frac > 1) { + $frac -= 1; + ++$y; + } + } + } else { + # y-directional + if ($x2 < $x1) { + ($x2, $y2, $x1, $y1) = ($x1, $y1, $x2, $y2); + } + my $x = POSIX::floor($x1); + my $frac = $x1 - $x; + my $dy = ($y2 > $y1) ? 1 : -1; + my $dx = ($x2 - $x1) / abs($y2 - $y1); + + for (my $y = $y1; $y != $y2 + $dy; $y += $dy) { + blendpx($gd, $x, $y, $r, $g, $b, $a * (1.0 - $frac)); + blendpx($gd, $x + 1, $y, $r, $g, $b, $a * $frac); + $frac += $dx; + if ($frac > 1) { + $frac -= 1; + ++$x; + } + } + } +} + +sub makegraph { + my $xoffset = 70; + my ($width, $height, $min_x, $max_x, $min_y, $max_y, $tickgran) = @_; + + # Create our base graph + my $graph = new GD::Image($width, $height, 1); + my $white = $graph->colorAllocate(255, 255, 255); + $graph->fill(0, 0, $white); + + my $gray = $graph->colorAllocate(230, 230, 255); + my $black = $graph->colorAllocate(0, 0, 0); + + $::xs = ($width - ($xoffset+2)) / ($max_x - $min_x); + $::ys = ($height - 33) / ($min_y - $max_y); + + # Hour marks + for my $i ($xoffset+1..$width-2) { + if (((($i-($xoffset+1)) / $::xs + $min_x) / 3600) % 2 == 1) { + $graph->line($i, 0, $i, $height - 1, $gray); + } + } + + # Hour text + for my $i (0..23) { + my @bounds = GD::Image::stringFT(undef, $black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 0, 0, $i); + my $w = $bounds[2] - $bounds[0]; + + # Determine where the center of this will be + my $starthour = POSIX::fmod(($min_x + Time::Zone::tz_local_offset()) / 3600, 24); + my $diff = POSIX::fmod($i - $starthour + 24, 24); + + my $center = ($diff * 3600 + 1800) * $::xs; + + next if ($center - $w / 2 < 1 || $center + $w / 2 > $width - ($xoffset+2)); + $graph->stringFT($black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, $xoffset + $center - $w / 2, $height - 6, $i); + } + + # + # Y lines; we want max 11 of them (zero-line, plus five on each side, or + # whatever) but we don't want the ticks to be on minimum 50 (or + # whatever $tickgran is set to). However, if there would be + # really really few lines, go down an order of magnitude and try + # again. + # + my $ytick; + do { + $ytick = ($max_y - $min_y) / 11; + $ytick = POSIX::ceil($ytick / $tickgran) * $tickgran; + $tickgran *= 0.1; + } while (($max_y - $min_y) / $ytick < 4); + + for my $i (-11..11) { + my $y = ($i * $ytick - $max_y) * $::ys + 10; + next if ($y < 2 || $y > $height - 18); + + if ($i == 0) { + wuline($graph, $xoffset, $y, $width - 1, $y, 0, 0, 0, 1.0); + wuline($graph, $xoffset, $y + 1, $width - 1, $y + 1, 0, 0, 0, 1.0); + } else { + wuline($graph, $xoffset, $y, $width - 1, $y, 0, 0, 0, 0.2); + } + + # text + my $traf = 8 * ($i * $ytick); + my $text; + if ($traf >= 500_000_000) { + $text = (sprintf "%.1f Gbit", ($traf/1_000_000_000)); + } elsif ($traf >= 500_000) { + $text = (sprintf "%.1f Mbit", ($traf/1_000_000)); + } else { + $text = (sprintf "%.1f kbit", ($traf/1_000)); + } + + my @bounds = GD::Image::stringFT(undef, $black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, 0, 0, $text); + my $w = $bounds[2] - $bounds[0]; + my $h = $bounds[1] - $bounds[5]; + + next if ($y - $h/2 < 2 || $y + $h/2 > $height - 12); + $graph->stringFT($black, "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 10, 0, ($xoffset - 4) - $w, $y + $h/2, $text); + } + + # Nice border(TM) + $graph->rectangle($xoffset, 0, $width - 1, $height - 1, $black); + + return $graph; +} + +sub plotseries { + my ($graph, $xvals, $yvals, $r, $g, $b, $min_x, $max_y) = @_; + my $xoffset = 70; + + my @xvals = @{$xvals}; + my @yvals = @{$yvals}; + + my $x = $xvals[0]; + my $y = $yvals[0]; + for my $i (1..$#xvals) { + next if ($::xs * ($xvals[$i] - $x) < 2 && $::ys * ($yvals[$i] - $y) > -2); + + wuline($graph, ($x-$min_x) * $::xs + $xoffset + 1, ($y-$max_y) * $::ys + 10, + ($xvals[$i]-$min_x) * $::xs + $xoffset + 1, ($yvals[$i]-$max_y) * $::ys + 10, $r, $g, $b, 1.0); + $x = $xvals[$i]; + $y = $yvals[$i]; + } +} + +1; diff --git a/web/nettkart-telnet.pl b/web/nettkart-telnet.pl new file mode 100755 index 0000000..fd32044 --- /dev/null +++ b/web/nettkart-telnet.pl @@ -0,0 +1,49 @@ +#! /usr/bin/perl +use CGI; +use DBI; +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; +print $cgi->header(-type=>'text/html', -refresh=>'45; http://nms.tg05.gathering.org/nettkart-telnet.pl'); + +print <<"EOF"; + + + nettkart - telnet + + + +EOF + +my $q = $dbh->prepare('select * from switches natural join placements natural left join +( select switch,sum(bytes_in)/count(*) as +bytes_in,sum(bytes_out)/count(*) as bytes_out from get_datarate() group +by switch ) t1'); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + my $ttext; + if ($traffic >= 1_000_000_000) { + $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000; + } elsif ($traffic => 1_000_000) { + $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000; + } else { + $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000; + } + + printf " {'ip'}\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n", + $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'}, + $ttext, $ref->{'sysname'}, $ttext; +} +$dbh->disconnect; + +print <<"EOF"; + + +

+ + +EOF diff --git a/web/nettkart-text.pl b/web/nettkart-text.pl new file mode 100755 index 0000000..6ac1d9f --- /dev/null +++ b/web/nettkart-text.pl @@ -0,0 +1,49 @@ +#! /usr/bin/perl +use CGI; +use DBI; +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; +print $cgi->header(-type=>'text/html', -refresh=>'10; http://nms.tg05.gathering.org/nettkart-text.pl'); + +print <<"EOF"; + + + nettkart + + + +EOF + +my $q = $dbh->prepare('select * from switches natural join placements natural left join +( select switch,sum(bytes_in)/count(*) as +bytes_in,sum(bytes_out)/count(*) as bytes_out from get_datarate() group +by switch ) t1'); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + my $ttext; + if ($traffic >= 1_000_000_000) { + $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000; + } elsif ($traffic => 1_000_000) { + $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000; + } else { + $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000; + } + + printf " \"%s\n", + $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'}, + $ttext, $ref->{'sysname'}, $ttext; +} +$dbh->disconnect; + +print <<"EOF"; + + +

+ + +EOF diff --git a/web/nettkart-web.pl b/web/nettkart-web.pl new file mode 100755 index 0000000..3da5fe5 --- /dev/null +++ b/web/nettkart-web.pl @@ -0,0 +1,49 @@ +#! /usr/bin/perl +use CGI; +use DBI; +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; +print $cgi->header(-type=>'text/html', -refresh=>'45; http://nms.tg05.gathering.org/nettkart-web.pl'); + +print <<"EOF"; + + + nettkart - web + + + +EOF + +my $q = $dbh->prepare('select * from switches natural join placements natural left join +( select switch,sum(bytes_in)/count(*) as +bytes_in,sum(bytes_out)/count(*) as bytes_out from get_datarate() group +by switch ) t1'); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + my $ttext; + if ($traffic >= 1_000_000_000) { + $ttext = sprintf "%.2f Gbit/port/sec", $traffic/1_000_000_000; + } elsif ($traffic => 1_000_000) { + $ttext = sprintf "%.2f Mbit/port/sec", $traffic/1_000_000; + } else { + $ttext = sprintf "%.2f kbit/port/sec", $traffic/1_000; + } + + printf " {'ip'}\" alt=\"%s (%s)\" onmouseover=\"window.status='%s (%s)'; return true\" onmouseout=\"window.status=''\" />\n", + $3, $4, $1, $2, $ref->{'switch'}, $ref->{'sysname'}, + $ttext, $ref->{'sysname'}, $ttext; +} +$dbh->disconnect; + +print <<"EOF"; + + +

+ + +EOF diff --git a/web/nettkart.pl b/web/nettkart.pl new file mode 100755 index 0000000..ac88162 --- /dev/null +++ b/web/nettkart.pl @@ -0,0 +1,68 @@ +#! /usr/bin/perl +use CGI; +use GD; +use DBI; +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +GD::Image->trueColor(1); +$img = GD::Image->new('snmp-bg.png'); + +my $blk = $img->colorResolve(0, 0, 0); + +for my $y (42..236) { + my $i = 2.0 * ($y - 236.0) / (42.0 - 237.0); + my $clr = get_color($i); + + $img->filledRectangle(32,$y,53,$y+1,$clr); +} + +my $q = $dbh->prepare('select * from switches natural join placements natural left join +( select switch,sum(bytes_in)/count(*) as +bytes_in,sum(bytes_out)/count(*) as bytes_out from get_datarate() group +by switch ) t1 where ip<>\'127.0.0.1\''); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + + # for now: + # 100kbit/port = all green + # 1gbit/port = all red + + my $clr; + + if (defined($ref->{'bytes_in'})) { + my $intensity = 0.0; + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + + my $max = 20_000_000.0; # 10mbit + my $min = 100_000.0; # 100kbit + if ($traffic >= $min) { + $intensity = 2.0 * (log($traffic / $min) / log(10)) / (log($max / $min) / log(10)); + $intensity = 2.0 if ($intensity > 2.0); + } + $clr = get_color($intensity); + } else { + $clr = $img->colorResolve(0, 0, 255); + } + + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + $img->filledRectangle($3,$4,$1,$2,$clr); + $img->rectangle($3,$4,$1,$2,$blk); + $img->stringUp(gdSmallFont,$3,$2-3,$ref->{'sysname'},$blk); +} +$dbh->disconnect; + +print $cgi->header(-type=>'image/png'); +print $img->png; + +sub get_color { + my $intensity = shift; + my $gamma = 1.0/1.90; + if ($intensity > 1.0) { + return $img->colorResolve(255.0, 255.0 * ((2.0 - $intensity) ** $gamma), 0); + } else { + return $img->colorResolve(255.0 * ($intensity ** $gamma), 255, 0); + } +} diff --git a/web/nms.sql b/web/nms.sql new file mode 100644 index 0000000..7974cd1 --- /dev/null +++ b/web/nms.sql @@ -0,0 +1,1369 @@ +-- +-- NOTE: the PL/SQL in this file should probably not be trusted, it is rather +-- wrong at places, especially when it comes to wraparound. -sesse +-- + +-- +-- Name: plpgsql_call_handler(); Type: FUNCTION; Schema: public; Owner: postgres +-- + +CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler + AS '$libdir/plpgsql', 'plpgsql_call_handler' + LANGUAGE c; + + +ALTER FUNCTION public.plpgsql_call_handler() OWNER TO postgres; + +-- +-- Name: plpgsql; Type: PROCEDURAL LANGUAGE; Schema: public; Owner: +-- + +CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql HANDLER plpgsql_call_handler; + +CREATE TABLE polls ( + "time" timestamp with time zone NOT NULL, + switch integer NOT NULL, + port integer NOT NULL, + bytes_in bigint NOT NULL, + bytes_out bigint NOT NULL +); +ALTER TABLE ONLY polls ALTER COLUMN "time" SET STATISTICS 100; + + +ALTER TABLE public.polls OWNER TO postgres; + +-- +-- Name: datarate; Type: TYPE; Schema: public; Owner: sesse +-- + +CREATE TYPE datarate AS ( + switch integer, + port integer, + bytes_in double precision, + bytes_out double precision +); + + +ALTER TYPE public.datarate OWNER TO sesse; + +-- +-- Name: get_current_datarate(); Type: FUNCTION; Schema: public; Owner: nms +-- + +CREATE FUNCTION get_current_datarate() RETURNS SETOF datarate + AS $$ +DECLARE + num_entries INTEGER; + poll polls; + first_poll polls; + last_poll polls; + timediff float; + ret datarate; +BEGIN + num_entries := 0; + last_poll.switch := -1; + + FOR poll IN select * from polls where time >= now() - '15 minutes'::interval and time < now() order by switch,port,time LOOP + IF poll.switch <> last_poll.switch OR poll.port <> last_poll.port THEN + IF num_entries >= 2 THEN + timediff := EXTRACT(epoch from last_poll.time - first_poll.time); + ret.switch := last_poll.switch; + ret.port := last_poll.port; + + IF last_poll.bytes_in >= first_poll.bytes_in AND last_poll.bytes_out >= first_poll.bytes_out THEN + ret.bytes_in := (last_poll.bytes_in - first_poll.bytes_in) / timediff; + ret.bytes_out := (last_poll.bytes_out - first_poll.bytes_out) / timediff; + return next ret; + END IF; + END IF; + num_entries := 0; + ELSE + -- reset if we have wraparound + IF last_poll.bytes_in < first_poll.bytes_in OR + last_poll.bytes_out < first_poll.bytes_out THEN + num_entries := 0; + END IF; + END IF; + + num_entries := num_entries + 1; + IF num_entries = 1 THEN + first_poll.switch := poll.switch; + first_poll.port := poll.port; + first_poll.time := poll.time; + first_poll.bytes_in := poll.bytes_in; + first_poll.bytes_out := poll.bytes_out; + END IF; + + last_poll.switch := poll.switch; + last_poll.port := poll.port; + last_poll.time := poll.time; + last_poll.bytes_in := poll.bytes_in; + last_poll.bytes_out := poll.bytes_out; + END LOOP; + + -- last + IF num_entries >= 2 THEN + timediff := EXTRACT(epoch from last_poll.time - first_poll.time); + ret.switch := last_poll.switch; + ret.port := last_poll.port; + + IF last_poll.bytes_in >= first_poll.bytes_in AND + last_poll.bytes_out >= first_poll.bytes_out THEN + ret.bytes_in := (last_poll.bytes_in - first_poll.bytes_in) / timediff; + ret.bytes_out := (last_poll.bytes_out - first_poll.bytes_out) / timediff; + return next ret; + END IF; + END IF; + + RETURN; +END; +$$ + LANGUAGE plpgsql; + + +ALTER FUNCTION public.get_current_datarate() OWNER TO nms; + +-- +-- Name: get_datarate(); Type: FUNCTION; Schema: public; Owner: postgres +-- + +CREATE FUNCTION get_datarate() RETURNS SETOF datarate + AS $$ +DECLARE + num_entries INTEGER; + poll polls; + second_last_poll polls; + last_poll polls; + timediff float; + ret datarate; +BEGIN + num_entries := 0; + last_poll.switch = -1; + + FOR poll IN select * from polls where time >= now() - '15 minutes'::interval and time < now() order by switch,port,time LOOP + IF poll.switch <> last_poll.switch OR poll.port <> last_poll.port THEN + IF num_entries >= 2 THEN + timediff := EXTRACT(epoch from last_poll.time - second_last_poll.time); + ret.switch := last_poll.switch; + ret.port := last_poll.port; + + IF last_poll.bytes_in < second_last_poll.bytes_in THEN + second_last_poll.bytes_in = 0; + END IF; + IF last_poll.bytes_out < second_last_poll.bytes_out THEN + second_last_poll.bytes_out = 0; + END IF; + + ret.bytes_in := (last_poll.bytes_in - second_last_poll.bytes_in) / timediff; + ret.bytes_out := (last_poll.bytes_out - second_last_poll.bytes_out) / timediff; + return next ret; + ELSIF num_entries = 1 THEN + ret.switch := last_poll.switch; + ret.port := last_poll.port; + ret.bytes_in := -1; + ret.bytes_out := -1; + return next ret; + END IF; + num_entries := 1; + ELSE + num_entries := num_entries + 1; + END IF; + second_last_poll.switch := last_poll.switch; + second_last_poll.port := last_poll.port; + second_last_poll.time := last_poll.time; + second_last_poll.bytes_in := last_poll.bytes_in; + second_last_poll.bytes_out := last_poll.bytes_out; + last_poll.switch := poll.switch; + last_poll.port := poll.port; + last_poll.time := poll.time; + last_poll.bytes_in := poll.bytes_in; + last_poll.bytes_out := poll.bytes_out; + END LOOP; + -- pah, and once more, for the last switch/port... + IF num_entries >= 2 THEN + timediff := EXTRACT(epoch from last_poll.time - second_last_poll.time); + ret.switch := last_poll.switch; + ret.port := last_poll.port; + + IF last_poll.bytes_in < second_last_poll.bytes_in THEN + second_last_poll.bytes_in = 0; + END IF; + IF last_poll.bytes_out < second_last_poll.bytes_out THEN + second_last_poll.bytes_out = 0; + END IF; + + ret.bytes_in := (last_poll.bytes_in - second_last_poll.bytes_in) / timediff; + ret.bytes_out := (last_poll.bytes_out - second_last_poll.bytes_out) / timediff; + return next ret; + ELSIF num_entries = 1 THEN + ret.switch := last_poll.switch; + ret.port := last_poll.port; + ret.bytes_in := -1; + ret.bytes_out := -1; + return next ret; + END IF; + + RETURN; +END; +$$ + LANGUAGE plpgsql; + + +ALTER FUNCTION public.get_datarate() OWNER TO postgres; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: dhcp; Type: TABLE; Schema: public; Owner: sesse; Tablespace: +-- + +CREATE TABLE dhcp ( + switch integer NOT NULL, + network cidr NOT NULL, + last_ack timestamp without time zone +); + + +ALTER TABLE public.dhcp OWNER TO sesse; + +-- +-- Name: placements; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE placements ( + switch integer NOT NULL, + placement box NOT NULL +); + + +ALTER TABLE public.placements OWNER TO postgres; + +SET default_with_oids = true; + +-- +-- Name: polls; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + + +-- +-- Name: polls_poll_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE polls_poll_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +ALTER TABLE public.polls_poll_seq OWNER TO postgres; + +-- +-- Name: polls_poll_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('polls_poll_seq', 1, false); + + +-- +-- Name: portnames; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE portnames ( + switchtype character varying NOT NULL, + port integer NOT NULL, + description character varying NOT NULL +); + + +ALTER TABLE public.portnames OWNER TO postgres; + +-- +-- Name: squeue; Type: TABLE; Schema: public; Owner: nms; Tablespace: +-- + +CREATE TABLE squeue ( + id integer DEFAULT nextval('squeue_sequence'::text) NOT NULL, + gid integer NOT NULL, + added timestamp with time zone NOT NULL, + updated timestamp with time zone, + addr inet, + cmd character varying NOT NULL, + locked boolean DEFAULT false NOT NULL, + processed boolean DEFAULT false NOT NULL, + disabled boolean DEFAULT false NOT NULL, + priority integer DEFAULT 3, + sysname character varying NOT NULL, + author character varying NOT NULL, + result character varying, + delay timestamp with time zone, + delaytime interval DEFAULT '00:01:00'::interval +); + + +ALTER TABLE public.squeue OWNER TO nms; + +-- +-- Name: squeue_group_sequence; Type: SEQUENCE; Schema: public; Owner: nms +-- + +CREATE SEQUENCE squeue_group_sequence + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +ALTER TABLE public.squeue_group_sequence OWNER TO nms; + +-- +-- Name: squeue_group_sequence; Type: SEQUENCE SET; Schema: public; Owner: nms +-- + +SELECT pg_catalog.setval('squeue_group_sequence', 21, true); + + +-- +-- Name: squeue_sequence; Type: SEQUENCE; Schema: public; Owner: nms +-- + +CREATE SEQUENCE squeue_sequence + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +ALTER TABLE public.squeue_sequence OWNER TO nms; + +-- +-- Name: squeue_sequence; Type: SEQUENCE SET; Schema: public; Owner: nms +-- + +SELECT pg_catalog.setval('squeue_sequence', 901, true); + + +-- +-- Name: stemppoll_sequence; Type: SEQUENCE; Schema: public; Owner: nms +-- + +CREATE SEQUENCE stemppoll_sequence + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +ALTER TABLE public.stemppoll_sequence OWNER TO nms; + +-- +-- Name: stemppoll_sequence; Type: SEQUENCE SET; Schema: public; Owner: nms +-- + +SELECT pg_catalog.setval('stemppoll_sequence', 182534, true); + + +SET default_with_oids = false; + +-- +-- Name: switches; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE switches ( + switch integer DEFAULT nextval('"switches_switch_seq"'::text) NOT NULL, + ip inet NOT NULL, + sysname character varying NOT NULL, + switchtype character varying NOT NULL, + last_updated timestamp with time zone, + locked boolean DEFAULT false NOT NULL, + priority integer DEFAULT 0 NOT NULL, + poll_frequency interval DEFAULT '00:05:00'::interval NOT NULL, + community character varying DEFAULT 'public'::character varying NOT NULL +); + + +ALTER TABLE public.switches OWNER TO postgres; + +-- +-- Name: switches_switch_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE switches_switch_seq + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +ALTER TABLE public.switches_switch_seq OWNER TO postgres; + +-- +-- Name: switches_switch_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('switches_switch_seq', 225, true); + + +-- +-- Name: switchtypes; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE switchtypes ( + switchtype character varying NOT NULL, + ports character varying NOT NULL +); + + +ALTER TABLE public.switchtypes OWNER TO postgres; + +SET default_with_oids = true; + +-- +-- Name: temppoll; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE temppoll ( + id integer DEFAULT nextval('stemppoll_sequence'::text) NOT NULL, + "time" timestamp without time zone NOT NULL, + switch integer NOT NULL, + "temp" double precision +); + + +ALTER TABLE public.temppoll OWNER TO postgres; + +-- +-- Data for Name: dhcp; Type: TABLE DATA; Schema: public; Owner: sesse +-- + +COPY dhcp (switch, network, last_ack) FROM stdin; +151 81.162.53.0/26 2005-03-27 11:53:29 +41 81.162.16.64/26 2005-03-27 11:53:35 +164 81.162.57.64/26 2005-03-27 11:53:39 +20 81.162.9.64/26 2005-03-27 11:54:27 +4 81.162.4.0/26 2005-03-27 11:55:33 +44 81.162.17.64/26 2005-03-27 11:56:37 +194 81.162.67.64/26 2005-03-27 11:56:38 +139 81.162.49.0/26 2005-03-27 11:57:08 +46 81.162.18.0/26 2005-03-27 11:57:27 +193 81.162.67.0/26 2005-03-27 11:57:36 +27 81.162.11.128/26 2005-03-27 11:58:07 +107 81.162.38.64/26 2005-03-27 11:58:31 +133 81.162.47.0/26 2005-03-27 11:58:52 +99 81.162.35.128/26 2005-03-27 11:59:09 +79 81.162.29.0/26 2005-03-27 11:59:18 +34 81.162.14.0/26 2005-03-27 11:59:28 +51 81.162.19.128/26 2005-03-27 11:59:34 +160 81.162.56.0/26 2005-03-27 12:00:01 +196 81.162.68.0/26 2005-03-27 12:00:11 +184 81.162.64.0/26 2005-03-27 12:01:48 +9 81.162.5.128/26 2005-03-27 12:01:54 +195 81.162.67.128/26 2005-03-27 12:02:18 +123 81.162.43.128/26 2005-03-27 12:02:46 +192 81.162.66.128/26 2005-03-27 12:03:09 +212 81.162.203.0/24 2005-03-27 12:04:12 +5 81.162.4.64/26 2005-03-27 12:04:14 +113 81.162.40.64/26 2005-03-27 12:05:01 +191 81.162.66.64/26 2005-03-27 12:05:01 +119 81.162.42.64/26 2005-03-27 12:06:01 +3 81.162.2.128/26 2005-03-27 12:06:03 +74 81.162.27.64/26 2005-03-27 12:06:12 +201 81.162.70.0/26 2005-03-27 12:06:25 +86 81.162.31.64/26 2005-03-27 12:07:56 +50 81.162.19.64/26 2005-03-27 12:08:36 +59 81.162.22.64/26 2005-03-27 12:08:59 +43 81.162.17.0/26 2005-03-27 12:09:02 +80 81.162.29.64/26 2005-03-27 12:09:14 +106 81.162.38.0/26 2005-03-27 12:09:15 +52 81.162.20.0/26 2005-03-27 12:09:22 +205 81.162.72.0/26 2005-03-27 12:10:08 +82 81.162.30.0/26 2005-03-27 12:10:10 +128 81.162.45.64/26 2005-03-27 12:10:38 +112 81.162.40.0/26 2005-03-27 12:11:16 +202 81.162.70.64/26 2005-03-27 12:12:30 +6 81.162.4.128/26 2005-03-27 12:12:49 +95 81.162.34.64/26 2005-03-27 12:13:02 +178 81.162.62.0/26 2005-03-27 12:13:10 +145 81.162.51.0/26 2005-03-27 12:13:15 +84 81.162.30.128/26 2005-03-27 12:13:34 +28 81.162.12.0/26 2005-03-27 12:13:58 +22 81.162.10.0/26 2005-03-27 12:14:40 +122 81.162.43.64/26 2005-03-27 12:14:57 +85 81.162.31.0/26 2005-03-27 12:15:21 +18 81.162.8.128/26 2005-03-27 12:15:24 +105 81.162.37.128/26 2005-03-27 12:15:24 +81 81.162.29.128/26 2005-03-27 12:15:36 +77 81.162.28.64/26 2005-03-27 12:15:47 +146 81.162.51.64/26 2005-03-27 12:17:09 +24 81.162.10.128/26 2005-03-27 12:17:10 +190 81.162.66.0/26 2005-03-27 12:17:10 +33 81.162.13.128/26 2005-03-27 12:17:17 +150 81.162.52.128/26 2005-03-27 12:17:27 +57 81.162.21.128/26 2005-03-27 12:17:37 +17 81.162.8.64/26 2005-03-27 12:17:39 +54 81.162.20.128/26 2005-03-27 12:18:24 +94 81.162.34.0/26 2005-03-27 12:18:24 +69 81.162.25.128/26 2005-03-27 12:18:26 +141 81.162.49.128/26 2005-03-27 12:18:43 +154 81.162.54.0/26 2005-03-27 12:19:25 +177 81.162.61.128/26 2005-03-27 12:20:17 +29 81.162.12.64/26 2005-03-27 12:20:37 +91 81.162.33.0/26 2005-03-27 12:20:53 +83 81.162.30.64/26 2005-03-27 12:20:57 +47 81.162.18.64/26 2005-03-27 12:21:10 +170 81.162.59.64/26 2005-03-27 12:22:01 +78 81.162.28.128/26 2005-03-27 12:22:26 +155 81.162.54.64/26 2005-03-27 12:23:11 +35 81.162.14.64/26 2005-03-27 12:23:12 +32 81.162.13.64/26 2005-03-27 12:23:55 +199 81.162.69.64/26 2005-03-27 12:24:13 +63 81.162.23.128/26 2005-03-27 12:24:33 +90 81.162.32.128/26 2005-03-27 12:25:31 +114 81.162.40.128/26 2005-03-27 12:26:04 +75 81.162.27.128/26 2005-03-27 12:26:06 +42 81.162.16.128/26 2005-03-27 12:26:26 +87 81.162.31.128/26 2005-03-27 12:26:42 +67 81.162.25.0/26 2005-03-27 12:27:31 +204 81.162.71.128/26 2005-03-27 12:34:04 +200 81.162.69.128/26 2005-03-27 12:37:19 +207 81.162.73.64/26 2005-03-27 12:41:57 +203 81.162.71.64/26 2005-03-27 12:58:48 +214 81.162.213.0/24 2005-03-27 13:02:26 +213 81.162.213.0/24 2005-03-27 13:02:26 +209 81.162.212.0/24 2005-03-27 13:16:02 +215 81.162.200.0/24 2005-03-27 13:16:14 +210 81.162.250.0/24 2005-03-27 13:18:02 +211 81.162.252.0/24 2005-03-27 12:39:02 +129 81.162.45.128/26 2005-03-27 10:44:11 +110 81.162.39.64/26 2005-03-27 08:19:17 +10 81.162.6.0/26 2005-03-27 08:35:15 +171 81.162.59.128/26 2005-03-27 08:42:52 +167 81.162.58.64/26 2005-03-27 09:07:47 +180 81.162.62.128/26 2005-03-27 09:22:15 +140 81.162.49.64/26 2005-03-27 09:41:51 +103 81.162.37.0/26 2005-03-27 09:42:30 +55 81.162.21.0/26 2005-03-27 09:42:54 +137 81.162.48.64/26 2005-03-27 09:47:06 +62 81.162.23.64/26 2005-03-27 09:51:30 +158 81.162.55.64/26 2005-03-27 09:51:55 +70 81.162.26.0/26 2005-03-27 09:52:09 +159 81.162.55.128/26 2005-03-27 10:05:56 +165 81.162.57.128/26 2005-03-27 10:09:30 +125 81.162.44.64/26 2005-03-27 10:10:14 +169 81.162.59.0/26 2005-03-27 10:10:29 +89 81.162.32.64/26 2005-03-27 10:11:14 +168 81.162.58.128/26 2005-03-27 10:11:42 +39 81.162.15.128/26 2005-03-27 10:11:49 +134 81.162.47.64/26 2005-03-27 10:12:00 +144 81.162.50.128/26 2005-03-27 10:15:46 +61 81.162.23.0/26 2005-03-27 10:19:36 +186 81.162.64.128/26 2005-03-27 10:24:08 +97 81.162.35.0/26 2005-03-27 10:26:13 +124 81.162.44.0/26 2005-03-27 10:28:37 +162 81.162.56.128/26 2005-03-27 10:36:33 +76 81.162.28.0/26 2005-03-27 10:38:20 +156 81.162.54.128/26 2005-03-27 10:41:07 +93 81.162.33.128/26 2005-03-27 10:42:16 +58 81.162.22.0/26 2005-03-27 10:42:50 +23 81.162.10.64/26 2005-03-27 10:43:27 +132 81.162.46.128/26 2005-03-27 10:46:35 +118 81.162.42.0/26 2005-03-27 10:47:16 +16 81.162.8.0/26 2005-03-27 10:47:53 +182 81.162.63.64/26 2005-03-27 10:47:58 +88 81.162.32.0/26 2005-03-27 10:49:28 +126 81.162.44.128/26 2005-03-27 10:50:02 +130 81.162.46.0/26 2005-03-27 10:50:46 +15 81.162.7.128/26 2005-03-27 10:54:20 +12 81.162.6.128/26 2005-03-27 10:54:40 +98 81.162.35.64/26 2005-03-27 10:55:15 +104 81.162.37.64/26 2005-03-27 10:57:11 +100 81.162.36.0/26 2005-03-27 10:58:55 +45 81.162.17.128/26 2005-03-27 11:02:32 +131 81.162.46.64/26 2005-03-27 11:04:23 +175 81.162.61.0/26 2005-03-27 11:04:47 +72 81.162.26.128/26 2005-03-27 11:04:50 +148 81.162.52.0/26 2005-03-27 11:05:19 +198 81.162.68.128/26 2005-03-27 11:06:42 +68 81.162.25.64/26 2005-03-27 11:06:55 +115 81.162.41.0/26 2005-03-27 11:08:58 +157 81.162.55.0/26 2005-03-27 11:10:30 +111 81.162.39.128/26 2005-03-27 11:11:10 +120 81.162.42.128/26 2005-03-27 10:14:01 +21 81.162.9.128/26 2005-03-27 10:39:11 +64 81.162.24.0/26 2005-03-27 11:14:54 +7 81.162.5.0/26 2005-03-27 11:15:07 +163 81.162.57.0/26 2005-03-27 11:18:50 +208 81.162.73.128/26 2005-03-27 11:18:53 +189 81.162.65.128/26 2005-03-27 11:20:12 +197 81.162.68.64/26 2005-03-27 11:20:46 +31 81.162.13.0/26 2005-03-27 11:22:31 +19 81.162.9.0/26 2005-03-27 11:22:48 +13 81.162.7.0/26 2005-03-27 11:24:35 +147 81.162.51.128/26 2005-03-27 11:27:37 +135 81.162.47.128/26 2005-03-27 11:28:43 +121 81.162.43.0/26 2005-03-27 11:28:58 +136 81.162.48.0/26 2005-03-27 11:31:04 +66 81.162.24.128/26 2005-03-27 11:32:10 +166 81.162.58.0/26 2005-03-27 09:25:55 +138 81.162.48.128/26 2005-03-27 10:08:33 +56 81.162.21.64/26 2005-03-27 11:32:34 +143 81.162.50.64/26 2005-03-27 11:33:03 +176 81.162.61.64/26 2005-03-27 11:33:36 +65 81.162.24.64/26 2005-03-27 11:33:40 +102 81.162.36.128/26 2005-03-27 11:34:00 +116 81.162.41.64/26 2005-03-27 11:34:56 +183 81.162.63.128/26 2005-03-27 11:36:02 +109 81.162.39.0/26 2005-03-27 11:36:45 +25 81.162.11.0/26 2005-03-27 11:37:44 +174 81.162.60.128/26 2005-03-27 11:38:11 +216 81.162.202.0/24 2005-03-27 11:39:03 +40 81.162.16.0/26 2005-03-27 11:39:31 +152 81.162.53.64/26 2005-03-27 11:39:47 +14 81.162.7.64/26 2005-03-27 11:39:59 +92 81.162.33.64/26 2005-03-27 11:40:05 +173 81.162.60.64/26 2005-03-27 11:40:28 +48 81.162.18.128/26 2005-03-27 11:40:28 +8 81.162.5.64/26 2005-03-27 11:40:45 +108 81.162.38.128/26 2005-03-27 11:42:43 +11 81.162.6.64/26 2005-03-27 08:50:50 +188 81.162.65.64/26 2005-03-27 08:55:21 +117 81.162.41.128/26 2005-03-27 09:23:35 +26 81.162.11.64/26 2005-03-27 11:43:18 +172 81.162.60.0/26 2005-03-27 11:43:21 +71 81.162.26.64/26 2005-03-27 11:43:51 +38 81.162.15.64/26 2005-03-27 11:44:11 +153 81.162.53.128/26 2005-03-27 11:45:51 +53 81.162.20.64/26 2005-03-27 11:46:24 +1 81.162.2.0/26 2005-03-27 11:47:03 +2 81.162.2.64/26 2005-03-27 11:47:10 +149 81.162.52.64/26 2005-03-27 11:48:35 +37 81.162.15.0/26 2005-03-27 11:49:04 +127 81.162.45.0/26 2005-03-27 11:49:22 +179 81.162.62.64/26 2005-03-27 11:49:48 +185 81.162.64.64/26 2005-03-27 11:50:36 +142 81.162.50.0/26 2005-03-27 11:51:18 +36 81.162.14.128/26 2005-03-27 11:51:19 +30 81.162.12.128/26 2005-03-27 11:51:20 +60 81.162.22.128/26 2005-03-27 11:52:08 +49 81.162.19.0/26 2005-03-27 10:22:15 +73 81.162.27.0/26 2005-03-27 11:27:55 +96 81.162.34.128/26 2005-03-27 11:32:26 +101 81.162.36.64/26 2005-03-27 11:40:47 +181 81.162.63.0/26 2005-03-27 11:52:55 +187 81.162.65.0/26 2005-03-27 11:53:23 +161 81.162.56.64/26 2005-03-27 08:54:44 +\. + + +-- +-- Data for Name: placements; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY placements (switch, placement) FROM stdin; +221 (375,325),(350,300) +222 (550,325),(525,300) +224 (775,325),(750,300) +223 (875,325),(850,300) +225 (675,325),(650,300) +218 (980,550),(930,520) +1 (306,306),(294,256) +2 (306,256),(294,206) +3 (306,206),(294,156) +4 (325,306),(313,256) +5 (325,256),(313,206) +6 (325,206),(313,156) +7 (344,470),(332,422) +8 (344,422),(332,374) +9 (344,374),(332,326) +10 (344,306),(332,256) +11 (344,256),(332,206) +12 (344,206),(332,156) +13 (363,470),(351,422) +14 (363,422),(351,374) +15 (363,374),(351,326) +16 (363,306),(351,256) +17 (363,256),(351,206) +18 (363,206),(351,156) +19 (382,470),(370,422) +20 (382,422),(370,374) +21 (382,374),(370,326) +22 (382,306),(370,256) +23 (382,256),(370,206) +24 (382,206),(370,156) +25 (400,470),(388,422) +26 (400,422),(388,374) +27 (400,374),(388,326) +28 (400,306),(388,256) +29 (400,256),(388,206) +30 (400,206),(388,156) +31 (419,470),(407,422) +32 (419,422),(407,374) +33 (419,374),(407,326) +34 (419,306),(407,256) +35 (419,256),(407,206) +36 (419,206),(407,156) +37 (438,470),(426,422) +38 (438,422),(426,374) +39 (438,374),(426,326) +40 (438,306),(426,256) +41 (438,256),(426,206) +42 (438,206),(426,156) +43 (457,470),(445,422) +44 (457,422),(445,374) +45 (457,374),(445,326) +46 (457,306),(445,256) +47 (457,256),(445,206) +48 (457,206),(445,156) +49 (483,470),(471,422) +50 (483,422),(471,374) +51 (483,374),(471,326) +52 (483,306),(471,256) +53 (483,256),(471,206) +54 (483,206),(471,156) +55 (502,470),(490,422) +56 (502,422),(490,374) +57 (502,374),(490,326) +58 (502,306),(490,256) +59 (502,256),(490,206) +60 (502,206),(490,156) +61 (521,470),(509,422) +62 (521,422),(509,374) +63 (521,374),(509,326) +64 (521,306),(509,256) +65 (521,256),(509,206) +66 (521,206),(509,156) +67 (540,470),(528,422) +68 (540,422),(528,374) +69 (540,374),(528,326) +70 (540,306),(528,256) +71 (540,256),(528,206) +72 (540,206),(528,156) +73 (559,470),(547,422) +74 (559,422),(547,374) +75 (559,374),(547,326) +76 (559,306),(547,256) +77 (559,256),(547,206) +78 (559,206),(547,156) +79 (578,470),(566,422) +80 (578,422),(566,374) +81 (578,374),(566,326) +82 (578,306),(566,256) +83 (578,256),(566,206) +84 (578,206),(566,156) +85 (596,470),(584,422) +86 (596,422),(584,374) +87 (596,374),(584,326) +88 (596,306),(584,256) +89 (596,256),(584,206) +90 (596,206),(584,156) +91 (615,470),(603,422) +92 (615,422),(603,374) +93 (615,374),(603,326) +94 (615,306),(603,256) +95 (615,256),(603,206) +96 (615,206),(603,156) +97 (648,470),(636,422) +98 (648,422),(636,374) +99 (648,374),(636,326) +100 (648,306),(636,256) +101 (648,256),(636,206) +102 (648,206),(636,156) +103 (667,470),(655,422) +104 (667,422),(655,374) +105 (667,374),(655,326) +106 (667,306),(655,256) +107 (667,256),(655,206) +108 (667,206),(655,156) +109 (686,470),(674,422) +110 (686,422),(674,374) +111 (686,374),(674,326) +112 (686,306),(674,256) +113 (686,256),(674,206) +114 (686,206),(674,156) +115 (705,470),(693,422) +116 (705,422),(693,374) +117 (705,374),(693,326) +118 (705,306),(693,256) +119 (705,256),(693,206) +120 (705,206),(693,156) +121 (724,470),(712,422) +122 (724,422),(712,374) +123 (724,374),(712,326) +124 (724,306),(712,256) +125 (724,256),(712,206) +126 (724,206),(712,156) +127 (743,470),(731,422) +128 (743,422),(731,374) +129 (743,374),(731,326) +130 (743,306),(731,256) +131 (743,256),(731,206) +132 (743,206),(731,156) +133 (762,470),(750,422) +134 (762,422),(750,374) +135 (762,374),(750,326) +136 (762,306),(750,256) +137 (762,256),(750,206) +138 (762,206),(750,156) +139 (781,470),(769,422) +140 (781,422),(769,374) +141 (781,374),(769,326) +142 (781,306),(769,256) +143 (781,256),(769,206) +144 (781,206),(769,156) +145 (808,470),(796,422) +146 (808,422),(796,374) +147 (808,374),(796,326) +148 (808,306),(796,256) +149 (808,256),(796,206) +150 (808,206),(796,156) +151 (827,470),(815,422) +152 (827,422),(815,374) +153 (827,374),(815,326) +154 (827,306),(815,256) +155 (827,256),(815,206) +156 (827,206),(815,156) +157 (846,470),(834,422) +158 (846,422),(834,374) +159 (846,374),(834,326) +160 (846,306),(834,256) +161 (846,256),(834,206) +162 (846,206),(834,156) +163 (865,470),(853,422) +164 (865,422),(853,374) +165 (865,374),(853,326) +166 (865,306),(853,256) +167 (865,256),(853,206) +168 (865,206),(853,156) +169 (884,470),(872,422) +170 (884,422),(872,374) +171 (884,374),(872,326) +172 (884,306),(872,256) +173 (884,256),(872,206) +174 (884,206),(872,156) +175 (903,470),(891,422) +176 (903,422),(891,374) +177 (903,374),(891,326) +178 (903,306),(891,256) +179 (903,256),(891,206) +180 (903,206),(891,156) +181 (922,470),(910,422) +182 (922,422),(910,374) +183 (922,374),(910,326) +184 (922,306),(910,256) +185 (922,256),(910,206) +186 (922,206),(910,156) +187 (941,470),(929,422) +188 (941,422),(929,374) +189 (941,374),(929,326) +190 (941,306),(929,256) +191 (941,256),(929,206) +192 (941,206),(929,156) +193 (960,470),(948,422) +194 (960,422),(948,374) +195 (960,374),(948,326) +196 (960,306),(948,256) +197 (960,256),(948,206) +198 (960,206),(948,156) +199 (988,422),(976,374) +200 (988,374),(976,326) +201 (979,306),(967,256) +202 (979,256),(967,206) +203 (1006,422),(994,374) +204 (1006,374),(994,326) +205 (997,306),(985,256) +207 (1025,422),(1013,374) +208 (1025,374),(1013,326) +209 (1125,225),(1100,200) +210 (680,550),(630,520) +211 (610,550),(560,520) +212 (305,385),(270,350) +213 (900,100),(800,75) +214 (900,100),(800,75) +215 (200,270),(170,240) +216 (250,180),(220,150) +\. + + +-- +-- Data for Name: polls; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +\. + + +-- +-- Data for Name: portnames; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY portnames (switchtype, port, description) FROM stdin; +blackdiamond 1001 BD6808/G8Xi-Port 1:1 +blackdiamond 1002 BD6808/G8Xi-Port 1:2 +blackdiamond 1003 BD6808/G8Xi-Port 1:3 +blackdiamond 1004 BD6808/G8Xi-Port 1:4 +blackdiamond 1005 BD6808/G8Xi-Port 1:5 +blackdiamond 1006 BD6808/G8Xi-Port 1:6 +blackdiamond 1007 BD6808/G8Xi-Port 1:7 +blackdiamond 4001 BD6808/G16X3-Port 4:1 +blackdiamond 4002 BD6808/G16X3-Port 4:2 +blackdiamond 4003 BD6808/G16X3-Port 4:3 +blackdiamond 4004 BD6808/G16X3-Port 4:4 +blackdiamond 4005 BD6808/G16X3-Port 4:5 +blackdiamond 4006 BD6808/G16X3-Port 4:6 +blackdiamond 4007 BD6808/G16X3-Port 4:7 +blackdiamond 4008 BD6808/G16X3-Port 4:8 +blackdiamond 4009 BD6808/G16X3-Port 4:9 +blackdiamond 4010 BD6808/G16X3-Port 4:10 +blackdiamond 4011 BD6808/G16X3-Port 4:11 +blackdiamond 4012 BD6808/G16X3-Port 4:12 +blackdiamond 4013 BD6808/G16X3-Port 4:13 +blackdiamond 4014 BD6808/G16X3-Port 4:14 +blackdiamond 4015 BD6808/G16X3-Port 4:15 +blackdiamond 4016 BD6808/G16X3-Port 4:16 +blackdiamond 5001 BD6808/G24T3-Port 5:1 +blackdiamond 5002 BD6808/G24T3-Port 5:2 +blackdiamond 5003 BD6808/G24T3-Port 5:3 +blackdiamond 5004 BD6808/G24T3-Port 5:4 +blackdiamond 5005 BD6808/G24T3-Port 5:5 +blackdiamond 5006 BD6808/G24T3-Port 5:6 +blackdiamond 5007 BD6808/G24T3-Port 5:7 +blackdiamond 5008 BD6808/G24T3-Port 5:8 +blackdiamond 5009 BD6808/G24T3-Port 5:9 +blackdiamond 5010 BD6808/G24T3-Port 5:10 +blackdiamond 5011 BD6808/G24T3-Port 5:11 +blackdiamond 5012 BD6808/G24T3-Port 5:12 +blackdiamond 5013 BD6808/G24T3-Port 5:13 +blackdiamond 5014 BD6808/G24T3-Port 5:14 +blackdiamond 5015 BD6808/G24T3-Port 5:15 +blackdiamond 5016 BD6808/G24T3-Port 5:16 +blackdiamond 5017 BD6808/G24T3-Port 5:17 +blackdiamond 5018 BD6808/G24T3-Port 5:18 +blackdiamond 5019 BD6808/G24T3-Port 5:19 +blackdiamond 5020 BD6808/G24T3-Port 5:20 +blackdiamond 5021 BD6808/G24T3-Port 5:21 +blackdiamond 5022 BD6808/G24T3-Port 5:22 +blackdiamond 5023 BD6808/G24T3-Port 5:23 +blackdiamond 5024 BD6808/G24T3-Port 5:24 +blackdiamond 6001 BD6808/F48Ti-Port 6:1 +blackdiamond 6002 BD6808/F48Ti-Port 6:2 +blackdiamond 6003 BD6808/F48Ti-Port 6:3 +blackdiamond 6004 BD6808/F48Ti-Port 6:4 +blackdiamond 6005 BD6808/F48Ti-Port 6:5 +blackdiamond 6006 BD6808/F48Ti-Port 6:6 +blackdiamond 6007 BD6808/F48Ti-Port 6:7 +blackdiamond 6008 BD6808/F48Ti-Port 6:8 +blackdiamond 6009 BD6808/F48Ti-Port 6:9 +blackdiamond 6010 BD6808/F48Ti-Port 6:10 +blackdiamond 6011 BD6808/F48Ti-Port 6:11 +blackdiamond 6012 BD6808/F48Ti-Port 6:12 +blackdiamond 6013 BD6808/F48Ti-Port 6:13 +blackdiamond 6014 BD6808/F48Ti-Port 6:14 +blackdiamond 6015 BD6808/F48Ti-Port 6:15 +blackdiamond 6016 BD6808/F48Ti-Port 6:16 +blackdiamond 6017 BD6808/F48Ti-Port 6:17 +blackdiamond 6018 BD6808/F48Ti-Port 6:18 +blackdiamond 6019 BD6808/F48Ti-Port 6:19 +blackdiamond 6020 BD6808/F48Ti-Port 6:20 +blackdiamond 6021 BD6808/F48Ti-Port 6:21 +blackdiamond 6022 BD6808/F48Ti-Port 6:22 +blackdiamond 6023 BD6808/F48Ti-Port 6:23 +blackdiamond 6024 BD6808/F48Ti-Port 6:24 +blackdiamond 6025 BD6808/F48Ti-Port 6:25 +blackdiamond 6026 BD6808/F48Ti-Port 6:26 +blackdiamond 6027 BD6808/F48Ti-Port 6:27 +blackdiamond 6028 BD6808/F48Ti-Port 6:28 +blackdiamond 6029 BD6808/F48Ti-Port 6:29 +blackdiamond 6030 BD6808/F48Ti-Port 6:30 +blackdiamond 6031 BD6808/F48Ti-Port 6:31 +blackdiamond 6032 BD6808/F48Ti-Port 6:32 +blackdiamond 6033 BD6808/F48Ti-Port 6:33 +blackdiamond 6034 BD6808/F48Ti-Port 6:34 +blackdiamond 6035 BD6808/F48Ti-Port 6:35 +blackdiamond 6036 BD6808/F48Ti-Port 6:36 +blackdiamond 6037 BD6808/F48Ti-Port 6:37 +blackdiamond 6038 BD6808/F48Ti-Port 6:38 +blackdiamond 6039 BD6808/F48Ti-Port 6:39 +blackdiamond 6040 BD6808/F48Ti-Port 6:40 +blackdiamond 6041 BD6808/F48Ti-Port 6:41 +blackdiamond 6042 BD6808/F48Ti-Port 6:42 +blackdiamond 6043 BD6808/F48Ti-Port 6:43 +blackdiamond 6044 BD6808/F48Ti-Port 6:44 +blackdiamond 6045 BD6808/F48Ti-Port 6:45 +blackdiamond 6046 BD6808/F48Ti-Port 6:46 +blackdiamond 6047 BD6808/F48Ti-Port 6:47 +blackdiamond 6048 BD6808/F48Ti-Port 6:48 +cisco6509 1 GigabitEthernet1/1 +cisco6509 2 GigabitEthernet1/2 +cisco6509 3 GigabitEthernet1/3 +cisco6509 4 GigabitEthernet1/4 +cisco6509 5 GigabitEthernet1/5 +cisco6509 6 GigabitEthernet1/6 +cisco6509 7 GigabitEthernet1/7 +cisco6509 8 GigabitEthernet1/8 +cisco6509 9 GigabitEthernet1/9 +cisco6509 10 GigabitEthernet1/10 +cisco6509 11 GigabitEthernet1/11 +cisco6509 12 GigabitEthernet1/12 +cisco6509 13 GigabitEthernet1/13 +cisco6509 14 GigabitEthernet1/14 +cisco6509 15 GigabitEthernet1/15 +cisco6509 16 GigabitEthernet1/16 +cisco6509 17 GigabitEthernet1/17 +cisco6509 18 GigabitEthernet1/18 +cisco6509 19 GigabitEthernet1/19 +cisco6509 20 GigabitEthernet1/20 +cisco6509 21 GigabitEthernet1/21 +cisco6509 22 GigabitEthernet1/22 +cisco6509 23 GigabitEthernet1/23 +cisco6509 24 GigabitEthernet1/24 +cisco6509 25 GigabitEthernet1/25 +cisco6509 26 GigabitEthernet1/26 +cisco6509 27 GigabitEthernet1/27 +cisco6509 28 GigabitEthernet1/28 +cisco6509 29 GigabitEthernet1/29 +cisco6509 30 GigabitEthernet1/30 +cisco6509 31 GigabitEthernet1/31 +cisco6509 32 GigabitEthernet1/32 +cisco6509 33 GigabitEthernet1/33 +cisco6509 34 GigabitEthernet1/34 +cisco6509 35 GigabitEthernet1/35 +cisco6509 36 GigabitEthernet1/36 +cisco6509 37 GigabitEthernet1/37 +cisco6509 38 GigabitEthernet1/38 +cisco6509 39 GigabitEthernet1/39 +cisco6509 40 GigabitEthernet1/40 +cisco6509 41 GigabitEthernet1/41 +cisco6509 42 GigabitEthernet1/42 +cisco6509 43 GigabitEthernet1/43 +cisco6509 44 GigabitEthernet1/44 +cisco6509 45 GigabitEthernet1/45 +cisco6509 46 GigabitEthernet1/46 +cisco6509 47 GigabitEthernet1/47 +cisco6509 48 GigabitEthernet1/48 +cisco6509 49 GigabitEthernet2/1 +cisco6509 50 GigabitEthernet2/2 +cisco6509 51 GigabitEthernet2/3 +cisco6509 52 GigabitEthernet2/4 +cisco6509 53 GigabitEthernet2/5 +cisco6509 54 GigabitEthernet2/6 +cisco6509 55 GigabitEthernet2/7 +cisco6509 56 GigabitEthernet2/8 +cisco6509 57 GigabitEthernet2/9 +cisco6509 58 GigabitEthernet2/10 +cisco6509 59 GigabitEthernet2/11 +cisco6509 60 GigabitEthernet2/12 +cisco6509 61 GigabitEthernet2/13 +cisco6509 62 GigabitEthernet2/14 +cisco6509 63 GigabitEthernet2/15 +cisco6509 64 GigabitEthernet2/16 +cisco6509 65 FastEthernet4/1 +cisco6509 66 FastEthernet4/2 +cisco6509 67 FastEthernet4/3 +cisco6509 68 FastEthernet4/4 +cisco6509 69 FastEthernet4/5 +cisco6509 70 FastEthernet4/6 +cisco6509 71 FastEthernet4/7 +cisco6509 72 FastEthernet4/8 +cisco6509 73 FastEthernet4/9 +cisco6509 74 FastEthernet4/10 +cisco6509 75 FastEthernet4/11 +cisco6509 76 FastEthernet4/12 +cisco6509 77 FastEthernet4/13 +cisco6509 78 FastEthernet4/14 +cisco6509 79 FastEthernet4/15 +cisco6509 80 FastEthernet4/16 +cisco6509 81 FastEthernet4/17 +cisco6509 82 FastEthernet4/18 +cisco6509 83 FastEthernet4/19 +cisco6509 84 FastEthernet4/20 +cisco6509 85 FastEthernet4/21 +cisco6509 86 FastEthernet4/22 +cisco6509 87 FastEthernet4/23 +cisco6509 88 FastEthernet4/24 +cisco6509 89 FastEthernet4/25 +cisco6509 90 FastEthernet4/26 +cisco6509 91 FastEthernet4/27 +cisco6509 92 FastEthernet4/28 +cisco6509 93 FastEthernet4/29 +cisco6509 94 FastEthernet4/30 +cisco6509 95 FastEthernet4/31 +cisco6509 96 FastEthernet4/32 +cisco6509 97 FastEthernet4/33 +cisco6509 98 FastEthernet4/34 +cisco6509 99 FastEthernet4/35 +cisco6509 100 FastEthernet4/36 +cisco6509 101 FastEthernet4/37 +cisco6509 102 FastEthernet4/38 +cisco6509 103 FastEthernet4/39 +cisco6509 104 FastEthernet4/40 +cisco6509 105 FastEthernet4/41 +cisco6509 106 FastEthernet4/42 +cisco6509 107 FastEthernet4/43 +cisco6509 108 FastEthernet4/44 +cisco6509 109 FastEthernet4/45 +cisco6509 110 FastEthernet4/46 +cisco6509 111 FastEthernet4/47 +cisco6509 112 FastEthernet4/48 +cisco6509 113 GigabitEthernet5/1 +cisco6509 114 GigabitEthernet5/2 +cisco6509 115 GigabitEthernet8/1 +cisco6509 116 GigabitEthernet8/2 +cisco6509 117 GigabitEthernet8/3 +cisco6509 118 GigabitEthernet8/4 +cisco6509 119 GigabitEthernet8/5 +cisco6509 120 GigabitEthernet8/6 +cisco6509 121 GigabitEthernet8/7 +cisco6509 122 GigabitEthernet8/8 +cisco6509 123 GigabitEthernet8/9 +\. + + +-- +-- Data for Name: switches; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY switches (switch, ip, sysname, switchtype, last_updated, locked, priority, poll_frequency, community) FROM stdin; +107 81.162.243.120 e37-5sw es3024 2005-03-27 13:17:34.571591+02 f 0 00:05:00 removed +82 81.162.242.95 e29-4sw es3024 2005-03-27 13:16:26.93166+02 f 0 00:05:00 removed +104 81.162.243.117 e37-2sw es3024 2005-03-27 13:17:56.76605+02 f 0 00:05:00 removed +54 81.162.242.67 e19-6sw es3024 2005-03-27 13:18:06.955298+02 f 0 00:05:00 removed +112 81.162.243.125 e39-4sw es3024 2005-03-27 13:18:08.119358+02 f 0 00:05:00 removed +99 81.162.243.112 e35-3sw es3024 2005-03-27 13:18:18.138712+02 f 0 00:05:00 removed +96 81.162.243.109 e33-6sw es3024 2005-03-27 13:19:12.471088+02 f 0 00:05:00 removed +189 81.162.245.202 e65-3sw es3024 2005-03-27 13:19:14.973227+02 f 0 00:05:00 removed +22 81.162.241.35 e9-4sw es3024 2005-03-27 13:20:32.530723+02 f 0 00:05:00 removed +11 81.162.241.24 e5-5sw es3024 2005-03-27 13:20:41.845068+02 f 0 00:05:00 removed +168 81.162.244.181 e57-6sw es3024 2005-03-27 13:20:42.537996+02 f 0 00:05:00 removed +21 81.162.241.34 e9-3sw es3024 2005-03-27 13:21:34.547743+02 t 0 00:05:00 removed +45 81.162.242.58 e17-3sw es3024 2005-03-27 13:21:35.095512+02 t 0 00:05:00 removed +171 81.162.245.184 e59-3sw es3024 2005-03-27 13:21:42.545292+02 t 0 00:05:00 removed +191 81.162.245.204 e65-5sw es3024 2005-03-27 13:16:31.123889+02 f 0 00:05:00 removed +209 127.0.0.1 game es3024 2005-03-27 13:17:24.559535+02 f 0 00:05:00 removed +213 127.0.0.1 logistics es3024 2005-03-27 13:17:24.565673+02 f 0 00:05:00 removed +65 81.162.242.78 e23-5sw es3024 2005-03-27 13:17:46.939821+02 f 0 00:05:00 removed +170 81.162.245.183 e59-2sw es3024 2005-03-27 13:18:04.978308+02 f 0 00:05:00 removed +27 81.162.241.40 e11-3sw es3024 2005-03-27 13:18:17.760774+02 f 0 00:05:00 removed +29 81.162.241.42 e11-5sw es3024 2005-03-27 13:18:31.402994+02 f 0 00:05:00 removed +190 81.162.245.203 e65-4sw es3024 2005-03-27 13:18:36.97826+02 f 0 00:05:00 removed +198 81.162.245.211 e67-6sw es3024 2005-03-27 13:18:46.960978+02 f 0 00:05:00 removed +94 81.162.243.107 e33-4sw es3024 2005-03-27 13:18:54.836293+02 f 0 00:05:00 removed +167 81.162.244.180 e57-5sw es3024 2005-03-27 13:18:59.347337+02 f 0 00:05:00 removed +207 81.162.245.220 e73-2sw es3024 2005-03-27 13:16:31.90388+02 f 0 00:05:00 removed +121 81.162.243.134 e43-1sw es3024 2005-03-27 13:17:32.374414+02 f 0 00:05:00 removed +35 81.162.241.48 e13-5sw es3024 2005-03-27 13:17:36.647606+02 f 0 00:05:00 removed +48 81.162.242.61 e17-6sw es3024 2005-03-27 13:17:37.509652+02 f 0 00:05:00 removed +39 81.162.241.52 e15-3sw es3024 2005-03-27 13:17:46.961826+02 f 0 00:05:00 removed +28 81.162.241.41 e11-4sw es3024 2005-03-27 13:17:46.6959+02 f 0 00:05:00 removed +109 81.162.243.122 e39-1sw es3024 2005-03-27 13:17:56.906062+02 f 0 00:05:00 removed +25 81.162.241.38 e11-1sw es3024 2005-03-27 13:18:31.344059+02 f 0 00:05:00 removed +72 81.162.242.85 e25-6sw es3024 2005-03-27 13:18:52.027008+02 f 0 00:05:00 removed +155 81.162.244.168 e53-5sw es3024 2005-03-27 13:19:11.997064+02 f 0 00:05:00 removed +19 81.162.241.32 e9-1sw es3024 2005-03-27 13:20:23.30851+02 f 0 00:05:00 removed +42 81.162.241.55 e15-6sw es3024 2005-03-27 13:20:23.334654+02 f 0 00:05:00 removed +180 81.162.245.193 e61-6sw es3024 2005-03-27 13:20:37.173987+02 f 0 00:05:00 removed +200 81.162.245.213 e69-3sw es3024 2005-03-27 13:20:47.20716+02 f 0 00:05:00 removed +224 81.162.239.24 d04 summit400 2005-03-27 13:21:24.972747+02 f 5 00:00:20 removed +219 81.162.240.61 game-gw summit48 2005-03-27 13:21:33.484975+02 t 5 00:00:20 removed +88 81.162.243.101 e31-4sw es3024 2005-03-27 13:16:26.527548+02 f 0 00:05:00 removed +113 81.162.243.126 e39-5sw es3024 2005-03-27 13:18:06.543322+02 f 0 00:05:00 removed +64 81.162.242.77 e23-4sw es3024 2005-03-27 13:18:26.656294+02 f 0 00:05:00 removed +81 81.162.242.94 e29-3sw es3024 2005-03-27 13:17:35.445561+02 f 0 00:05:00 removed +101 81.162.243.114 e35-5sw es3024 2005-03-27 13:17:36.945531+02 f 0 00:05:00 removed +16 81.162.241.29 e7-4sw es3024 2005-03-27 13:17:45.453891+02 f 0 00:05:00 removed +43 81.162.242.56 e17-1sw es3024 2005-03-27 13:17:55.459964+02 f 0 00:05:00 removed +122 81.162.243.135 e43-2sw es3024 2005-03-27 13:18:05.467243+02 f 0 00:05:00 removed +133 81.162.244.146 e47-1sw es3024 2005-03-27 13:18:41.709491+02 f 0 00:05:00 removed +32 81.162.241.45 e13-2sw es3024 2005-03-27 13:19:11.73096+02 f 0 00:05:00 removed +4 81.162.241.17 e3-4sw es3024 2005-03-27 13:19:21.737736+02 f 0 00:05:00 removed +80 81.162.242.93 e29-2sw es3024 2005-03-27 13:20:34.240028+02 f 0 00:05:00 removed +62 81.162.242.75 e23-2sw es3024 2005-03-27 13:21:31.873108+02 f 0 00:05:00 removed +214 127.0.0.1 logistics es3024 2005-03-27 13:21:31.924796+02 f 0 00:05:00 removed +215 127.0.0.1 vision es3024 2005-03-27 13:21:31.930782+02 f 0 00:05:00 removed +57 81.162.242.70 e21-3sw es3024 2005-03-27 13:21:40.84502+02 f 0 00:05:00 removed +146 81.162.244.159 e51-2sw es3024 2005-03-27 13:17:45.214911+02 f 0 00:05:00 removed +47 81.162.242.60 e17-5sw es3024 2005-03-27 13:17:51.983994+02 f 0 00:05:00 removed +140 81.162.244.153 e49-2sw es3024 2005-03-27 13:18:28.990817+02 f 0 00:05:00 removed +186 81.162.245.199 e63-6sw es3024 2005-03-27 13:18:38.997342+02 f 0 00:05:00 removed +152 81.162.244.165 e53-2sw es3024 2005-03-27 13:18:49.281799+02 f 0 00:05:00 removed +108 81.162.243.121 e37-6sw es3024 2005-03-27 13:19:01.723458+02 f 0 00:05:00 removed +158 81.162.244.171 e55-2sw es3024 2005-03-27 13:19:09.602985+02 f 0 00:05:00 removed +178 81.162.245.191 e61-4sw es3024 2005-03-27 13:19:19.609527+02 f 0 00:05:00 removed +85 81.162.243.98 e31-1sw es3024 2005-03-27 13:20:29.849688+02 f 0 00:05:00 removed +70 81.162.242.83 e25-4sw es3024 2005-03-27 13:20:39.869994+02 f 0 00:05:00 removed +75 81.162.242.88 e27-3sw es3024 2005-03-27 13:20:49.343969+02 f 0 00:05:00 removed +223 81.162.245.2 d05 summit400 2005-03-27 13:21:36.931022+02 t 5 00:00:20 removed +61 81.162.242.74 e23-1sw es3024 2005-03-27 13:16:26.916608+02 f 0 00:05:00 removed +149 81.162.244.162 e51-5sw es3024 2005-03-27 13:17:41.922862+02 f 0 00:05:00 removed +157 81.162.244.170 e55-1sw es3024 2005-03-27 13:18:18.9515+02 f 0 00:05:00 removed +63 81.162.242.76 e23-3sw es3024 2005-03-27 13:18:27.768739+02 f 0 00:05:00 removed +141 81.162.244.154 e49-3sw es3024 2005-03-27 13:18:31.991117+02 f 0 00:05:00 removed +84 81.162.242.97 e29-6sw es3024 2005-03-27 13:18:37.040327+02 f 0 00:05:00 removed +18 81.162.241.31 e7-6sw es3024 2005-03-27 13:18:41.999541+02 f 0 00:05:00 removed +97 81.162.243.110 e35-1sw es3024 2005-03-27 13:18:45.253797+02 f 0 00:05:00 removed +195 81.162.245.208 e67-3sw es3024 2005-03-27 13:18:51.715929+02 f 0 00:05:00 removed +127 81.162.244.140 e45-1sw es3024 2005-03-27 13:19:02.072477+02 f 0 00:05:00 removed +98 81.162.243.111 e35-2sw es3024 2005-03-27 13:19:04.918692+02 f 0 00:05:00 removed +150 81.162.244.163 e51-6sw es3024 2005-03-27 13:20:32.007722+02 f 0 00:05:00 removed +23 81.162.241.36 e9-5sw es3024 2005-03-27 13:20:41.903998+02 f 0 00:05:00 removed +201 81.162.245.214 e69-4sw es3024 2005-03-27 13:20:49.876993+02 f 0 00:05:00 removed +30 81.162.241.43 e11-6sw es3024 2005-03-27 13:17:56.948002+02 f 0 00:05:00 removed +87 81.162.243.100 e31-3sw es3024 2005-03-27 13:17:58.687121+02 f 0 00:05:00 removed +86 81.162.243.99 e31-2sw es3024 2005-03-27 13:18:05.554204+02 f 0 00:05:00 removed +14 81.162.241.27 e7-2sw es3024 2005-03-27 13:18:08.944334+02 f 0 00:05:00 removed +10 81.162.241.23 e5-4sw es3024 2005-03-27 13:18:16.601602+02 f 0 00:05:00 removed +17 81.162.241.30 e7-5sw es3024 2005-03-27 13:18:28.157952+02 f 0 00:05:00 removed +9 81.162.241.22 e5-3sw es3024 2005-03-27 13:18:36.939248+02 f 0 00:05:00 removed +67 81.162.242.80 e25-1sw es3024 2005-03-27 13:18:51.943995+02 f 0 00:05:00 removed +7 81.162.241.20 e5-1sw es3024 2005-03-27 13:18:58.991329+02 f 0 00:05:00 removed +92 81.162.243.105 e33-2sw es3024 2005-03-27 13:19:06.989323+02 f 0 00:05:00 removed +71 81.162.242.84 e25-5sw es3024 2005-03-27 13:19:09.011272+02 f 0 00:05:00 removed +179 81.162.245.192 e61-5sw es3024 2005-03-27 13:20:29.194747+02 f 0 00:05:00 removed +124 81.162.243.137 e43-4sw es3024 2005-03-27 13:20:39.258962+02 f 0 00:05:00 removed +162 81.162.244.175 e55-6sw es3024 2005-03-27 13:20:42.061636+02 f 0 00:05:00 removed +78 81.162.242.91 e27-6sw es3024 2005-03-27 13:16:29.572827+02 f 0 00:05:00 removed +176 81.162.245.189 e61-2sw es3024 2005-03-27 13:17:32.393394+02 f 0 00:05:00 removed +105 81.162.243.118 e37-3sw es3024 2005-03-27 13:17:45.539842+02 f 0 00:05:00 removed +116 81.162.243.129 e41-2sw es3024 2005-03-27 13:17:42.437966+02 f 0 00:05:00 removed +119 81.162.243.132 e41-5sw es3024 2005-03-27 13:18:07.716339+02 f 0 00:05:00 removed +31 81.162.241.44 e13-1sw es3024 2005-03-27 13:18:44.72174+02 f 0 00:05:00 removed +203 81.162.245.216 e71-2sw es3024 2005-03-27 13:20:52.126954+02 f 0 00:05:00 removed +217 81.162.239.1 inet-gw cisco3550 2005-03-27 13:21:34.339813+02 f 5 00:00:20 removed +221 81.162.241.2 d01 summit400 2005-03-27 13:21:38.690758+02 f 5 00:00:20 removed +220 81.162.240.7 info-gw summit48 2005-03-27 13:21:38.74123+02 t 5 00:00:20 removed +37 81.162.241.50 e15-1sw es3024 2005-03-27 13:21:42.323351+02 t 0 00:05:00 removed +53 81.162.242.66 e19-5sw es3024 2005-03-27 13:17:44.668027+02 f 0 00:05:00 removed +192 81.162.245.205 e65-6sw es3024 2005-03-27 13:19:11.969024+02 f 0 00:05:00 removed +46 81.162.242.59 e17-4sw es3024 2005-03-27 13:20:43.449971+02 f 0 00:05:00 removed +204 81.162.245.217 e71-3sw es3024 2005-03-27 13:20:52.107916+02 f 0 00:05:00 removed +161 81.162.244.174 e55-5sw es3024 2005-03-27 13:21:35.234881+02 t 0 00:05:00 removed +142 81.162.244.155 e49-4sw es3024 2005-03-27 13:21:41.936852+02 f 0 00:05:00 removed +143 81.162.244.156 e49-5sw es3024 2005-03-27 13:21:42.169429+02 t 0 00:05:00 removed +165 81.162.244.178 e57-3sw es3024 2005-03-27 13:17:57.668107+02 f 0 00:05:00 removed +2 81.162.241.12 e1-5sw es3024 2005-03-27 13:18:06.980239+02 f 0 00:05:00 removed +182 81.162.245.195 e63-2sw es3024 2005-03-27 13:16:31.752876+02 f 0 00:05:00 removed +147 81.162.244.160 e51-3sw es3024 2005-03-27 13:17:58.091146+02 f 0 00:05:00 removed +193 81.162.245.206 e67-1sw es3024 2005-03-27 13:18:35.580223+02 f 0 00:05:00 removed +83 81.162.242.96 e29-5sw es3024 2005-03-27 13:18:36.721338+02 f 0 00:05:00 removed +194 81.162.245.207 e67-2sw es3024 2005-03-27 13:18:38.974352+02 f 0 00:05:00 removed +6 81.162.241.19 e3-6sw es3024 2005-03-27 13:18:47.075003+02 f 0 00:05:00 removed +49 81.162.242.62 e19-1sw es3024 2005-03-27 13:19:01.806447+02 f 0 00:05:00 removed +211 127.0.0.1 presse es3024 2005-03-27 13:17:25.438397+02 f 0 00:05:00 removed +90 81.162.243.103 e31-6sw es3024 2005-03-27 13:17:36.889596+02 f 0 00:05:00 removed +52 81.162.242.65 e19-4sw es3024 2005-03-27 13:18:26.931818+02 f 0 00:05:00 removed +136 81.162.244.149 e47-4sw es3024 2005-03-27 13:18:38.226473+02 f 0 00:05:00 removed +5 81.162.241.18 e3-5sw es3024 2005-03-27 13:18:42.447575+02 f 0 00:05:00 removed +183 81.162.245.196 e63-3sw es3024 2005-03-27 13:18:48.289809+02 f 0 00:05:00 removed +169 81.162.245.182 e59-1sw es3024 2005-03-27 13:18:51.524996+02 f 0 00:05:00 removed +137 81.162.244.150 e47-5sw es3024 2005-03-27 13:18:58.34439+02 f 0 00:05:00 removed +111 81.162.243.124 e39-3sw es3024 2005-03-27 13:19:08.389862+02 f 0 00:05:00 removed +126 81.162.243.139 e43-6sw es3024 2005-03-27 13:19:18.396631+02 f 0 00:05:00 removed +115 81.162.243.128 e41-1sw es3024 2005-03-27 13:20:21.794673+02 f 0 00:05:00 removed +144 81.162.244.157 e49-6sw es3024 2005-03-27 13:20:27.601697+02 f 0 00:05:00 removed +205 81.162.245.218 e71-4sw es3024 2005-03-27 13:20:37.610991+02 f 0 00:05:00 removed +103 81.162.243.116 e37-1sw es3024 2005-03-27 13:17:35.19156+02 f 0 00:05:00 removed +160 81.162.244.173 e55-4sw es3024 2005-03-27 13:17:46.897831+02 f 0 00:05:00 removed +177 81.162.245.190 e61-3sw es3024 2005-03-27 13:18:15.475485+02 f 0 00:05:00 removed +79 81.162.242.92 e29-1sw es3024 2005-03-27 13:18:36.728294+02 f 0 00:05:00 removed +208 81.162.245.221 e73-3sw es3024 2005-03-27 13:19:22.036778+02 f 0 00:05:00 removed +24 81.162.241.37 e9-6sw es3024 2005-03-27 13:20:32.103714+02 f 0 00:05:00 removed +76 81.162.242.89 e27-4sw es3024 2005-03-27 13:20:42.111557+02 f 0 00:05:00 removed +44 81.162.242.57 e17-2sw es3024 2005-03-27 13:17:41.971894+02 f 0 00:05:00 removed +66 81.162.242.79 e23-6sw es3024 2005-03-27 13:17:56.972013+02 f 0 00:05:00 removed +41 81.162.241.54 e15-5sw es3024 2005-03-27 13:18:21.393627+02 f 0 00:05:00 removed +8 81.162.241.21 e5-2sw es3024 2005-03-27 13:18:28.967927+02 f 0 00:05:00 removed +15 81.162.241.28 e7-3sw es3024 2005-03-27 13:18:36.799213+02 f 0 00:05:00 removed +1 81.162.241.11 e1-4sw es3024 2005-03-27 13:18:42.522553+02 f 0 00:05:00 removed +123 81.162.243.136 e43-3sw es3024 2005-03-27 13:18:51.995005+02 f 0 00:05:00 removed +129 81.162.244.142 e45-3sw es3024 2005-03-27 13:18:54.851215+02 f 0 00:05:00 removed +56 81.162.242.69 e21-2sw es3024 2005-03-27 13:19:02.014465+02 f 0 00:05:00 removed +181 81.162.245.194 e63-1sw es3024 2005-03-27 13:19:12.059112+02 f 0 00:05:00 removed +33 81.162.241.46 e13-3sw es3024 2005-03-27 13:19:12.08011+02 f 0 00:05:00 removed +68 81.162.242.81 e25-2sw es3024 2005-03-27 13:20:22.092638+02 f 0 00:05:00 removed +139 81.162.244.152 e49-1sw es3024 2005-03-27 13:21:32.131187+02 f 0 00:05:00 removed +166 81.162.244.179 e57-4sw es3024 2005-03-27 13:21:42.167871+02 f 0 00:05:00 removed +55 81.162.242.68 e21-1sw es3024 2005-03-27 13:18:27.760928+02 f 0 00:05:00 removed +187 81.162.245.200 e65-1sw es3024 2005-03-27 13:18:37.783633+02 f 0 00:05:00 removed +135 81.162.244.148 e47-3sw es3024 2005-03-27 13:18:47.790825+02 f 0 00:05:00 removed +69 81.162.242.82 e25-3sw es3024 2005-03-27 13:19:01.960433+02 f 0 00:05:00 removed +114 81.162.243.127 e39-6sw es3024 2005-03-27 13:19:07.807795+02 f 0 00:05:00 removed +185 81.162.245.198 e63-5sw es3024 2005-03-27 13:19:21.979734+02 f 0 00:05:00 removed +163 81.162.244.176 e57-1sw es3024 2005-03-27 13:20:37.80015+02 f 0 00:05:00 removed +222 81.162.242.2 d02 summit400 2005-03-27 13:21:26.058745+02 f 5 00:00:20 removed +120 81.162.243.133 e41-6sw es3024 2005-03-27 13:21:30.769149+02 f 0 00:05:00 removed +128 81.162.244.141 e45-2sw es3024 2005-03-27 13:17:36.931503+02 f 0 00:05:00 removed +174 81.162.245.187 e59-6sw es3024 2005-03-27 13:18:16.963474+02 f 0 00:05:00 removed +148 81.162.244.161 e51-4sw es3024 2005-03-27 13:18:26.970802+02 f 0 00:05:00 removed +110 81.162.243.123 e39-2sw es3024 2005-03-27 13:18:47.000886+02 f 0 00:05:00 removed +77 81.162.242.90 e27-5sw es3024 2005-03-27 13:19:11.815032+02 f 0 00:05:00 removed +145 81.162.244.158 e51-1sw es3024 2005-03-27 13:21:33.428323+02 f 0 00:05:00 removed +218 81.162.239.11 telematics-gw summit7i 2005-03-27 13:21:40.916277+02 t 5 00:00:20 removed +153 81.162.244.166 e53-3sw es3024 2005-03-27 13:17:44.926073+02 f 0 00:05:00 removed +3 81.162.241.13 e1-6sw es3024 2005-03-27 13:19:01.621559+02 f 0 00:05:00 removed +175 81.162.245.188 e61-1sw es3024 2005-03-27 13:19:21.726775+02 f 0 00:05:00 removed +159 81.162.244.172 e55-3sw es3024 2005-03-27 13:20:47.807065+02 f 0 00:05:00 removed +13 81.162.241.26 e7-1sw es3024 2005-03-27 13:20:48.110995+02 f 0 00:05:00 removed +210 81.162.239.10 noc cisco6509 2005-03-27 13:21:26.109659+02 f 5 00:00:20 removed +34 81.162.241.47 e13-4sw es3024 2005-03-27 13:17:34.658518+02 f 0 00:05:00 removed +151 81.162.244.164 e53-1sw es3024 2005-03-27 13:21:41.93941+02 t 0 00:05:00 removed +93 81.162.243.106 e33-3sw es3024 2005-03-27 13:21:42.589349+02 t 0 00:05:00 removed +51 81.162.242.64 e19-3sw es3024 2005-03-27 13:16:25.080516+02 f 0 00:05:00 removed +58 81.162.242.71 e21-4sw es3024 2005-03-27 13:17:35.16855+02 f 0 00:05:00 removed +130 81.162.244.143 e45-4sw es3024 2005-03-27 13:17:55.221024+02 f 0 00:05:00 removed +172 81.162.245.185 e59-4sw es3024 2005-03-27 13:18:05.249512+02 f 0 00:05:00 removed +91 81.162.243.104 e33-1sw es3024 2005-03-27 13:18:51.619208+02 f 0 00:05:00 removed +74 81.162.242.87 e27-2sw es3024 2005-03-27 13:19:01.627392+02 f 0 00:05:00 removed +12 81.162.241.25 e5-6sw es3024 2005-03-27 13:19:11.65907+02 f 0 00:05:00 removed +89 81.162.243.102 e31-5sw es3024 2005-03-27 13:20:31.837713+02 f 0 00:05:00 removed +225 81.162.240.98 bd blackdiamond 2005-03-27 13:21:35.038465+02 f 10 00:00:20 removed +154 81.162.244.167 e53-4sw es3024 2005-03-27 13:16:25.504565+02 f 0 00:05:00 removed +36 81.162.241.49 e13-6sw es3024 2005-03-27 13:17:35.531534+02 f 0 00:05:00 removed +50 81.162.242.63 e19-2sw es3024 2005-03-27 13:17:55.547006+02 f 0 00:05:00 removed +106 81.162.243.119 e37-4sw es3024 2005-03-27 13:18:15.562463+02 f 0 00:05:00 removed +138 81.162.244.151 e47-6sw es3024 2005-03-27 13:19:21.822733+02 f 0 00:05:00 removed +59 81.162.242.72 e21-5sw es3024 2005-03-27 13:17:47.590918+02 f 0 00:05:00 removed +102 81.162.243.115 e35-6sw es3024 2005-03-27 13:18:06.775277+02 f 0 00:05:00 removed +134 81.162.244.147 e47-2sw es3024 2005-03-27 13:18:16.783539+02 f 0 00:05:00 removed +26 81.162.241.39 e11-2sw es3024 2005-03-27 13:18:26.79084+02 f 0 00:05:00 removed +216 127.0.0.1 vision-sponsor es3024 2005-03-27 13:20:53.695607+02 f 0 00:05:00 removed +184 81.162.245.197 e63-4sw es3024 2005-03-27 13:18:06.9152+02 f 0 00:05:00 removed +196 81.162.245.209 e67-4sw es3024 2005-03-27 13:18:16.922538+02 f 0 00:05:00 removed +95 81.162.243.108 e33-5sw es3024 2005-03-27 13:18:16.988269+02 f 0 00:05:00 removed +38 81.162.241.51 e15-2sw es3024 2005-03-27 13:18:26.99682+02 f 0 00:05:00 removed +60 81.162.242.73 e21-6sw es3024 2005-03-27 13:18:57.086812+02 f 0 00:05:00 removed +73 81.162.242.86 e27-1sw es3024 2005-03-27 13:19:07.114926+02 f 0 00:05:00 removed +118 81.162.243.131 e41-4sw es3024 2005-03-27 13:18:52.456053+02 f 0 00:05:00 removed +100 81.162.243.113 e35-4sw es3024 2005-03-27 13:20:22.485517+02 f 0 00:05:00 removed +132 81.162.244.145 e45-6sw es3024 2005-03-27 13:20:32.492844+02 f 0 00:05:00 removed +131 81.162.244.144 e45-5sw es3024 2005-03-27 13:21:42.507294+02 t 0 00:05:00 removed +125 81.162.243.138 e43-5sw es3024 2005-03-27 13:18:52.532065+02 f 0 00:05:00 removed +173 81.162.245.186 e59-5sw es3024 2005-03-27 13:19:12.547121+02 f 0 00:05:00 removed +212 127.0.0.1 info-desk es3024 2005-03-27 13:20:12.561191+02 f 0 00:05:00 removed +188 81.162.245.201 e65-2sw es3024 2005-03-27 13:20:22.567537+02 f 0 00:05:00 removed +40 81.162.241.53 e15-4sw es3024 2005-03-27 13:20:32.574729+02 f 0 00:05:00 removed +199 81.162.245.212 e69-2sw es3024 2005-03-27 13:20:42.582037+02 f 0 00:05:00 removed +156 81.162.244.169 e53-6sw es3024 2005-03-27 13:20:33.372782+02 f 0 00:05:00 removed +202 81.162.245.215 e69-5sw es3024 2005-03-27 13:20:47.618076+02 f 0 00:05:00 removed +20 81.162.241.33 e9-2sw es3024 2005-03-27 13:18:57.800335+02 f 0 00:05:00 removed +117 81.162.243.130 e41-3sw es3024 2005-03-27 13:19:02.463533+02 f 0 00:05:00 removed +164 81.162.244.177 e57-2sw es3024 2005-03-27 13:20:42.500004+02 f 0 00:05:00 removed +197 81.162.245.210 e67-5sw es3024 2005-03-27 13:19:13.321114+02 f 0 00:05:00 removed +\. + + +-- +-- Data for Name: switchtypes; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY switchtypes (switchtype, ports) FROM stdin; +blackdiamond 1001-1007,4001-4016,5001-5024,6001-6048 +es3024 1-25 +cisco6509 1-123 +summit400 1-50 +cisco3550 1-50 +summit7i 1-32 +summit48 1-50 +\. + + diff --git a/web/overlay.pl b/web/overlay.pl new file mode 100755 index 0000000..21eff19 --- /dev/null +++ b/web/overlay.pl @@ -0,0 +1,160 @@ +#! /usr/bin/perl +use GD; +use LWP::Simple; +use CGI; +use DBI; + +my $cgi = CGI->new; +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") +or die "Couldn't connect to database"; + +my $cam = $cgi->param('cam'); +if (!defined($cam) || ($cam ne "1" && $cam ne "2")) { + $cam = 1; +} + +GD::Image->trueColor(1); +my $imgfile = LWP::Simple::get(($cam == 1) ? 'http://tgcam.jodal.no/techserver.php' : 'http://tgcam.jodal.no/crewcam.php') + or die "LWP: $!"; +my $gd = GD::Image->newFromJpegData($imgfile) + or die "GD: $!"; + +my @coeffs; +if ($cam == 1) { + @coeffs = ( + 2.295433895, -3.779680538, 1041.484066, + 0.2246879859, 6.923972919, -1575.662172, + -0.0004822922595, 0.01151624710, -1.684908753 + ); +} else { + @coeffs = ( + 3.656223906, -6.265111699, 863.9199590, + -5.954616242, 51.56856164, -9307.725196, + -0.006634136987, 0.04963057393, -7.875733154 + ); +} + +# fetch our data +my $q = $dbh->prepare('select * from switches natural left join + ( select switch,sum(bytes_in)/count(*) as + bytes_in,sum(bytes_out)/count(*) as bytes_out from get_datarate() group + by switch ) t1 where ip<>\'127.0.0.1\' and sysname like \'e%-%sw\''); +$q->execute(); + +my %sc = (); +while (my $ref = $q->fetchrow_hashref()) { + if (defined($ref->{'bytes_in'})) { + my $intensity = 0.0; + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + + my $max = 20_000_000.0; # 10mbit + my $min = 100_000.0; # 100kbit + if ($traffic >= $min) { + $intensity = 2.0 * (log($traffic / $min) / log(10)) / (log($max / $min) / log(10)); + $intensity = 2.0 if ($intensity > 2.0); + } + + $sc{$ref->{'sysname'}} = get_color($intensity); + } +} + +for my $y (0..479) { + for my $x (0..639) { + my $z = 1.0; + + my $nx = $coeffs[0] * $x + $coeffs[1] * $y + $coeffs[2] * $z; + my $ny = $coeffs[3] * $x + $coeffs[4] * $y + $coeffs[5] * $z; + my $nz = $coeffs[6] * $x + $coeffs[7] * $y + $coeffs[8] * $z; + + my $kx = $nx / $nz + (($cam == 2) ? 700 : 0); + my $ky = $ny / $nz + (($cam == 2) ? -15 : 0); + + if ($kx >= 0 && $kx < 640 && $ky >= 0 && $ky < 476) { + my $col = int($kx / 213) + 1; + my $row = int($ky / 32) * 2 + 5; + + my $gnf = $sc{"e$row-${col}sw"}; + if (defined($gnf)) { + my ($ra, $ga, $ba) = $gd->rgb($gd->getPixel($x, $y)); + my ($rb, $gb, $bb) = $gd->rgb($gnf); + + my $f = 0.5; + + my $r = $ra * (1.0 - $f) + $rb * $f; + my $g = $ga * (1.0 - $f) + $gb * $f; + my $b = $ba * (1.0 - $f) + $bb * $f; + + $gd->setPixel($x, $y, $gd->colorAllocate($r, $g, $b)); + } + } + if ($kx >= 680 && $kx < 1280 && $ky >= 0 && $ky < 476) { + my $col = int(($kx - 680) / 213) + 4; + my $row = int($ky / 32) * 2 + 5; + + my $gnf = $sc{"e$row-${col}sw"}; + if (defined($gnf)) { + my ($ra, $ga, $ba) = $gd->rgb($gd->getPixel($x, $y)); + my ($rb, $gb, $bb) = $gd->rgb($gnf); + + my $f = 0.5; + + my $r = $ra * (1.0 - $f) + $rb * $f; + my $g = $ga * (1.0 - $f) + $gb * $f; + my $b = $ba * (1.0 - $f) + $bb * $f; + + $gd->setPixel($x, $y, $gd->colorAllocate($r, $g, $b)); + } + } + if ($kx >= 0 && $kx < 640 && $ky >= 510 && $ky < 1050) { + my $col = int($kx / 213) + 1; + my $row = int($ky / 32) * 2 + 5; + + my $gnf = $sc{"e$row-${col}sw"}; + if (defined($gnf)) { + my ($ra, $ga, $ba) = $gd->rgb($gd->getPixel($x, $y)); + my ($rb, $gb, $bb) = $gd->rgb($gnf); + + my $f = 0.5; + + my $r = $ra * (1.0 - $f) + $rb * $f; + my $g = $ga * (1.0 - $f) + $gb * $f; + my $b = $ba * (1.0 - $f) + $bb * $f; + + $gd->setPixel($x, $y, $gd->colorAllocate($r, $g, $b)); + } + } + if ($kx >= 680 && $kx < 1280 && $ky >= 510 && $ky < 1050) { + my $col = int(($kx - 680) / 213) + 4; + my $row = int($ky / 32) * 2 + 5; + + my $gnf = $sc{"e$row-${col}sw"}; + if (defined($gnf)) { + my ($ra, $ga, $ba) = $gd->rgb($gd->getPixel($x, $y)); + my ($rb, $gb, $bb) = $gd->rgb($gnf); + + my $f = 0.5; + + my $r = $ra * (1.0 - $f) + $rb * $f; + my $g = $ga * (1.0 - $f) + $gb * $f; + my $b = $ba * (1.0 - $f) + $bb * $f; + + $gd->setPixel($x, $y, $gd->colorAllocate($r, $g, $b)); + } + } + } +} + + +print CGI::header(-type=>'image/png', -refresh=>'10; http://nms.tg05.gathering.org/overlay.pl?cam=' . $cam); +print $gd->png; + +sub get_color { + my $intensity = shift; + my $gamma = 1.0/1.90; + if ($intensity > 1.0) { + return $gd->colorAllocate(255.0, 255.0 * ((2.0 - $intensity) ** $gamma), 0); + } else { + return $gd->colorAllocate(255.0 * ($intensity ** $gamma), 255, 0); + } +} + diff --git a/web/portkart.pl b/web/portkart.pl new file mode 100755 index 0000000..24a26ec --- /dev/null +++ b/web/portkart.pl @@ -0,0 +1,71 @@ +#! /usr/bin/perl +use CGI; +use GD; +use DBI; +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +GD::Image->trueColor(1); +$img = GD::Image->new('snmp-bg.png'); + +my $blk = $img->colorResolve(0, 0, 0); + +for my $y (42..236) { + my $i = 2.0 * ($y - 236.0) / (42.0 - 237.0); + my $clr = get_color($i); + + $img->filledRectangle(32,$y,53,$y+1,$clr); +} + +my $q = $dbh->prepare('select switch,port,bytes_in,bytes_out,placement,switchtype from switches natural join placements natural join get_current_datarate() where switchtype in (\'es3024\')'); +$q->execute(); +while (my $ref = $q->fetchrow_hashref()) { + + # for now: + # 100kbit/port = all green + # 1gbit/port = all red + + my $clr; + + if (defined($ref->{'bytes_in'})) { + my $intensity = 0.0; + my $traffic = 4.0 * $ref->{'bytes_in'} + $ref->{'bytes_out'}; # average and convert to bits (should be about the same in practice) + + my $max = 20_000_000.0; # 100mbit + my $min = 100_000.0; # 100kbit + if ($traffic >= $min) { + $intensity = 2.0 * (log($traffic / $min) / log(10)) / (log($max / $min) / log(10)); + $intensity = 2.0 if ($intensity > 2.0); + } + $clr = get_color($intensity); + } else { + $clr = $img->colorResolve(0, 0, 255); + } + + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + my $npo = ($ref->{'switchtype'} eq 'es3024') ? 26 : 25; + my $f = ($ref->{'port'} - 1) % 2; + my $po = ($ref->{'port'} - 1 - $f)/2; + my $h = 2*($2-$4)/$npo; + my $w = ($1-$3)/2; + + $img->filledRectangle($3+$w*$f,$4+$po*$h,$3+$w+$w*$f,$4+$h*($po+1),$clr); +# $img->rectangle($3+$w*$f,$4+$po*$h,$3+$w+$w*$f,$4+$h*($po+1),$blk); + $img->rectangle($3,$4,$1,$2,$blk); +} +$dbh->disconnect; + +print $cgi->header(-type=>'image/png'); +print $img->png; + +sub get_color { + my $intensity = shift; + my $gamma = 1.0/1.90; + if ($intensity > 1.0) { + return $img->colorResolve(255.0, 255.0 * ((2.0 - $intensity) ** $gamma), 0); + } else { + return $img->colorResolve(255.0 * ($intensity ** $gamma), 255, 0); + } +} diff --git a/web/sendsms.pl b/web/sendsms.pl new file mode 100755 index 0000000..86b80ef --- /dev/null +++ b/web/sendsms.pl @@ -0,0 +1,55 @@ +#!/usr/bin/perl +# + +use HTTP::Cookies; +use LWP::UserAgent; +use Data::Dumper; +use strict; +use warnings; + +my $uname = "eirikn"; +my $pass = "removed"; + +my $ua = new LWP::UserAgent; +$ua->timeout(15); +$ua->agent('Mozilla/5.0'); + +#$ua->credentials( "http://zepo.tg05.gathering.org", "/", $uname, $pass ); + +my $content; +my %form; +$form{'userid'} = $uname; +$form{'next'} = "Look me up"; + +#my $content = $ua->get("http://zepo.tg05.gathering.org/"); + + +$content = $ua->post("http://zepo.tg05.gathering.org/login", \%form); + +if (!defined($content->{'_headers'}{'location'})) { + die "Could not find dudes"; +} +$content->{'_headers'}{'set-cookie'} =~ /SID=(\w+);/; +my $sessioncookie = $1; +$content = $ua->get("https://partyticket.net/enter?dude_id=39457&got=it", "cookie" => "SID=".$sessioncookie.";"); + +$content->{'_headers'}{'set-cookie'} =~ /SID=(\w+);/; +$sessioncookie = $1; + +print Dumper($content); + +$form{'password'} = $pass; +$form{'userid'} = 39457; +$form{'next'} = "Log in"; +$content = $ua->post("https://zepo.tg05.gathering.org/enter&got=it", "cookie" => "SID=".$sessioncookie, \%form); + +print Dumper($content); + + + + +sub getpage { + my ($page) = @_; + + +} diff --git a/web/showswitch.pl b/web/showswitch.pl new file mode 100755 index 0000000..7dd716c --- /dev/null +++ b/web/showswitch.pl @@ -0,0 +1,215 @@ +#! /usr/bin/perl +use CGI; +use DBI; +use Time::HiRes; +use POSIX ":sys_wait_h"; +use strict; +use warnings; +my $cgi = CGI->new; +my $switch = $cgi->param('id'); +my $width = $cgi->param('width'); +my $height = $cgi->param('height'); +my @pids = (); +my $resthtml = ""; + +$width = 500 unless (defined($width)); +$height = 250 unless (defined($height)); + +require './mygraph.pl'; + +my $start = [Time::HiRes::gettimeofday]; +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +# Fetch the name +my $ref = $dbh->selectrow_hashref('SELECT sysname FROM switches WHERE switch=?', undef, $switch); + +print $cgi->header(-type=>'text/html; charset=utf-8'); +print <<"EOF"; + + + snmp + + +

Switch $switch ($ref->{'sysname'})

+EOF + +my $q = $dbh->prepare('select port,coalesce(description, \'Port \' || port) as description,extract(epoch from time) as time,bytes_in,bytes_out from polls natural join switches natural left join portnames where time between now() - \'1 day\'::interval and now() and switch=? order by switch,port,time;'); +$q->execute($switch); + +my (@totx, @toty1, @toty2) = (); + +my (@x, @y1, @y2) = (); +my $last_port = -1; +my $portname = ""; +my $min_x = time; +my $max_x = time - 86400; +my ($min_y, $max_y, $prev_time, $prev_in, $prev_out); +my ($if,$of,$ifv,$ofv); +my $idx; +my ($min_ty,$max_ty) = (0, 10_000_000/8); + +$prev_time = -1; +my $last_totx; +while (my $ref = $q->fetchrow_hashref()) { + my $time = $ref->{'time'}; + my $in = $ref->{'bytes_in'}; + my $out = $ref->{'bytes_out'}; + next if ($time == $prev_time); + + if ($ref->{'port'} != $last_port) { + if ($last_port != -1) { + my $filename = "$switch-$last_port-$width-$height.png"; + + # reap children + waitpid(-1, WNOHANG); + + my $pid = fork(); + if ($pid == 0) { +# write out the graph + my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5); + plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y); + plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y); + + open GRAPH, ">img/$filename" + or die "img/$filename: $!"; + print GRAPH $graph->png; + close GRAPH; + exit; + } + + push @pids, $pid; + + $resthtml .= "

$portname

\n"; + $resthtml .= "

\n"; + } + + # Reset all the variables + @x = (); + @y1 = (); + @y2 = (); + ($min_y,$max_y) = (0, 10_000_000/8); + $prev_time = $ref->{'time'}; + $prev_in = $ref->{'bytes_in'}; + $prev_out = $ref->{'bytes_out'}; + $last_port = $ref->{'port'}; + $portname = $ref->{'description'}; + ($if,$of,$ifv,$ofv) = (0,0,0,0); + ($prev_time,$prev_in,$prev_out) = ($time,$in,$out); + $idx = 0; + $last_totx = undef; + next; + } + + # Assume overflow (unless the switch has been down for >10 minutes) + my ($calc_in, $calc_out) = ($in, $out); + if ($in < $prev_in || $out < $prev_out) { + # ick, heuristics + if ($prev_time - $time > 600 || ($in + 4294967296 - $prev_in) > 2147483648 || ($out + 4294967296 - $prev_out) > 2147483648) { + ($prev_time,$prev_in,$prev_out) = ($time,$in,$out); + next; + } + + $calc_in += 4294967296 if ($in < $prev_in); + $calc_out += 4294967296 if ($out < $prev_out); + } + + # Remove dupes + if ($in == $prev_in && $out == $prev_out) { + ($prev_time,$prev_in,$prev_out) = ($time,$in,$out); + next; + } + + # Find the current flow + my $if = ($calc_in - $prev_in) / ($time - $prev_time); + my $of = ($calc_out - $prev_out) / ($time - $prev_time); + + # Summarize (we don't care about the summed variance for now) + $min_x = $time if (!defined($min_x) || $time < $min_x); + $max_x = $time if (!defined($max_x) || $time > $max_x); + $min_y = $if if (!defined($min_y) || $if < $min_y); + $min_y = $of if ($of < $min_y); + $max_y = $if if (!defined($max_y) || $if > $max_y); + $max_y = $of if ($of > $max_y); + + my $pt = 0.5 * ($time + $prev_time); + + push @x, $pt; + push @y1, $if; + push @y2, $of; + + while ($idx < $#totx && $pt > $totx[$idx]) { + ++$idx; + } + if ($idx >= $#totx) { + push @totx, $pt; + push @toty1, $if; + push @toty2, $of; + ++$idx; + + $min_ty = $if if (!defined($min_ty) || $if < $min_ty); + $min_ty = $of if ($of < $min_ty); + $max_ty = $if if (!defined($max_ty) || $if > $max_ty); + $max_ty = $of if ($of > $max_ty); + } else { + if (!defined($last_totx) || $last_totx != $idx) { + $toty1[$idx] += $if; + $toty2[$idx] += $of; + } + $last_totx = $idx; + + $min_ty = $toty1[$idx] if (!defined($min_ty) || $toty1[$idx] < $min_ty); + $min_ty = $toty2[$idx] if ($toty2[$idx] < $min_ty); + $max_ty = $toty1[$idx] if (!defined($max_ty) || $toty1[$idx] > $max_ty); + $max_ty = $toty2[$idx] if ($toty2[$idx] > $max_ty); + } + + ($prev_time,$prev_in,$prev_out) = ($time,$in,$out); +} +$dbh->disconnect; + +# last graph +my $filename = "$switch-$last_port-$width-$height.png"; + +my $pid = fork(); +if ($pid == 0) { + my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5); + plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y); + plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y); + + open GRAPH, ">img/$filename" + or die "img/$filename: $!"; + print GRAPH $graph->png; + close GRAPH; + exit; +} + +push @pids, $pid; + +$resthtml .= "

$portname

\n"; +$resthtml .= "

\n"; + +# total graph +my $graph = makegraph($width, $height, $min_x, $max_x, $min_ty, $max_ty, 5); +plotseries($graph, \@totx, \@toty1, 255, 0, 0, $min_x, $max_ty); +plotseries($graph, \@totx, \@toty2, 0, 0, 255, $min_x, $max_ty); + +my $filename = "$switch-$width-$height.png"; +open GRAPH, ">img/$filename" +or die "img/$filename: $!"; +print GRAPH $graph->png; +close GRAPH; + +# Wait for all the other graphs to be done +while (waitpid(-1, 0) != -1) { + 1; +} + +print $resthtml; + +print "

Total

\n"; +print "

\n"; + +my $elapsed = Time::HiRes::tv_interval($start); +printf "

Page and all graphs generated in %.2f seconds.

\n", $elapsed; +print "\n\n"; diff --git a/web/smanagement.pl b/web/smanagement.pl new file mode 100755 index 0000000..ce270c3 --- /dev/null +++ b/web/smanagement.pl @@ -0,0 +1,273 @@ +#!/usr/bin/perl +# +# + +my $username = ''; +my $password = 'removed'; + +# Seconds to wait for connection +my $timeout = 15; + + +use warnings; +use strict; +use Switch; +use CGI; +use Net::Telnet; +use DBI; +use Data::Dumper; + +# Grab from .htaccess-authentication +my $user = $ENV{'REMOTE_USER'}; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", + "snmpfetch", "removed") + or die "Couldn't connect to database"; +$dbh->{AutoCommit} = 0; + +# Ugly casting, found not other way +my $sinsert = $dbh->prepare( "INSERT INTO squeue + (gid, added, priority, addr, sysname, cmd, author) + VALUES(?::text::int, now(), ?::text::int, ?::text::inet, ?, ?, ?)") + or die "Could not prepare sinsert"; +my $sgetip = $dbh->prepare("SELECT ip FROM switches WHERE sysname = ?") + or die "Could not prepare sgetip"; +my $sgid = $dbh->prepare("SELECT nextval('squeue_group_sequence') as gid"); + +# Send a command to switch and return the data recvied from the switch +sub switch_exec($$) { + my ($cmd, $conn) = @_; + + # Send the command and get data from switch + my @data = $conn->cmd($cmd); + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push (@lines, $line); + } + + return @lines; +} + +sub switch_connect($) { + my ($ip) = @_; + + my $conn = new Net::Telnet( Timeout => $timeout, + Errmode => 'return', + Prompt => '/(es3024|e\d+\-\dsw)>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (0); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login( Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + $conn->cmd($password); + # Get rid of banner + $conn->get; + return ($conn); +} + +sub parse_range($) { + my $switches = $_; + my @range; + + my @rangecomma = split(/\s*,\s*/, $switches); + foreach (@rangecomma) { + my ($first, $drop1, $last, $drop2) = $_ =~ /(e\d+\-[123456])(sw)?\s*\-\s*(e\d+\-[123456])?(sw)?/; + if (!defined($first) && $_ =~ /e\d+\-[123456]/) { + $first = $_; + } + if (!defined($first)) { + print "Parse error in: $_
\n"; + next; + } + my ($rowstart, $placestart) = $first =~ /e(\d+)\-([123456])/; + if (!defined($rowstart) || !defined($placestart)) { + print "Parse error in: $_
\n"; + next; + } + my ($rowend, $placeend); + if (!defined($last)) { + $rowend = $rowstart; + $placeend = $placestart; + } + else { + ($rowend, $placeend) = $last =~ /e(\d+)\-([123456])/; + } + if (!defined($rowend) || !defined($placeend)) { + print "Parse error in: $_
\n"; + next; + } + #print "e $rowstart - $placestart to e $rowend - $placeend
\n"; + for (my $i = $rowstart; $i <= $rowend; $i++) { + my $dostart; + if ($rowstart != $i) { + $dostart = 1; + } + else { + $dostart = $placestart; + } + for (my $j = $dostart; $j <= 6; $j++) { + last if ($i == $rowend && $j > $placeend); + push(@range, "e$i-$j"); + } + } + } +# foreach (@range) { +# print ":: $_
\n"; +# } + return @range; +} + +sub get_addr_from_switchnum($) { + my ($sysname) = @_; + + $sgetip->execute($sysname."sw"); + if ($sgetip->rows() < 1) { + print "Could not get the ip for: ".$sysname."sw"; + return undef; + } + my $row = $sgetip->fetchrow_hashref(); + return $row->{'ip'}; +} + +my $cgi = new CGI; + +print $cgi->header(-type=>'text/html'); + +print << "EOF"; + + + Switch managment + + +

Du er logget inn som: $user

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Alle switcheneDisabled
Switche1-2, e3-3 - e10-2
Rad1,3-5 (Disabled)




Prioritet + +
Kommando(er):En kommando per linje




+
+
+EOF + +print "
\n"; + +my @switches = (); +switch ($cgi->param('rangetype')) { + case 'all' { +# print "Sender `".$cgi->param('cmd')."` til alle switchene
"; + @switches = (); + print "Slått av!\n"; + } + case 'switch' { +# print "Sender `".$cgi->param('cmd')."` til switchene `" +# .$cgi->param('range')."`.
"; + $_ = $cgi->param('range'); + @switches = parse_range($_); + } + case 'row' { +# print "Sender `".$cgi->param('cmd')."` til radene `" +# .$cgi->param('range')."`.
"; +# print "This function does not work yet."; +# $_ = $cgi->param('range'); +# @switches = &parse_row_range($_); + @switches = (); + print "Slått av!\n"; + } +} + +my $gid; +if (@switches > 0) { + $sgid->execute(); + my $row = $sgid->fetchrow_hashref(); + $gid = $row->{gid}; +} + +my $pri = $cgi->param('priority'); + +print "
\n";
+foreach my $switch (@switches) {
+	my $addr = get_addr_from_switchnum($switch);
+	if (!defined($addr)) {
+		next;
+	}
+	print "$switch got addr $addr 
\n"; + my @cmds = split(/[\n\r]+/, $cgi->param('cmd')); + print "Queuing commands for $switch:\n"; + foreach my $cmd (@cmds) { + my $result = $sinsert->execute($gid, $pri, $addr, $switch, $cmd, $user); + # my $result = 1; + if (!$result) { + print "\t" + ."Could not execute query." + ."\n"; + print "\t".$dbh->errstr."\n"; + } + else { + print "\tQueued: $cmd\n"; + } + } + print "\n"; +} +$dbh->commit; +if (defined($gid)) { + print "Vis resultat\n"; +} +print "
\n"; + +print << "EOF"; + + +EOF diff --git a/web/snmp-bg.png b/web/snmp-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..a63a19e9812bb547ddf6a5ca34db1294878bafd3 GIT binary patch literal 54273 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ⅇ}5JZ`=JSf^T3l`+v88^$g4m!OhB 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 + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push (@lines, $line); + } + + return @lines; +} + +sub switch_connect($) { + my ($ip) = @_; + +# Dump_Log => '/tmp/dumplog-queue', + my $conn = new Net::Telnet( Timeout => $timeout, + Errmode => 'return', + Prompt => '/(es3024|e\d+\-\dsw)>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (undef); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login(»·Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + $conn->cmd($password); + # Get rid of banner + $conn->get; + return ($conn); +} + +sub mylog { + my $msg = shift; + my $time = POSIX::ctime(time); + $time =~ s/\n.*$//; + printf STDERR "[%s] %s\n", $time, $msg; +} + +if ($#ARGV != 1) { + die("Error in arguments passed\n". + "./ssendfile.pl addr configfile\n"); +} + +my $conn = switch_connect($ARGV[0]); +if (!defined($conn)) { + die("Could not connect to switch.\n"); +} + +open(CONFIG, $ARGV[1]); +while () { + my $cmd = $_; + $cmd =~ s/[\r\n]+//g; + print "Executing: `$cmd`\n"; +# if ($cmd =~ /ip ifconfig swif0 (\d{1-3}\.\d{1-3}\.\d{1-3}\.\d{1-3})/) { +# print "New ip: $1\n"; +# $conn->cmd( String => $cmd, +# Timeout => 3); +# $conn = switch_connect($1); +# if (!defined($conn)) { +# die "Could not connect to new ip: $1\n"; +# } +# } +# else { + my @data = switch_exec($cmd, $conn); + foreach my $line (@data) { + $line =~ s/[\r\n]+//g; + print "$line\n"; + } +# } +} diff --git a/web/sshow.pl b/web/sshow.pl new file mode 100755 index 0000000..32a8306 --- /dev/null +++ b/web/sshow.pl @@ -0,0 +1,269 @@ +#!/usr/bin/perl +# +# + +my $username = ''; +my $password = 'removed'; + +# Seconds to wait for connection +my $timeout = 15; + +use warnings; +use strict; +use Switch; +use CGI; +use Net::Telnet; +use DBI; + +# Grab from .htaccess-authentication +my $user = $ENV{'REMOTE_USER'}; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", + "snmpfetch", "removed") + or die "Couldn't connect to database"; +$dbh->{AutoCommit} = 0; + +my $sgetdone = $dbh->prepare( +"SELECT * +FROM squeue +WHERE processed = 't' +ORDER BY updated DESC, sysname +LIMIT ?::text::int") + or die "Could not prepare sgetdone"; + +my $sgetdonegid = $dbh->prepare( +"SELECT * +FROM squeue +WHERE processed = 't' AND gid = ?::text::int +ORDER BY updated DESC, sysname") + or die "Could not prepare sgetdonegid"; + +my $slistdonegid = $dbh->prepare( +"SELECT DISTINCT gid, cmd, author, added +FROM squeue +WHERE processed = 't' +ORDER BY gid") + or die "Could not prepare slistdonegid"; + +my $slistprocgid = $dbh->prepare( +"SELECT DISTINCT gid, cmd, author, added +FROM squeue +WHERE processed = 'f' +ORDER BY gid") + or die "Could not prepare slistdonegid"; + +my $sgetgid = $dbh->prepare( +"SELECT * +FROM squeue +WHERE gid = ?") + or die "Could not prepare sgetgid"; + +my $sgetprocessing = $dbh->prepare( +"SELECT * +FROM squeue +WHERE processed = 'f' +ORDER BY updated DESC, gid, sysname") + or die "Could not prepare sgetdone"; + +my $sgetnoconnect = $dbh->prepare( +"SELECT * +FROM squeue +WHERE result = 'Could not connect to switch, delaying...'") + or die "Could not prepare sgetnoconnect"; + +my $sdisablegid = $dbh->prepare(" +UPDATE squeue SET disabled = 't' +WHERE gid = ?::text::int") + or die "Could not prepare sdisablegid"; +my $senablegid = $dbh->prepare(" +UPDATE squeue SET disabled = 'f' +WHERE gid = ?::text::int") + or die "Could not prepare sdisablegid"; + + +my $cgi = new CGI; + +print $cgi->header(-type=>'text/html'); + +print << "EOF"; + + + Switch managment + + +

Du er logget inn som: $user

+
+

+ Vis siste
+ Vis: +
+

+
+
+EOF + +my $limit = $cgi->param('count'); +if (!defined($limit)) { + $limit = 10; +} +my $action = $cgi->param('action'); +if (!defined($action)) { + $action = 'listgid'; +} + +if (defined($cgi->param('agid'))) { + my $gid = $cgi->param('gid'); + if (!defined($gid)) { + print "Du har ikke valgt en gid å slette.\n"; + } + if ($cgi->param('agid') eq 'Disable') { + $sdisablegid->execute($gid); + print "

gid: ".$cgi->param('gid')." har blitt disablet.\n"; + } + else { + $senablegid->execute($gid); + print "

gid: ".$cgi->param('gid')." har blitt enablet.\n"; + } + $dbh->commit(); +} + +if ($action eq 'noconnect') { + print "

Kunne ikke koble til disse switchene:

\n"; + $sgetnoconnect->execute(); + print "
\n";
+	while ((my $row = $sgetnoconnect->fetchrow_hashref())) {
+		print "$row->{'sysname'} : $row->{'cmd'} : Added: $row->{'added'} : Updated: $row->{'updated'}\n";
+	}
+	print "
\n"; +} + +if ($action eq 'listgid') { + print "
\n";
+	print "Kunne ikke koble til\n\n\n";
+	print "Ferdige:\n";
+	$slistdonegid->execute();
+	my ($gid, $author);
+	$gid = -1;
+	while ((my $row = $slistdonegid->fetchrow_hashref())) {
+		$author = $row->{author};
+		if ($gid != $row->{gid}) {
+			$gid = $row->{gid};
+			print "GID: $gid\n";
+			print "Author: $author\n";
+			print "Added: ".$row->{added}."\n";
+		}
+		my $cmd = $row->{cmd};
+		print "\t$cmd\n";
+	}
+	print "\n\n";
+	print "I kø:\n";
+	$slistprocgid->execute();
+	$gid = -1;
+	while ((my $row = $slistprocgid->fetchrow_hashref())) {
+		$author = $row->{author};
+		if ($gid != $row->{gid}) {
+			$gid = $row->{gid};
+			print "GID: $gid\n";
+			print "Author: $author\n";
+			print "Added: ".$row->{added}."\n";
+		}
+		my $cmd = $row->{cmd};
+		print "\t$cmd\n";
+	}
+	$dbh->commit();
+	print "
\n"; +} + +if ($action eq 'showgid') { + print "
\n";
+	$sgetgid->execute($cgi->param('gid'));
+	my $row = $sgetgid->fetchrow_hashref();
+	print "GID: ".$row->{gid}."\n";
+	print "Author: ".$row->{author}."\n";
+	do {
+		print "    Name: ".$row->{sysname}." Addr: ".$row->{addr}."\n";
+		print "    `".$row->{cmd}."`\n";
+		print "    Added: ".$row->{added}." executed ".$row->{updated}."\n";
+		my $data = $row->{result};
+		if (!defined($data)) {
+			$data = "Not executed yet!";
+		}
+		my @lines = split(/[\n\r]+/, $data);
+		foreach my $line (@lines) {
+			print "\t$line\n";
+		}
+	} while (($row = $sgetgid->fetchrow_hashref()));
+	print "
\n"; +} + +if ($action eq 'done') { + print "

Done

\n"; + print "
\n";
+
+	my $squery;
+	if (defined($cgi->param('gid'))) {
+		my $gid = $cgi->param('gid');
+		$sgetdonegid->execute($gid);
+		$squery = $sgetdonegid;
+	}
+	else {
+		$sgetdone->execute($limit);
+		$squery = $sgetdone;
+	}
+	my $sysname = '';
+	while (my $row = $squery->fetchrow_hashref()) {
+		if ($sysname ne $row->{'sysname'}) {
+			$sysname = $row->{'sysname'};
+			print "$sysname (".$row->{addr}."):\n";
+		}
+		print "   Author: ".$row->{author}."\n";
+		print "   Cmd: ".$row->{cmd}."\n";
+		print "   Added: ".$row->{added}." Updated: ".$row->{updated}."\n";
+		print "   gID: ".$row->{gid}."\n";
+		my @result = split(/[\n\r]+/, $row->{result});
+		foreach (@result) {
+			print "\t".$_."\n";
+		}
+		print "\n";
+	}
+	$dbh->commit();
+	print "
\n"; +} +elsif ($action eq 'processing') { + print "

Processing

\n"; + print "
\n";
+	$sgetprocessing->execute();
+	while (my $row = $sgetprocessing->fetchrow_hashref()) {
+		my $sysname = $row->{'sysname'};
+		print "$sysname (".$row->{addr}."):\n";
+		print "   Author: ".$row->{author}."\n";
+		print "   Cmd: ".$row->{cmd}."\n";
+		my $updated;
+		if (defined($row->{updated})) { $updated = $row->{updated}; }
+		else { $updated = 'never'; }
+		print "   Added: ".$row->{added}." Updated: ".$updated."\n";
+		print "   Disabled: ".$row->{disabled}."\n";
+		print "   Locked: ".$row->{locked}."\n";
+		print "   gID: ".$row->{gid};
+		print "   
"; + print "{gid}."\">"; + print ""; + if ($row->{disabled} == 0) { + print "\n"; + } + else { + print "\n"; + } + } + $dbh->commit(); + print "
\n"; +} + +print << "EOF"; + + +EOF diff --git a/web/stemp-bg5.png b/web/stemp-bg5.png new file mode 100644 index 0000000000000000000000000000000000000000..e48227aaca9efd9690b2cdfef4ad5a5aa0bfb132 GIT binary patch literal 3036 zcmbtWX;c&E8jgA~ZfFG+(IPIPR1grCibV0SGe-8U3IRbD0|~Sc2p9?C0#dYi0|pl& zr6^mA0YU~bLcAb1NC3+wfh1sA4G_X&5=nwIK|BcUJw2!Q$GqRncjkTGWxnTmC)vrt zR&~v`H4q3y6|l2%fk2j%AdqFQs}viMTsQSoie>e8cBdmDkhSW{YZ>HT=2pcf6bsl} zL)%wu+O%s`YR1~riY+ay^|x5da116e3=6T02=v1S2JFP4u;+KWoe$h;3)nje19ZX^ zATEHFxm!$^fES8x7ilpkULCFc%>sq0h`O{s?_Ao^BMDa2qyCo<*4(*;tYdQz@PZEY zVoz!Ch!xdmZ>+g|7NX+kZ+@+I&F}u{_ngBFYDpFe&1=gZNk+2sGJQOq|4V+#$`~PRO`%ugiD#`J^imR)>lOTp4@YS-Y9(90VUM? zc8~f}+Cl+pVlIYQ)lmF&NtIcRl z1K^CWvBfo4qFY(mWf;m8DE&bO0#O>trj13}Hyk7rf< zaAf8&x8GZ|y$Q*E^VnXlri%u!BCw(H*7^XuIB|OoNMScoc^LY0aUka!Xw+#4@`C6u zqNxHZxE-C*^;oNauf9OE77Rsaa2}V(HASZh4uW2otWvE~WB?p3dm^|lkeffy4WVd{ zX5132FzV9Sq7qfCZ+sW((3DfJlhgL< zRlO1qyOHZ1U0>cX-*J8>hKv9_`Bd=8n0sumnfoymzLkKy{?d6M2kdEZ7v&{kOJ-%k z0|ns7o#8#)@MGLcFMn3HKWjW<$n+pNWnax_G3EPz)mO>bY(Mztm%KYb2fGNwFOGO#p z4>1?s=cWOEsQXcsdTYOp!Sj!W1t&*VrjSz%t3MC|35Qdc`!rA+NpigR7sy$JVj z%lgMYXy9+FnJZP%^^J-g=i)5!QC76H1M}_iL+t+arIh{u3}OBZeC%PhqV~C?p?vg1 z{5%rK>RKnHd5!*}3WkF`H2!D7Hypl#AUi_ot*9M5P_21{cOzY^oC6aPiaJn6)0NXQE2 zzDCoSLN}Q!A+@v0Gn*Z^=6Kj_)oEG##yV%_9ztGNllv3lt?CV&S3~4uQ8uakNpIQo zz$U$xNQ;fspq2!+DC?&D5p!9rwt*`yxZ*<4G&$zk$;#{y(fY}Y6L|;Up&}E_$b-03 zs6^?u18umZ8RmpVqBk<}Q0<3=OMR(dO&~I_Q(;ZSMMg1YsIWz5Ve-u1?QSBPAQqVg zgtyWyc=z}Yd5KFS4Apy%a6*xQR9!hn@S_(QS%^uvNRyG}_zpgeBg`6i3pX+(GDl;A z?z8>l65lUH6sTZ@4N3f7utiGNoPa-N3pe{Q@FZ!aUOx`jDm+|7Nb-DN3BDAHJ>`U= zZXwANN_f!d{z3G#W2QTzTX;`(8PEboE^BvKl^>1CgrS%PKMl8BDfB(+O-x5_%}F#a z38{OR1u2!C&)nA9+x8@;49360jXC^io$FM}2X)H`vy)B;m&<2-?i_kE^<`}QldeA7 z{FwqH1o20Vqs!Od0NKp&4A|ztn{AKY*hL+S$b<3Q1_Q3iTs9Hdv%WdAG(x&*P7Ze3 z7Kb3#cRbWjfU>7SJ-R?4($t1WKG$||gaEj-R+kK`-gFf<2$hq_ zQ(gN~HS{O>3GGXhcl$C-6lXXz7-8luWc1aD%=(f><`ip@axLM*A{H)T)c@kpi_?D= z)xRXvX8?aC#B)BM1b3d}izvAfge}lmfv}*zA4PiJN1<5@H2&OYi7>DJ9O3^~y(Mb2 zNH^#8_>+Py(-+ZeikdT;uf0u}D76$jH*G03%0B08`7+v0F7EFH`T_KQ~SH;sR zeNgn*(bohkIgh~mm@Jxdu8VazwICd$(KQAl_t#Cm>l{hKK+zJfgT-Ix*C35e{lRtn zl3jhgo=s{~EBBeJ(2`9*sB>7h`NjJH>mb(i`hd+@r|IV-sGwqPQ%~H3m zEu5vL6M{0$c}?&N$|$JJ_1;AdJnMPew8>NdVi8*NJ9#sVkgWbaNpZv$jB3#b)x#M- WjfzbIpDBLBA%L}m)nkjZm;V5j(FOqk literal 0 HcmV?d00001 diff --git a/web/stempmap-ptn.pl b/web/stempmap-ptn.pl new file mode 100755 index 0000000..3522b51 --- /dev/null +++ b/web/stempmap-ptn.pl @@ -0,0 +1,57 @@ +#!/usr/bin/perl +# +# + +use CGI; +use GD; +use DBI; +use strict; +use warnings; + +my $img = GD::Image->new('stemp-bg5.png'); +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +my $black = $img->colorAllocate(0,0,0); +my $white = $img->colorAllocate(255,255,255); +my $green = $img->colorAllocate(0,255,0); +my $blue = $img->colorAllocate(0,0,255); + +my $avrgtemp = 54; +my $mintemp = 10.0; +my $maxtemp = 80.0; + +my $color = &getcolor($avrgtemp); + +for (my $i = $mintemp; $i <= $maxtemp; $i++) { + $img->line(600, 220 + $i - $mintemp, 645, 220 + $i - $mintemp, &getcolor($i)); +} + +$img->string(gdMediumBoldFont, 600, 200, "Freezing!$mintemp", $black); +$img->string(gdMediumBoldFont, 600, 210, "$mintemp C", $black); +$img->string(gdMediumBoldFont, 600, 220 + $maxtemp, "Too hot! $maxtemp", $black); +$img->string(gdMediumBoldFont, 600, 210 + $maxtemp, "$maxtemp C", $black); + +my $px = 5; +my $py = 30; + +#$img->stringUp(gdGiantFont,$px,$py - 2,"$avrgtemp",$white); +$img->filledRectangle($px - 0, $py - 17, $px + 12, $py + 5, $white); +$img->stringUp(gdLargeFont,$px - 4,$py - 1,"$avrgtemp",$blue); +$img->rectangle($px, $py, $px + 7,$py + 7,$black); +$img->filledRectangle($px + 1, $py + 1, $px + 6, $py + 6,$color); + +print $cgi->header(-type=>'image/png'); +print $img->png; + +sub getcolor { + my ($temp) = @_; + + my $percent = ($temp - $mintemp) / ($maxtemp - $mintemp); + my $colorred = 255 * $percent; + my $colorblue = 255 - $colorred; + + return $img->colorAllocate($colorred, $colorblue, 0); +} diff --git a/web/stempmap.pl b/web/stempmap.pl new file mode 100755 index 0000000..b2df70b --- /dev/null +++ b/web/stempmap.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl +# +# + +use CGI; +use GD; +use DBI; +use strict; +use warnings; + +GD::Image->trueColor(1); + +my $img = GD::Image->new('snmp-bg.png'); +#my $img = GD::Image->new(100,100); +my $cgi = CGI->new; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; + +my $sgetpoll = $dbh->prepare('select switch,(select temp from temppoll where switches.switch=temppoll.switch AND temp != 0 order by id desc limit 1) AS temp,placement from switches natural join placements'); + +my $black = $img->colorAllocate(0,0,0); +my $white = $img->colorAllocate(255,255,255); +my $green = $img->colorAllocate(0,255,0); +my $blue = $img->colorAllocate(0,0,255); + +my $avrgtemp = 54.5; +my $mintemp = 30.0; +my $maxtemp = 55.0; +my $steps = 100; + +my $color = &getcolor($avrgtemp); + +open (OUT, "> /tmp/outtemps"); +for (my $i = 0; $i < $steps; $i++) { + my $diff = $maxtemp - $mintemp; + my $temp = $mintemp + ($maxtemp - $mintemp) * ((($diff / $steps) * $i)/$diff); + $img->line(5, $i, 45, $i, &getcolor2($temp)); +} +close(OUT); + +$img->string(gdMediumBoldFont, 50, 0, "Freezing!", $black); +$img->string(gdMediumBoldFont, 50, $steps - 11, "Too hot!", $black); +$img->string(gdMediumBoldFont, 50, 12, "$mintemp C", $black); +$img->string(gdMediumBoldFont, 50, $steps - 22, "$maxtemp C", $black); + +#$img->string(gdMediumBoldFont, 600, 200, "Freezing!$mintemp", $black); +#$img->string(gdMediumBoldFont, 600, 210, "$mintemp C", $black); +#$img->string(gdMediumBoldFont, 600, 220 + $maxtemp, "Too hot! $maxtemp", $black); +#$img->string(gdMediumBoldFont, 600, 210 + $maxtemp, "$maxtemp C", $black); + + +$sgetpoll->execute(); +while (my $ref = $sgetpoll->fetchrow_hashref()) { + next if (!defined($ref->{'temp'})); + + $ref->{'placement'} =~ /\((\d+),(\d+)\),\((\d+),(\d+)\)/; + $avrgtemp = $ref->{'temp'}; + my $px = $3; + my $py = $4 + 16; + my $roundtemp = sprintf ("%.0f", $avrgtemp); + $color = getcolor($avrgtemp); + $img->filledRectangle($px - 0, $py - 17, $px + 12, $py + 5, $white); + $img->stringUp(gdGiantFont,$px - 1,$py - 1,"$roundtemp",$blue); + $img->rectangle($px, $py, $px + 10,$py + 10,$black); + $img->filledRectangle($px + 1, $py + 1, $px + 9, $py + 9,$color); +} + +print $cgi->header(-type=>'image/png'); +print $img->png; + +sub getcolor { + my ($temp) = @_; + + my $t = ($temp - $mintemp) / ($maxtemp - $mintemp); + $t = 0 if ($t < 0); + $t = 1 if ($t > 1); + + my $colorred = 255 * $t; + my $colorblue = 255 - $colorred; + + return $img->colorResolve($colorred, 0, $colorblue); +} + +sub getcolor2 { + my ($temp) = @_; + + my $t = ($temp - $mintemp) / ($maxtemp - $mintemp); + $t = 0 if ($t < 0); + $t = 1 if ($t > 1); + + my $colorred = 255 * $t; + my $colorblue = 255 - $colorred; + + return $img->colorResolve($colorred, 0, $colorblue); +} diff --git a/web/streaming.pl b/web/streaming.pl new file mode 100755 index 0000000..4b12add --- /dev/null +++ b/web/streaming.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl +use GD; +use CGI; +use strict; + +my $cgi = CGI->new; + +GD::Image->trueColor(1); +my $img = new GD::Image(100,100); + +my $wht = $img->colorResolve(0,0,0); +my $blk = $img->colorResolve(255,255,255); +my $red = $img->colorResolve(255,0,0); +my $grn = $img->colorResolve(0,255,0); +my $blu = $img->colorResolve(0,0,255); + +$img->transparent($wht); +$img->interlaced('true'); + +$img->string(gdMediumBoldFont,0,0,"TG05 - Streaming",$blu); + +print $cgi->header(-type=>'image/png', + -refresh=>'10; http://nms.tg05.gathering.org/streaming.pl'); +print $img->png; + diff --git a/web/tempfetch.pl b/web/tempfetch.pl new file mode 100644 index 0000000..eed5417 --- /dev/null +++ b/web/tempfetch.pl @@ -0,0 +1,139 @@ +#! /usr/bin/perl +#use BER; +use Data::Dumper; +use DBI; +use Net::Telnet; +use POSIX; +use Time::HiRes; +use strict; +use warnings; +#require 'SNMP_Session.pm'; + +# Tweak timeouit og sjekk med :support||:net hva passord vil bli +my $password = 'removed'; +my $timeout = 25; +my $location = 'skipet'; + +my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed") + or die "Couldn't connect to database"; +$dbh->{AutoCommit} = 0; + +my $qswitch = $dbh->prepare(<<"EOF") +SELECT + * +FROM + switches + NATURAL LEFT JOIN switchtypes +WHERE + (locked='f' OR now() - last_updated > '15 minutes'::interval) +LIMIT 1 +FOR UPDATE OF switches +EOF + or die "Couldn't prepare qswitch"; +my $qlock = $dbh->prepare("UPDATE switches SET locked='t', last_updated=now() WHERE switch=?") + or die "Couldn't prepare qlock"; +my $qunlock = $dbh->prepare("UPDATE switches SET locked='f', last_updated=now() WHERE switch=?") + or die "Couldn't prepare qunlock"; +my $qpoll = $dbh->prepare("INSERT INTO temppoll (time, switch, temp) VALUES (timeofday()::timestamp,?::text::int,?::text::float)") + or die "Couldn't prepare qpoll"; + +while (1) { + # Find a switch to grab + $qswitch->execute() + or die "Couldn't get switch"; + my $switch = $qswitch->fetchrow_hashref(); + + if (!defined($switch)) { + $dbh->commit; + mylog("No available switches in pool, sleeping."); + sleep 60; + next; + } + + $qlock->execute($switch->{'switch'}) + or die "Couldn't lock switch"; + $dbh->commit; + + if ($switch->{'locked'}) { + mylog("WARNING: Lock timed out on $switch->{'ip'}, breaking lock"); + } + + my $msg; + if (defined($switch->{'overdue'})) { + $msg = sprintf "Polling temp on %s (%s), %s overdue.", + $switch->{'ip'}, $switch->{'sysname'}, $switch->{'overdue'}; + } else { + $msg = sprintf "Polling temp on %s (%s), never polled before.", + $switch->{'ip'}, $switch->{'sysname'}; + } + mylog($msg); + + my $ip = $switch->{'ip'}; + my $start = [Time::HiRes::gettimeofday]; + eval { + my $conn = switch_connect($ip); + if (!defined($conn)) { + print "Could not connect to switch ".$switch->{'switch'}."\n"; + } + my @data = switch_exec('sys monitor status', $conn); + my @fields = split(/\s+/, $data[2]); + # The temp fields are 6, 7, 8 + my $avgtemp = ($fields[6] + $fields[7] + $fields[8]) / 3; + print $avgtemp." avgtemp\n"; + $qpoll->execute($switch->{'switch'}, + $avgtemp) or die "Could not exec qpoll"; + }; + my $elapsed = Time::HiRes::tv_interval($start); + $msg = sprintf "Polled $switch->{'ip'} in %5.3f seconds.", $elapsed; + mylog($msg); + + $qunlock->execute($switch->{'switch'}) + or die "Couldn't unlock switch"; + sleep 1; + $dbh->commit; +} + +sub switch_exec { + my ($cmd, $conn) = @_; + + # Send the command and get data from switch + my @data = $conn->cmd($cmd); + my @lines = (); + foreach my $line (@data) { + # Remove escape-7 sequence + $line =~ s/\x1b\x37//g; + push (@lines, $line); + } + + return @lines; +} + +sub switch_connect { + my ($ip) = @_; + + my $conn = new Net::Telnet( Timeout => $timeout, + Dump_Log => '/tmp/dumplog', + Errmode => 'return', + Prompt => '/(es3024|e\d+\-\dsw)>/i'); + my $ret = $conn->open( Host => $ip); + if (!$ret || $ret != 1) { + return (0); + } + # XXX: Just send the password as text, I did not figure out how to + # handle authentication with only password through $conn->login(). + #$conn->login( Prompt => '/password[: ]*$/i', + # Name => $password, + # Password => $password); + my @data = $conn->cmd($password); + # Get rid of banner + $conn->get; + return ($conn); +} + + +sub mylog { + my $msg = shift; + my $time = POSIX::ctime(time); + $time =~ s/\n.*$//; + printf STDERR "[%s] %s\n", $time, $msg; +} -- 2.39.2