root/indexmrtg.cgi @ 9afdb02d
| 00588b29 | Hamish Coleman | #!/usr/bin/perl
 | ||
| #
 | ||||
| 9c83a251 | Hamish Coleman | # Generate a machine readable index from mrtg.cfg inputs
 | ||
| 00588b29 | Hamish Coleman | #
 | ||
| our $VERSION=0.5;
 | ||||
| use strict;
 | ||||
| use warnings;
 | ||||
| use FileHandle;
 | ||||
| 04a6764e | Hamish Coleman | use JSON;
 | ||
| 00588b29 | Hamish Coleman | use Data::Dumper;
 | ||
| $Data::Dumper::Indent = 1;
 | ||||
| $Data::Dumper::Sortkeys = 1;
 | ||||
| use CGI ':all';
 | ||||
| use CGI::Carp qw(fatalsToBrowser);
 | ||||
| use Sys::Hostname;
 | ||||
| use HTML::Entities();
 | ||||
| # List of config files to search for
 | ||||
| my @config_files = (
 | ||||
| 	'/etc/mrtg.cfg',
 | ||||
| 	'/usr/share/WWW/mrtg/mrtg.cfg',
 | ||||
| );
 | ||||
| # FIXME - globals
 | ||||
| my $warnings;
 | ||||
| my $db = {};	# storage for all tests found
 | ||||
| 7d6cf686 | Hamish Coleman | $db->{mrtg}{gifdone} = 0; # Scan for newest graph and save info for later
 | ||
| $db->{mrtg}{global}{postfix}{xsize} = 500;
 | ||||
| $db->{mrtg}{global}{postfix}{ysize} = 135;
 | ||||
| 00588b29 | Hamish Coleman | |||
| sub config_save_val($$$$) {
 | ||||
| 04a6764e | Hamish Coleman | 	my ($filename,$name,$var,$val) = @_;
 | ||
| 00588b29 | Hamish Coleman | |||
| 	my $this_ysize;
 | ||||
| 	my $this_xsize;
 | ||||
| 	my $this_title;
 | ||||
| 	# HACK!
 | ||||
| 	if ( $var eq 'ysize' ) {
 | ||||
| 		$val += 35;
 | ||||
| 	} elsif ( $var eq 'xsize' ) {
 | ||||
| 		$val += 100;
 | ||||
| 	}
 | ||||
| 	# Save any default initializers
 | ||||
| 04a6764e | Hamish Coleman | 	if ($name eq '_') {
 | ||
| 7d6cf686 | Hamish Coleman | 		$db->{mrtg}{global}{postfix}{$var} = $val;
 | ||
| 00588b29 | Hamish Coleman | 		return;
 | ||
| 	}
 | ||||
| 04a6764e | Hamish Coleman | 	if ($name eq '^') {
 | ||
| 7d6cf686 | Hamish Coleman | 		$db->{mrtg}{global}{prefix}{$var} = $val;
 | ||
| 00588b29 | Hamish Coleman | 		return;
 | ||
| 	}
 | ||||
| 04a6764e | Hamish Coleman | 	# Check for name name collision, and uniqueify
 | ||
| 	my $unique_name = $name;
 | ||||
| 00588b29 | Hamish Coleman | 	my $unique_id = 1;
 | ||
| 04a6764e | Hamish Coleman | 	while (defined $db->{graph}->{$unique_name}
 | ||
| 7d6cf686 | Hamish Coleman | 		 && $db->{graph}->{$unique_name}->{definedby} ne $filename) {
 | ||
| 04a6764e | Hamish Coleman | 		$unique_name = $name . '_' . $unique_id;
 | ||
| 00588b29 | Hamish Coleman | 		$unique_id++;
 | ||
| 	}
 | ||||
| 04a6764e | Hamish Coleman | 	if (!defined $db->{graph}->{$unique_name}) {
 | ||
| 		# initialize a new name
 | ||||
| 00588b29 | Hamish Coleman | |||
| 		#TODO - instantiate new tests from all of the "_"/"^" defaults
 | ||||
| 04a6764e | Hamish Coleman | 		push @{$db->{sequence}}, $unique_name;
 | ||
| 00588b29 | Hamish Coleman | |||
| 04a6764e | Hamish Coleman | 		$db->{graph}->{$unique_name}->{name} = $name;
 | ||
| 7d6cf686 | Hamish Coleman | 		$db->{graph}->{$unique_name}->{definedby} = $filename;
 | ||
| 04a6764e | Hamish Coleman | 		$db->{graph}->{$unique_name}->{sequence} = @{$db->{sequence}};
 | ||
| 00588b29 | Hamish Coleman | |||
| 7d6cf686 | Hamish Coleman | 		$db->{graph}{$unique_name}{img}{xsize} = $db->{mrtg}{global}{postfix}{xsize};
 | ||
| 		$db->{graph}{$unique_name}{img}{ysize} = $db->{mrtg}{global}{postfix}{ysize};
 | ||||
| 00588b29 | Hamish Coleman | |||
| 	}
 | ||||
| 7d6cf686 | Hamish Coleman | 	$db->{mrtg}{target}{$unique_name}{$var} = $val;
 | ||
| 00588b29 | Hamish Coleman | }
 | ||
