network map

Templates, scripts for templates, scripts and requests for templates.

Moderators: Developers, Moderators

Post Reply
madjeff
Posts: 11
Joined: Mon Feb 09, 2004 2:19 pm

Re: Works... confirmed!

Post by madjeff »

Howie wrote:I can run cacti2weathermap.pl from the command line and it creates the files perfectly. But when I run it via cron, it doesn't create/update the files. Any idea what might be causing this?
As you can see from the example, I've been running the script as root:

Code: Select all

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root nice -n 19 run-parts /etc/cron.hourly
02 4 * * * root nice -n 19 run-parts /etc/cron.daily
22 4 * * 0 root nice -n 19 run-parts /etc/cron.weekly
42 4 1 * * root nice -n 19 run-parts /etc/cron.monthly
*/5 * * * * root php /var/www/html/poller.php > /dev/null 2>&1
*/5 * * * * root /var/www/html/weathermap/cacti2weathermap.pl >> test.log 2>&1
*/5 * * * * root /var/www/html/weathermap/weathermap > /dev/null 2>&1
I've been running the script as root until I could get the issue figured out, as I thought at first it was a permissions problem. I'm stumped, as the output to test.log shows no errors, nothing. :D While researching the issue I noticed a couple posts of people having problems with some perl scripts not running in cron with regards to full paths and such, but it sounds like others here have got the script to run just fine.

FYI, I'm running Mandrake 10.1 and the latest and greatest Perl/Cacti/etc. Thanks in advance for any help you can give.
User avatar
Howie
Cacti Guru User
Posts: 5508
Joined: Thu Sep 16, 2004 5:53 am
Location: United Kingdom
Contact:

Post by Howie »

I've started writing up the changes I made to weathermap-1.1.1, and a page showing how it can be set up with Cacti. The page is half-finished, but it does have a download for the modified version, and has the documentation for my changes.

Here it is if anyone wants to take a look. The last section is missing pieces in particular.

I'm actually playing with a PHP version of this program too, so that you wouldn't need to have perl/GD installed, and hopefully that can read from rrd files directly. So far the config-file is read OK, and it draws the map. No data-reading yet, but I'm still going :-) This is the largest PHP project I've written from scratch, so it's slow sometimes. I'll post something if I get it all going enough to be useful. The theory is that it'd have the same dependencies as Cacti, so if you have gotten that running, this should just drop in - maybe even read Cacti's database to find links.
pfouquet
Posts: 7
Joined: Mon Jan 10, 2005 6:32 am

Post by pfouquet »

Hie Howie,

Looks great.

Automatic image map is a pleasure.

Just one problem : on the generated html page, the link to the image is absolute :
<IMG SRC="/data/web/html/meteo/noc.png" WIDTH="1200" HEIGHT="800".......

Need to be
<IMG SRC="noc.png" WIDTH="1200" HEIGHT="800".....

Thanks for your job.

Patrick
User avatar
Howie
Cacti Guru User
Posts: 5508
Joined: Thu Sep 16, 2004 5:53 am
Location: United Kingdom
Contact:

Post by Howie »

pfouquet wrote:Just one problem : on the generated html page, the link to the image is absolute :
<IMG SRC="/data/web/html/meteo/noc.png" WIDTH="1200" HEIGHT="800".......

Need to be
<IMG SRC="noc.png" WIDTH="1200" HEIGHT="800".....
Ooops. Hehe. If you cd to the script directory first, then it's OK ;-)

I'll take a look, but it's a bit complex - it means that the weathermap script needs to know what the URL of the HTML page is, and the relative position of the image, since you can get . Maybe it should have an --output-dir option and dump both files in there instead?
pfouquet
Posts: 7
Joined: Mon Jan 10, 2005 6:32 am

Post by pfouquet »

I've add a new option to the script:
$IMG = "noc.png";

And change the HTML generation:
print HTML sprintf('<IMG SRC="%s" WIDTH="%s" HEIGHT="%s" BORDER=0 USEMAP="#weathermap_imap" />', $IMG, $width, $height);

Regards

