#!/usr/bin/perl -w # # ============================== SUMMARY ===================================== # # Program : ngraphs.cgi # Version : 0.8 # Date : Oct 10 2006 # Author : William Leibzon - william@leibzon.org # (parts of code by Gerd Mueller & Marius Hein and copyright Netways GmbH) # Summary:: ngraphs (Nagios Graphs) is frontend for displaying RRD Graphs # using nagios cgi style with host, hostgroup, servicegroup views. # It can serve as replacement for graphs.cgi provided with NagiosGrapher. # Licence : GPL - summary below, full text at http://www.fsf.org/licenses/gpl.txt # # =========================== PROGRAM LICENSE ================================ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GnU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # ===================== INFORMATION ABOUT THIS PROGRAM ======================== # # [DOCUMENTATION TO BE WRITTEN] # # =================================== TODO =================================== # # 1. Better support user security access similar to what is provided by nagios # where only users who are listed as contacts for some host or service can # see its status & graphs or see links to it from other pages # 2. Move all NagiosGrapher specific code into separate library as follows, # creating general hooks instead as follows: # a. function that lists what graphs are available for given service name # (graphs in this case represents 'pages' in nagiosgrapher # b. function that lists graphs for certain host including additional graphs # that are defined for the host but are not service-specific (this would # be used to support nmgraphs). # c. function that prints link to CGI that displays actual graph image # d. authorization function to supplement #1 (nagiosgrapher config # allows to define list of users that can see all graphs). # 3. Move all functions that are used to access nagios config data into another # library with option to either use NagiosGrapher object or reimpliment # its functionality (i.e. read and cache nagios config data) otherwise. # 4. Although listed with under 2b it is still open question as to how best # integrate nmgraphs into this interface (perhaps separate hostgroup view?). # 5. Add calendar (javascript?) to allow to choose specific period dates # (both from and to) for displayin graph. Look into other places where # UI could be improved potentially with elements of AJAX # # ========================== START OF PROGRAM CODE =========================== use strict; use CGI qw(:standard); use CGI::Carp qw(fatalsToBrowser); use URI::Escape; use NagiosGrapher; use Time::Local; use vars qw ( $self $stylesheet $q %params $height $width $graph_img $host $old_host $service $old_service @rrd %rrd_desc %rrd_cmd $title $refresh %refresh_values %period_values $page_act $page_list $is_showpagelist $img_source %type_values $type $use_browser $use_browser_overwrite $xmlhash $action $ng $t1 $t2 $pnum $pmult $cdate $pdate $hostgroup $servicegroup $hostgroups $nagios_url $nagios_cgis_url $ngrapher_stylesheet $cgi_version ); $| = 1; $graph_img = "./rrd2-system.cgi"; $cgi_version = "0.8"; # define all the functions sub action_sgraph; sub action_hgraph; sub action_hgroupgraph; sub action_sgroupgraph; sub print_htmlhead; sub anchor_name; sub cgiself_action; sub print_nagios_infobox; sub print_nagios_linkbox; sub print_nagios_pagestart; sub time2str; sub str2time; sub list2hash; # NagiosGrapher specific functions to be moved out into separate library sub action_agraph; sub action_rrdinfo; sub action_showtemplate; sub init_nmgraphs; sub get_pages; # Functions working with nagios config data to be moved into separate library sub find_hostgroups; sub find_servicegroup_members; sub find_servicegroups; # now get CGI and NagiosGrapher objects and setup global variables $q = new CGI; $ng = NagiosGrapher::getInstance(); if (!defined($ng)) { print $q->start_html( -title=>"Nagios Grapher - Error Message" ); print '

collect2.pl is not running ...

'; print '

The NagiosGrapher Object Cache was not found. Please make shure that the collect2.pl daemon is running. (reload)

