]> git.sesse.net Git - nms/blob - web/showswitch.pl
initial import
[nms] / web / showswitch.pl
1 #! /usr/bin/perl
2 use CGI;
3 use DBI;
4 use Time::HiRes;
5 use POSIX ":sys_wait_h";
6 use strict;
7 use warnings;
8 my $cgi = CGI->new;
9 my $switch = $cgi->param('id');
10 my $width = $cgi->param('width');
11 my $height = $cgi->param('height');
12 my @pids = ();
13 my $resthtml = "";
14
15 $width = 500 unless (defined($width));
16 $height = 250 unless (defined($height));
17
18 require './mygraph.pl';
19
20 my $start = [Time::HiRes::gettimeofday];
21 my $dbh = DBI->connect("dbi:Pg:dbname=snmpfetch;host=violet.tg05.gathering.org", "snmpfetch", "removed")
22         or die "Couldn't connect to database";
23
24 # Fetch the name
25 my $ref = $dbh->selectrow_hashref('SELECT sysname FROM switches WHERE switch=?', undef, $switch);
26
27 print $cgi->header(-type=>'text/html; charset=utf-8');
28 print <<"EOF";
29 <html>
30   <head>
31     <title>snmp</title>
32   </head>
33   <body>
34     <h1>Switch $switch ($ref->{'sysname'})</h1>
35 EOF
36
37 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;');
38 $q->execute($switch);
39
40 my (@totx, @toty1, @toty2) = ();
41
42 my (@x, @y1, @y2) = ();
43 my $last_port = -1;
44 my $portname = "";
45 my $min_x = time;
46 my $max_x = time - 86400;
47 my ($min_y, $max_y, $prev_time, $prev_in, $prev_out);
48 my ($if,$of,$ifv,$ofv);
49 my $idx;
50 my ($min_ty,$max_ty) = (0, 10_000_000/8);
51
52 $prev_time = -1;
53 my $last_totx;
54 while (my $ref = $q->fetchrow_hashref()) {
55         my $time = $ref->{'time'};
56         my $in = $ref->{'bytes_in'};
57         my $out = $ref->{'bytes_out'};
58         next if ($time == $prev_time);
59
60         if ($ref->{'port'} != $last_port) {
61                 if ($last_port != -1) {
62                         my $filename = "$switch-$last_port-$width-$height.png";
63
64                         # reap children
65                         waitpid(-1, WNOHANG);
66
67                         my $pid = fork();
68                         if ($pid == 0) {
69 # write out the graph
70                                 my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5);
71                                 plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y);
72                                 plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y);
73
74                                 open GRAPH, ">img/$filename"
75                                         or die "img/$filename: $!";
76                                 print GRAPH $graph->png;
77                                 close GRAPH;
78                                 exit;
79                         }
80
81                         push @pids, $pid;
82
83                         $resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
84                         $resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
85                 }
86         
87                 # Reset all the variables
88                 @x = ();
89                 @y1 = ();
90                 @y2 = ();
91                 ($min_y,$max_y) = (0, 10_000_000/8);
92                 $prev_time = $ref->{'time'};
93                 $prev_in = $ref->{'bytes_in'};
94                 $prev_out = $ref->{'bytes_out'};
95                 $last_port = $ref->{'port'};
96                 $portname = $ref->{'description'};
97                 ($if,$of,$ifv,$ofv) = (0,0,0,0);
98                 ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
99                 $idx = 0;
100                 $last_totx = undef;
101                 next;
102         }
103
104         # Assume overflow (unless the switch has been down for >10 minutes)
105         my ($calc_in, $calc_out) = ($in, $out);
106         if ($in < $prev_in || $out < $prev_out) {
107                 # ick, heuristics
108                 if ($prev_time - $time > 600 || ($in + 4294967296 - $prev_in) > 2147483648 || ($out + 4294967296 - $prev_out) > 2147483648) {
109                         ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
110                         next;
111                 }
112
113                 $calc_in += 4294967296 if ($in < $prev_in);
114                 $calc_out += 4294967296 if ($out < $prev_out);
115         }
116
117         # Remove dupes
118         if ($in == $prev_in && $out == $prev_out) {
119                 ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
120                 next;
121         }
122
123         # Find the current flow
124         my $if = ($calc_in - $prev_in) / ($time - $prev_time);
125         my $of = ($calc_out - $prev_out) / ($time - $prev_time);
126
127         # Summarize (we don't care about the summed variance for now)   
128         $min_x = $time if (!defined($min_x) || $time < $min_x);
129         $max_x = $time if (!defined($max_x) || $time > $max_x);
130         $min_y = $if if (!defined($min_y) || $if < $min_y);
131         $min_y = $of if ($of < $min_y);
132         $max_y = $if if (!defined($max_y) || $if > $max_y);
133         $max_y = $of if ($of > $max_y);
134
135         my $pt = 0.5 * ($time + $prev_time);
136
137         push @x, $pt;
138         push @y1, $if;
139         push @y2, $of;
140
141         while ($idx < $#totx && $pt > $totx[$idx]) {
142                 ++$idx;
143         }
144         if ($idx >= $#totx) {
145                 push @totx, $pt;
146                 push @toty1, $if;
147                 push @toty2, $of;
148                 ++$idx;
149
150                 $min_ty = $if if (!defined($min_ty) || $if < $min_ty);
151                 $min_ty = $of if ($of < $min_ty);
152                 $max_ty = $if if (!defined($max_ty) || $if > $max_ty);
153                 $max_ty = $of if ($of > $max_ty);
154         } else {
155                 if (!defined($last_totx) || $last_totx != $idx) {
156                         $toty1[$idx] += $if;
157                         $toty2[$idx] += $of;
158                 }
159                 $last_totx = $idx;
160
161                 $min_ty = $toty1[$idx] if (!defined($min_ty) || $toty1[$idx] < $min_ty);
162                 $min_ty = $toty2[$idx] if ($toty2[$idx] < $min_ty);
163                 $max_ty = $toty1[$idx] if (!defined($max_ty) || $toty1[$idx] > $max_ty);
164                 $max_ty = $toty2[$idx] if ($toty2[$idx] > $max_ty);
165         }
166         
167         ($prev_time,$prev_in,$prev_out) = ($time,$in,$out);
168 }
169 $dbh->disconnect;
170
171 # last graph
172 my $filename = "$switch-$last_port-$width-$height.png";
173
174 my $pid = fork();
175 if ($pid == 0) {
176         my $graph = makegraph($width, $height, $min_x, $max_x, $min_y, $max_y, 5);
177         plotseries($graph, \@x, \@y1, 255, 0, 0, $min_x, $max_y);
178         plotseries($graph, \@x, \@y2, 0, 0, 255, $min_x, $max_y);
179
180         open GRAPH, ">img/$filename"
181         or die "img/$filename: $!";
182         print GRAPH $graph->png;
183         close GRAPH;
184         exit;
185 }
186
187 push @pids, $pid;
188
189 $resthtml .= "<div style=\"float: left;\"><h2>$portname</h2>\n";
190 $resthtml .= "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
191                 
192 # total graph
193 my $graph = makegraph($width, $height, $min_x, $max_x, $min_ty, $max_ty, 5);
194 plotseries($graph, \@totx, \@toty1, 255, 0, 0, $min_x, $max_ty);
195 plotseries($graph, \@totx, \@toty2, 0, 0, 255, $min_x, $max_ty);
196
197 my $filename = "$switch-$width-$height.png";
198 open GRAPH, ">img/$filename"
199 or die "img/$filename: $!";
200 print GRAPH $graph->png;
201 close GRAPH;
202
203 # Wait for all the other graphs to be done
204 while (waitpid(-1, 0) != -1) {
205         1;
206 }
207
208 print $resthtml;
209
210 print "<div style=\"float: left;\"><h2>Total</h2>\n";
211 print "<p><img src=\"img/$filename\" width=\"$width\" height=\"$height\" /></p></div>\n";
212
213 my $elapsed = Time::HiRes::tv_interval($start); 
214 printf "<p style=\"clear: both;\">Page and all graphs generated in %.2f seconds.</p>\n", $elapsed;
215 print "</body>\n</html>\n";