Patrick
stelaras1
Cacti User
Posts: 57
Joined: Wed Nov 03, 2004 10:11 am

Post by stelaras1 »

Good job Howie

thanx a lot!
Last edited by stelaras1 on Fri Jan 21, 2005 4:17 am, edited 2 times in total.
madjeff
Posts: 11
Joined: Mon Feb 09, 2004 2:19 pm

Post by madjeff »

Howie, great work on the package! This is going to be a popular script. :D
pfouquet
Posts: 7
Joined: Mon Jan 10, 2005 6:32 am

Post by pfouquet »

Howie,

One time again: thank you for your job.

Do you think that in a next version of your script, we could use auto image map for NODE ?

Ex:

NODE my_router
POSITION 60 400
LABEL my_routeur
OVERLIBGRAPH http://my_host/my_router_cpu_graph.gif
INFOURL http://my_host/my_router_cpu_graph.html

Regards

Patrick
jas0420
Cacti User
Posts: 91
Joined: Thu Jan 13, 2005 3:58 pm
Location: College Station, TX - USA

Post by jas0420 »

pfouquet:

I believe I am doing what you are after... Got mine working just today, actually... I basically define the icon I want to overlay on my map inside my .conf file, and it is dynamically overlayed (in place of the node label)each time the map is redrawn. In my map, I have a mixture of routers and telco providers that I overlay as nodes.

I also changed it to make a time-stamped copy of the map in a seperate folder (planning on animating them each night once I find an .mpg creator I like), so strip out that part of the code if you don't want that. (or make a valid path in the config section for $ANIM_OUTPUT if you want to keep it)

Anyway, below is the Perl file...


Code: Select all

#!/usr/bin/perl
# Network Wearthermap - version 1.1.1 (20040422)
# http://netmon.grnet.gr/weathermap/
# Panagiotis Christias, <christias@noc.ntua.gr>

$VERSION = "1.1.1";

use Getopt::Long;
use GD;

$t=localtime(time);
$t =~ s/:/_/g;

################################################################
#
# Configuration parameters
#
$WGET   = "../wget/wget -qO -";
$CONFIG = "SatDelUtil.conf";
$OUTPUT = "../cacti/images/maps/SatDelUtil.png";
$MAPNAME ="SatDelUtil";  #name prepended to animated file names
$ANIM_OUTPUT = "../cacti/images/maps/animated/" . $MAPNAME . " " . $t . ".png";
$DEBUG  = 1;
$WIDTH  = 800;
$HEIGHT = 493;
#
################################################################


#%optctl=();
#GetOptions(\%optctl, "config:s", "output:s", "version", "help", "debug", "") || exit(1);

#if($optctl{"config"}) { $CONFIG = $optctl{"config"} };

#if($optctl{"output"}) { $OUTPUT = $optctl{"output"} };

#if($optctl{"version"}) { &version; exit; }

#if($optctl{"help"}) { &usage; exit; }

#if($optctl{"debug"}) { $DEBUG=1; }

&read_config($CONFIG);

if($background){
	open (PNG,"$background") || die "$background: $!\n";
	$map = newFromPng GD::Image(PNG) || die "newFromPng failed.";
	close PNG;
} else {
	$map=new GD::Image($WIDTH,$HEIGHT)
}

#open(PNG, "router_ok.png");
#$router = newFromPng GD::Image(PNG);
#close PNG;


&alloc_colors;