'; exit(0); } else { $xmlhash = $ng->get_ngrapherxml; } # Parameters of URL locations (TODO - rework in unified code, get rid of unused) $nagios_url = $ng->get_ngraphercfg_value('nagios_url'); $nagios_url = "/nagios/" if !defined($nagios_url) || !$nagios_url; $nagios_cgis_url = $ng->get_ngraphercfg_value('nagios_cgi_url'); $nagios_cgis_url = $nagios_url . "cgi-bin/" if !defined($nagios_cgis_url) || !$nagios_cgis_url; $ngrapher_stylesheet = $ng->get_ngraphercfg_value('stylesheet'); $ngrapher_stylesheet = $nagios_url . '/stylesheets/ngraphs.css' if !defined($ngrapher_stylesheet) || !$ngrapher_stylesheet; # Self referencing url $self = $q->self_url; $self =~ s/;/&/g; # making selfreferencing URL without ';' for meta reload tag. # The param hash from the CGI Object %params = $q->Vars; # Refresh param (seconds) $refresh=$params{refresh}; $refresh=300 if (!defined($refresh)); # Graph type param (string) $type=$params{type}; $type="AVERAGE" unless(defined($type)); # Graph height param (integer) $height=$params{height}; $height=250 if (!defined($height) || length($height) <= 0); # Graph width param (integer) $width=$params{width}; $width=645 if (!defined($width) || length($width) <= 0); # What are we looking to get data for? (strings) $host=$params{host}; $service=$params{service}; $hostgroup=$params{hostgroup}; $servicegroup=$params{servicegroup}; $host='' if !defined($host); $service='' if !defined($service); $hostgroup='' if !defined($hostgroup); $servicegroup='' if !defined($servicegroup); $is_showpagelist=0; # Parameters that define range of data graph being shown (integers) # pnum defines number of days, number or hours, weeks, etc, while pmult is multipler # defining measurement unit, i.e. hour, day, week, etc $pnum = $params{pnum}; $pnum = undef if defined($pnum) && $pnum !~ /^\d+$/; $pmult = $params{pmult}; $pmult = undef if defined($pmult) && $pmult !~ /^\d+$/; # Data parameters (string with full data in ngrapher form) # cdate CGI parameter holds user visible date # while cdate is hidden as is set to what it was when page last displayed # if user modifies cdate then it would be different then pdate and that causes it to be used, # otherwise we reset this back to current data and use $pdate as holding place for this info $cdate = undef; $cdate = uc($params{cdate}) if exists($params{cdate}); $pdate = undef; $pdate = uc($params{pdate}) if exists($params{pdate}); $cdate = undef if (defined($cdate) && defined($pdate) && $pdate eq $cdate); $pdate = defined($cdate) ? $cdate : time2str(time()); # Action parameter (string) - very important $action = uc($params{action}); # Few other parameters that are hidden $t1=$params{t1}; $t1=0 if (!defined($t1)); $t2=$params{t2}; $t2=0 if (!defined($t2)); $old_host = $params{old_host}; $old_service = $params{old_service}; # Use the host/service browser (COMMON) or not and override browser if specified to do so $use_browser=$ng->get_ngraphercfg_value('fe_use_browser_all'); $use_browser_overwrite = $params{browser}; $use_browser=$use_browser_overwrite if (defined($use_browser_overwrite) && $ng->get_ngraphercfg_value('fe_use_browser_url') eq "1"); # Check if the user can view the browser ... if ( (defined($use_browser) && $use_browser eq "1") || ($ng->AuthCheckType($ENV{REMOTE_USER}, 'fe_use_browser_for')) ) { $use_browser=1; $q->param("old_host", $host); $q->param("old_service", $service); } # If the current differs from the selected, start the default service ... # - this check will not work for when linking from hostgroup view # - in general the authorization really needs to be rewritten (on my todo) # if (defined($old_host) && defined ($host) && $old_host ne $host) { # $service = [sort(keys(%{$xmlhash->{host}->{$host}->{service}}))]->[0]; # $q->param("service", $service); # } # Set values for some hash tables used later %refresh_values = ( "" => "None", "030" => "30 seconds", "060" => "1 minute", "300" => "5 minutes", "600" => "10 minutes", ); %type_values = ( AVERAGE => "Average values", MAX => "Max values", MIN => "Min values", ); %period_values = ( "0000090" => "minute(s)", "0005400" => "hour(s)", "0129600" => "day(s)", "0907201" => "week(s)", "4017600" => "month(s)", ); # Starting the HTML Output - DTD and default HTTP header $q->default_dtd('-//W3C//DTD HTML 4.01 Transitional//EN'); print $q->header(-type=>'text/html', -expires=>'+1s'); # --- # The ACTIONS # --- $action='SGRAPH' if $action eq 'SERVICEGRAPH' || $action eq 'SERVICEVIEW'; $action='HGRAPH' if $action eq 'HOSTGRAPH' || $action eq 'HOSTVIEW'; $action='HGROUPGRAPH' if $action eq 'HOSTGROUP' || $action eq 'HOSTGROUPGRAPH' || $action eq 'HOSTGROUPVIEW'; $action='SGROUPGRAPH' if $action eq 'SERVICEGROUP' || $action eq 'SERVICEGROUPGRAPH' || $action eq 'SERVICEGROUPVIEW'; if (($action eq 'SGRAPH' || $action eq 'GRAPH') && $host && $service) { action_sgraph(); # Graphs for one service with nagios-like UI } elsif ($action eq 'HGRAPH' && $host) { action_hgraph(); # Graphs for one host with nagios-like UI } elsif ($action eq 'HGROUPGRAPH' && $hostgroup) { action_hgroupgraph(); # Graphs for multiple hosts from same hostgroups with nagios-like UI } elsif ($action eq 'SGROUPGRAPH' && $servicegroup) { action_sgroupgraph(); # Graphs for services in the same servicegroup with nagios-like UI } elsif ($action eq 'AGRAPH' || $action eq 'GRAPH') { action_agraph(); # Original ngrapher UI that lets you choose which host, which service } elsif ($action eq 'RRDINFO') { # TODO - these may need separate security as not everyone who can view graphs should be allowed to access this action_rrdinfo(); # Debug information about RRD specific to one service } elsif ($action eq 'SHOWTEMPLATE') { # TODO - these may need separate security as not everyone who can view graphs should be allowed to access this action_showtemplate(); # Debug information about entire Ngrapher template } else { print $q->start_html( -title=>"CGI Fatal Error" ); print '

Not enough data to process action ('. $action. ') ...

'; } # End HTML Output and exit ... print $q->end_html(); exit(0); ########################## MAIN ACTION AND OTHER FUNCTIONS ################################# # HTML Header, with / without refresh ... sub print_htmlhead { my $title = shift; my $meta_data = { }; $meta_data = { -http_equiv => 'refresh', -content => $refresh,";URL=".$self, } if $refresh; if ($action eq 'SGRAPH' || $action eq 'HGRAPH' || $action eq 'HGROUPGRAPH' || $action eq 'SGROUPGRAPH') { print $q->start_html( -title=>$title, -class=>lc $action, -style=>{-src => [ $nagios_url."stylesheets/common.css", $ngrapher_stylesheet, ]}, -head=>meta($meta_data) ); } elsif ($action eq 'GRAPH' || $action eq 'AGRAPH') { print $q->start_html( -title=>$title, -class=>'agraph', -style=>{ -src => [ $ngrapher_stylesheet ] }, -head=>meta($meta_data) ); } else { print $q->start_html( -title=>$title, -class=>'agraph', -style=>{ -src => [ $ngrapher_stylesheet ] }, ); } } sub action_showtemplate { my $title = "Graph template for $host, $service"; print_htmlhead($title); # The maintable print "\n"; print '
'. "\n"; # The MENU: print $q->span({-class => "head1"}, "Nagios Grapher v$NagiosGrapher::VERSION"), " (Logged in as $ENV{REMOTE_USER})"; print "
"; print $q->span({-class => "head2"}, "Graphtemplate for $service:"). " "; print '
'. $q->a({-href=>'Javascript: history.back();'}, 'Go back') if !defined($params{debugwindow}); print '
'. $q->a({-href=>'Javascript: window.close();'}, 'Close window') if defined($params{debugwindow}); print '

'; my @blocks = $ng->get_ngrapherdef($service); if (@blocks > 0) { print ''; foreach (@blocks) { print ''; foreach my $template_key (sort(keys(%{ $_ }))) { next if ($template_key eq 'define'); print ''; print ''; print ''; print ''; print ''; } print ''; print ''; } print '
define {
 '. $template_key. ''. $_->{$template_key}. '
}
 