| # Load one or more files
 | ||||
| #
 | ||||
| sub config_load_file(@) {
 | ||||
| 	while (@_) {
 | ||||
| 		my $filename = shift;
 | ||||
| 		my $fh = new FileHandle $filename,"r";
 | ||||
| 		if (!defined $fh) {
 | ||||
| 			# FIXME globals
 | ||||
| 			$warnings .= "Warning: Could not open $filename $!\n";
 | ||||
| 			return;
 | ||||
| 		}
 | ||||
| 		#TODO - multi-line values
 | ||||
| 7d6cf686 | Hamish Coleman | 		#TODO - reset the {mrtg}{global} vars
 | ||
| 00588b29 | Hamish Coleman | |||
| 		while(<$fh>){
 | ||||
| 			# Is this a standard MRTG setting?
 | ||||
| 			if ( $_ =~ /^([^#[][^[]+)\[(.*)\]:\s*(.+)$/ ) {
 | ||||
| 				my $var=lc $1;
 | ||||
| 04a6764e | Hamish Coleman | 				my $name=lc $2;
 | ||
| 00588b29 | Hamish Coleman | 				my $val=$3;
 | ||
| 04a6764e | Hamish Coleman | 				config_save_val($filename,$name,$var,$val);
 | ||
| 00588b29 | Hamish Coleman | |||
| 7d6cf686 | Hamish Coleman | 			} elsif ( $_ =~ /^([^#[][^[]+):\s*(.+)$/ ) {
 | ||
| 				# its a global statement
 | ||||
| 				my $var=lc $1;
 | ||||
| 				my $val=$2;
 | ||||
| 				$db->{mrtg}{global}{$var}=$val;
 | ||||
| 00588b29 | Hamish Coleman | 			}
 | ||
| 7d6cf686 | Hamish Coleman | |||
| 00588b29 | Hamish Coleman | 			# TODO - Handle extra statements:
 | ||
| 			#	Include
 | ||||
| 7d6cf686 | Hamish Coleman | 			# 	WorkDir - see config_read_filesystem
 | ||
| 00588b29 | Hamish Coleman | 			#	LogDir
 | ||
| 			#	##HC Magic for baseurl
 | ||||
| 		}
 | ||||
| 	}
 | ||||
| }
 | ||||
| 04a6764e | Hamish Coleman | # Itterate through the loaded name and read their mtime and
 | ||
| 00588b29 | Hamish Coleman | # any other filesystem details for them.
 | ||
| #
 | ||||
| sub config_read_filesystem() {
 | ||||
| 7d6cf686 | Hamish Coleman | |||
| 	# TODO - also check the other directory statements
 | ||||
| 	if ($db->{mrtg}{global}{workdir}) {
 | ||||
| 		chdir $db->{mrtg}{global}{workdir};
 | ||||
| 	}
 | ||||
| 00588b29 | Hamish Coleman | 	# check and update details for all known tests;
 | ||
| 04a6764e | Hamish Coleman | 	for my $i (keys %{$db->{graph}}) {
 | ||
| 7d6cf686 | Hamish Coleman | 		my $graph = $db->{graph}->{$i};
 | ||
| 		my $graphname = $graph->{name};
 | ||||
| 		my $mrtg = $db->{mrtg}{target}{$i};
 | ||||
| 00588b29 | Hamish Coleman | |||
| 		# Default is GIF, unless a PNG file exists
 | ||||
| 7d6cf686 | Hamish Coleman | 		$mrtg->{_imagetype} = 'gif';
 | ||
| 		if ( -e "$graphname-day.png" ) {
 | ||||
| 			$mrtg->{_imagetype} = "png";
 | ||||
| 00588b29 | Hamish Coleman | 		}
 | ||
| 7d6cf686 | Hamish Coleman | 		# TODO - determine correct URL prefix
 | ||
| 00588b29 | Hamish Coleman | 		# TODO - change the filename based on the displayed period
 | ||
| 7d6cf686 | Hamish Coleman | 		my $filename = $graphname . "-day." . $mrtg->{_imagetype};
 | ||
| 9afdb02d | Hamish Coleman | 		$graph->{img}{URL}{day} = $filename;
 | ||
| 		$graph->{img}{URL}{week}  = $graphname."-week.".$mrtg->{_imagetype};
 | ||||
| 		$graph->{img}{URL}{month} = $graphname."-month.".$mrtg->{_imagetype};
 | ||||
| 		$graph->{img}{URL}{year}  = $graphname."-year.".$mrtg->{_imagetype};
 | ||||
| 00588b29 | Hamish Coleman | |||
| 		my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
 | ||||
| 			$atime,$mtime,$ctime,$blksize,$blocks)
 | ||||
| 			= stat($filename);
 | ||||
| 		if (!defined $mtime) {
 | ||||
| 			# if we cannot stat the file, skip it
 | ||||
| 			next;
 | ||||
| 		}
 | ||||
| 7d6cf686 | Hamish Coleman | 		# TODO - move these to a better function
 | ||
| 		$graph->{URL} = $graphname . '.html';
 | ||||
| 		$graph->{title} = $mrtg->{title};
 | ||||
| 		$graph->{img}{mtime} = $mtime;
 | ||||
| 00588b29 | Hamish Coleman | |||
| 		# find the newest file
 | ||||
| 7d6cf686 | Hamish Coleman | 		if ($mtime > $db->{mrtg}{gifdone}) {
 | ||
| 			$db->{mrtg}{gifdone} = $mtime;
 | ||||
| 00588b29 | Hamish Coleman | 		}
 | ||
| 	}
 | ||||
| }
 | ||||
| sub extract_grouphosttest($) {
 | ||||
| 	my ($name) = @_;
 | ||||
| 	# Do not classify a test with no separators in it
 | ||||
| 	if ($name !~ /,/) {
 | ||||
| 		return undef;
 | ||||
| 	}
 | ||||
| 	my ($group,$host,$test) = split ',', $name;
 | ||||
| 	# TODO cope with missing group/host/test parts.
 | ||||
| 	if (!defined $group || !defined $host || !defined $test) {
 | ||||
| 		return undef;
 | ||||
| 	}
 | ||||
| 	return ($group,$host,$test);
 | ||||
| }
 | ||||
| 04a6764e | Hamish Coleman | # Read through the list of name and find common hostname prefixes,
 | ||
| 00588b29 | Hamish Coleman | # so that we can group these hosts together
 | ||
| # (a hosttype entry)
 | ||||
| #
 | ||||
| sub maketree_find_hosttypes() {
 | ||||
| 04a6764e | Hamish Coleman | 	for my $name (keys %{$db->{graph}}) {
 | ||
| 00588b29 | Hamish Coleman | 		my ($group,$host,$test) = extract_grouphosttest($name);
 | ||
| 		if (!defined($group)) {
 | ||||
| 			next;
 | ||||
| 		}
 | ||||
| 		my $hosttype;
 | ||||
| 		# TODO - this needs to have a better way...
 | ||||
| 		# hosttype is the non digit hostname prefix - thus
 | ||||
| 		# "proxy-1" and "proxy-2" would both end up in the
 | ||||
| 		# "proxy-" hosttype
 | ||||
| 		if ($host =~ m/^(.*[^0-9])(\d+)$/) {
 | ||||
| 			$hosttype = $1.'*';
 | ||||
| 		} else {
 | ||||
| 			next;
 | ||||
| 		}
 | ||||
| 9afdb02d | Hamish Coleman | 		$db->{graph}{$name}{tag}{hosttype} = $hosttype;
 | ||
| 00588b29 | Hamish Coleman | 		$db->{hosttype}->{$hosttype}->{$host}++;
 | ||
| 	}
 | ||||
| 	for my $hosttype (keys %{$db->{hosttype}}) {
 | ||||
| 		if ((keys %{$db->{hosttype}->{$hosttype}})<2) {
 | ||||
| 			delete $db->{hosttype}->{$hosttype};
 | ||||
| 		}
 | ||||
| 	}
 | ||||
| }
 | ||||
| sub maketree_grouphosttest($$) {
 | ||||
| 	my ($name,$sequence) = @_;
 | ||||
| 	my ($group,$host,$test) = extract_grouphosttest($name);
 | ||||
| 	if (!defined($group)) {
 | ||||
| 		# TODO cope with missing group/host/test parts.
 | ||||
| 		# for now, just assume it is not a group/host/test
 | ||||
| 		$db->{tree}->{other}->{$name} = $sequence;
 | ||||
| 		return;
 | ||||
| 	}
 | ||||
| 	# a valid hosttype both:
 | ||||
| 04a6764e | Hamish Coleman | 	#	defined($db->{graph}->{$name}->{hosttype}) &&
 | ||
| 00588b29 | Hamish Coleman | 	#	defined($db->{hosttype}->{$hosttype})
 | ||
| 9afdb02d | Hamish Coleman | 	my $hosttype = $db->{graph}{$name}{tag}{hosttype};
 | ||
| 00588b29 | Hamish Coleman | 	if (defined($hosttype) && !defined($db->{hosttype}->{$hosttype})) {
 | ||
| 		$hosttype=undef;
 | ||||
| 	}
 | ||||
| 	# TODO - determine a better description for this tree leaf
 | ||||
| 	my $testtreename = 'Graph Type';
 | ||||
| 	if (defined $hosttype) {
 | ||||
| 		$db->{tree}->{group}->{$group}->{$hosttype}->{$host}->{$test}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{$group}->{$hosttype}->{$testtreename}->{$test}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{ALL}->{$hosttype}->{$host}->{$test}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{ALL}->{$testtreename}->{$test}->{$hosttype}->{$host}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{$group}->{$testtreename}->{$test}->{$hosttype}->{$host}->{$name} = $sequence;
 | ||||
| 	} else {
 | ||||
| 		$db->{tree}->{group}->{$group}->{$host}->{$test}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{ALL}->{$host}->{$test}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{ALL}->{$testtreename}->{$test}->{$host}->{$name} = $sequence;
 | ||||
| 		$db->{tree}->{group}->{$group}->{$testtreename}->{$test}->{$host}->{$name} = $sequence;
 | ||||
| 	}
 | ||||
| }
 | ||||
| 7d6cf686 | Hamish Coleman | sub maketree_definedby($$) {
 | ||
| 00588b29 | Hamish Coleman | 	my ($name,$sequence) = @_;
 | ||
| 	# config files
 | ||||
| 7d6cf686 | Hamish Coleman | 	my $definedby = $db->{graph}->{$name}->{definedby};
 | ||
| 00588b29 | Hamish Coleman | |||
| 7d6cf686 | Hamish Coleman | 	my @srcpath = split /\//,$definedby;
 | ||
| 00588b29 | Hamish Coleman | |||
| 04a6764e | Hamish Coleman | 	shift @srcpath;	# remove initial slash
 | ||
| 00588b29 | Hamish Coleman | |||
| 04a6764e | Hamish Coleman | 	unshift @srcpath,"config";	# ensure that the config node exists
 | ||
| 00588b29 | Hamish Coleman | 	my $node = $db->{tree};
 | ||
| 04a6764e | Hamish Coleman | 	while (@srcpath ) {
 | ||
| 		if (!defined $node->{$srcpath[0]}) {
 | ||||
| 			$node->{$srcpath[0]} = {};
 | ||||
| 00588b29 | Hamish Coleman | 		}
 | ||
| 04a6764e | Hamish Coleman | 		$node = $node->{$srcpath[0]};
 | ||
| 		shift @srcpath;
 | ||||
| 00588b29 | Hamish Coleman | 	}
 | ||
| 04a6764e | Hamish Coleman | 	# assign a name name and sequence to the final node
 | ||
| 00588b29 | Hamish Coleman | 	$node->{$name} = $sequence;
 | ||
| }
 | ||||
| 04a6764e | Hamish Coleman | # Look through the name database and create tree entries for each cfgfile
 | ||
| 00588b29 | Hamish Coleman | #
 | ||
| sub maketree() {
 | ||||
| 04a6764e | Hamish Coleman | 	for my $name (keys %{$db->{graph}}) {
 | ||
| 		my $sequence = $db->{graph}->{$name}->{sequence};
 | ||||
| 7d6cf686 | Hamish Coleman | 		maketree_definedby($name,$sequence);
 | ||
| 00588b29 | Hamish Coleman | 		maketree_grouphosttest($name,$sequence);
 | ||
| 		# TODO - parse the Target setting and create trees
 | ||||
| 		# TODO - parse magic comments and create trees here
 | ||||
| 	}
 | ||||
| 	# TODO - look for nodes that have only one child and that child is
 | ||||
| 	#	childless and prune the child
 | ||||
| }
 | ||||
| 9afdb02d | Hamish Coleman | sub maketags() {
 | ||
| 	maketree_find_hosttypes();
 | ||||
| 	for my $name (keys %{$db->{graph}}) {
 | ||||
| 		my $graph = $db->{graph}->{$name};
 | ||||
| 		my ($group,$host,$test) = extract_grouphosttest($name);
 | ||||
| 		$graph->{tag}{group}=$group if $group;
 | ||||
| 		$graph->{tag}{host}=$host if $host;
 | ||||
| 		$graph->{tag}{test}=$test if $test;
 | ||||
| 	}
 | ||||
| }
 | ||||
| 9c83a251 | Hamish Coleman | my $this_host = hostname;
 | ||
| 00588b29 | Hamish Coleman | |||
| 9c83a251 | Hamish Coleman | print header,
 | ||
| 	start_html(-TITLE=>"$this_host indexmrtg (V$VERSION)"),
 | ||||
| 	"\n";
 | ||||
| 00588b29 | Hamish Coleman | |||
| 9c83a251 | Hamish Coleman | config_load_file(@config_files);
 | ||
| config_read_filesystem();
 | ||||
| 9afdb02d | Hamish Coleman | maketags();
 | ||
| #maketree();
 | ||||
| 00588b29 | Hamish Coleman | |||
| 9c83a251 | Hamish Coleman | # Time the next update to occur a little while after the next interval completes
 | ||
| my $interval = 300; # 5 min update interval
 | ||||
| my $guardband = 15; # updates occur this many seconds after predicted gif completion
 | ||||
| 7d6cf686 | Hamish Coleman | my $refresh = $interval + $guardband + $db->{mrtg}{gifdone} - time; # predict how long until next update
 | ||
| 9c83a251 | Hamish Coleman | $refresh = $interval if $refresh <= $guardband;
 | ||
| my $expires = gmtime (time + $interval * 2 + $guardband);
 | ||||
| 00588b29 | Hamish Coleman | |||
| 9c83a251 | Hamish Coleman | print
 | ||
| 	"<meta http-equiv=\"expires\" content=\"$expires GMT\">\n",
 | ||||
| 	"<meta http-equiv=\"refresh\" content=$refresh>\n";
 | ||||
| 00588b29 | Hamish Coleman | |||
| 9c83a251 | Hamish Coleman | print end_html;
 | ||
| 00588b29 | Hamish Coleman | |||
| if (param('debug')) {
 | ||||
| 9c83a251 | Hamish Coleman | 	print "\n",Dumper(\$db),"\n";
 | ||
| 00588b29 | Hamish Coleman | }
 | ||
| 9afdb02d | Hamish Coleman | print "\n",JSON->new->utf8(1)->pretty(1)->canonical(1)->encode($db),"\n";
 |