print "Opening log files...\n\n" if($DEBUG);
foreach $link (keys %target){

	$data = $target{$link};
	print "FILE: $data\n" if($DEBUG);

	if(($data =~ /^https?:\/\//i) || ($data =~ /^ftp:\/\//i) ) {
		open(LOG, "$WGET $data |") or warn "$data: $!\n";
	} else {
		open(LOG, "$data") or warn "data file $data: $!\n";
	}

	while(<LOG>){
		# <!-- cuin d 5585966 -->
		# <!-- cuout d 10589424 -->
		if(/<\!-- cuin d (\d+) -->/){
			$input{$link}=$1;
			print "LINK: $link, Input: $input{$link}\n" if($DEBUG);
		}
		if(/<\!-- cuout d (\d+) -->/){
			$output{$link}=$1;
			print "LINK: $link, Output: $output{$link}\n" if($DEBUG);
		}
	}
	close(LOG);
}

print "\nCalculating rates...\n\n" if($DEBUG);

foreach $link (keys %target){
	$outrate=(int(($output{$link}/$maxbytes{$link}+0.005)*100)>100) ? 100:int(($output{$link}/$maxbytes{$link}+0.005)*100);
	$inrate=(int(($input{$link}/$maxbytes{$link}+0.005)*100)>100) ? 100:int(($input{$link}/$maxbytes{$link}+0.005)*100);

	if($output{$link} != 0 && $outrate == 0) { $outrate=1 }
	if($input{$link} != 0 && $inrate == 0) { $inrate=1 }

	print "$target{$link}: outrate=$outrate%, inrate=$inrate%\n" if($DEBUG);

	# draw lines...

	$width=3;

	&draw_arrow(
		$xpos{$nodea{$link}},
		$ypos{$nodea{$link}},
		&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}}),
		&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}}),
		$width, 1, &select_color($outrate));
	&draw_arrow(
		$xpos{$nodea{$link}},
		$ypos{$nodea{$link}},
		&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}}),
		&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}}),
		$width, 0, $black);

	&label(&middle($xpos{$nodea{$link}},&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}})),
		&middle($ypos{$nodea{$link}},&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}})),
		$outrate . "%", 0);

	&draw_arrow(
		$xpos{$nodeb{$link}},
		$ypos{$nodeb{$link}},
		&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}}),
		&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}}),
		$width, 1, &select_color($inrate));
	&draw_arrow(
		$xpos{$nodeb{$link}},
		$ypos{$nodeb{$link}},
		&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}}),
		&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}}),
		$width, 0, $black);

	&label(&middle($xpos{$nodeb{$link}},&middle($xpos{$nodea{$link}},$xpos{$nodeb{$link}})),
		&middle($ypos{$nodeb{$link}},&middle($ypos{$nodea{$link}},$ypos{$nodeb{$link}})),
		$inrate . "%", 0);
}
print "\n" if($DEBUG);

foreach(keys %xpos){
open(PNG, $icon_image{$_});
$icon = newFromPng GD::Image(PNG);
close PNG;
my ($width,$height) = $icon->getBounds();
$map->copy($icon,($xpos{$_}-($width/2)),($ypos{$_}-($height/2)),0,0,$width,$height);
}


&annotation;

# print image...
print "Generating image file $OUTPUT...\n\n" if($DEBUG);
open(PNG,">$OUTPUT")||die("$OUTPUT: $!\n");
binmode(PNG);
print PNG $map->png;
close PNG;

open(PNG,">$ANIM_OUTPUT")||die("$ANIM_OUTPUT: $!\n");
binmode(PNG);
print PNG $map->png;
close PNG;

# hint, resizing the image could make it look better

exit;


# print labels
sub label{
	my($xpos,$ypos,$label,$pad)=@_;
	my($strwidth)=gdSmallFont->width*length($label);
	my($strheight)=gdSmallFont->height;
	$map->filledRectangle(
		$xpos-$strwidth/2-$pad-2, $ypos-$strheight/2-$pad+1,
		$xpos+$strwidth/2+$pad+1, $ypos+$strheight/2+$pad,
		$black);
	$map->filledRectangle(
		$xpos-$strwidth/2-$pad-1, $ypos-$strheight/2-$pad+2,
		$xpos+$strwidth/2+$pad, $ypos+$strheight/2+$pad-1,
		$white);
	$map->string(gdSmallFont,
		$xpos-$strwidth/2, $ypos-$strheight/2+1,
		$label, $black)
}