'; } else { print '
No templatedata found !'; } print '
'; } sub action_rrdinfo { my $title = "RRDInfo for $host, $service"; print_htmlhead($title); # The maintable print "\n"; print '
'. "\n"; # The MENU: print $q->span({-class => "head1"}, "Nagios Grapher ver $NagiosGrapher::VERSION"), " (Logged in as $ENV{REMOTE_USER})"; print "
"; print $q->span({-class => "head2"}, "RRDInfo for $host, $service:"). " "; print '
'. $q->a({-href=>'Javascript: history.back();'}, 'Go back') if !defined($params{debugwindow}); print '
'. $q->a({-href=>'Javascript: window.close();'}, 'Close window') if defined($params{debugwindow}); print '

'; $xmlhash = $ng->get_ngrapherxml; if (exists($xmlhash->{host}->{$host}->{service}->{$service}->{rrd_file})) { my $info = $ng->rrd_info($host, $xmlhash->{host}->{$host}->{service}->{$service}->{rrd_file}); print ''; my $i=0; foreach (sort(keys(%{ $info }))) { $i++; if ($i%2) { print ''; } else { print '' } print ''; print ''; print ''; } print '
'. $_. ':'. ($info->{$_} || '(empty)'). '
'; } else { print '
No RRDFile found !'; } print '
'; } sub action_agraph { my $title = "Graphs for $host, $service"; print_htmlhead($title); # Check if it is a multigraph and initialize nmgraphs my $multigraph = 0; unless(exists($xmlhash->{host}->{$host}->{service}->{$service}->{rrd_file})) { $multigraph = 1; } init_nmgraphs(); # Preparing the page browsing $page_list=get_pages($service); if (scalar(@$page_list)>2) { # 2 because --ALL-- is also added $is_showpagelist=1; $page_act=$params{act_page}; $page_act=$page_list->[0] unless (defined $page_act); $page_act=undef if ($page_act eq '-ALL'); } # RRD Type Array @rrd = (0..4); @rrd = sort(@rrd); # RRD Description HASH %rrd_desc = (0 => "Actual", 1 => "Daily", 2 => "Weekly", 3 => "Monthly", 4 => "Yearly"); # RRD TimeInterval HASH %rrd_cmd = (0 => 5400, 1 => 129600, 2 => 907201, 3 => 4017600, 4 => 48211200); # The maintable print "\n"; print '
'. "\n"; # The MENU: print $q->span({-class => "head1"}, "Nagios Grapher v$NagiosGrapher::VERSION"), " (Logged in as $ENV{REMOTE_USER})"; print "
"; print '
'; # Graph description print $q->span({-class => "head2"}, "Graphs for $host, $service:"). " "; # The image anchors foreach (@rrd) { print "[ ", $q->a({href=>$q->self_url. "#". anchor_name($rrd_desc{$_})}, $rrd_desc{$_}), " ] ", "\n"; } # Close and reload link print '', "[ ", $q->a({-href=>"#", -onclick=>"window.location.reload(); return true;"}, "Reload"), " ]", "  [ ", $q->a({-href=>"#", -onclick=>"top.close(); return true;"}, "Close"), " ]", '
'; # Starting the form print "\n\n", $q->start_form(-method=>"get", -action=>$q->self_url, -enctype=>"application/x-www-form-urlencoded"); # Writing some hiddenfields, with or without browser ... print $q->hidden(-name=>"action", -default=>$action), $q->hidden(-name=>"t1", -default=>$t1), $q->hidden(-name=>"t2", -default=>$t2); if (defined($use_browser) && $use_browser eq "1") { print $q->hidden(-name=>"old_host", -default=>$host), $q->hidden(-name=>"old_service", -default=>$service); # Remind the overwriting setting if allowed ... print $q->hidden(-name=>"browser", -default=>$use_browser_overwrite) if (defined($use_browser_overwrite) && $use_browser_overwrite eq "1"); } else { print $q->hidden(-name=>"host", -default=>$host), $q->hidden(-name=>"service", -default=>$service); } print # Starting the table for from elements '', '', # Width field '', # Height field '', # Refresh Combo ''; # Displaying the page combo if needed... if ($is_showpagelist) { print "'; } # Type combo print ''; # Only use the browser if it ist allowed ;-) ... # Can be overwritten if allowed ... # Overwrite handling in top of the script. if (defined($use_browser) && $use_browser eq "1") { # Host combo print ''; # Service combo print ''; } print '', '
Width:', $q->textfield(-name=>"width", -default=>$width, -override=>1, -size=>4), 'Height:', $q->textfield(-name=>"height", -default=>$height, -override=>1, -size=>4), 'Refresh', $q->popup_menu( -name=>"refresh", -default=>$refresh, -values=>[sort keys(%refresh_values)], -labels=>\%refresh_values, -onchange=>"this.form.submit();", ), '
page:", $q->popup_menu( -name=>"act_page", -default=>$page_act, -values=>$page_list, -labels=>list2hash($page_list), -style=>"width: 287px; background-color: #fc8888;", -onchange=>"this.form.submit();", ), '
Type:', $q->popup_menu( -name=>"type", -default=>$type, -values=>[keys(%type_values)], -labels=>\%type_values, -style=>"width: 287px; background-color: #bbccff;", -onchange=>"this.form.submit();", ), '
Host:', $q->popup_menu( -name=>"host", -default=>$host, -values=>[sort(keys(%{$xmlhash->{host}}))], -style=>"width: 287px; background-color: #ffff00;", -onchange=>"this.form.submit();", ), '
Service:', $q->popup_menu( -name=>"service", -default=>$service, -values=>[sort(keys(%{$xmlhash->{host}->{$host}->{service}}))], -style=>"width: 287px; background-color: #ffff00;", -onchange=>"this.form.submit();", ), '
  '. ($multigraph == 1 ? ' ' : ('[ '. $q->a({-href=>cgiself_action('rrdinfo').';host='.uri_escape($host).';service='.uri_escape($service)}, 'RRDInfo'). ' ]  [ '. $q->a({-href=>cgiself_action('showtemplate').';host='.uri_escape($host).';service='.uri_escape($service)}, 'TemplateInfo'). ' ]')). ' ', $q->submit(-name=>"cmd_change", -value=>"Change"), '