# print annotation
sub annotation{
	my($title)="Circuit Load";
        $strwidth=gdSmallFont->width*length($label{$_});
	$strheight=gdSmallFont->height;

	$t=localtime(time);
#	$t=gmtime(time);
	$map->string(gdSmallFont, 1, 480, "Last update on $t CST", $black);

	$map->filledRectangle($keyxpos,$keyypos,
		$keyxpos+gdSmallFont->width*length($title)+10,
		$keyypos+gdSmallFont->height*($scales+1)+10,
		$gray);
	$map->rectangle($keyxpos,$keyypos,
		$keyxpos+gdSmallFont->width*length($title)+10,
		$keyypos+gdSmallFont->height*($scales+1)+10,
		$black);
	$map->string(gdSmallFont,
		$keyxpos+4,
		$keyypos+4,
		"Circuit Load",  $black);

	my($i)=1;
	foreach(sort {$scale_low{$a}<=>$scale_low{$b}} keys %scale_low){
		$map->filledRectangle(
			$keyxpos+6,
			$keyypos+gdSmallFont->height*$i+8,
			$keyxpos+6+16,
			$keyypos+gdSmallFont->height*$i+gdSmallFont->height+6,
			$color{$_});
		$map->string(gdSmallFont,
			$keyxpos+6+20,
			$keyypos+gdSmallFont->height*$i+8,
			"$scale_low{$_}-$scale_high{$_}%", $black);
		$i++
	}
}

sub select_color {
	my($rate)=($_[0]>100) ? 100:$_[0];
	if($rate=="0"){return($darkgray)}
	foreach(sort {$scale_high{$a}<=>$scale_high{$b}} keys %scale_high){
		if($scale_low{$_}<=$rate && $rate<=$scale_high{$_}){
			return($color{$_});
		}
	}
}

sub alloc_colors {
	$white=$map->colorAllocate(255,255,255);
	$gray=$map->colorAllocate(248,248,248);
	$black=$map->colorAllocate(0,0,0);
	$darkgray=$map->colorAllocate(128,128,128);

	foreach(keys %scale_red){
		$color{$_} = $map->colorAllocate($scale_red{$_},$scale_green{$_},$scale_blue{$_});
	}
}


sub read_config {
my($config)=shift;
my($node,$link);

print "\nReading configuration file...\n\n" if($DEBUG);

$scales=0;
open(CONF,$config) or die "$config: $!\n";
while(<CONF>){
	if(/^\s*BACKGROUND\s+(\S+)/i){
		if(-s "$1"){
			$background=$1;
			print "found BACKGROUND: $background\n" if($DEBUG);
		}
	}
	if(/^\s*WIDTH\s+(\d+)/i){
		if("$1" ne ""){
			$WIDTH=$1;
			print "found WIDTH: $WIDTH\n" if($DEBUG);
		}
	}
	if(/^\s*HEIGHT\s+(\d+)/i){
		if("$1" ne ""){
			$HEIGHT=$1;
			print "found HEIGHT: $HEIGHT\n" if($DEBUG);
		}
	}
	if(/^\s*NODE\s+(\w+)/i){
		$node=$1;
		print "found NODE: $node\n" if($DEBUG);
	}
	if(/^\s*POSITION\s+(\d+)\s+(\d+)/i){
		$xpos{$node}=$1;
		$ypos{$node}=$2;
		print "found NODE: $node XPOS: $xpos{$node} YPOS: $xpos{$node}\n" if($DEBUG);
	}
	if(/^\s*LABEL\s+(\S+)/i){
		$label{$node}=$1;
		print "found NODE: $node LABEL: $label{$node}\n" if($DEBUG);
	}
	if(/^\s*ICON\s+(\S+)/i){
		$icon_image{$node}=$1;
		print "found ICON: $node ICON: $icon_image{$node}\n" if($DEBUG);
	}
	if(/^\s*LINK\s+(\S+)/i){
		$link=$1;
		print "found LINK: $link\n" if($DEBUG);
	}
	if(/^\s*NODES\s+(\S+)\s+(\S+)/i){
		$nodea{$link}=$1;
		$nodeb{$link}=$2;
		print "found LINK: $link NODEA: $nodea{$link} NODEB: $nodeb{$link}\n" if($DEBUG);
	}
	if(/^\s*TARGET\s+(\S+)/i){
		$target{$link}=$1;
		print "found LINK: $link TARGET: $target{$link}\n" if($DEBUG);
	}
	if(/^\s*BANDWIDTH\s+(\d+)/i){
		$bandwidth{$link}=$1;
		$maxbytes{$link}=$bandwidth{$link}*1024/8;
		print "found LINK: $link BANDWIDTH: $bandwidth{$link}\n" if($DEBUG);
	}
	if(/^\s*KEYPOS\s+(\d+)\s+(\d+)/i){
		$keyxpos=$1;
		$keyypos=$2;
		print "found KEY POSITION: $keyxpos $keyypos\n" if($DEBUG);
	}
	if(/^\s*SCALE\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/i){
		$scale_low{"$1:$2"}=$1;
		$scale_high{"$1:$2"}=$2;
		$scale_red{"$1:$2"}=$3;
		$scale_green{"$1:$2"}=$4;
		$scale_blue{"$1:$2"}=$5;
		$scales++;
		print "found SCALE DATA: $1:$2 $3:$4:$5\n" if($DEBUG);
	}
}
print "\n" if($DEBUG);
}


sub middle{
	return int( $_[0] + ($_[1]-$_[0])/2 )
}

sub dist{
	return int( sqrt( $_[0]*$_[0] + $_[1]*$_[1] ) )
}

sub newx{
	my($a,$b,$x,$y)=@_;
	return int( cos( atan2($y,$x) + atan2($b,$a) ) * sqrt( $x*$x + $y*$y ) );
}

sub newy{
	my($a,$b,$x,$y)=@_;
	return int( sin( atan2($y,$x) + atan2($b,$a) ) * sqrt( $x*$x + $y*$y ) );
}



sub draw_arrow {
	my($x1,$y1,$x2,$y2,$w,$solid,$color)=($_[0],$_[1],$_[2],$_[3],$_[4],$_[5],$_[6]);
	my($arrow)=new GD::Polygon;

	$arrow->addPt(
		$x1 + &newx($x2-$x1, $y2-$y1, 0, $w),
		$y1 + &newy($x2-$x1, $y2-$y1, 0, $w)
		);

	$arrow->addPt(
		$x2 + &newx($x2-$x1, $y2-$y1, -4*$w, $w),
		$y2 + &newy($x2-$x1, $y2-$y1, -4*$w, $w)
		);

	$arrow->addPt(
		$x2 + &newx($x2-$x1, $y2-$y1, -4*$w, 2*$w),
		$y2 + &newy($x2-$x1, $y2-$y1, -4*$w, 2*$w)
		);

	$arrow->addPt( $x2, $y2);

	$arrow->addPt(
		$x2 + &newx($x2-$x1, $y2-$y1, -4*$w, -2*$w),
		$y2 + &newy($x2-$x1, $y2-$y1, -4*$w, -2*$w)
		);

	$arrow->addPt(
		$x2 + &newx($x2-$x1, $y2-$y1, -4*$w, -$w),
		$y2 + &newy($x2-$x1, $y2-$y1, -4*$w, -$w)
		);

	$arrow->addPt(
		$x1 + &newx($x2-$x1, $y2-$y1, 0, -$w),
		$y1 + &newy($x2-$x1, $y2-$y1, 0, -$w)
		);

	if($solid){
		$map->filledPolygon($arrow,$color);
	}else{
		$map->polygon($arrow,$color);
	}
}


sub version {
        print <<EOM;
Network Wearthermap v$VERSION - http://netmon.grnet.gr/weathermap/
EOM
}

sub usage {
        print <<EOM;
Network Wearthermap v$VERSION - http://netmon.grnet.gr/weathermap/
Usage: $0 [OPTION]...

 -c, --config=FILE  configuration file (default $CONFIG)
 -o, --output=FILE  output image file default (default $OUTPUT)
 -v, --version      print version
 -h, --help         print this text
 -d, --debug        enable debug output

EOM
}