', $q->endform, "\n\n"; print ''. "\n"; # Displaying the RRD's foreach (@rrd) { $img_source = $graph_img. '?host='. uri_escape($host). ';service='. uri_escape($service). ';start=-'. $rrd_cmd{$_}. ';title='. uri_escape($rrd_desc{$_}). ';width='. $width. ';height='. $height; $img_source .= ';act_page='. uri_escape($page_act) if (defined($page_act)); $img_source .= ';type='. $type if (defined($type)); # Print the menu print "\n"; # Some space at the end of a image print ''; } # Footer # print # ''; print "
 "; print ''; print ''; print ''; print '
'. '[ ', $q->a({name=>anchor_name($rrd_desc{$_}), -href=>$q->self_url. '#'}, 'To top'), ' ] '. $rrd_desc{$_}. ' graph'. 'View as: ', $q->a({-href=>$img_source. ';imageformat=pdf', -target=>'_blank'}, 'PDF'), ', ', $q->a({-href=>$img_source. ';imageformat=svg', -target=>'_blank'}, 'SVG'), ', ', $q->a({-href=>$img_source. ';imageformat=eps', -target=>'_blank'}, 'EPS'), '
'; # Print the RRD Image print $q->a({-href => $img_source, -target=>"_blank"}, $q->img({src => $img_source, border => 0, alt => $rrd_desc{$_}})); print "
 
', # 'Nagios Grapher v'. $NagiosGrapher::VERSION. ' © MMIV, MMV (2004, 2005) ' # $q->a({-href=>"http://www.netways.de/", -target=>"_blank"}, "NETWAYS GmbH"), # '
\n"; } # Nagios style graphs for one service sub action_sgraph { my $title = "Graphs for Service $service on Host $host"; # Check if it is a multigraph and initialize nmgraphs my $multigraph = 0; unless(exists($xmlhash->{host}->{$host}->{service}->{$service}->{rrd_file})) { $multigraph = 1; } init_nmgraphs(); # Preparing the page browsing $page_list=get_pages($service); if (scalar(@$page_list)>2) { # 2 because --ALL-- is also added $is_showpagelist=1; $page_act=$params{act_page}; $page_act=$page_list->[0] unless (defined $page_act); $page_act=undef if ($page_act eq '-ALL'); } # RRD Type Array @rrd = (0..5); @rrd = sort(@rrd); # RRD Description HASH %rrd_desc = (0 => "Custom", 1 => "Actual", 2 => "Daily", 3 => "Weekly", 4 => "Monthly", 5 => "Yearly"); # RRD TimeInterval HASH %rrd_cmd = (0 => 5400, 1 => 5400, 2 => 129600, 3 => 907201, 4 => 4017600, 5 => 48211200); print_htmlhead($title); print_nagios_pagestart({'AllGraphs' => 'agraph', 'RRDInfo' => 'rrdinfo', 'TemplateInfo' => 'showtemplate'}); print "\n"; print "
\n"; print "Service \'$service\' on Host \'$host\'\n"; print "


\n"; my $servicegroups = find_servicegroups($host, $service); if (defined($servicegroups) && scalar(keys %$servicegroups)>0) { print "
\n"; print "(Member of Servicegroups:"; foreach (keys %$servicegroups) { print " ".$q->a({-href=>cgiself_action('sgroupgraph',['service','servicegroup']).';servicegroup='.uri_escape($_)}, $_); } print ")

\n"; } # The image anchors print "Graphs:
\n"; foreach (@rrd) { print "[ ", $q->a({href=>$q->self_url. "#". anchor_name($rrd_desc{$_})}, $rrd_desc{$_}), " ] ", "\n"; } print "\n"; print $q->hidden(-name=>"action", -default=>$action), $q->hidden(-name=>'t1',-default=>$t1), $q->hidden(-name=>'t2',-default=>$t2), $q->hidden(-name=>'host',-default=>$host), $q->hidden(-name=>'service',-default=>$service); print "\n"; if (defined($is_showpagelist) && $is_showpagelist) { print "\n"; print "\n"; } print "\n"; print "\n"; print ""; print "
Metrics Group
\n"; print $q->popup_menu( -name=>"act_page", -default=>$page_act, -values=>$page_list, -labels=>list2hash($page_list), -onchange=>"this.form.submit();", ); print "
Displayed Values
\n"; print $q->popup_menu( -name=>"type", -default=>$type, -values=>[keys(%type_values)], -labels=>\%type_values, -onchange=>"this.form.submit();", ); print "
"; print "\n"; print "\n"; print "
WidthHeight
\n"; print $q->textfield(-name=>"width", -default=>$width, -override=>1, -size=>4); print "\n"; print $q->textfield(-name=>"height", -default=>$height, -override=>1, -size=>4); print "
Refresh
"; print $q->popup_menu( -name=>"refresh", -default=>$refresh, -values=>[sort keys %refresh_values], -labels=>\%refresh_values, -onchange=>"this.form.submit();", ); print '  '.$q->submit(-name=>'cmd_change', -value=>'Update')."
\n
\n"; print ''. "\n"; # Displaying the RRD's foreach (@rrd) { $img_source = $graph_img. '?host='. uri_escape($host). ';service='. uri_escape($service). ';width='. $width. ';height='. $height; $img_source .= ';act_page='. uri_escape($page_act) if (defined($page_act)); $img_source .= ';type='. $type if (defined($type)); if ($_ == 0) { $pnum = 1 if !defined($pnum); $pmult = "0005400" if !defined($pmult); my $udate = str2time($cdate); if (!defined($udate)) { (my $tl = $period_values{$pmult}) =~ s/[\)\(\*\^]//g; $img_source .= ';title=' . uri_escape($pnum . ' ' . $tl); $img_source .= ';start=-' . $pmult * $pnum ; $cdate = undef; } else { $img_source .= ';title=' . uri_escape(time2str($udate-$pmult*$pnum) . ' to ' . time2str($udate)); $img_source .= ';start=end-' . $pmult * $pnum ; $img_source .= ';end=' . $udate ; } } else { $img_source .= ';title=' . uri_escape($rrd_desc{$_}); $img_source .= ';start=-'. $rrd_cmd{$_} ; } # Print the menu print "\n"; # Some space at the end of a image print ''; } print "
 "; print ''; print '
'. '[ ', $q->a({name=>anchor_name($rrd_desc{$_}), -href=>$q->self_url. '#'}, 'To top'), ' ] '. $rrd_desc{$_}. ' graph'; if ($_ == 0) { print " for period: \n"; print $q->textfield(-name=>'pnum',-default=>(defined($pnum)?$pnum:'1'), -override=>1, -size=>2); print $q->popup_menu(-name=>"pmult", -selected=>$pmult, -default=>$pmult, -values=>[sort keys %period_values], -labels=>\%period_values, -onchange=>"this.form.submit();", ); print " ending "; print $q->textfield(-name=>'cdate',-default=>$pdate, -override=>1, -size=>14); print $q->hidden('pdate', defined($cdate)?'*':$pdate ); } print 'View as: ', $q->a({-href=>$img_source. ';imageformat=pdf', -target=>'_blank'}, 'PDF'), ', ', $q->a({-href=>$img_source. ';imageformat=svg', -target=>'_blank'}, 'SVG'), ', ', $q->a({-href=>$img_source. ';imageformat=eps', -target=>'_blank'}, 'EPS'); print "
\n"; # Print the RRD Image print $q->a({-href => $img_source, -target=>"_blank"}, $q->img({src => $img_source, border => 0, alt => $rrd_desc{$_}})); print "
 
\n"; } sub action_hgraph { my $title = "Graphs for Host $host"; # Initialize nmgraphs - N/A for host services view # init_nmgraphs(); $pnum = 1 if !defined($pnum); $pmult = "0129600" if !defined($pmult); $hostgroups = find_hostgroups($host); print_htmlhead($title); print_nagios_pagestart({'AllGraphs' => 'agraph'}); print "\n"; print "
"; print "Graphs for Host \'$host\'\n"; print "

\n"; if (scalar(@$hostgroups)>0) { print "
\n"; print "(Member of Hostgroups:"; foreach (@$hostgroups) { print " ".$q->a({-href=>cgiself_action('hgroupgraph',['service','host','hostgroup']).';hostgroup='.uri_escape($_)}, $_); } print ")

\n"; } print "
\n"; my $servicegroups = find_servicegroups($host); if (scalar(keys %$servicegroups)>0) { print "
\n"; print "(Servicegroups:"; foreach (keys %$servicegroups) { print " ".$q->a({-href=>cgiself_action('sgroupgraph',['service','servicegroup']).';servicegroup='.uri_escape($_)}, $_); } print ")

\n"; } # The image anchors print "Services:
\n"; foreach (sort keys(%{$xmlhash->{host}->{$host}->{service}})) { print "[ ",$q->a({href=>$q->self_url."#".anchor_name($_)},$_)." ]\n"; } print "\n"; # Some hidden fields print $q->hidden(-name=>"action", -default=>$action), $q->hidden(-name=>'t1',-default=>$t1), $q->hidden(-name=>'t2',-default=>$t2), $q->hidden(-name=>'host',-default=>$host); print "\n"; print "\n"; print "\n"; print ""; print "
Time Period
\n"; print $q->textfield(-name=>'pnum',-default=>$pnum, -override=>1, -size=>2); print $q->popup_menu(-name=>"pmult", -selected=>$pmult, -default=>$pmult, -values=>[sort keys %period_values], -labels=>\%period_values, -onchange=>"this.form.submit();", ); print "
ending"; print $q->textfield(-name=>'cdate',-default=>$pdate, -override=>1, -size=>14); print $q->hidden('pdate', defined($cdate)?'*':$pdate ); print "
"; print "\n"; print "\n"; print "
WidthHeight
\n"; print $q->textfield(-name=>"width", -default=>$width, -override=>1, -size=>4); print "\n"; print $q->textfield(-name=>"height", -default=>$height, -override=>1, -size=>4); print "
Refresh
"; print $q->popup_menu( -name=>"refresh", -default=>$refresh, -values=>[sort keys %refresh_values], -labels=>\%refresh_values, -onchange=>"this.form.submit();", ); print "
".$q->submit(-name=>'cmd_change', -value=>'Update')."
\n
\n"; print ''."\n"; my $udate = str2time($cdate); $cdate = undef if !defined($udate); my $sgraph = ''; # Displaying the RRD's foreach (sort keys(%{$xmlhash->{host}->{$host}->{service}})) { $page_list = get_pages($_); if (scalar(@$page_list)>2) { # 2 because --ALL-- is also added $is_showpagelist=1; $page_act=$params{$_.'_act_page'}; $page_act=$page_list->[0] unless (defined $page_act); $page_act=undef if ($page_act eq '-ALL'); } else { $is_showpagelist=0; $page_act=undef; } $img_source = $graph_img. '?host='. uri_escape($host). ';service='. uri_escape($_). ';title='. uri_escape($_). ';width='. $width. ';height='. $height;; $img_source .= ';act_page='. uri_escape($page_act) if (defined($page_act)); $img_source .= ';type='. $type if (defined($type)); if (!defined($udate)) { $img_source .= ';start=-' . $pmult * $pnum ; } else { $img_source .= ';start=end-' . $pmult * $pnum ; $img_source .= ';end=' . $udate ; } # Print the menu print "\n"; # Some space at the end of a image print ''; } print "
 "; print ''; print ''; print ''; print '
'. '[ ', $q->a({name=>anchor_name($_), -href=>$q->self_url. '#'}, 'To top'), ' ] '. $_; if ($is_showpagelist) { print " "; print $q->popup_menu( -name=>$_.'_act_page', -default=>$page_act, -values=>$page_list, -labels=>list2hash($page_list), -onchange=>"this.form.submit();", ); } print ' graph'. 'View as: ', $q->a({-href=>$img_source. ';imageformat=pdf', -target=>'_blank'}, 'PDF'), ', ', $q->a({-href=>$img_source. ';imageformat=svg', -target=>'_blank'}, 'SVG'), ', ', $q->a({-href=>$img_source. ';imageformat=eps', -target=>'_blank'}, 'EPS'), '
'; # Print the RRD Image $sgraph = cgiself_action('SGRAPH'). ';host='. uri_escape($host). ';service='. uri_escape($_); $sgraph .= ';act_page='. uri_escape($page_act) if (defined($page_act)); print $q->a({-href => $sgraph}, $q->img({src => $img_source, border => 0, alt => $_})); print "
 
\n"; } sub action_hgroupgraph { my $title = "Graphs for Hostgroup $hostgroup"; $pnum = 1 if !defined($pnum); $pmult = "0129600" if !defined($pmult); print_htmlhead($title); print_nagios_pagestart({'AllGraphs' => 'agraph'}); print "\n"; print "
\n"; print "Graphs for Hostgroup \'$hostgroup\'\n"; print "

\n"; # Preparing list of services and hosts my @hosts; my %services; my $maxsnum=0; my $maxsname=undef; my $allhostlinks=''; my $hostgraphlinks=''; my $sgraph; foreach (sort keys(%{$xmlhash->{host}})) { $host=$_; if ($ng->parse_nagios_cfg('hostgroup',$hostgroup,'members') =~ m/$host(,|$)/) { foreach (sort keys(%{$xmlhash->{host}->{$host}->{service}})) { $services{$_}=[] if !defined $services{$_}; push @{$services{$_}}, $host; if (scalar(@{$services{$_}})>$maxsnum) { $maxsname=$_; $maxsnum=scalar(@{$services{$_}}); } } if (!$service || defined($xmlhash->{host}->{$host}->{service}->{$service})) { push @hosts, $host; # The image anchors $hostgraphlinks.= "[ ".$q->a({href=>$q->self_url."#".anchor_name($host)},$host)." ]\n"; } $allhostlinks.= " ".$q->a({href=>cgiself_action('hgraph').';host='.uri_escape($host)},$host); } } $service=$maxsname if !$service && defined($maxsname); # TODO - if (!$service) { DISPLAY AN ERROR AND EXIT } print "
\n"; print "(All group hosts:". $allhostlinks. ")"; print "


\n"; print "Hosts that have $service graphs:
\n" . $hostgraphlinks; # find pages (metric groups) associated with selected service $page_list = get_pages($service); if (scalar(@$page_list)>2) { # 2 becuase --ALL-- is also added $is_showpagelist=1; $page_act=$params{$service.'_act_page'}; $page_act=$page_list->[0] unless (defined $page_act); $page_act=undef if ($page_act eq '-ALL'); } else { $is_showpagelist=0; $page_act=undef; } # Now display right-side with most of form elements (as per nagios format) print "\n"; # Some hidden fields print $q->hidden(-name=>"action", -default=>$action), $q->hidden(-name=>'t1',-default=>$t1), $q->hidden(-name=>'t2',-default=>$t2), $q->hidden(-name=>'hostgroup',-default=>$hostgroup); print "\n"; print "\n"; print ""; if ($is_showpagelist) { print "\n"; print ""; } print ""; print ""; print ""; print "
Service
\n"; my $services_list=[sort keys %services]; print $q->popup_menu(-name=>'service', -selected=>$service, -values=>$services_list, -labels=>list2hash($services_list), -onchange=>"this.form.submit();", ); print "
Metrics Group
\n"; print $q->popup_menu( -name=>$service.'_act_page', -default=>$page_act, -values=>$page_list, -labels=>list2hash($page_list), -onchange=>"this.form.submit();", ); print "
"; print "\n"; print "\n"; print "
Time PeriodEnding
\n"; print $q->textfield(-name=>'pnum',-default=>$pnum, -override=>1, -size=>2); print $q->popup_menu(-name=>"pmult", -selected=>$pmult, -default=>$pmult, -values=>[sort keys %period_values], -labels=>\%period_values, -onchange=>"this.form.submit();", ); print "\n"; print $q->textfield(-name=>'cdate',-default=>$pdate, -override=>1, -size=>14); print $q->hidden('pdate', defined($cdate)?'*':$pdate ); print "
"; print "\n"; print "\n"; print "\n"; print "
WidthHeight  Refresh
\n"; print $q->textfield(-name=>"width", -default=>$width, -override=>1, -size=>4); print "\n"; print $q->textfield(-name=>"height", -default=>$height, -override=>1, -size=>4); print "  "; print $q->popup_menu( -name=>"refresh", -default=>$refresh, -values=>[sort keys %refresh_values], -labels=>\%refresh_values, -onchange=>"this.form.submit();", ); print "
".$q->submit(-name=>'cmd_change', -value=>'Update')."
\n
\n"; print ''."\n"; my $udate = str2time($cdate); $cdate = undef if !defined($udate); # Displaying the RRD's foreach (@hosts) { $img_source = $graph_img. '?host='. uri_escape($_). ';service='. uri_escape($service). ';width='. $width. ';height='. $height; $img_source .= ';act_page='. uri_escape($page_act) if (defined($page_act)); $img_source .= ';type='. $type if (defined($type)); if (!defined($udate)) { (my $tl = $period_values{$pmult}) =~ s/[\)\(\*\^]//g; $img_source .= ';start=-' . $pmult * $pnum ; $img_source .= ';title=' . uri_escape($pnum . ' ' . $tl); } else { $img_source .= ';start=end-' . $pmult * $pnum ; $img_source .= ';end=' . $udate ; $img_source .= ';title=' . uri_escape(time2str($udate-$pmult*$pnum) . ' to ' . time2str($udate)); } print "\n"; # Some space at the end of a image print ''; } print "
 "; print ''; print '"; print "Host $_ "; print ''; print '
'. '[ ', $q->a({name=>anchor_name($_), -href=>$q->self_url. '#'}, 'To top'), ' ] '; # print "Host $_ $service graphView as: ', $q->a({-href=>$img_source. ';imageformat=pdf', -target=>'_blank'}, 'PDF'), ', ', $q->a({-href=>$img_source. ';imageformat=svg', -target=>'_blank'}, 'SVG'), ', ', $q->a({-href=>$img_source. ';imageformat=eps', -target=>'_blank'}, 'EPS'), '
'; # Print the RRD Image $sgraph = cgiself_action('SGRAPH'). ';host='. uri_escape($_). ';service='. uri_escape($service); $sgraph .= ';act_page='. uri_escape($page_act) if (defined($page_act)); print $q->a({-href => $sgraph}, $q->img({src => $img_source, border => 0, alt => $_})); print "
 
\n"; } sub action_sgroupgraph { my $title = "Graphs for Servicegroup $servicegroup"; $host="" if ($host eq '__@ALL@__'); $pnum = 1 if !defined($pnum); $pmult = "0129600" if !defined($pmult); print_htmlhead($title); print_nagios_pagestart({'AllGraphs' => 'agraph'}); print "\n"; print "
\n"; print "Graphs for Servicegroup \'$servicegroup\'\n"; print "

\n"; # Preparing list of services and hosts my @services=(); my $maxsnum=0; my $maxsname=undef; my $graphlinks=''; my $allhostlinks=''; my $sgraph=""; my $hst; my $srv; my $hs = find_servicegroup_members($servicegroup); foreach (sort keys %$hs) { $hst=$_; $allhostlinks.= " ".$q->a({href=>cgiself_action('hgraph').';host='.uri_escape($hst)},$hst); foreach (@{ $hs->{$hst} }) { if (defined($xmlhash->{host}->{$hst}->{service}->{$_})) { if ($host && $host eq $hst) { $graphlinks.= "[ ".$q->a({href=>$q->self_url."#".anchor_name($hst."_".$_)},$_)." ]\n"; push @services, [$hst,$_]; } elsif (!$host) { $graphlinks.= "[ ".$q->a({href=>$q->self_url."#".anchor_name($hst."_".$_)},$hst.":".$_)." ]\n"; push @services, [$hst,$_]; } } } } # TODO - if (!defined(%services)) { DISPLAY AN ERROR AND EXIT } print "
\n"; print "(All servicegroup hosts:". $allhostlinks. ")"; print "


\n"; print "Service Graphs"; print " for Host \'$host\'" if $host; print ":
\n". $graphlinks; # Now display right-side with most of form elements (as per nagios format) print "\n"; # Some hidden fields print $q->hidden(-name=>"action", -default=>$action), $q->hidden(-name=>'t1',-default=>$t1), $q->hidden(-name=>'t2',-default=>$t2), $q->hidden(-name=>'servicegroup',-default=>$servicegroup); print "\n"; print "\n"; print ""; print ""; print ""; print ""; print "
Host
\n"; my $hosts_arf=[sort keys %$hs]; unshift(@$hosts_arf,'__@ALL@__'); my $hosts_hrf=list2hash($hosts_arf); $hosts_hrf->{'__@ALL@__'}='-ALL'; print $q->popup_menu(-name=>'host', -selected=>$host, -values=>$hosts_arf, -labels=>$hosts_hrf, -onchange=>"this.form.submit();", ); print "
"; print "\n"; print "\n"; print "
Time PeriodEnding
\n"; print $q->textfield(-name=>'pnum',-default=>$pnum, -override=>1, -size=>2); print $q->popup_menu(-name=>"pmult", -selected=>$pmult, -default=>$pmult, -values=>[sort keys %period_values], -labels=>\%period_values, -onchange=>"this.form.submit();", ); print "\n"; print $q->textfield(-name=>'cdate',-default=>$pdate, -override=>1, -size=>14); print $q->hidden('pdate', defined($cdate)?'*':$pdate ); print "
"; print "\n"; print "\n"; print "\n"; print "
WidthHeight  Refresh
\n"; print $q->textfield(-name=>"width", -default=>$width, -override=>1, -size=>4); print "\n"; print $q->textfield(-name=>"height", -default=>$height, -override=>1, -size=>4); print "  "; print $q->popup_menu( -name=>"refresh", -default=>$refresh, -values=>[sort keys %refresh_values], -labels=>\%refresh_values, -onchange=>"this.form.submit();", ); print "
".$q->submit(-name=>'cmd_change', -value=>'Update')."
\n
\n"; print ''."\n"; my $udate = str2time($cdate); $cdate = undef if !defined($udate); # Displaying the RRD's foreach (@services) { $hst=$_->[0]; $srv=$_->[1]; $page_list = get_pages($srv); if (scalar(@$page_list)>2) { # 2 because --ALL-- is also added $is_showpagelist=1; $page_act=$params{$hst.'_'.$srv.'_act_page'}; $page_act=$page_list->[0] unless (defined $page_act); $page_act=undef if ($page_act eq '-ALL'); } else { $is_showpagelist=0; $page_act=undef; } $img_source = $graph_img. '?host='. uri_escape($hst). ';service='. uri_escape($srv). ';title='. uri_escape($srv." on host ".$hst). ';width='. $width. ';height='. $height; $img_source .= ';act_page='. uri_escape($page_act) if (defined($page_act)); $img_source .= ';type='. $type if (defined($type)); if (!defined($udate)) { $img_source .= ';start=-' . $pmult * $pnum ; } else { $img_source .= ';start=end-' . $pmult * $pnum ; $img_source .= ';end=' . $udate ; } # Print the menu print "\n"; # Some space at the end of a image print ''; } print "
 "; print ''; print ''; print ''; print '
'. '[ ', $q->a({name=>anchor_name($hst.'_'.$srv), -href=>$q->self_url. '#'}, 'To top'), ' ] '.$hst.' service '.$srv; if ($is_showpagelist) { print " "; print $q->popup_menu( -name=>$hst.'_'.$srv.'_act_page', -default=>$page_act, -values=>$page_list, -labels=>list2hash($page_list), -onchange=>"this.form.submit();", ); } print ' graph'. 'View as: ', $q->a({-href=>$img_source. ';imageformat=pdf', -target=>'_blank'}, 'PDF'), ', ', $q->a({-href=>$img_source. ';imageformat=svg', -target=>'_blank'}, 'SVG'), ', ', $q->a({-href=>$img_source. ';imageformat=eps', -target=>'_blank'}, 'EPS'), '
'; # Print the RRD Image $sgraph = cgiself_action('SGRAPH'). ';host='. uri_escape($hst). ';service='. uri_escape($srv); $sgraph .= ';act_page='. uri_escape($page_act) if (defined($page_act)); print $q->a({-href => $sgraph}, $q->img({src => $img_source, border => 0, alt => $srv.' on '.$hst})); print "
 
\n"; } # Nagios style infobox used with SGRAPH, HGRAPH, HGROUPGRAPH, SGROUPGRAPH sub print_nagios_infobox { my $graph_type=''; $graph_type = "Service" if $action eq 'SGRAPH'; $graph_type = "Host" if $action eq 'HGRAPH'; $graph_type = "Host Group" if $action eq 'HGROUPGRAPH'; $graph_type = "Service Group" if $action eq 'SGROUPGRAPH'; print "\n"; print "
\n"; print "
$graph_type Graphs
\n"; # print "Last Updated: [TODO]
\n"; print "Ngraphs CGI: ver ".$cgi_version."
\n"; print "NagiosGrapher: ver $NagiosGrapher::VERSION
\n"; print "Nagios® - www.nagios.org
\n"; print "Logged in as $ENV{REMOTE_USER}
\n"; print "
\n"; } # Nagios style linkbox use with SGRAPH, HGRAPH, HGROUPGRAPH, SGROUPGRAPH sub print_nagios_linkbox { print "\n"; print "\n"; } # common for how nagios-style pages start sub print_nagios_pagestart { my $debugactions=shift @_; print $q->start_form(-method=>"get", -action=>$q->self_url, -enctype=>"application/x-www-form-urlencoded"); print "\n"; print "\n"; } # Very simple function to create anchors names (#anchor) that are W3 compliant sub anchor_name { my $an = shift; $an =~ s/[^A-Za-z0-9\:-_\.]/_/g; $an = 'a_'. $an if $an !~ /^[A-Za-z]/; return $an; } # This prepares new url for self-referencing with possibly new action sub cgiself_action { my ($new_act,$exclude_list) = @_; # Build list of cgi parameters to not be included when self-referencing $exclude_list = ['service','host'] if !defined($exclude_list); push @$exclude_list, 'action'; push @$exclude_list, 'cmd_change'; my $exclude_hash = list2hash($exclude_list); $q->self_url =~ /^(.*)\?(.*)$/; my $u = $1; if ($2) { $u .= "?action=" . $new_act; foreach (keys %params) { $u .= ';'.$_.'='.uri_escape($params{$_}) unless defined($exclude_hash->{$_}); } return $u; } else { # these are in case the self url reference was incomplete to start with return $u . "?action=" . $new_act if ($u); return $self . "?action=" . $new_act; } } # Init the NMgraphs sub init_nmgraphs { my @nmgraphs = $ng->get_nmgrapherdef(); foreach (@nmgraphs) { unless ($xmlhash->{host}->{$_->{host_name}}) { $xmlhash->{host}->{$_->{host_name}}->{service}->{$_->{service_name}} = {}; } else { unless ($xmlhash->{host}->{$_->{host_name}}->{service}->{$_->{service_name}}) { $xmlhash->{host}->{$_->{host_name}}->{service}->{$_->{service_name}} = {}; } } } } # moved out of NagiosGrapher.pm (although its still used there separately) sub time2str { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(shift @_); return sprintf( "%02d\:%02d/%04d-%02d-%02d", $hour, $min, $year + 1900, $mon + 1, $mday ); } sub str2time { my $datestring = shift @_; return undef if !defined($datestring); $datestring =~ /(\d{1,2}):(\d{1,2})\/(\d{4})\-(\d{1,2})\-(\d{1,2})/; my ($hour,$min,$year,$mon,$mday) = ($1,$2,$3,$4,$5); return undef if !(defined($hour) && defined($min) && defined($year) && defined($mon) && defined($mday)); return timelocal(0,$min,$hour,$mday,$mon-1,$year-1900); } sub list2hash { my $list = shift @_; my $hash = {}; $hash->{$_}=$_ foreach (@$list); return $hash; } # Extract the pagebrowser values from configuration # (the function is from graphs.cgi slightly modified to return reference to a list instead of hash) sub get_pages { my $service = shift; my $page_list = []; my $page_hash = {}; my @conf = $ng->get_ngrapherdef($service, "GRAPH"); foreach (@conf) { if (exists $_->{page}) { push @$page_list, $_->{page} if !exists $page_hash->{$_->{page}}; $page_hash->{$_->{page}} = $_->{page}; } } push @$page_list, "-ALL"; return $page_list; } # find_hostgroups: finds list of hostgroups that a host belongs to, this function returns reference to list sub find_hostgroups { my $host_name = shift @_; my $hostgroups = []; my $temp_gname; return $hostgroups if ($host_name eq ""); # parse all items in nagios config $temp_gname=""; foreach(@{ $ng->{configuration} }) { if(m/define hostgroup {/../\t}/) { if (m/hostgroup_name\s*(.*)/) { $temp_gname=$1; } if ($temp_gname && m/\s*members.*$host_name(,|$)/) { push @$hostgroups, $temp_gname; $temp_gname=""; } } } return $hostgroups; } # find_servicegroup_members: finds list of hosts & services in given servicegroup, # this function returns reference to a hash where a key is a host name and data is an array of service names sub find_servicegroup_members { my $servicegroup_name = shift @_; my $hosts_services = {}; my $gname=""; my @temp_member_list; my $temp_hostname; my $temp_ref; return $hosts_services if ($servicegroup_name eq ""); foreach(@{ $ng->{configuration} }) { if(m/define servicegroup {/../\t}/) { if (m/servicegroup_name\s*(.*)/) { $gname=$1; } if ($gname eq $servicegroup_name && m/\s*members\s*(.*)/) { @temp_member_list=split(/,/, $1); $temp_hostname=""; foreach(@temp_member_list) { if ($temp_hostname) { $hosts_services->{$temp_hostname}=[] if !defined($hosts_services->{$temp_hostname}); $temp_ref=$hosts_services->{$temp_hostname}; push @$temp_ref, $_; $temp_hostname=""; } else { $temp_hostname=$_; } } return $hosts_services; } } } # returns empty result if none found return $hosts_services; } # find_servicegroups: finds list of servicegroups for a host (or for specific service in that host) # this function returns reference to a hash where a key is a service group name and data is an array of service names sub find_servicegroups { my ($host_name,$service_name) = @_; my $servicegroups = {}; my $temp_gname; my @temp_member_list; my $temp_hostname; my $temp_ref; return $servicegroups if (!defined($host_name) || $host_name eq ""); # Note: service name can be null # parse all items in nagios config $temp_gname=""; foreach(@{ $ng->{configuration} }) { if(m/define servicegroup {/../\t}/) { if (m/servicegroup_name\s*(.*)/) { $temp_gname=$1; } if ($temp_gname && m/\s*members\s*(.*)/) { @temp_member_list=split(/,/, $1); $temp_hostname=""; foreach(@temp_member_list) { if ($temp_hostname) { if ($temp_hostname eq $host_name && (!defined($service_name) || $service_name eq "" || $service_name eq $_)) { $servicegroups->{$temp_gname}=[] if !defined($servicegroups->{$temp_gname}); $temp_ref = $servicegroups->{$temp_gname}; push @$temp_ref, $_; } $temp_hostname=""; } else { $temp_hostname=$_; } } $temp_gname=""; } } } return $servicegroups; }
\n"; print "
\n"; print_nagios_infobox(); print "
\n"; print_nagios_linkbox(); print "