Then in your .conf file (mine's named satdelutil.conf in this case), add a line to each of your nodes to define the icon you want to overlay on your map.

Code: Select all



<snip>

NODE MCI
        POSITION 700 391
        LABEL MCI
        ICON mci_small.png

NODE Sprint
        POSITION 775 391
        LABEL SPR
        ICON sprint_small.png

NODE CollegeStation
        POSITION 423 398
        LABEL CLL
        ICON Router_ok.png

NODE Raleigh
        POSITION 677 295
        LABEL RAL
        ICON Router_ok.png
In my case, I just threw in some small .png files called "sprint_small.png", "router_ok.png", and "mci_small.png" into the same directory as my .conf file. Each of my icons are about 35x35 pixels. I did them in Visio, and finished them up (shrank them and saved for web) in Photoshop. They will overlay in place of the node name label from the original weathermap code.

My next plan is to have an ok, warning, and alert version of each of the icons and have them displayed (a bright red router for example). After THAT, I want to take it beyond circuit utilization and have it be for pretty much anything... Say a Visio diagram of a rack of computers and a script that checks the RRD's for anything from fan speed to disk space, and overlays a red server icon instead of the all's well icon when something is amiss. I'm currently thinking this is it easiest way for me to get thresholds into Cacti data with my limited programming ability...... :)
User avatar
Howie
Cacti Guru User
Posts: 5508
Joined: Thu Sep 16, 2004 5:53 am
Location: United Kingdom
Contact:

Post by Howie »

pfouquet wrote:Do you think that in a next version of your script, we could use auto image map for NODE ?

Ex:

NODE my_router
POSITION 60 400
LABEL my_routeur
OVERLIBGRAPH http://my_host/my_router_cpu_graph.gif
INFOURL http://my_host/my_router_cpu_graph.html
Good idea. Done. Exactly like that :-)

I also added an option to specify the URI for the image on the command-line, so that the IMG tag has a sensible SRC in it, and a WIDTH option per link to let you vary the width of the link arrows, which should help with clutter, and differentiating 'major' from 'minor' links on the same map.

Version 1.1.1hj2 at http://wotsit.thingy.com/haj/cacti-weathermap.html
weathermap4rrd
Posts: 6
Joined: Sat Jan 22, 2005 10:02 am

Weathermap4rrd version 1.1.1b released

Post by weathermap4rrd »

Hi,

I just find your discussion about Network Weather map and RRDTool. I just created a new version of Weathermap from Panagiotis one. It is called Weathermap4rrd. You can find it at : http://weathermap4rrd.tropicalex.net

Your last modifications seems intersting. I will check them and if you agree I will add them to my version with your name of course.

Let me know

Alex
User avatar
Howie
Cacti Guru User
Posts: 5508
Joined: Thu Sep 16, 2004 5:53 am
Location: United Kingdom
Contact:

Re: Weathermap4rrd version 1.1.1b released

Post by Howie »

weathermap4rrd wrote:Your last modifications seems intersting. I will check them and if you agree I will add them to my version with your name of course.

Let me know
Well, it's all GPLed anyway, so go for it... :)

I just finished adding direct RRD reading too, as a strange coincidence.
weathermap4rrd
Posts: 6
Joined: Sat Jan 22, 2005 10:02 am

Re: Weathermap4rrd version 1.1.1b released

Post by weathermap4rrd »

Howie wrote:
weathermap4rrd wrote:Your last modifications seems intersting. I will check them and if you agree I will add them to my version with your name of course.

Let me know
Well, it's all GPLed anyway, so go for it... :)

I just finished adding direct RRD reading too, as a strange coincidence.
Yes it is funny. Perhaps we could merge our efforts in next versions ? ;-)
pfouquet
Posts: 7
Joined: Mon Jan 10, 2005 6:32 am

Post by pfouquet »

Howie wrote:
Good idea. Done. Exactly like that :-)

I also added an option to specify the URI for the image on the command-line, so that the IMG tag has a sensible SRC in it, and a WIDTH option per link to let you vary the width of the link arrows, which should help with clutter, and differentiating 'major' from 'minor' links on the same map.
Thanks Howie.

Really great job.

Patrick
stelaras1
Cacti User
Posts: 57
Joined: Wed Nov 03, 2004 10:11 am

Post by stelaras1 »

Howie

very useful the WIDTH option for LINKs ;)

Another useful option would be to grab values from different rrd files for "In" and "Out" arrows...
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests