smeserver-smeadmin/root/etc/e-smith/web/functions/smeadmin

2021 lines
107 KiB
Perl
Executable File

#!/usr/bin/perl -w
# Smeadmin - panel cgi perl affichant les infos dans le server-manager
# Copyright (C) 2006
# This file is distributed under the GPL license.
# Landry Breuil <landry@firewall-services.com>, 2006.
# heading : Administration
# description : Smeadmin
# navigation : 4000 4020
#----------------------------------------------------------------
#inclusion des modules
use strict;
no strict 'refs';
use CGI':all';
use CGI::Carp qw(fatalsToBrowser);
use DBD::mysql;
use RRDs;
use esmith::cgi;
use esmith::ConfigDB;
use esmith::I18N;
use POSIX;
use Locale::gettext;
##raid status
use Getopt::Long;
#----------------------------------------------------------------
#declaration de variables globales
my ($DomainName,$SystemName,$SystemMode,$ExternalInterface,$InternalInterface,$ExternalIP,$InternalIP);
my $progname="smeadmin";
#handle de la db sme
my $smedb=esmith::ConfigDB->open;
my $smeadmindb = $smedb->get('smeadmind') || die "Error opening smeadmind db\n";
#handle de la bd mysql
my $bd;
my $rrddir="/var/lib/smeadmin";
my $imgdir="/etc/e-smith/web/panels/manager/html/smeadmin";
#my $maxping=0.1;
my $maxping=0.5;
my $SshPort;
#----------------------------------------------------------------
#declaration des fonctions
#webpages-funcs
sub showConf;
sub showAlertConf;
sub readConf;
sub changeOk;
sub accueil;
sub svcControl;
sub showAdvancedTest;
#details de services
sub showHttpd;
sub showSquid;
sub showSamba;
sub showAfp;
sub showFtp;
sub showPppoe;
sub showVpn;
sub showSsh;
sub showDhcpd;
sub showQpsmtpd;
sub showQmail;
#graph-pages-funcs
sub showHardGraph;
sub showNetGraph;
sub showSystmGraph;
#misc-funcs
sub ipnum2ipdot;
sub connectDB;
sub deconnectDB;
sub printPopupMenu;
sub showService;
sub showSvcGraph;
sub showDbData;
#----------------------------------------------------------------
#----------------------------------------------------------------
#debut pre-main
BEGIN
{
# Clear PATH and related environment variables so that calls to
# external programs do not cause results to be tainted. See
# "perlsec" manual page for details.
$ENV {'PATH'} = '/bin:/usr/bin:/sbin';
$ENV {'SHELL'} = '/bin/bash';
delete $ENV {'ENV'};
}
my $i18n = new esmith::I18N;
my $http_lang = $i18n->preferredLanguage( $ENV{HTTP_ACCEPT_LANGUAGE} );
if ($http_lang =~ /^([a-z]{2})$/) { $http_lang .= "_" .uc($1) }
$http_lang =~ s/([a-z]{2})-([a-z]{2})/"$1_".uc($2)/e;
$ENV{LC_MESSAGES} = "$http_lang";
unless(setlocale(LC_MESSAGES, "")){
$http_lang = 'en_US';
$ENV{LC_MESSAGES} = "$http_lang";
setlocale(LC_MESSAGES, "");
}
bindtextdomain("smeadmin","/usr/share/locale");
textdomain("smeadmin");
bind_textdomain_codeset "smeadmin", 'utf-8';
#la locale est reglee => on peut balancer les gettext
#rapide hash de labels utilise dans les 3 pages de graphes
my %labels=("-1h"=>gettext("Graphs on one hour, average on 5mn."),
"-6h"=>gettext("Graphs on six hours, average on 5mn."),
"-1d"=>gettext("Graphs on one day, average on 5mn."),
"-3d"=>gettext("Graphs on three days, average on 30mn."),
"-7d"=>gettext("Graphs on one week, average on 30mn."),
"-1m"=>gettext("Graphs on one month, average on 2h"),
"-6months"=>gettext("Graphs on six months, average on 1d."),
"-1y"=>gettext("Graphs on one year, average on 1d"));
#chaines de caracteres pour le tableau de bounds
my %strings=(
'MaxMailIn'=>gettext("Maximum number of incoming e-mails "),
'MaxMailOut'=>gettext("Maximum number of outgoing e-mails "),
'MaxDiskSpace'=>gettext("Maximum % of hard disk usage "),
'MaxCpu'=>gettext("Maximum % of cpu usage "),
'MaxHwTemp'=>gettext("Maximum temperature for cpu and motherboard "),
'MaxHdTemp'=>gettext("Maximum hard disk temperature "),
'MaxSamba'=>gettext("Maximum number of samba sessions "),
'MaxSsh'=>gettext("Maximum number of ssh sessions "),
'MaxFtp'=>gettext("Maximum number of ftp sessions "),
'MaxVpn'=>gettext("Maximum number of vpn sessions "));
#hash faisant correspondre la cle (nom du param) a sa valeur [ICI, CE SONT LES VALEURS PAR DEFAUT !!]
#idem dans le daemon /usr/bin/smeadmind
my %params=(
'DbName'=>"smeadmin",
'DbPassword'=>"pass",
'DbUser'=>"smeadmin",
# 'if_internal'=>"eth0",
# 'if_external'=>"eth1",
'ImgFormat'=>"PNG",
'ImgWidth'=>"500",
'ImgHeight'=>"300",
# /sbin/e-smith/db domains keys pour voir les autres domaines du serveur
'OtherMailDomains'=>"",
'PingTarget'=>"www.google.fr",
'hd1'=>"hda",
'hd2'=>"",
'hd3'=>"",
'hd4'=>"",
'hd5'=>"",
'hd6'=>"",
'UseDu'=>"on",
'SensorsTag1'=>"temp1",
'SensorsTag2'=>"temp2",
'SensorsTagFan'=>"fan1",
'SensorsTagFan2'=>"",
'LimitPppoeDisconnect'=>"1",
'LimitPppoeDuration'=>"4",
'LimitVpnDuration'=>"2",
'AlertMailRecipient'=>'admin',
'StatusMailRecipient'=>'admin',
'StatusInterval'=>"3",
'MaxMailIn'=>"1",
'MaxMailOut'=>"1",
'MaxDiskSpace'=>"60",
'MaxCpu'=>"50",
'MaxHwTemp'=>"40",
'MaxHdTemp'=>"40",
'MaxSamba'=>"1",
'MaxSsh'=>"1",
'MaxFtp'=>"1",
'MaxVpn'=>"1");
#----------------------------------------------------------------
#----------------------------------------------------------------
#debut MAIN
#on envoie le cgi
esmith::util::setRealToEffective ();
my $q = new CGI;
$q->charset('utf-8');
#on lit les parametres dans la db
readConf();
#on genere l'entete de la page
$q->default_dtd('-//W3C//DTD XHTML 1.0 Transitional//EN');
print $q->header ('text/html');
print $q->start_html (
-TITLE => "$progname - $DomainName",
-AUTHOR => 'landry@firewall-services.com',
-CLASS => "main",
-STYLE => {
-verbatim => '@import url("/server-common/css/sme_main.css");',
-src => '/server-common/css/sme_core.css'});
print $q->h1 ("$progname : $DomainName");
#examine le param 'state' pour savoir quelle page on demande
#METTRE UN SWITCH ??? => NON, le switch PERL est LEEEEEEEENT *4
# a voir : un hash de fonctions
if (! grep (/^state$/, $q->param)) {accueil();}
elsif ($q->param('state') eq 'conf') {showConf();}
elsif ($q->param('state') eq 'conf_alert') {showAlertConf();}
elsif ($q->param('state') eq 'validate') {changeOk();}
elsif ($q->param('state') eq 'service_control') {svcControl();}
elsif ($q->param('state') eq 'advanced') {showAdvancedTest();}
elsif ($q->param('state') eq 'service_detail') {showService();}
elsif ($q->param('state') eq 'hard') {showHardGraph();}
elsif ($q->param('state') eq 'net') {showNetGraph();}
elsif ($q->param('state') eq 'systm') {showSystmGraph();}
else { print $q->p("PrOTcH !! No page !!");}
esmith::cgi::genFooter ($q);
exit (0);
#fin MAIN
#----------------------------------------------------------------
#----------------------------------------------------------------
# definition des fonctions
#----------------------------------------------------------------
sub accueil
{
#affichage des liens vers les autres pages
print $q->p(gettext("View graphs on :"),$q->ul(
$q->li($q->a ({href => "$progname?state=hard"},gettext("server's hardware (sensors)\n"))),
$q->li($q->a ({href => "$progname?state=net"},gettext("network use (connections,sessions,load)\n"))),
$q->li($q->a ({href => "$progname?state=systm"},gettext("system performance (cpu, memory, hard disk)\n"))))),
$q->p($q->a ({href => "$progname?state=advanced"},gettext("Advanced connection tests on services\n"))),
$q->p($q->a ({href => "$progname?state=conf"},gettext("Configuration of smeadmin\n"))),
$q->hr({width=>'80%'});
#hack pour la mise en forme : a) debut 1er case a gauche
print $q->start_table,$q->start_Tr,$q->start_td;
#affichage du tableau des connexions reseau actives
print $q->p(gettext("Active tcp connections tcp with external(blue)/local(green) connections highlighted :\n")),$q->br;
print $q->start_table({-border => '1'}),
$q->Tr($q->th(gettext("Local IP:port")),$q->th(gettext("Remote IP:port")),$q->th(gettext("State")),$q->th(gettext("PID/Process")));
foreach (`/bin/netstat --tcp --numeric-host --program `)
{
my($proto,undef,undef,$loc,$dist,$stat,$prog)=split(/\s+/,$_);
#mise en couleur de l'ip en fct ext/loc
if ($proto eq 'tcp')
{
print $q->Tr($q->td({bgcolor=>(($loc =~ /($InternalIP|127.0.0.1):/o)?"#32CD32":(($loc =~ /$ExternalIP:/o)?"#1E90FF":"#FFFFFF"))},$loc),$q->td($dist),$q->td($stat),$q->td($prog));
}
}
print $q->end_table,$q->br;
#hack pour la mise en forme : b) fin 1er case a gauche et debut 2e case
print $q->end_td,$q->td({-width=>'20'}),$q->start_td({-valign=>'top'});
#affichage du resultat de 'uptime'
my $uptime=`/usr/bin/uptime`;
print $q->p(gettext("Stats :\n")),$q->p($uptime);
##Start to check linux raid status and display the content
my $Raidcheck = `/bin/cat /proc/mdstat`;
if ( $Raidcheck =~ "raid")
{
print $q->br;
print $q->p(gettext("Status of Linux software RAID :"));
my $file = "/proc/mdstat";
my $device = "all";
# Get command line options.
GetOptions ('file=s' => \$file,
'device=s' => \$device,
'help' => sub { &usage() } );
## Strip leading "/dev/" from --device in case it has been given
$device =~ s/^\/dev\///;
## This is a global return value - set to the worst result we get overall
my $retval = 0;
my (%active_devs, %failed_devs, %spare_devs);
open FILE, "< $file" or die "Can't open $file : $!";
while (<FILE>) {
next if ! /^(md\d+)+\s*:/;
next if $device ne "all" and $device ne $1;
my $dev = $1;
my @array = split(/ /);
for $_ (@array) {
next if ! /(\w+)\[\d+\](\(.\))*/;
if (defined $2 && $2 eq "(F)") {
$failed_devs{$dev} .= "$1,";
}
elsif (defined $2 && $2 eq "(S)") {
$spare_devs{$dev} .= "$1,";
}
else {
$active_devs{$dev} .= "$1,";
}
}
if (! defined($active_devs{$dev})) { $active_devs{$dev} = "none"; }
else { $active_devs{$dev} =~ s/,$//; }
if (! defined($spare_devs{$dev})) { $spare_devs{$dev} = "none"; }
else { $spare_devs{$dev} =~ s/,$//; }
if (! defined($failed_devs{$dev})) { $failed_devs{$dev} = "none"; }
else { $failed_devs{$dev} =~ s/,$//; }
$_ = <FILE>;
/\[(\d+)\/(\d+)\]\s+\[(.*)\]$/;
my $devs_total = $1;
my $devs_up = $2;
my $stat = $3;
my $result = "OK";
if ($devs_total > $devs_up or $failed_devs{$dev} ne "none") {
$result = "CRITICAL";
}
my @raidstatus = "$result - $dev [$stat] has $devs_up of $devs_total devices active (active=$active_devs{$dev} failed=$failed_devs{$dev} spare=$spare_devs{$dev})\n";
foreach my $raid (@raidstatus)
{
#if the raid is degraded (but not failed) on one drive then we get the orange colour, else green
if ( $raid =~ ("CRITICAL" && "failed=none") ){
print $q->table( $q->td($q->td({bgcolor=>(($raid =~ "CRITICAL")?"orange":"#32CD32")},$raid)));}
#if the raid is degraded and failed on drive(s) then we get the red colour, else green
elsif ( $raid =~ ("CRITICAL" && "_") ){
print $q->table ($q->td($q->td({bgcolor=>(($raid =~ "CRITICAL")?"red":"#32CD32")},$raid)));}
}
}
}
#s'il ya des users connectes on affiche le resultat de la commande 'w'
if (!($uptime =~ /0 user /))
{
print $q->br;
print $q->p(gettext("Connected users :")),$q->start_table({-border => '1'}),
$q->Tr($q->th(gettext("Login")),$q->th(gettext("TTY")),$q->th(gettext("From")),$q->th(gettext("Since")),$q->th(gettext("Idle")),$q->th(gettext("Command")));
#root pts/3 pc-00010:S.0 17:09 58.00s 1.13s 1.05s vim smeadmin
#root pts/2 pc-00010.plop.gr 17:07 0.00s 0.19s 0.05s w -h
foreach(`/usr/bin/w -h`)
{
my($user,$tty,$src,$since,$idle,undef,undef,@cmd)=split(/\s+/,$_);
print $q->Tr($q->td({bgcolor=>(($user eq "root")?"red":"white")},$user),
$q->td({bgcolor=>(($tty =~ /tty/)?"orange":"white")},$tty),$q->td($src),$q->td($since),$q->td($idle),$q->td(@cmd));
}
print $q->end_table;
}
print $q->end_td,$q->end_Tr,$q->end_table;
print $q->hr({width=>'80%'});
#liste des services et classification
my @services = ("#".gettext("Web services"),"httpd-e-smith","httpd-admin","httpd-bkpc","httpd-fpbx","httpd-pki","httpd-isoqlog","squid","php-fpm", "php55-php-fpm", "php56-php-fpm", "php70-php-fpm", "php71-php-fpm", "php72-php-fpm", "php73-php-fpm", "php74-php-fpm", "php80-php-fpm", "php81-php-fpm", "php82-php-fpm", "php83-php-fpm",
"#".gettext("Administrative services"), "sshd", "smeadmind",
"#".gettext("Network services"),"wan","dhcpd","pptpd","ippp","bridge","openvpn-s2s","openvpn-routed","openvpn-bridge","wireguard","ipsec","vpnserver",
"#".gettext("File-sharing services"),"smb","smbd","nmbd","ftp","nfs","madsonic",
"#".gettext("E-mail services"),"dovecot","pop3","pop3s","imaps","imap","qmail","altqmail","qpsmtpd","sqpsmtpd","clamd","freshclam","spamassassin","mailman",#mail
"#".gettext("DNS services"),"tinydns","dnscache", "dnscache.forwarder", "DynDNS", #dns
"#".gettext("Authentication services"),"oidentd","ldap","smtp-auth-proxy","radiusd","cvm-unix", #auth
"#".gettext("Misc. services"),"mariadb","ntpd","lpd", "backuppc", "bandwidthd","unifi", #misc
"#".gettext("System services"),"crond","rsyslog","ulogd","acpid","raidmonitor","local", "yum"); #sys et materiel
#hack pour la mise en forme : a) debut 1er case a gauche
print $q->start_table,$q->start_Tr,$q->start_td;
#affichage du tableau des services
print $q->p(gettext("System services (Click on a service name for details) :\n")),$q->br,
$q->start_table({-border => '1'});
$q->Tr($q->th(gettext("Service")),$q->th(gettext("State")),$q->th(gettext("Nb process")),$q->th(gettext("Action")));
print $q->startform(-method => 'GET', -action => $q->url (-absolute => 1));
foreach my $svc (@services)
{
# si le service pppoe est disabled on n'affiche pas la ligne correspondante
next if ($svc eq 'pppoe' && $smedb->get('pppoe')->prop('status') eq 'disabled');
my $cmd;
my $details=0;
#si c'est un 'header'
if ($svc=~/^#(.*)/)
{
print $q->Tr(),$q->Tr($q->th($1),$q->th(gettext("State")),$q->th(gettext("Action")),$q->th("DB Status"),$q->th("DB Action"));
}
else
{
#si c'est un service pour lequel on a des infos complementaires...
if($svc=~/^(httpd-e-smith|httpd-admin|smb|smbd|nmbd|squid|pptpd|dhcpd|sshd|ftp|pppoe|pppd|wan|altqmail|qmail|qpsmtpd|sqpsmtpd)$/) {$details=1;}
if ($svc=~/^(imaps|imap|pop3|pop3s)$/) { $cmd = "/usr/bin/systemctl is-active dovecot"; }
else {$cmd = "/usr/bin/systemctl is-active $svc";}
my @res=`$cmd`;
foreach (@res)
{
my $dbsv=$smedb->get("$svc") ||next;
# workaround to see db config status
my $dbstatus="not defined";
if ( length(`/sbin/e-smith/db configuration show $svc`) > 1 )
{$dbstatus=$smedb->get("$svc")->prop('status')||"disabled";} # trouver un moyen de verifier que le nom du service est bien trouvé dans liste
else
{$dbstatus="";}
if ($svc=~/^(imaps|imap|pop3|pop3s)$/)
{
print $q->Tr(
(($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
$q->td(""),$q->td( "dovecot" ) ,
$q->td("$dbstatus"),
$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") )
);
}
#si le service est arrete^:il ya down ou il n'y a pas de () pour le pid et ca ne fini pas par ...
elsif(/^down:/ || /^([a-zA-Z0-9]*) [^(^)]*([^.]{3})$/ || /^failed/ || /^unknown/|| /^inactive/)
{
#on fait une conditionnelle pour savoir si on met le nom du service en lien ou pas
print $q->Tr((($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
$q->td(gettext("Stopped")),$q->td( (("$dbstatus" eq "enabled" || "$dbstatus" eq "" )? $q->submit(-name=>"start_$svc",-value=>'start'): "disabled") ) ,$q->td("$dbstatus"),
$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") ) );
}
elsif (/^run:(.*)\(pid ([\d\s]+)\)/ || /^([a-zA-Z0-9]*) \(pid ([\d\s]+)\).*\.\.\.$/ || /^active/ )
{
#$2=liste pids
my @pids;
@pids=split(/ /,$2) if defined $2;
print $q->Tr(
(($details==1)? $q->td($q->a({href=>"$progname?state=service_detail&service=$svc"},"$svc")) : $q->td("$svc")),
$q->td(gettext("Started")),
$q->td($q->submit(-name=>"stop_$svc",-value=>'stop')) ,$q->td("$dbstatus"),
$q->td( ( ("$dbstatus" ne "") ? (("$dbstatus" eq "enabled" )? $q->submit(-name=>"disabled_$svc",-value=>'disable'): $q->submit(-name=>"enabled_$svc",-value=>'enable')) : " ") ) );
}
}
}
}
#service_control est le parametre qui prend le nom du service a arreter/demarrer
print $q->hidden(-name=>'state',-default=>'service_control',-override=>1),
$q->end_table,
$q->endform;
#hack pour la mise en forme : b) fin 1er case a gauche et debut 2e case
print $q->end_td,$q->td({-width=>'100'}),$q->start_td({-valign=>'top'});
#affichage du tableau des connexions reseau en ecoute
print $q->p(gettext("Listening tcp sockets, and corresponding process :\n")),$q->br;
print $q->start_table({-border => '1'}),
$q->Tr($q->th(gettext("Local IP:port")),$q->th(gettext("PID/Process")));
foreach (`/bin/netstat --tcp --numeric-host --program --listen`)
{
my($proto,undef,undef,$loc,undef,undef,$prog)=split(/\s+/,$_);
#mise en couleur de l'ip en fct ext/loc
if ($proto eq 'tcp')
{
print $q->Tr($q->td($loc),$q->td($prog));
}
}
print $q->end_table;
print $q->end_td,$q->end_Tr,$q->end_table;
print $q->br,$q->hr({width=>'80%'});
if (-e "/usr/sbin/clamd")
{
#affichage des infos sur l'antivirus
my $sigs=0;
foreach (`/usr/bin/tail -n 6 /var/log/freshclam/current`)
{
#ClamAV update process started at Thu Jul 29 18:36:00 2004
if (/ClamAV update process started at (\w{3} \w{3}\s{1,2}\d{1,3} [0-9:]{8} \d{4})/)
{print $q->p(sprintf(gettext("Last update of ClamAV antivirus : %s.\n"),$1));}
#LOL !! le guide du routard galactique
if (/DON'T PANIC/)
{print $q->p(gettext("Warning ! Your antivirus may not be up-to-date.\n"));}
# main.cvd is up to date (version: 24, sigs: 21793, f-level: 2, builder: tomek)
# daily.cvd is up to date (version: 428, sigs: 1177, f-level: 2, builder: acab)
# Database updated (23150 signatures) from database
# 2005-12-01 21:46:29.777100500 ClamAV update process started at Thu Dec 1 21:46:29 2005
# 2005-12-01 21:46:29.981397500 WARNING: Your ClamAV installation is OUTDATED!
# 2005-12-01 21:46:29.981407500 WARNING: Local version: 0.87 Recommended version: 0.87.1
# 2005-12-01 21:46:29.981414500 DON'T PANIC! Read http://www.clamav.net/faq.html
# 2005-12-01 21:46:29.981420500 main.cvd is up to date (version: 34, sigs: 39625, f-level: 5, builder: tkojm)
# 2005-12-01 21:46:29.981428500 daily.cvd is up to date (version: 1200, sigs: 1669, f-level: 6, builder: tomek)
if (/sigs: (\d+)/) {$sigs+=$1;}
}
print $q->p(sprintf(gettext("The database contains %s virus signatures.\n"),$sigs));
}
#un peu de bug report ?
# rem jpp waiting for full dormmagick translation. Landry do not support anymore this contrib, will have a direct link to bugzilla here
# print $q->p(gettext("Some feature request, comment or bug report ? send an e-mail to "),$q->b($q->i(gettext("landry at firewall-services dot com\n"))));
}
#----------------------------------------------------------------
# lecture de la conf dans la smedb et dans le fichier de conf
sub readConf
{
#lecture des parametres contenus dans la db de sme
my $smedb=esmith::ConfigDB->open;
$DomainName = $smedb->get('DomainName')->value;
$SystemName = $smedb->get('SystemName')->value;
$SystemMode = $smedb->get("SystemMode")->value;
#on n'a une external ip que si on est en server-passerelle
if ($SystemMode =~ /servergateway/)
{
$ExternalIP = $smedb->get("ExternalIP")->value;
$ExternalInterface = $smedb->get("ExternalInterface")->prop('Name');
}
else{
$ExternalIP = '';
$ExternalInterface ='';
}
$InternalIP = $smedb->get("LocalIP")->value;
foreach my $key (keys(%params)){
$params{$key} = $smeadmindb->prop($key);
}
$SshPort = $smedb->get('sshd')->prop('TCPPort');
}
#----------------------------------------------------------------
#affiche le formulaire permettant de parametrer smeadmin
sub showConf
{
print $q->startform (-method => 'GET', -action => $q->url (-absolute => 1 )),
$q->i($q->p(gettext("Configuration of status e-mails.\n"))),
$q->p(gettext("If you set the frequency to 0, status e-mails are disabled. You can put only the username if the recipient is a local user.\n")),
$q->start_table,
esmith::cgi::genNameValueRow($q,gettext("Status e-mails recipient"),"StatusMailRecipient",$params{"StatusMailRecipient"}),
esmith::cgi::genNameValueRow($q,gettext("Frequency of status e-mails (* 5min)"),"StatusInterval",$params{"StatusInterval"}),
$q->end_table,
$q->hr({width=>'50%'});
#partie MySQL du formulaire
print $q->i($q->p(gettext("Configuration of MySQL connection.\n"))),
$q->p(gettext("You shall only modify these settings if you change the default values with phpMyAdmin or mysqladmin. These settings don't directly affect the configuration of MySQL.")),$q->br,
$q->start_table,
esmith::cgi::genNameValueRow($q,gettext("Database"),'DbName',$params{'DbName'}),
esmith::cgi::genNameValueRow($q,gettext("MySQL user"),'DbUser',$params{'DbUser'}),
esmith::cgi::genNameValueRow($q,gettext("Password"),'DbPassword',$params{'DbPassword'}),
$q->end_table,$q->hr({width=>'50%'});
#partie reseau du formulaire
print $q->i($q->p(gettext("Configuration of network settings.\n"))),
$q->p(gettext('You can specify the names of the network interfaces to monitor, the e-mail domains and adresses to count in the e-mail graph (list of domains or adresses separated by semicolons. "me@domain.fr ; other-domain.com ; virtual.domain.fr" - the primary domain name and virtual domains are already counted). You can already choose a target for the ping latency graph (www.google.fr, default gateway,...)')),$q->br,
$q->start_table;
print esmith::cgi::genNameValueRow($q,gettext("Other e-mail domains"),'OtherMailDomains',$params{'OtherMailDomains'}),
esmith::cgi::genNameValueRow($q,gettext("Ping target"),'PingTarget',$params{'PingTarget'}),
$q->end_table,$q->hr({width=>'50%'});
#partie graphique/interface
print $q->i($q->p(gettext("Web panel configuration.\n"))),
$q->p(gettext("You can set the format and size of graphs, and the bounds upon which pppoe and vpn connections need to be highlighted.\n")),$q->br,
$q->start_table,
#vieux hack pour récuperer la css du NameValueRow
# esmith::cgi::genNameValueRow($q,gettext("Format d'image (PNG/GIF)"),'img_format',$params{'img_format'}),
$q->Tr ($q->td ({-class => "sme-noborders-label"},gettext("Image Format:")),"\n",
$q->td($q->popup_menu(-name=>'ImgFormat', -values=>['PNG','GIF'], -default=>$params{'ImgFormat'}))),
esmith::cgi::genNameValueRow($q,gettext("Graphs width"),'ImgWidth',$params{'ImgWidth'}),
esmith::cgi::genNameValueRow($q,gettext("Graphs height"),'ImgHeight',$params{'ImgHeight'}),
esmith::cgi::genNameValueRow($q,gettext("Pppoe disconnection lasting more than (in minutes)"),'LimitPppoeDisconnect',$params{'LimitPppoeDisconnect'}),
esmith::cgi::genNameValueRow($q,gettext("Pppoe connection lasting less than (in hours)"),'LimitPppoeDuration',$params{'LimitPppoeDuration'}),
esmith::cgi::genNameValueRow($q,gettext("Vpn connection lasting more than (in hours)"),'LimitVpnDuration',$params{'LimitVpnDuration'}),
$q->end_table,$q->hr({width=>'50%'});
#partie senseurs materiels
print $q->i($q->p(gettext("Configuration of hardware sensors.\n"))),
$q->p(gettext("For the hard disks, generally you have 'hda' or 'hdb' with IDE and 'sda' or 'sdb' with SATA/SCSI. If you have only on disk, let the second field blank. You can choose to activate the computing of the main directories' size of SME. (maybe long and resource-consuming on large disks). To find available sensors, execute 'sensors' in a shell, and look for the keywords corresponding to the working sensors ('temp1','CPU Temp','MB Temp','fan3',....). Let the fields blank if you have no sensors available.\n")),$q->br,
$q->start_table,
$q->Tr ($q->td ({-class => "sme-noborders-label"},gettext("Activate du -s:")),"\n",
$q->td($q->popup_menu(-name=>'UseDu', -values=>['on','off'], -default=>$params{'UseDu'}))),
esmith::cgi::genNameValueRow($q,gettext("First hard disk"),'hd1',$params{'hd1'}),
esmith::cgi::genNameValueRow($q,gettext("Second hard disk"),'hd2',$params{'hd2'}),
esmith::cgi::genNameValueRow($q,gettext("Third hard disk"),'hd3',$params{'hd3'}),
esmith::cgi::genNameValueRow($q,gettext("Fourth hard disk"),'hd4',$params{'hd4'}),
esmith::cgi::genNameValueRow($q,gettext("Fifth hard disk"),'hd5',$params{'hd5'}),
esmith::cgi::genNameValueRow($q,gettext("Sixth hard disk"),'hd6',$params{'hd6'}),
esmith::cgi::genNameValueRow($q,gettext("First sensor (cpu)"),'SensorsTag1',$params{'SensorsTag1'}),
esmith::cgi::genNameValueRow($q,gettext("Second sensor (motherboard)"),'SensorsTag2',$params{'SensorsTag2'}),
esmith::cgi::genNameValueRow($q,gettext("Third sensor (fan)"),'SensorsTagFan',$params{'SensorsTagFan'}),
esmith::cgi::genNameValueRow($q,gettext("Fourth sensor (fan)"),'SensorsTagFan2',$params{'SensorsTagFan2'}),
$q->end_table,$q->hr({width=>'50%'});
#partie alertes
print $q->i($q->p(gettext("Configuration of alerts.\n"))),
$q->p(gettext("You should notice that these values are not limits FOR the system, but just values beyond which an alert e-mail is sent. If you set the limit to 0, the alert is disabled. You can put only the username if the recipient is a local user.\n")),$q->br;
print $q->start_table,
esmith::cgi::genNameValueRow($q,gettext("Alert e-mails recipient "),"AlertMailRecipient",$params{"AlertMailRecipient"});
#affichage du tableau des strings/limites parametree
foreach my $key (keys(%strings))
{
print esmith::cgi::genNameValueRow($q,$strings{$key},$key,$params{$key});
}
print $q->end_table,
$q->hr({width=>'50%'}),
esmith::cgi::genButtonRow($q,$q->submit(-name=>'action',-value=>gettext("Save"))),
$q->hidden(-name=>'state',-default=>'validate',-override=>1),
$q->endform;
}
#----------------------------------------------------------------
#little patch : on montre juste la limite pour UNE alerte (cible du lien contenu dans le mail d'alerte)
# cette fonction affiche juste un petit formulaire pour modifier la limite
sub showAlertConf
{
my $key=$q->param('alert');
print $q->startform (-method => 'GET', -action => $q->url (-absolute => 1 )),
$q->i($q->p(gettext("Alert configuration.\n"))),$q->p(gettext("Put 0 to desactivate it.\n")),$q->br,
$q->start_table,
esmith::cgi::genNameValueRow($q,$strings{$key},$key,$params{$key}),
$q->end_table,$q->br,
esmith::cgi::genButtonRow($q,$q->submit(-name=>'action',-value=>gettext("Save"))),
$q->hidden(-name=>'state',-default=>'validate',-override=>1),
$q->hidden(-name=>'alert',-default=>"$key",-override=>1),
$q->endform;
}
#----------------------------------------------------------------
#verifie et sauve les nouveaux parametres
sub changeOk
{
# faire juste une verification des valeurs, et afficher le formulaire vert changements appliques (meme si rien n'est modifie)
# eventuellement un message si les mails de status viennent d'etre desactives
# sinon, ne rien appliquer, donner la raison de l'erreur et afficher le formulaire rouge
#Verification des parametres
my $modified=0;
my $verifok=1;
my $str;
#il y a deux cas :
# - on verifie TOUTE la conf (on vient de changer plusieurs params)
# - on verifie UN parametre (on vient de changer une limite numerique)
# cas 1 :)
if (!defined $q->param ('alert'))
{
# on regarde si un parametre a ete modifie
foreach my $key (keys(%params))
{
#print $key.": ".$q->param("$key")."<br>";
$modified=1 if ($params{$key} ne $q->param("$key"));
}
# ces 2 verifs ont ete "assouplies" pour permettre de ne mettre qu'un username local au serveur sans mettre tout l'adresse mail complete
#verification validite e-mail alertes
if (! ($q->param('AlertMailRecipient') =~ /^[\w.-]+(@[\dA-Za-z-.]+)?$/) )
{
$verifok=0;
$str=sprintf(gettext("\"%s\" is not a valid e-mail address.\n"),$q->param("AlertMailRecipient"));
print esmith::cgi::genTextRow($q,$q->p($str));
}
#verification validite e-mail status
if (! ($q->param('StatusMailRecipient') =~ /^[\w.-]+(@[\dA-Za-z-.]+)?$/) )
{
$verifok=0;
$str=sprintf(gettext("\"%s\" is not a valid e-mail address.\n"),$q->param("StatusMailRecipient"));
print esmith::cgi::genTextRow($q,$q->p($str));
}
#verification valeurs numeriques
foreach my $key ( 'ImgWidth', 'ImgHeight', 'LimitPppoeDisconnect', 'LimitPppoeDuration', 'LimitVpnDuration',
'StatusInterval', 'MaxMailIn', 'MaxMailOut', 'MaxDiskSpace', 'MaxCpu', 'MaxHdTemp',
'MaxHwTemp', 'MaxSamba', 'MaxSsh', 'MaxFtp', 'MaxVpn')
{
if (!($q->param("$key")=~/\d+/))
{
$verifok=0;
$str=sprintf(gettext("\"%s\" is not an integer numeric value for the setting '%s'.\n"),$q->param("$key"),$key);
print esmith::cgi::genTextRow($q,$q->p($str));
}
}
# si on vient de desactiver les mails de status, on affiche un message
if ($params{'StatusInterval'} != 0 && $q->param('StatusInterval') == 0)
{
print esmith::cgi::genTextRow($q,$q->p(gettext("Status e-mails have been disabled.\n")));
}
if ($modified){
foreach my $key (keys(%params))
{
$smeadmindb->set_prop($key,$q->param($key));
}
}
}
else
#cas 2 :)
{
my $key=$q->param('alert');
$modified=1 if ($params{$key} ne $q->param("$key"));
if (!($q->param("$key")=~/\d+/))
{
$verifok=0;
$str=sprintf(gettext("\"%s\" is not an integer numeric value for the setting '%s'.\n"),$q->param("$key"),$key);
print esmith::cgi::genTextRow($q,$q->p($str));
}
else
{
#on applique la nouvelle valeur
$params{$q->param('alert')}=$q->param("$key");
}
$smeadmindb->set_prop($key,$q->param($key)) if ($modified);
}
if ($verifok)
{
if ($modified)
{
#si un param a ete change, on notifie le demon avec un -SIGHUP
# `pkill -SIGHUP smeadmind`;
#notify the deamon is not enough we want to restart it when parameters are changed
system ('service smeadmind restart 2>&1 1>/dev/null') == 0 or die 'ERROR: the service smeadmind can not be restarted';
print $q->table({-class =>"sme-borders"},
$q->Tr(
$q->td( '<img src="/server-common/tickmark.jpg" ALT="SUCCESS" >'),
$q->td( $q->div( {-class=>"success"}, gettext("New settings have been saved."))))) ;
}
else
{
print esmith::cgi::genTextRow($q,$q->p(gettext("The settings are the same, nothing has been modified.\n")));
}
}
else
{
print $q->table({-class =>"sme-borders"},
$q->Tr(
$q->td( '<img src="/server-common/checkmark.jpg" ALT="ERROR" >'),
$q->td( $q->div( {-class=>"error"}, gettext("An error occured. Check the settings you provided."))))) ;
}
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#arret/demarrage du service (bourrin, oui, j'utilise pas serviceControl)
sub svcControl
{
#pour tous les champs du formulaire qu'on a recu (normalement , juste 'state', et un 'start_$service' ou 'stop_$service'
foreach ($q->param())
{
#si le nom du parametre est (start|stop)_$svc
if(/^(stop|start)_([\w-]+)$/)
{
#$_ est le nom du champ
#$1 est l'action
#$2 est le nom du service==doit etre egal a la valeur
#si la valeur correspond a l'action
if ($q->param("$_") eq "$1")
{
my $cmd='';
$cmd=`/usr/bin/systemctl $1 $2`;
my @res=$cmd;
foreach (@res)
{ print $q->p("$_\n");}
}
else
#on a affaire a un petit malin qui bricole les parametres
{
print $q->p("Parametre incorrect1\n");
}
}
#si le nom du parametre est (enable|disable)_$svc
if(/^(enabled|disabled)_([\w-]+)$/)
{
#$_ est le nom du champ
#$1 est l'action
#$2 est le nom du service==doit etre egal a la valeur
#si la valeur correspond a l'action
if ($q->param("$_")."d" eq "$1")
{
my @res=`/sbin/e-smith/db configuration setprop $2 status $1`;
push(@res,`/sbin/e-smith/db configuration printprop $2 status`);
# we should restart the service here because it should be stop if disabled !!!
my $ordre="";
if ( $1 eq "enabled")
{$ordre="start";}
if ( $1 eq "disabled")
{$ordre="stop";}
my $cmd='';
if ($2=~/^(ulogd|smbd|nmbd|rsyslog)$/)#(-d "/service/$2")
{$cmd = `/usr/bin/sv $ordre $2`;}
else
{$cmd=`/sbin/e-smith/service $2 $ordre`;}
push(@res,$cmd);
foreach (@res)
{ print $q->p("$_\n");}
}
else
#on a affaire a un petit malin qui bricole les parametres
{
print $q->p("Parametre incorrect2\n");
}
}
}
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#Tests de connexion aux services de SME
sub showAdvancedTest
{
#affichage de la liste des tests si le param 'service' n'est pas défini.
if (!defined($q->param('service')))
{
print $q->p(gettext("These differents tests may produce false positives, do not take care of them.")),
$q->p(gettext("Execute them only if you know what they do, and how to analyse their results.")),$q->br,
$q->start_table,
$q->Tr($q->td(gettext("Test http service")),
$q->td($q->a ({href => "$progname?state=advanced&service=http"},"http@\n"))),
$q->Tr($q->td(gettext("Test samba service")),
$q->td($q->a ({href => "$progname?state=advanced&service=samba"},"smbcontrol\n"))),
$q->Tr($q->td(gettext("Test network latency")),
$q->td($q->a ({href => "$progname?state=advanced&service=ping"},"ping\n"))),
$q->Tr($q->td(gettext("Test ftp service")),
$q->td($q->a ({href => "$progname?state=advanced&service=ftp"},"telnet 21\n"))),
$q->Tr($q->td(gettext("Test ssh service")),
$q->td($q->a ({href => "$progname?state=advanced&service=ssh"},"telnet ${SshPort}\n"))),
$q->Tr($q->td(gettext("Test pop service")),
$q->td($q->a ({href => "$progname?state=advanced&service=pop"},"telnet 110\n"))),
$q->Tr($q->td(gettext("Test smtp service")),
$q->td($q->a ({href => "$progname?state=advanced&service=smtp"},"telnet 25\n"))),
$q->end_table;
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#on fait le test avance
else
{
#hack this to handle the server-only case
my $record;
$record = $smedb->get("SystemMode");
#on n'a une external ip que si on est en server-passerelle
if ($record->value =~ /servergateway/)
{
$record = $smedb->get("ExternalIP");
}
else
{
$record = $smedb->get("LocalIP");
}
my $ip =$record->value;
#test du service http => http@
if ($q->param('service') eq 'http')
{
print $q->p($q->b(gettext("Execution of 'http\@' (should return html source code of server's homepage):"))),$q->br;
foreach (`/usr/local/bin/http@ 2>&1`)
{
print escapeHTML($_),$q->br;
}
}
#test du service samba => smbcontrol smbd ping
elsif ($q->param('service') eq 'samba')
{
print $q->p($q->b(gettext("Execution of 'smbcontrol smbd ping' (samba server answers giving its PID):"))),$q->br;
foreach (`/usr/bin/smbcontrol smbd ping 2>&1`)
{
print $q->p($_);
}
}
#test du service http => http@
elsif ($q->param('service') eq 'ping')
{
print $q->p($q->b(gettext("Execution of 'ping google.fr -c 1' (latency):"))),$q->br;
foreach (`/bin/ping google.fr -c 1 2>&1`)
{
print $q->p($_);
}
}
elsif ($q->param('service') eq 'ftp')
{
print $q->p($q->b(sprintf(gettext("Execution of 'echo \"SYST\" | nc %s 21' (ftp opened to the external network):"),$ip))),$q->br;
foreach (`/bin/echo "SYST" | /usr/bin/nc $ip 21 2>&1`)
{
print $q->p($_);
}
}
elsif ($q->param('service') eq 'ssh')
{
print $q->p($q->b(sprintf(gettext("Execution of 'echo \"hello\" | nc %s %s' (ssh opened to the external network):"),$ip,$SshPort))),$q->br;
foreach (`/bin/echo "hello" | /usr/bin/nc $ip $SshPort 2>&1`)
{
print $q->p($_);
}
}
elsif ($q->param('service') eq 'pop')
{
print $q->p($q->b(sprintf(gettext("Execution of 'echo \"quit\" | nc %s 110' (pop server running):"),$ip))),$q->br;
foreach (`/bin/echo "quit" | /usr/bin/nc $ip 110 2>&1`)
{
print $q->p($_);
}
}
elsif ($q->param('service') eq 'smtp')
{
print $q->p($q->b(sprintf(gettext("Execution of 'echo \"quit\" | nc -i 2 %s 25' (smtp server running):"),$ip))),$q->br;
foreach (`/bin/echo "quit" | /usr/bin/nc -i 2 $ip 25 2>&1`)
{
print $q->p($_);
}
}
print $q->p($q->a ({href => "$progname?state=advanced"},gettext("Another test\n")));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
}
#----------------------------------------------------------------
#DBI:mysql, connecte MOI
sub connectBD
{
$bd=DBI->connect ("DBI:mysql:$params{'DbName'}","$params{'DbUser'}","$params{'DbPassword'}");
if (!defined ($bd))
{
print $q->p("MySQL error : $DBI::errstr");
die (gettext("Check MySQL connection settings.\n"));
}
}
#----------------------------------------------------------------
#DBI:mysql, deconnecte MOI
sub deconnectBD
{
$bd->disconnect;
if (!defined ($bd))
{
print $q->p("MySQL error : $DBI::errstr");
die (gettext("Check MySQL connection settings.\n"));
}
}
#----------------------------------------------------------------
# fonction prenant une ip numerique et renvoyant une ip format a.b.c.d
# rapide hack peut-etre efficace...
# (en fait j'ai trouve mieux dans esmith::util::IPaddrToQuad, je repompe le
# code pour pas avoir a loader tout esmith::util)
sub ipnum2ipdot
{
my ($addrBits) = @_;
return sprintf( "%d.%d.%d.%d",
( $addrBits >> 24 ) & 0xff,
( $addrBits >> 16 ) & 0xff,
( $addrBits >> 8 ) & 0xff,
$addrBits & 0xff );
}
#----------------------------------------------------------------
# affiche un menu deroulant pour le choix de la duree des graphes
sub printPopupMenu
{
my ($msg)=(@_);
my %labels=("-1h"=>gettext("one hour"),
"-6h"=>gettext("six hours"),
"-1d"=>gettext("the day"),
"-3d"=>gettext("three days"),
"-7d"=>gettext("one week"),
"-1m"=>gettext("one month"),
"-6months"=>gettext("six months"),
"-1y"=>gettext("one year"));
print $q->start_form,
$msg,
$q->popup_menu(-name=>'duree', -values=>['-1h','-6h','-1d','-3d','-7d','-1m','-6months','-1y'], -default=>'-1d', -labels=>\%labels),
$q->submit('action',"Go !"),
$q->hidden(-name=>'state',-default=>$q->param('state'),-override=>1),
$q->hidden(-name=>'service',-default=>$q->param('service'),-override=>1),
$q->end_form,"\n";
}
#----------------------------------------------------------------
#cette fonction cree et affiche le graphe supervisant $svc
# $svc = {httpd, squid, samba, afp}
sub showSvcGraph
{
my ($svc,$msg)=(@_);
my $start='-1d';
printPopupMenu($msg);
$start=$q->param('duree') if defined($q->param('duree'));
#creation du graphe
createShowGraph("","$svc$start",
"--title=Service $svc",
"--start=$start",
"DEF:cpu=$rrddir/$svc.rrd:cpu:AVERAGE","DEF:maxcpu=$rrddir/$svc.rrd:cpu:MAX",
"DEF:mem=$rrddir/$svc.rrd:mem:AVERAGE","DEF:maxmem=$rrddir/$svc.rrd:mem:MAX",
"DEF:nbproc=$rrddir/$svc.rrd:nbproc:AVERAGE","DEF:maxnbproc=$rrddir/$svc.rrd:nbproc:MAX",
"COMMENT: ", "AREA:mem#1144BB:\%Mem", "LINE2:cpu#FFDD00:\%Cpu", "LINE2:nbproc#CC1100:Nb Proc", "COMMENT:\\n",
"COMMENT:Max\\:", "GPRINT:maxmem:MAX:%2.2lf %%", "GPRINT:maxcpu:MAX:%2.2lf %%", "GPRINT:maxnbproc:MAX:%2lg" );
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#cette fonction est juste un "aiguillage" vers la fonction qui affiche le service demande
# on passe par ici en cliquant sur les liens correspondant aux noms des services
sub showService
{
#les 4 premiers sont les services qui ont des rrds
#les 7 derniers sont ceux qui ont des donnees dans mysql
if ($q->param('service') eq 'httpd-e-smith' || $q->param('service') eq 'httpd-admin') {showHttpd();}
elsif ($q->param('service') eq 'squid') {showSquid();}
elsif ($q->param('service') eq 'smbd' || $q->param('service') eq 'smb' || $q->param('service') eq 'nmbd') {showSamba();}
elsif ($q->param('service') eq 'atalkd') {showAfp();}
elsif ($q->param('service') eq 'pptpd') {showVpn();}
elsif ($q->param('service') eq 'dhcpd') {showDhcpd();}
elsif ($q->param('service') eq 'sshd') {showSsh();}
elsif ($q->param('service') eq 'proftpd') {showFtp();}
elsif ($q->param('service') eq 'ftp') {showFtp();}
elsif ($q->param('service') eq 'pppoe' || $q->param('service') eq 'wan' || $q->param('service') eq 'pppd' ) {showPppoe();}
elsif ($q->param('service') eq 'qpsmtpd' || $q->param('service') eq 'sqpsmtpd' ) {showQpsmtpd();}
elsif ($q->param('service') eq 'qmail') {showQmail();}
elsif ($q->param('service') eq 'altqmail') {showQmail();}
}
#----------------------------------------------------------------
#details du service httpd
sub showHttpd
{
showSvcGraph("httpd",gettext("System load for the apache web server (httpd-e-smith & httpd-admin processes) on "));
}
#----------------------------------------------------------------
#details du service qmail
sub showQmail
{
my $start='-1d';
printPopupMenu(gettext("View graphs on "));
$start=$q->param('duree') if defined($q->param('duree'));
print $q->p($q->b($labels{"$start"}));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
#qmail local and remote email
createGraphQmail($start);
createGraphAltQmail($start);
}
#----------------------------------------------------------------
#details du service s?qpsmtpd
sub showQpsmtpd
{
my $start='-1d';
printPopupMenu(gettext("View graphs on "));
$start=$q->param('duree') if defined($q->param('duree'));
print $q->p($q->b($labels{"$start"}));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
#qpsmtpd incoming emails from outside the server( local network and internet)
createGraphQpsmtpd($start);
}
#----------------------------------------------------------------
#details du service squid
sub showSquid
{
showSvcGraph("squid",gettext("System load for the transparent http/ftp proxy squid on "));
}
#----------------------------------------------------------------
#details du service samba
sub showSamba
{
#voir plus bas pour explication des params
showDbData( [
[gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
[gettext("Login"),],
[gettext("Hostname"),],
[gettext("Start"),],
[gettext("End"),]
],
\"SELECT ip,login,machine,debut,derniere_vue FROM samba ORDER BY debut DESC",
\gettext("Detailed list of the last times a host has connected to a samba share.\n"));
#affichage du graphe
showSvcGraph("samba",gettext("System load for the samba server (smbd & nmbd processes) on "));
}
#----------------------------------------------------------------
#details du service appletalk
sub showAfp
{
#voir plus bas pour explication des params
showDbData( [
[gettext("Start"),],
[gettext("End"),],
[gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
[gettext("Login"),],
[gettext("Written data (Ko)"),],
[gettext("Read data (Ko)"),]
],
\"SELECT debut,fin,ip,login,volume_read,volume_write FROM afp WHERE debut > CURDATE() - INTERVAL 7 DAY ORDER BY debut DESC",
\gettext("Detailed list of the last connections (on the last 7 days) to the afp service (Apple File Protocol).\n"));
#affichage du graphe
showSvcGraph("afp",gettext("System load for the appletalk server (atalkd, papd, afpd and cnid_metad processes)."));
}
#----------------------------------------------------------------
#details du service pptpd vpn
sub showVpn
{
showDbData( [
[gettext("Start"),],
[gettext("End"),],
[gettext("Duration"),],
[gettext("Client IP address"),sub { return ipnum2ipdot(@_); } ],
[gettext("Client local IP address"),sub { return ipnum2ipdot(@_); } ],
[gettext("Incoming data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
[gettext("Outgoing data (ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
[gettext("Login"),]
],
\"SELECT debut,fin,duree,ip,vpn_clt,volume_in,volume_out,login FROM vpn ORDER BY debut DESC",
\gettext("Detailed list of vpn connections (Virtual Private Network).\n"));
}
#----------------------------------------------------------------
#details du service dhcpd
sub showDhcpd
{
showDbData( [
[gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
[gettext("MAC Address"),],
[gettext("Hostname"),],
[gettext("Date of renewal"),]
],
\"SELECT ip,mac,hostname,debut FROM dhcpd ORDER BY debut DESC",
\gettext("List of the last dhcp leases renewal (Dynamic Host Control Protocol).\n"));
}
#----------------------------------------------------------------
#details du service pppoe
sub showPppoe
{
# get first db entry
my $requete="SELECT substr(debut,1,4), substr(debut,6,2) FROM pppoe WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut ASC LIMIT 1";
#connexion a la base de donnees mySQL
connectBD();
#recuperation des donnees
my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
$rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
my @debut = $rq->fetchrow_array();
# get first db entry
my $requete_DESC="SELECT substr(fin,1,4), substr(fin,6,2) FROM pppoe WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut DESC LIMIT 1";
#connexion a la base de donnees mySQL
connectBD();
#recuperation des donnees
my $rq_DESC=$bd->prepare($requete_DESC) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete_DESC,$bd->errstr));
$rq_DESC->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq_DESC->errstr));
my @fin = $rq_DESC->fetchrow_array();
#$debut[1] -- if ($debut[1] == $fin[1]);
my $end_yymm = $debut[0].$debut[1];
my $yymm = $fin[0].$fin[1];
my $startMonth = $debut[1];
my $startYear = $debut[0];
my $endMonth;
my $endYear;
my $preMonth;
my $preYear;
my $i=0;
print $q->p(gettext("Traffic by Month"));
print $q->start_table({-border=>'1'}),
$q->start_Tr;
print $q->th(gettext("year-month"));
print $q->th(gettext("IN (GB)"));
print $q->th(gettext("OUT (GB)"));
print $q->th(gettext("TOTAL (GB)"));
$q->end_Tr;
my $nblines = 0;
while ($end_yymm < $yymm || $nblines < 1) {
$nblines =1;
if ($startMonth eq '12') {
$endMonth = 1;
$endYear = $startYear + 1;
} else {
$endMonth = $startMonth + 1;
$endYear = $startYear;
}
## Now that you have the end year and month incremented setup the end_yymm variable again to be picked up in the while statement:
$end_yymm = $startYear . ${\(length($startMonth) == 1 ? '0' : '')} . $startMonth;
if ($startMonth eq '1') {
$preMonth=12;
$preYear=$startYear-1;
}
else {
$preMonth=$startMonth-1;
$preYear= $startYear;
}
# ...... carry on with the rest of your code
# print "**$end_yymm<br>\n";
$requete="SELECT substring(`fin`,1,7) as 'month',
round(SUM(`volume_in`)/1000/1000/1000,3) as 'In (Go)' ,
round(SUM(`volume_out`) /1000/1000/1000,3) as 'Out (Go)' ,
round(SUM(`volume_in` + `volume_out`)/1000/1000/1000,3) as 'Total (Go)' ,
SUM(TIME_TO_SEC(`duree`))/3600/24 as 'duree'
FROM `pppoe` WHERE
# mois
(`debut`> '$startYear-$startMonth-01 00:00:00' and `fin`< '$endYear-$endMonth-01 00:00:00')
# bordure
or ( `debut`> '$preYear-$preMonth-01 00:00:00' and `debut`< '$startYear-$startMonth-01 00:00:00' and `fin`> '$startYear-$startMonth-01 00:00:00')
or ( `debut`< '$endYear-$endMonth-01 00:00:00' and `fin`> '$endYear-$endMonth-01 00:00:00' and `fin`< '$endYear-$endMonth-28 00:00:00')";
my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
$rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
my @ligne = $rq->fetchrow_array();
print $q->start_Tr;
print $q->td("$startYear-". ${\(length($startMonth) == 1 ? '0' : '')} ."$startMonth");
print $q->td($ligne[1]);
print $q->td($ligne[2]);
print $q->td($ligne[3]);
print $q->end_Tr;
# get ready for next loop
if ($startMonth eq '12') {
$startMonth = 1;
$startYear++;
} else {
$startMonth++
}
} # end the while loop
print $q->end_table;
deconnectBD();
showDbData( [
[gettext("Start"),],
[gettext("End"),],
[gettext("Duration"),],
[gettext("IP Address"),sub { return ipnum2ipdot(@_); } ],
[gettext("Connection peer"),sub { return ipnum2ipdot(@_); } ],
[gettext("Incoming data (MB)"),sub {return sprintf('%.2f',$_[0]/1000/1000);}],
[gettext("Outgoing data (MB)"),sub {return sprintf('%.2f',$_[0]/1000/1000);}]
],
\"SELECT debut,fin,duree,ip,peer,volume_in,volume_out,fin-debut as 'encours' FROM pppoe WHERE debut >= CURDATE() - INTERVAL 24 MONTH ORDER BY debut DESC",
\gettext("Detailed list of ADSL/PPPoE connections.\n"));
}
#----------------------------------------------------------------
#details du service ssh
sub showSsh
{
showDbData( [
[gettext("Start"),],
[gettext("IP Address"),sub {return ipnum2ipdot(@_);}],
[gettext("Login"),],
[gettext("Connected ?"),sub {return (($_[0])?gettext('Yes'):gettext('No'));}]
],
#pour cause de sprintf, la requete est dans le showDbData
\"",
\gettext("Detailed list of ssh connections (Secure SHell).\n"));
}
#----------------------------------------------------------------
#details du service ftp
sub showFtp
{
#WARN ! Highly complicated !!
# @tab est un tableau a 2 dimensions, chaque "ligne" du tableau contient 2 champs :
# - le label/entete de la colonne a afficher
# - une fonction inline de modification de l'affichage de la valeur allant dans la colonne
# ( pour ce champ, il peut etre nul (d'ou le ["Start",]).
my @tab=([gettext("Start"),],
[gettext("End"),],
[gettext("Duration"),],
[gettext("IP Address"),sub {return ipnum2ipdot(@_);}],
[gettext("Login"),],
[gettext("Connected ?"),sub {return (($_[0])?gettext('Yes'):gettext('No'));}],
[gettext("Written data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}],
[gettext("Read data (Ko)"),sub {return sprintf('%.2f',$_[0]/1024);}]);
#appel de la fonction qui va interroger la bdd et afficher le tableau
#passage des params par REFERENCE (tab, requete et titre a afficher)
showDbData(\@tab,
\"SELECT debut,fin,duree,ip,login,connecte,volume_in,volume_out FROM ftp WHERE debut > CURDATE() - INTERVAL 7 DAY ORDER BY debut DESC",
\gettext("Detailed list of the last connections (on the last 7 days) to the ftp service (File Transfer Protocol).\n"));
}
#----------------------------------------------------------------
#DOCUMENT IT OR YOU'LL BE MAD - Magnifique HACK qui est trop elegant
#Fonction qui fait la requete vers la BDD, et affiche le resultat en fonction
#du @tab passe en param qui contient les entetes de colonne et les fonctions de
#modif d'affichage.
sub showDbData
{
#recuperation des params et DEREFERENCEMENT
my ($ref_tab,$ref_requete,$ref_title)=(@_);
my @tab=@$ref_tab;
my $requete=$$ref_requete;
my $title=$$ref_title;
my $i=0;
#utilise uniquement si service=pppoe
my $start_next_cnx;
#utilise uniquement si service=sshd
my $interval;
if ($q->param('service') eq 'sshd')
{
#gruika hack pour avoir le tableau sur plusieurs periodes
printPopupMenu(gettext("See the records on "));
$interval=$q->param('duree');
#somebody please put a SWITCH CASE !!
if ((!defined($interval)) || $interval eq '-7d') {$interval="7 DAY";}
elsif ($interval eq '-1h') {$interval="1 HOUR";}
elsif ($interval eq '-6h') {$interval="6 HOUR";}
elsif ($interval eq '-1d') {$interval="1 DAY";}
elsif ($interval eq '-3d') {$interval="3 DAY";}
elsif ($interval eq '-1m') {$interval="1 MONTH";}
elsif ($interval eq '-6months') {$interval="6 MONTH";}
elsif ($interval eq '-1y') {$interval="1 YEAR";}
$requete="SELECT debut,ip,login,ok FROM ssh WHERE debut > NOW() - INTERVAL $interval ORDER BY debut DESC";
}
#connexion a la base de donnees mySQL
connectBD();
#recuperation des donnees
my $rq=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
$rq->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
#affichage du debut de page
print $q->p(gettext($title));
#affichage des eventuelles mises en evidence
if ($q->param('service') eq 'pptpd')
{
print $q->table($q->Tr($q->td(gettext("Connections which lasted ")),
$q->td({bgcolor=>"#FF4444"},sprintf(gettext("more than %s hours are highlighted.\n"),$params{'LimitVpnDuration'}))));
}
elsif ($q->param('service') eq 'wan'|| $q->param('service') eq 'pppoe' )
{
print $q->table($q->Tr($q->td(gettext("Connections which lasted ")),
$q->td({bgcolor=>"#FF4444"},sprintf(gettext("less than %s hours are highlighted.\n"),$params{'LimitPppoeDuration'})))),
$q->table($q->Tr($q->td(gettext("Disconnections which lasted ")),
$q->td({bgcolor=>"#9999FF"},sprintf(gettext("more than %s minutes are highlighted.\n"),$params{'LimitPppoeDisconnect'}))));
}
elsif ($q->param('service') eq 'sshd')
{
print $q->table($q->Tr($q->td(gettext("Successful ")),$q->td({bgcolor=>"#33CC00"},gettext(" root connections are highlighted.\n"))));
}
print $q->br,
$q->start_table({-border=>'1'}),
$q->start_Tr;
#affichage des entetes du tableau
foreach (@tab)
{
#j'aimerai bien comprendre le pourquoi du comment du 1er [0]
#le $i est pour recup la "ligne" du tab passe en param
#le 2e [0] est pour recup le label, 1ere valeur de la ligne
print $q->th(gettext($_[0][$i][0]));
$i++;
}
print $q->end_Tr;
#boucle sur les lignes / resultats de la requete SQL
while(my @ligne = $rq->fetchrow_array())
{
$i=0;
#affichage des lignes speciales (pour pptpd,ssh et pppoe only)
if ($q->param('service') eq 'pptpd')
{
$ligne[2]=~/(\d{2}):\d{2}:\d{2}/;
#si le nb d'heure > limite, surbrillance
print $q->start_Tr({bgcolor=>(($1 >= $params{'LimitVpnDuration'})?"#FF4444":"#FFFFFF")});
}
elsif ($q->param('service') eq 'wan' || $q->param('service') eq 'pppoe')
{
#on interroge la bd pour voir si il y a eu une longue deconnexion
#(beaucoup plus simple que de parser les 2 dates et faire une difference, la on utilise la possibilite de calcul de diff de dates de MySQL)
$requete="select '$start_next_cnx' > '$ligne[1]' + interval $params{'LimitPppoeDisconnect'} minute";
my $rq2=$bd->prepare($requete) or print $q->p(sprintf(gettext("MySQL error : Impossible to prepare SQL query \"%s\" : %s\n"),$requete,$bd->errstr));
$rq2->execute or print $q->p(sprintf(gettext("MySQL error : Can't execute query : %s\n"),$rq->errstr));
#on sauve le debut de la cnx pour faire la comparaison au debut de boucle
$start_next_cnx=$ligne[0];
#si on a trouve que la connexion suivante avait commence apres la fin de connexion precedente + interval defini
#alors afficher une ligne de separation
print $q->Tr($q->td({bgcolor=>"#9999FF",colspan=>"7"},sprintf(gettext("Disconnection lasted more than %s minutes"),$params{'LimitPppoeDisconnect'}))) if (($rq2->fetchrow_array)[0] eq '1');
#on match le nb d'heure de la duree cnx
my $curdur;
if ($ligne[2]) {
# ended connection
$ligne[2]=~/(\d{2}):\d{2}:\d{2}/;
$curdur=$1;
}else{
# ongoing connection
$curdur=$ligne[7]/3600;
}
#si le nb d'heure < limite et different de null, surbrillance
print $q->start_Tr({bgcolor=>((($curdur < $params{'LimitPppoeDuration'}) && ($1 ne ''))?"#FF4444":"#FFFFFF")});
}
elsif ($q->param('service') eq 'sshd')
{
#si login root && connecte, surbrillance
print $q->start_Tr({bgcolor=>(($ligne[2] eq 'root')&& $ligne[3])?"#33CC00":"#FFFFFF"});
}
else
{
print $q->start_Tr;
}
#boucle sur les champs de la ligne
foreach (@tab)
{
#on recupere la fonction de mise en forme de la valeur
my $func=$_[0][$i][1];
#si elle existe
if (defined ($func))
#on l'applique a la valeur (contenue dans $ligne[$i])
{ print $q->td(&$func($ligne[$i]));}
else
#sinon, on affiche directement la valeur
{ print $q->td($ligne[$i]);}
$i++;
}
print $q->end_Tr;
}
print $q->end_table,
$q->p($q->a ({href => "$progname"},gettext("Back\n")));
deconnectBD();
}
#----------------------------------------------------------------
#fonction faisant les appels a RRDs::graph
#creation de l'image, affichage d'un titre, affichage de l'image
sub createShowGraph
{
my($title,$imgFilename,@rrdparams)=(@_);
# print "<br>" . join("|", @rrdparams) . "<br>";
my (undef,$xsize,$ysize)=RRDs::graph ("$imgdir/$imgFilename.$params{'ImgFormat'}",
"--imgformat=$params{'ImgFormat'}",
"--width=$params{'ImgWidth'}",
"--height=$params{'ImgHeight'}",
@rrdparams);
my $error=RRDs::error;
print $q->p(sprintf(gettext("Error at RRDs::graph(%s) : %s\n"),"$imgFilename.$params{'ImgFormat'}",$error)) if $error;
print $q->p($title),$q->br,
$q->img({src=>"../smeadmin/$imgFilename.$params{'ImgFormat'}",alt=>"../smeadmin/$imgFilename.$params{'ImgFormat'}",width=>$xsize,height=>$ysize});
}
#----------------------------------------------------------------
#affiche les graphes avec les sensors materiels
# - temp process, mb & hdd1/2
# - vitesse rotation ventilateur
#----------------------------------------------------------------
sub showHardGraph
{
my $start='-1d';
printPopupMenu(gettext("View graphs on "));
$start=$q->param('duree') if defined($q->param('duree'));
print $q->p($q->b($labels{"$start"}));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
my @tab=("--title=".gettext("Temperatures"),
"--vertical-label=T°C",
"--start=$start",
"DEF:t1=$rrddir/sensors.rrd:t1:AVERAGE", "DEF:maxt1=$rrddir/sensors.rrd:t1:MAX", "DEF:mint1=$rrddir/sensors.rrd:t1:MIN",
"DEF:t2=$rrddir/sensors.rrd:t2:AVERAGE", "DEF:maxt2=$rrddir/sensors.rrd:t2:MAX", "DEF:mint2=$rrddir/sensors.rrd:t2:MIN",
"COMMENT: ", "LINE2:t1#1000FF:Temp 1 ", "LINE2:t2#00EEBB:Temp 2 ",
"COMMENT:\\n", "COMMENT:Max\\: ", "GPRINT:maxt1:MAX:%5.2lf °C", "GPRINT:maxt2:MAX:%5.2lf °C ",
"COMMENT:\\n", "COMMENT:Min\\: ", "GPRINT:mint1:MIN:%5.2lf °C", "GPRINT:mint2:MIN:%5.2lf °C ",
"COMMENT:\\n", "COMMENT:Avg\\: ", "GPRINT:t1:AVERAGE:%5.2lf °C", "GPRINT:t2:AVERAGE:%5.2lf °C ",
"COMMENT:\\n", "COMMENT:Last\\:", "GPRINT:t1:LAST:%5.2lf °C", "GPRINT:t2:LAST:%5.2lf °C ",
"COMMENT:\\n");
#creation du graphe des temperatures
createShowGraph(gettext("Hardware temperatures (Processor, motherboard)."),"temperature",@tab);
#start to retrieve data for the hard disks sensors
my $has_second_hd=1;
$has_second_hd=0 if ($params{'hd2'} eq '');
my $has_third_hd=1;
$has_third_hd=0 if ($params{'hd3'} eq '');
my $has_fourth_hd=1;
$has_fourth_hd=0 if ($params{'hd4'} eq '');
my $has_fifth_hd=1;
$has_fifth_hd=0 if ($params{'hd5'} eq '');
my $has_sixth_hd=1;
$has_sixth_hd=0 if ($params{'hd6'} eq '');
my @HDtab=("--title=".gettext("Hard-disks Temperatures"),
"--vertical-label=T°C",
"--start=$start",
"DEF:thd1=$rrddir/sensors.rrd:thd1:AVERAGE", "DEF:maxthd1=$rrddir/sensors.rrd:thd1:MAX", "DEF:minthd1=$rrddir/sensors.rrd:thd1:MIN");
push @HDtab, "DEF:thd2=$rrddir/sensors.rrd:thd2:AVERAGE", "DEF:maxthd2=$rrddir/sensors.rrd:thd2:MAX", "DEF:minthd2=$rrddir/sensors.rrd:thd2:MIN" if ($has_second_hd);
push @HDtab, "DEF:thd3=$rrddir/sensors.rrd:thd3:AVERAGE", "DEF:maxthd3=$rrddir/sensors.rrd:thd3:MAX", "DEF:minthd3=$rrddir/sensors.rrd:thd3:MIN" if ($has_third_hd);
push @HDtab, "DEF:thd4=$rrddir/sensors.rrd:thd4:AVERAGE", "DEF:maxthd4=$rrddir/sensors.rrd:thd4:MAX", "DEF:minthd4=$rrddir/sensors.rrd:thd4:MIN" if ($has_fourth_hd);
push @HDtab, "DEF:thd5=$rrddir/sensors.rrd:thd5:AVERAGE", "DEF:maxthd5=$rrddir/sensors.rrd:thd5:MAX", "DEF:minthd5=$rrddir/sensors.rrd:thd5:MIN" if ($has_fifth_hd);
push @HDtab, "DEF:thd6=$rrddir/sensors.rrd:thd6:AVERAGE", "DEF:maxthd6=$rrddir/sensors.rrd:thd6:MAX", "DEF:minthd6=$rrddir/sensors.rrd:thd6:MIN" if ($has_sixth_hd);
push @HDtab, "COMMENT: ", "LINE2:thd1#CC5500:Temp hd 1";
push @HDtab, "LINE2:thd2#550000:Temp hd 2" if ($has_second_hd);
push @HDtab, "LINE2:thd3#1000FF:Temp hd 3" if ($has_third_hd);
push @HDtab, "LINE2:thd4#00EEBB:Temp hd 4" if ($has_fourth_hd);
push @HDtab, "LINE2:thd5#FF2222:Temp hd 5" if ($has_fifth_hd);
push @HDtab, "LINE2:thd6#FFD700:Temp hd 6" if ($has_sixth_hd);
push @HDtab, "COMMENT:\\n", "COMMENT:Max\\:", "GPRINT:maxthd1:MAX:%5.2lf °C ";
push @HDtab, "GPRINT:maxthd2:MAX:%5.2lf °C " if ($has_second_hd);
push @HDtab, "GPRINT:maxthd3:MAX:%5.2lf °C " if ($has_third_hd);
push @HDtab, "GPRINT:maxthd4:MAX:%5.2lf °C " if ($has_fourth_hd);
push @HDtab, "GPRINT:maxthd5:MAX:%5.2lf °C " if ($has_fifth_hd);
push @HDtab, "GPRINT:maxthd6:MAX:%5.2lf °C" if ($has_sixth_hd);
push @HDtab, "COMMENT:\\n", "COMMENT:Min\\: ", "GPRINT:minthd1:MIN:%5.2lf °C ";
push @HDtab, "GPRINT:minthd2:MIN:%5.2lf °C " if ($has_second_hd);
push @HDtab, "GPRINT:minthd3:MIN:%5.2lf °C " if ($has_third_hd);
push @HDtab, "GPRINT:minthd4:MIN:%5.2lf °C " if ($has_fourth_hd);
push @HDtab, "GPRINT:minthd5:MIN:%5.2lf °C " if ($has_fifth_hd);
push @HDtab, "GPRINT:minthd6:MIN:%5.2lf °C" if ($has_sixth_hd);
push @HDtab, "COMMENT:\\n", "COMMENT:Avg\\: ", "GPRINT:thd1:AVERAGE:%5.2lf °C ";
push @HDtab, "GPRINT:thd2:AVERAGE:%5.2lf °C " if ($has_second_hd);
push @HDtab, "GPRINT:thd3:AVERAGE:%5.2lf °C " if ($has_third_hd);
push @HDtab, "GPRINT:thd4:AVERAGE:%5.2lf °C " if ($has_fourth_hd);
push @HDtab, "GPRINT:thd5:AVERAGE:%5.2lf °C " if ($has_fifth_hd);
push @HDtab, "GPRINT:thd6:AVERAGE:%5.2lf °C" if ($has_sixth_hd);
push @HDtab, "COMMENT:\\n", "COMMENT:Last\\:", "GPRINT:thd1:LAST:%5.2lf °C ";
push @HDtab, "GPRINT:thd2:LAST:%5.2lf °C " if ($has_second_hd);
push @HDtab, "GPRINT:thd3:LAST:%5.2lf °C " if ($has_third_hd);
push @HDtab, "GPRINT:thd4:LAST:%5.2lf °C " if ($has_fourth_hd);
push @HDtab, "GPRINT:thd5:LAST:%5.2lf °C " if ($has_fifth_hd);
push @HDtab, "GPRINT:thd6:LAST:%5.2lf °C" if ($has_sixth_hd);
push @HDtab, "COMMENT:\\n";
#creation du graphe des temperatures
createShowGraph(gettext("Hard disks temperatures."),"HD temperature",@HDtab);
#start to retrieve data for the Fan speed
my $has_second_fan=1;
$has_second_fan=0 if ($params{'SensorsTagFan2'} eq '');
my @tabfan=("--title=".gettext("Fan speed"),
"--vertical-label=".gettext("Rpm"),
"--start=$start",
"DEF:fspd=$rrddir/sensors.rrd:fspd:AVERAGE","DEF:maxfspd=$rrddir/sensors.rrd:fspd:MAX","DEF:minfspd=$rrddir/sensors.rrd:fspd:MIN");
push @tabfan, "DEF:fspd2=$rrddir/sensors.rrd:fspd2:AVERAGE", "DEF:maxfspd2=$rrddir/sensors.rrd:fspd2:MAX", "DEF:minfspd2=$rrddir/sensors.rrd:fspd2:MIN" if ($has_second_fan);
push @tabfan, "COMMENT: ", "LINE2:fspd#1000FF:".gettext("Fan speed") . " ";
push @tabfan, "LINE2:fspd2#550000:".gettext("Fan speed"), "COMMENT:\\n" if ($has_second_fan);
push @tabfan, "COMMENT:\\n", "COMMENT:Max\\: ", "GPRINT:maxfspd:MAX:%5.0lf ".gettext("Rpm"). " ";
push @tabfan, "GPRINT:maxfspd2:MAX:%5.0lf ".gettext("Rpm") if ($has_second_fan);
push @tabfan, "COMMENT:\\n", "COMMENT:Min\\: ", "GPRINT:minfspd:MIN:%5.0lf ".gettext("Rpm"). " ";
push @tabfan, "GPRINT:minfspd2:MIN:%5.0lf ".gettext("Rpm") if ($has_second_fan);
push @tabfan, "COMMENT:\\n", "COMMENT:Avg\\: ", "GPRINT:fspd:AVERAGE:%5.0lf ".gettext("Rpm"). " ";
push @tabfan, "GPRINT:fspd2:AVERAGE:%5.0lf ".gettext("Rpm") if ($has_second_fan);
push @tabfan, "COMMENT:\\n", "COMMENT:Last\\: ", "GPRINT:fspd:LAST:%5.0lf ".gettext("Rpm"). " ";
push @tabfan, "GPRINT:fspd2:LAST:%5.0lf ".gettext("Rpm") if ($has_second_fan);
push @tabfan, "COMMENT:\\n";
#creation of the fan speed sensors
createShowGraph(gettext("Processor fan speed."),"fanspeed",@tabfan);
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#affiche les graphes reseau
# - sessions
# - volume brut transfert / reseau local / externe / route
# - baux dhcp
# - volume mail/spam/virus
# - latency
#----------------------------------------------------------------
sub showNetGraph
{
my $start='-1d';
printPopupMenu(gettext("View graphs on "));
$start=$q->param('duree') if defined($q->param('duree'));
print $q->p($q->b($labels{$start}));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
#sessions par netstat
createShowGraph(gettext("Number of opened tcp connections for ssh, ftp, vpn, afp and netbios protocols."),"sessions",
"--title=".gettext("Opened connections"),
"--start=$start",
"DEF:ssh=$rrddir/sessions.rrd:ssh:AVERAGE", "DEF:maxssh=$rrddir/sessions.rrd:ssh:MAX", "DEF:minssh=$rrddir/sessions.rrd:ssh:MIN",
"DEF:vpn=$rrddir/sessions.rrd:vpn:AVERAGE", "DEF:maxvpn=$rrddir/sessions.rrd:vpn:MAX", "DEF:minvpn=$rrddir/sessions.rrd:vpn:MIN",
"DEF:ftp=$rrddir/sessions.rrd:ftp:AVERAGE", "DEF:maxftp=$rrddir/sessions.rrd:ftp:MAX", "DEF:minftp=$rrddir/sessions.rrd:ftp:MIN",
"DEF:netbios=$rrddir/sessions.rrd:netbios:AVERAGE", "DEF:maxnetbios=$rrddir/sessions.rrd:netbios:MAX", "DEF:minnetbios=$rrddir/sessions.rrd:netbios:MIN",
"DEF:afp=$rrddir/sessions.rrd:afp:AVERAGE", "DEF:maxafp=$rrddir/sessions.rrd:afp:MAX", "DEF:minafp=$rrddir/sessions.rrd:afp:MIN",
"COMMENT: ","LINE2:ssh#0000FF:ssh ($SshPort)","LINE2:ftp#FF2222:ftp (21)","LINE2:vpn#AA3300:vpn (1723)",
"LINE2:netbios#33B010:netbios (139)","LINE2:afp#FFD700:afp (548)","COMMENT:\\n",
"COMMENT:Max\\: ","GPRINT:maxssh:MAX:%4.0lf ","GPRINT:maxftp:MAX:%4.0lf ","GPRINT:maxvpn:MAX:%4.0lf ",
"GPRINT:maxnetbios:MAX:%4.0lf ","GPRINT:maxafp:MAX:%4.0lf ","COMMENT:\\n",
"COMMENT:Min\\: ","GPRINT:minssh:MIN:%4.0lf ","GPRINT:minftp:MIN:%4.0lf ","GPRINT:minvpn:MIN:%4.0lf ",
"GPRINT:minnetbios:MIN:%4.0lf ","GPRINT:minafp:MIN:%4.0lf ","COMMENT:\\n",
"COMMENT:Last\\:","GPRINT:ssh:LAST:%4.0lf ","GPRINT:ftp:LAST:%4.0lf ","GPRINT:vpn:LAST:%4.0lf ",
"GPRINT:netbios:LAST:%4.0lf ","GPRINT:afp:LAST:%4.0lf ","COMMENT:\\n");
#baux dhcp, smbstatus:S
createShowGraph(gettext("Number of dhcp leases renewals and opened samba shares."),"dhcpsmb",
"--title=".gettext("Dhcp & Smbstatus"),
"--start=$start",
"DEF:samba=$rrddir/net.rrd:samba:AVERAGE", "DEF:maxsamba=$rrddir/net.rrd:samba:MAX", "DEF:minsamba=$rrddir/net.rrd:samba:MIN",
"DEF:dhcp=$rrddir/net.rrd:dhcp:AVERAGE", "DEF:maxdhcp=$rrddir/net.rrd:dhcp:MAX", "DEF:mindhcp=$rrddir/net.rrd:dhcp:MIN",
"COMMENT: ","LINE2:dhcp#8B4513:Dhcp","LINE2:samba#DAA520:Samba","COMMENT:\\n",
"COMMENT:Max\\: ","GPRINT:maxdhcp:MAX:%4.0lf ","GPRINT:maxsamba:MAX:%4.0lf","COMMENT:\\n",
"COMMENT:Min\\: ","GPRINT:mindhcp:MIN:%4.0lf ","GPRINT:minsamba:MIN:%4.0lf","COMMENT:\\n",
"COMMENT:Last\\:","GPRINT:dhcp:LAST:%4.0lf ","GPRINT:samba:LAST:%4.0lf","COMMENT:\\n");
#qmail local and remote email
createGraphQmail($start);
#qpsmtpd incoming emails from outside the server( local network and internet)
createGraphQpsmtpd($start);
#ping latency
createShowGraph(gettext("Average and maximal ping with the selected target."),"latency",
"--title=".gettext("Target ping latency"),
"--vertical-label=s/%",
"--start=$start",
"DEF:avglatency=$rrddir/net.rrd:avglatency:AVERAGE","DEF:maxavglatency=$rrddir/net.rrd:avglatency:MAX","DEF:minavglatency=$rrddir/net.rrd:avglatency:MIN",
"DEF:maxlatency=$rrddir/net.rrd:maxlatency:AVERAGE","DEF:maxmaxlatency=$rrddir/net.rrd:maxlatency:MAX","DEF:minmaxlatency=$rrddir/net.rrd:maxlatency:MIN",
"DEF:minlatency=$rrddir/net.rrd:minlatency:AVERAGE","DEF:maxminlatency=$rrddir/net.rrd:minlatency:MAX", "DEF:minminlatency=$rrddir/net.rrd:minlatency:MIN",
"DEF:loss=$rrddir/net.rrd:loss:AVERAGE","DEF:maxloss=$rrddir/net.rrd:loss:MAX","DEF:minloss=$rrddir/net.rrd:loss:MIN",
"CDEF:adjavglatency=avglatency,$maxping,MIN","CDEF:adjmaxlatency=maxlatency,$maxping,MIN","CDEF:adjloss=loss,1000,/",
"COMMENT: ","AREA:adjmaxlatency#00008B:".gettext("Max ping"),"AREA:adjavglatency#00EE22:".gettext("Avg ping"),
"LINE1:adjloss#FF4444:".gettext("Pkt loss"),"COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxmaxlatency:MAX:%6.2lf %ss ','GPRINT:maxavglatency:MAX:%6.2lf %ss ','GPRINT:maxloss:MAX:%6.2lf %%',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minmaxlatency:MIN:%6.2lf %ss ','GPRINT:minavglatency:MIN:%6.2lf %ss ','GPRINT:minloss:MAX:%6.2lf %%',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:maxlatency:LAST:%6.2lf %ss ','GPRINT:avglatency:LAST:%6.2lf %ss ','GPRINT:loss:LAST:%6.2lf %%',"COMMENT:\\n");
#trafic sur l'interface cote reseau local
createShowGraph(gettext("Load on the local network interface."),"if_loc",
"--title=".gettext("Local network load"),
"--vertical-label=KB/s",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:bin=$rrddir/if_loc.rrd:bin:AVERAGE","DEF:maxbin=$rrddir/if_loc.rrd:bin:MAX","DEF:bout=$rrddir/if_loc.rrd:bout:AVERAGE","DEF:maxbout=$rrddir/if_loc.rrd:bout:MAX","DEF:minbin=$rrddir/if_loc.rrd:bin:MIN","DEF:minbout=$rrddir/if_loc.rrd:bout:MIN",
"CDEF:adj_bout=0,bout,-",
"COMMENT: ","AREA:bin#0066FF:".gettext("Incoming Kilobytes"),"AREA:adj_bout#FF6633:".gettext("Outgoing Kilobytes"),"COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxbin:MAX:%8.2lf %sKB/s','GPRINT:maxbout:MAX:%8.2lf %sKB/s',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minbin:MIN:%8.2lf %sKB/s','GPRINT:minbout:MIN:%8.2lf %sKB/s',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:bin:LAST:%8.2lf %sKB/s','GPRINT:bout:LAST:%8.2lf %sKB/s',"COMMENT:\\n");
#si on a une 2e interface reseay
if ($ExternalInterface ne "")
{
#trafic sur l'interface cote reseau externe
createShowGraph(gettext("Load on the external network interface (to internet)."),"if_ext",
"--title=".gettext("External network load"),
"--vertical-label=KB/s",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:bin=$rrddir/if_ext.rrd:bin:AVERAGE","DEF:maxbin=$rrddir/if_ext.rrd:bin:MAX","DEF:bout=$rrddir/if_ext.rrd:bout:AVERAGE","DEF:maxbout=$rrddir/if_ext.rrd:bout:MAX","DEF:minbin=$rrddir/if_ext.rrd:bin:MIN","DEF:minbout=$rrddir/if_ext.rrd:bout:MIN",
"CDEF:adj_bout=0,bout,-",
"COMMENT: ","AREA:bin#FF6633:".gettext("Incoming Kilobytes"),"AREA:adj_bout#0066FF:".gettext("Outgoing Kilobytes"),"COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxbin:MAX:%8.2lf %sKB/s','GPRINT:maxbout:MAX:%8.2lf %sKB/s',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minbin:MIN:%8.2lf %sKB/s','GPRINT:minbout:MIN:%8.2lf %sKB/s',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:bin:LAST:%8.2lf %sKB/s','GPRINT:bout:LAST:%8.2lf %sKB/s',"COMMENT:\\n");
print $q->p(gettext("Network load on the server except routing.")),
$q->ul(
$q->li(gettext("If the blue curve is :")),
$q->ul(
$q->li(gettext("positive => download from the internet")),
$q->li(gettext("negative => upload from the local network")),
),
$q->li(gettext("If the red curve is :")),
$q->ul(
$q->li(gettext("positive => upload from the internet")),
$q->li(gettext("negative => download from the local network"))
)),$q->br;
createShowGraph("","if_delta",
"--title=".gettext("Network load on the server"),
"--vertical-label=KB/s",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:extbin=$rrddir/if_ext.rrd:bin:AVERAGE","DEF:maxextbin=$rrddir/if_ext.rrd:bin:MAX","DEF:extbout=$rrddir/if_ext.rrd:bout:AVERAGE","DEF:maxextbout=$rrddir/if_ext.rrd:bout:MAX",
"DEF:locbin=$rrddir/if_loc.rrd:bin:AVERAGE","DEF:maxlocbin=$rrddir/if_loc.rrd:bin:MAX","DEF:locbout=$rrddir/if_loc.rrd:bout:AVERAGE","DEF:maxlocbout=$rrddir/if_loc.rrd:bout:MAX",
"CDEF:loc_srv=extbout,locbin,-","CDEF:srv_net=extbin,locbout,-",
"COMMENT: ","LINE2:loc_srv#3300FF:Server=>Net - Local=>Server","LINE2:srv_net#FF0033:Net=>Server - Server=>Local","COMMENT:\\n");
}
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
#----------------------------------------------------------------
#----------------------------------------------------------------
#affiche les graphes systeme
# - cpu:user/system/nice
# - cpu:load1/load5/load15/total
# - cpu:runq/plist
# - cpu:uptime
# - mem:used/cached/buffer/free
# - mem:swap used/free
# - hd:du
# - hd:blkread/blkwrite
sub showSystmGraph
{
my $start='-1d';
printPopupMenu(gettext("View graphs on "));
$start=$q->param('duree') if defined($q->param('duree'));
print $q->p($q->b($labels{$start}));
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
#repartition user/nice/system
createShowGraph(gettext("Distribution of cpu usage for system, user and niced processes."),"cpu_usage",
"--title=".gettext("Cpu usage"),
"--vertical-label=%",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:user=$rrddir/cpu.rrd:user:AVERAGE","DEF:maxuser=$rrddir/cpu.rrd:user:MAX","DEF:minuser=$rrddir/cpu.rrd:user:MIN",
"DEF:system=$rrddir/cpu.rrd:system:AVERAGE","DEF:maxsystem=$rrddir/cpu.rrd:system:MAX","DEF:minsystem=$rrddir/cpu.rrd:system:MIN",
"DEF:nice=$rrddir/cpu.rrd:nice:AVERAGE","DEF:maxnice=$rrddir/cpu.rrd:nice:MAX","DEF:minnice=$rrddir/cpu.rrd:nice:MIN",
"COMMENT: ", "AREA:system#0066FF: System ", "STACK:nice#330066: Nice ", "STACK:user#00FF33: User", "COMMENT:\\n",
"COMMENT:Max\\: ", 'GPRINT:maxsystem:MAX:%7.2lf %%', 'GPRINT:maxnice:MAX: %7.2lf %%', 'GPRINT:maxuser:MAX: %7.2lf %%', "COMMENT:\\n",
"COMMENT:Min\\: ", 'GPRINT:minsystem:MIN:%7.2lf %%', 'GPRINT:minnice:MIN: %7.2lf %%', 'GPRINT:minuser:MIN: %7.2lf %%', "COMMENT:\\n",
"COMMENT:Avg\\: ", 'GPRINT:system:AVERAGE:%7.2lf %%', 'GPRINT:nice:AVERAGE: %7.2lf %%', 'GPRINT:user:AVERAGE: %7.2lf %%', "COMMENT:\\n",
"COMMENT:Last\\:", 'GPRINT:system:LAST:%7.2lf %%', 'GPRINT:nice:LAST: %7.2lf %%', 'GPRINT:user:LAST: %7.2lf %%',"COMMENT:\\n");
#load average sur 1/5 & 15mn // total cpu
createShowGraph(gettext("System load average on 1mn,5mn,15mn compared to cpu usage."),"cpu_load",
"--title=".gettext("System load / Cpu %"),
"--vertical-label={Load*10} / %",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:load1=$rrddir/cpu.rrd:load1:AVERAGE", "DEF:maxload1=$rrddir/cpu.rrd:load1:MAX", "DEF:minload1=$rrddir/cpu.rrd:load1:MIN",
"DEF:load5=$rrddir/cpu.rrd:load5:AVERAGE", "DEF:maxload5=$rrddir/cpu.rrd:load5:MAX", "DEF:minload5=$rrddir/cpu.rrd:load5:MIN",
"DEF:load15=$rrddir/cpu.rrd:load15:AVERAGE","DEF:maxload15=$rrddir/cpu.rrd:load15:MAX", "DEF:minload15=$rrddir/cpu.rrd:load15:MIN",
"DEF:total=$rrddir/cpu.rrd:total:AVERAGE", "DEF:maxtotal=$rrddir/cpu.rrd:total:MAX", "DEF:mintotal=$rrddir/cpu.rrd:total:MIN",
"CDEF:adjload1=load1,10,*", "CDEF:adjload5=load5,10,*", "CDEF:adjload15=load15,10,*",
"COMMENT: ", "AREA:total#22BB00: Cpu ","LINE1:adjload1#0000DD: Load1 ",
"LINE1:adjload5#EE2200: Load5 ","LINE1:adjload15#EEFF00: Load15 ", "COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxtotal:MAX:%7.2lf %%','GPRINT:maxload1:MAX:%7.3lf ',
'GPRINT:maxload5:MAX: %7.3lf ', 'GPRINT:maxload15:MAX: %7.3lf ', "COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:mintotal:MIN:%7.2lf %%','GPRINT:minload1:MIN:%7.3lf ',
'GPRINT:minload5:MIN: %7.3lf ', 'GPRINT:minload15:MIN: %7.3lf ', "COMMENT:\\n",
"COMMENT:Avg\\: ",'GPRINT:total:AVERAGE:%7.2lf %%','GPRINT:load1:AVERAGE:%7.3lf ',
'GPRINT:load5:AVERAGE: %7.3lf ','GPRINT:load15:AVERAGE: %7.3lf ',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:total:LAST:%7.2lf %%','GPRINT:load1:LAST:%7.3lf ',
'GPRINT:load5:LAST: %7.3lf ','GPRINT:load15:LAST: %7.3lf ',"COMMENT:\\n");
#process list/run queue
createShowGraph(gettext("Number of running processes on the server, and kernel run queue size."),"cpu_process",
"--title=".gettext("Number of processes / run queue size"),
"--vertical-label=Nb proc / {Rq*10}",
"--start=$start","--base=1000","--lower-limit=0",
"DEF:plist=$rrddir/cpu.rrd:plist:AVERAGE","DEF:maxplist=$rrddir/cpu.rrd:plist:MAX","DEF:minplist=$rrddir/cpu.rrd:plist:MIN",
"DEF:runq=$rrddir/cpu.rrd:runq:AVERAGE","DEF:maxrunq=$rrddir/cpu.rrd:runq:MAX","DEF:minrunq=$rrddir/cpu.rrd:runq:MIN",
"CDEF:adjrunq=runq,10,*",
"COMMENT: ", "AREA:plist#FFDD00: ".gettext("Processes"),"LINE1:adjrunq#EE3300: ".gettext("Run queue"), "COMMENT:\\n",
"COMMENT:Max\\: ", 'GPRINT:maxplist:MAX:%4.0lf ','GPRINT:maxrunq:MAX: %7.3lf ', "COMMENT:\\n",
"COMMENT:Min\\: ", 'GPRINT:minplist:MIN:%4.0lf ','GPRINT:minrunq:MIN: %7.3lf ', "COMMENT:\\n",
"COMMENT:Avg\\: ", 'GPRINT:plist:AVERAGE:%4.0lf ', 'GPRINT:runq:AVERAGE: %7.3lf ',"COMMENT:\\n",
"COMMENT:Last\\:", 'GPRINT:plist:LAST:%4.0lf ', 'GPRINT:runq:LAST: %7.3lf',"COMMENT:\\n");
#uptime
createShowGraph(gettext("Server uptime."),"cpu_uptime",
"--title=".gettext("Uptime"),
"--vertical-label=".gettext("Days"),
"--start=$start","--base=1000","--lower-limit=0",
"DEF:uptime=$rrddir/cpu.rrd:uptime:AVERAGE","DEF:maxuptime=$rrddir/cpu.rrd:uptime:MAX","DEF:minuptime=$rrddir/cpu.rrd:uptime:MIN",
"CDEF:adjuptime=uptime,86400,/", "CDEF:adjmaxuptime=maxuptime,86400,/", "CDEF:adjminuptime=minuptime,86400,/",
"COMMENT: ", "AREA:adjuptime#FF1100: ".gettext("Uptime"),"COMMENT:\\n",
"COMMENT:Max\\: ", 'GPRINT:adjmaxuptime:MAX: %4.1lf', "COMMENT:\\n",
"COMMENT:Min\\: ", 'GPRINT:adjminuptime:MIN: %4.1lf', "COMMENT:\\n",
"COMMENT:Last\\: ", 'GPRINT:adjuptime:LAST:%4.1lf',"COMMENT:\\n");
#memoire : used/cached/buffers/free
createShowGraph(gettext("Detailed usage of the server memory."),"mem",
"--title=".gettext("Memory usage"),
"--vertical-label=".gettext("Bytes"),
"--start=$start","--base=1024","--lower-limit=0",
"DEF:used=$rrddir/mem.rrd:memused:AVERAGE","DEF:maxused=$rrddir/mem.rrd:memused:MAX","DEF:minused=$rrddir/mem.rrd:memused:MIN",
"DEF:cached=$rrddir/mem.rrd:memcached:AVERAGE","DEF:maxcached=$rrddir/mem.rrd:memcached:MAX","DEF:mincached=$rrddir/mem.rrd:memcached:MIN",
"DEF:buffers=$rrddir/mem.rrd:membuffers:AVERAGE","DEF:maxbuffers=$rrddir/mem.rrd:membuffers:MAX","DEF:minbuffers=$rrddir/mem.rrd:membuffers:MIN",
"DEF:actualfree=$rrddir/mem.rrd:memactualfree:AVERAGE","DEF:maxactualfree=$rrddir/mem.rrd:memactualfree:MAX","DEF:minactualfree=$rrddir/mem.rrd:memactualfree:MIN",
"DEF:total=$rrddir/mem.rrd:memtotal:AVERAGE",
"COMMENT: ", "AREA:used#000066: ".gettext("Used"),"STACK:buffers#6633CC: ".gettext("Buffers"),"STACK:cached#339933: ".gettext("Cached"),
"STACK:actualfree#00FF99: ".gettext("Free"),"LINE1:total#FF0000: ".gettext("Total"),"COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxused:MAX:%6.2lf%sb','GPRINT:maxbuffers:MAX:%6.2lf%sb','GPRINT:maxcached:MAX:%6.2lf%sb',
'GPRINT:maxactualfree:MAX:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minused:MIN:%6.2lf%sb','GPRINT:minbuffers:MIN:%6.2lf%sb','GPRINT:mincached:MIN:%6.2lf%sb',
'GPRINT:minactualfree:MIN:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%6.2lf%sb','GPRINT:buffers:AVERAGE:%6.2lf%sb','GPRINT:cached:AVERAGE:%6.2lf%sb',
'GPRINT:actualfree:AVERAGE:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:used:LAST:%6.2lf%sb','GPRINT:buffers:LAST:%6.2lf%sb','GPRINT:cached:LAST:%6.2lf%sb',
'GPRINT:actualfree:LAST:%6.2lf%sb','GPRINT:total:LAST:%6.2lf%sb',"COMMENT:\\n");
#memoire : swap used/free/total
createShowGraph(gettext("Swap usage (virtual memory) on the server's hard disk."),"swap",
"--title=".gettext("Swap usage"),
"--vertical-label=".gettext("Bytes"),
"--start=$start","--base=1024","--lower-limit=0",
"DEF:used=$rrddir/mem.rrd:swapused:AVERAGE","DEF:maxused=$rrddir/mem.rrd:swapused:MAX","DEF:minused=$rrddir/mem.rrd:swapused:MIN",
"DEF:free=$rrddir/mem.rrd:swapfree:AVERAGE","DEF:maxfree=$rrddir/mem.rrd:swapfree:MAX","DEF:minfree=$rrddir/mem.rrd:swapfree:MIN",
"DEF:total=$rrddir/mem.rrd:swaptotal:AVERAGE","DEF:maxtotal=$rrddir/mem.rrd:swaptotal:MAX","DEF:mintotal=$rrddir/mem.rrd:swaptotal:MIN",
"COMMENT: ", "AREA:used#FF0033: ".gettext("Used"),"STACK:free#FF9966: ".gettext("Free"),"LINE1:total#006600: ".gettext("Total"),
"COMMENT:\\n",
"COMMENT:Max\\: ",
'GPRINT:maxused:MAX:%6.2lf%sb','GPRINT:maxfree:MAX:%6.2lf%sb','GPRINT:maxtotal:MAX:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minused:MIN:%6.2lf%sb','GPRINT:minfree:MIN:%6.2lf%sb','GPRINT:mintotal:MIN:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%6.2lf%sb','GPRINT:free:AVERAGE:%6.2lf%sb','GPRINT:total:AVERAGE:%6.2lf%sb',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:used:LAST:%6.2lf%sb','GPRINT:free:LAST:%6.2lf%sb','GPRINT:total:LAST:%6.2lf%sb',"COMMENT:\\n");
#taux d'ecriture/lecture sur le disque dur
createShowGraph(gettext("Amount of raw data read/written on the hard disk."),"hd_hard",
"--title=".gettext("Data written/read"),
"--vertical-label=".gettext("Blocks/s"),
"--start=$start","--base=1024",
"DEF:read=$rrddir/hd.rrd:blckread:AVERAGE","DEF:maxread=$rrddir/hd.rrd:blckread:MAX","DEF:minread=$rrddir/hd.rrd:blckread:MIN",
"DEF:write=$rrddir/hd.rrd:blckwrite:AVERAGE","DEF:maxwrite=$rrddir/hd.rrd:blckwrite:MAX","DEF:minwrite=$rrddir/hd.rrd:blckwrite:MIN",
"CDEF:adjread=0,read,-",
"COMMENT: ", "LINE1:adjread#FF0033: ".gettext("Read"),"LINE1:write#3300FF: ".gettext("Written"),"COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxread:MAX:%6.2lf %sblk/s','GPRINT:maxwrite:MAX:%6.2lf %sblk/s',"COMMENT:\\n",
"COMMENT:Min\\: ",'GPRINT:minread:MIN:%6.2lf %sblk/s','GPRINT:minwrite:MIN:%6.2lf %sblk/s',"COMMENT:\\n",
"COMMENT:Avg\\: ",'GPRINT:read:AVERAGE:%6.2lf %sblk/s','GPRINT:write:AVERAGE:%6.2lf %sblk/s',"COMMENT:\\n",
"COMMENT:Last\\:",'GPRINT:read:LAST:%6.2lf %sblk/s','GPRINT:write:LAST:%6.2lf %sblk/s',"COMMENT:\\n");
#ici, hack en fonction du param du_enabled : on met toutes les infos ou juste used/free/total
#taux de remplissage du hd, place prise par log/squidcache/mysql/smefiles
my $du_enabled=$params{'UseDu'};
my @tab=(
"--title=".gettext("Hard disk usage"),
"--vertical-label=".gettext("Bytes"),
"--start=$start","--base=1024","--lower-limit=0",
"DEF:used=$rrddir/hd.rrd:used:AVERAGE","DEF:maxused=$rrddir/hd.rrd:used:MAX","DEF:minused=$rrddir/hd.rrd:used:MIN",
"DEF:free=$rrddir/hd.rrd:free:AVERAGE","DEF:maxfree=$rrddir/hd.rrd:free:MAX","DEF:minfree=$rrddir/hd.rrd:free:MIN",
"DEF:total=$rrddir/hd.rrd:total:AVERAGE");
push @tab,
"DEF:log=$rrddir/hd.rrd:log:AVERAGE","DEF:maxlog=$rrddir/hd.rrd:log:MAX","DEF:minlog=$rrddir/hd.rrd:log:MIN",
"DEF:squid=$rrddir/hd.rrd:squid:AVERAGE","DEF:maxsquid=$rrddir/hd.rrd:squid:MAX","DEF:minsquid=$rrddir/hd.rrd:squid:MIN",
"DEF:files=$rrddir/hd.rrd:files:AVERAGE","DEF:maxfiles=$rrddir/hd.rrd:files:MAX","DEF:minfiles=$rrddir/hd.rrd:files:MIN",
"DEF:mysql=$rrddir/hd.rrd:mysql:AVERAGE","DEF:maxmysql=$rrddir/hd.rrd:mysql:MAX","DEF:minmysql=$rrddir/hd.rrd:mysql:MIN" if ($du_enabled eq "on");
push @tab,"COMMENT: ", "AREA:used#FF0033:".gettext("Used"),"STACK:free#44CCFF:".gettext("Free");
push @tab,"AREA:files#23EF41:Files","STACK:squid#AA1A00:Squid", "STACK:log#11AA00:Log", "STACK:mysql#FFFF00:Mysql" if ($du_enabled eq "on");
push @tab,"LINE1:total#0000FF:Total", "COMMENT:\\n",
"COMMENT:Max\\: ",'GPRINT:maxused:MAX:%5.1lf%sb ','GPRINT:maxfree:MAX:%5.1lf%sb ';
push @tab,'GPRINT:maxfiles:MAX:%5.1lf%sb','GPRINT:maxsquid:MAX:%5.1lf%sb','GPRINT:maxlog:MAX:%5.1lf%sb','GPRINT:maxmysql:MAX:%5.1lf%sb' if ($du_enabled eq "on");
push @tab,"COMMENT:\\n","COMMENT:Min\\: ",'GPRINT:minused:MIN:%5.1lf%sb ','GPRINT:minfree:MIN:%5.1lf%sb ';
push @tab,'GPRINT:minfiles:MIN:%5.1lf%sb','GPRINT:minsquid:MIN:%5.1lf%sb','GPRINT:minlog:MIN:%5.1lf%sb','GPRINT:minmysql:MIN:%5.1lf%sb' if ($du_enabled eq "on");
push @tab,"COMMENT:\\n","COMMENT:Avg\\: ",'GPRINT:used:AVERAGE:%5.1lf%sb ','GPRINT:free:AVERAGE:%5.1lf%sb ';
push @tab,'GPRINT:files:AVERAGE:%5.1lf%sb','GPRINT:squid:AVERAGE:%5.1lf%sb','GPRINT:log:AVERAGE:%5.1lf%sb','GPRINT:mysql:AVERAGE:%5.1lf%sb' if ($du_enabled eq "on");
push @tab,"COMMENT:\\n","COMMENT:Last\\:",'GPRINT:used:LAST:%5.1lf%sb ','GPRINT:free:LAST:%5.1lf%sb ';
push @tab,'GPRINT:files:LAST:%5.1lf%sb','GPRINT:squid:LAST:%5.1lf%sb','GPRINT:log:LAST:%5.1lf%sb','GPRINT:mysql:LAST:%5.1lf%sb' if ($du_enabled eq "on");
push @tab,'GPRINT:total:LAST:%5.1lf%sb',"COMMENT:\\n";
my $title=gettext("Detailed usage of disk space (squid cache, mysql databases, log files, user files..).");
$title=gettext("Disk space usage.") if ($du_enabled eq "off");
createShowGraph($title,"hd_usage",@tab);
print $q->p($q->a ({href => "$progname"},gettext("Back\n")));
}
sub createGraphQmail {
my($start)=(@_);
#qmail entrant/sortant
createShowGraph(gettext("Number of local/remote e-mails handled by the internal mail service (including other service generated e-mails)."),"qmail",
"--title=".gettext("Local/Remote e-mails"),
"--start=$start",
"DEF:local_failure=$rrddir/qmail.rrd:local_failure:AVERAGE","DEF:maxlocal_failure=$rrddir/qmail.rrd:local_failure:MAX","DEF:minlocal_failure=$rrddir/qmail.rrd:local_failure:MIN",
"DEF:local_deferral=$rrddir/qmail.rrd:local_deferral:AVERAGE","DEF:maxlocal_deferral=$rrddir/qmail.rrd:local_deferral:MAX","DEF:minlocal_deferral=$rrddir/qmail.rrd:local_deferral:MIN",
"DEF:local_success=$rrddir/qmail.rrd:local_success:AVERAGE","DEF:maxlocal_success=$rrddir/qmail.rrd:local_success:MAX","DEF:minlocal_success=$rrddir/qmail.rrd:local_success:MIN",
"DEF:local_total=$rrddir/qmail.rrd:local_total:AVERAGE","DEF:maxlocal_total=$rrddir/qmail.rrd:local_total:MAX","DEF:minlocal_total=$rrddir/qmail.rrd:local_total:MIN",
"DEF:remote_failure=$rrddir/qmail.rrd:remote_failure:AVERAGE","DEF:maxremote_failure=$rrddir/qmail.rrd:remote_failure:MAX","DEF:minremote_failure=$rrddir/qmail.rrd:remote_failure:MIN",
"DEF:remote_deferral=$rrddir/qmail.rrd:remote_deferral:AVERAGE","DEF:maxremote_deferral=$rrddir/qmail.rrd:remote_deferral:MAX","DEF:minremote_deferral=$rrddir/qmail.rrd:remote_deferral:MIN",
"DEF:remote_success=$rrddir/qmail.rrd:remote_success:AVERAGE","DEF:maxremote_success=$rrddir/qmail.rrd:remote_success:MAX","DEF:minremote_success=$rrddir/qmail.rrd:remote_success:MIN",
"DEF:remote_total=$rrddir/qmail.rrd:remote_total:AVERAGE","DEF:maxremote_total=$rrddir/qmail.rrd:remote_total:MAX","DEF:minremote_total=$rrddir/qmail.rrd:remote_total:MIN",
"DEF:local_queue=$rrddir/qmail.rrd:local_queue:AVERAGE","DEF:maxlocal_queue=$rrddir/qmail.rrd:local_queue:MAX","DEF:minlocal_queue=$rrddir/qmail.rrd:local_queue:MIN",
"DEF:remote_queue=$rrddir/qmail.rrd:remote_queue:AVERAGE","DEF:maxremote_queue=$rrddir/qmail.rrd:remote_queue:MAX","DEF:minremote_queue=$rrddir/qmail.rrd:remote_queue:MIN",
"CDEF:adj_remote_total=0,remote_total,-", "CDEF:adj_remote_queue=0,remote_queue,-",
"CDEF:adj_remote_failure=0,remote_failure,-", "CDEF:adj_remote_deferral=0,remote_deferral,-","CDEF:adj_remote_success=0,remote_success,-",
"COMMENT:Last\\t Min\\t Avg\\t Max\\r",
"COMMENT:\\n","AREA:local_total#1ED408:".gettext("Total local e-mails"),"COMMENT:\\u","GPRINT:local_total:LAST:%4.0lf ","GPRINT:minlocal_total:MIN:%4.0lf ","GPRINT:local_total:AVERAGE:%4.0lf ","GPRINT:maxlocal_total:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ".gettext("Total remote e-mails"), "COMMENT:\\u","GPRINT:remote_total:LAST:%4.0lf ","GPRINT:minremote_total:MIN:%4.0lf ","GPRINT:remote_total:AVERAGE:%4.0lf ","GPRINT:maxremote_total:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_success#0000ff:".gettext("Remote e-mail success"), "COMMENT:\\u","GPRINT:remote_success:LAST:%4.0lf ","GPRINT:minremote_success:MIN:%4.0lf ","GPRINT:remote_success:AVERAGE:%4.0lf ","GPRINT:maxremote_success:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_deferral#ffff00:".gettext("Remote e-mail deferral").":STACK", "COMMENT:\\u","GPRINT:remote_deferral:LAST:%4.0lf ","GPRINT:minremote_deferral:MIN:%4.0lf ","GPRINT:remote_deferral:AVERAGE:%4.0lf ","GPRINT:maxremote_deferral:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_failure#ff0000:".gettext("Remote e-mail failure").":STACK", "COMMENT:\\u","GPRINT:remote_failure:LAST:%4.0lf ","GPRINT:minremote_failure:MIN:%4.0lf ","GPRINT:remote_failure:AVERAGE:%4.0lf ","GPRINT:maxremote_failure:MAX:%4.0lf \\r",
"COMMENT:\\n","LINE2:local_queue#666666:".gettext("Local queue"),"COMMENT:\\u", "GPRINT:local_queue:LAST:%4.0lf ","GPRINT:minlocal_queue:MIN:%4.0lf ","GPRINT:local_queue:AVERAGE:%4.0lf ","GPRINT:maxlocal_queue:MAX:%4.0lf \\r",
"COMMENT:\\n","LINE2:adj_remote_queue#000000:".gettext("Remote queue"),"COMMENT:\\u", "GPRINT:remote_queue:LAST:%4.0lf ","GPRINT:minremote_queue:MIN:%4.0lf ","GPRINT:remote_queue:AVERAGE:%4.0lf ","GPRINT:maxremote_queue:MAX:%4.0lf \\r",
"COMMENT:\\n");
}
sub createGraphAltQmail {
my($start)=(@_);
#qmail entrant/sortant
createShowGraph(gettext("Number of remote e-mails handled by the alternative mail service (altqmail)."),"altqmail",
"--title=".gettext("Remote e-mails (altqmail)"),
"--start=$start",
"DEF:local_failure=$rrddir/altqmail.rrd:local_failure:AVERAGE","DEF:maxlocal_failure=$rrddir/altqmail.rrd:local_failure:MAX","DEF:minlocal_failure=$rrddir/altqmail.rrd:local_failure:MIN",
"DEF:local_deferral=$rrddir/altqmail.rrd:local_deferral:AVERAGE","DEF:maxlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MAX","DEF:minlocal_deferral=$rrddir/altqmail.rrd:local_deferral:MIN",
"DEF:local_success=$rrddir/altqmail.rrd:local_success:AVERAGE","DEF:maxlocal_success=$rrddir/altqmail.rrd:local_success:MAX","DEF:minlocal_success=$rrddir/altqmail.rrd:local_success:MIN",
"DEF:local_total=$rrddir/altqmail.rrd:local_total:AVERAGE","DEF:maxlocal_total=$rrddir/altqmail.rrd:local_total:MAX","DEF:minlocal_total=$rrddir/altqmail.rrd:local_total:MIN",
"DEF:remote_failure=$rrddir/altqmail.rrd:remote_failure:AVERAGE","DEF:maxremote_failure=$rrddir/altqmail.rrd:remote_failure:MAX","DEF:minremote_failure=$rrddir/altqmail.rrd:remote_failure:MIN",
"DEF:remote_deferral=$rrddir/altqmail.rrd:remote_deferral:AVERAGE","DEF:maxremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MAX","DEF:minremote_deferral=$rrddir/altqmail.rrd:remote_deferral:MIN",
"DEF:remote_success=$rrddir/altqmail.rrd:remote_success:AVERAGE","DEF:maxremote_success=$rrddir/altqmail.rrd:remote_success:MAX","DEF:minremote_success=$rrddir/altqmail.rrd:remote_success:MIN",
"DEF:remote_total=$rrddir/altqmail.rrd:remote_total:AVERAGE","DEF:maxremote_total=$rrddir/altqmail.rrd:remote_total:MAX","DEF:minremote_total=$rrddir/altqmail.rrd:remote_total:MIN",
"DEF:local_queue=$rrddir/altqmail.rrd:local_queue:AVERAGE","DEF:maxlocal_queue=$rrddir/altqmail.rrd:local_queue:MAX","DEF:minlocal_queue=$rrddir/altqmail.rrd:local_queue:MIN",
"DEF:remote_queue=$rrddir/altqmail.rrd:remote_queue:AVERAGE","DEF:maxremote_queue=$rrddir/altqmail.rrd:remote_queue:MAX","DEF:minremote_queue=$rrddir/altqmail.rrd:remote_queue:MIN",
"CDEF:adj_remote_total=0,remote_total,-", "CDEF:adj_remote_queue=0,remote_queue,-",
"CDEF:adj_remote_failure=0,remote_failure,-", "CDEF:adj_remote_deferral=0,remote_deferral,-","CDEF:adj_remote_success=0,remote_success,-",
"COMMENT:Last\\t Min\\t Avg\\t Max\\r",
"COMMENT:\\n","AREA:local_total#1ED408:".gettext("Total local e-mails"),"COMMENT:\\u","GPRINT:local_total:LAST:%4.0lf ","GPRINT:minlocal_total:MIN:%4.0lf ","GPRINT:local_total:AVERAGE:%4.0lf ","GPRINT:maxlocal_total:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ".gettext("Total remote e-mails"), "COMMENT:\\u","GPRINT:remote_total:LAST:%4.0lf ","GPRINT:minremote_total:MIN:%4.0lf ","GPRINT:remote_total:AVERAGE:%4.0lf ","GPRINT:maxremote_total:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_success#0000ff:".gettext("Remote e-mail success"), "COMMENT:\\u","GPRINT:remote_success:LAST:%4.0lf ","GPRINT:minremote_success:MIN:%4.0lf ","GPRINT:remote_success:AVERAGE:%4.0lf ","GPRINT:maxremote_success:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_deferral#ffff00:".gettext("Remote e-mail deferral").":STACK", "COMMENT:\\u","GPRINT:remote_deferral:LAST:%4.0lf ","GPRINT:minremote_deferral:MIN:%4.0lf ","GPRINT:remote_deferral:AVERAGE:%4.0lf ","GPRINT:maxremote_deferral:MAX:%4.0lf \\r",
"COMMENT:\\n","COMMENT: ","AREA:adj_remote_failure#ff0000:".gettext("Remote e-mail failure").":STACK", "COMMENT:\\u","GPRINT:remote_failure:LAST:%4.0lf ","GPRINT:minremote_failure:MIN:%4.0lf ","GPRINT:remote_failure:AVERAGE:%4.0lf ","GPRINT:maxremote_failure:MAX:%4.0lf \\r",
"COMMENT:\\n","LINE2:local_queue#666666:".gettext("Local queue"),"COMMENT:\\u", "GPRINT:local_queue:LAST:%4.0lf ","GPRINT:minlocal_queue:MIN:%4.0lf ","GPRINT:local_queue:AVERAGE:%4.0lf ","GPRINT:maxlocal_queue:MAX:%4.0lf \\r",
"COMMENT:\\n","LINE2:adj_remote_queue#000000:".gettext("Remote queue"),"COMMENT:\\u", "GPRINT:remote_queue:LAST:%4.0lf ","GPRINT:minremote_queue:MIN:%4.0lf ","GPRINT:remote_queue:AVERAGE:%4.0lf ","GPRINT:maxremote_queue:MAX:%4.0lf \\r",
"COMMENT:\\n");
}
sub createGraphQpsmtpd {
my($start)=(@_);
#qpsmtpd
#check_basicheaders:check_goodrcptto:clamav:karma:tls_failed:rhsbl:check_earlytalker:resolvable_fromhost:dnsbl:fcrdns:spf:check_spamhelo:uribl:dmarc:total_denied:spam_denied:other_denied:spam_queued:queued:total
createShowGraph(gettext("Number of incoming e-mail connections to qpsmtpd services (outside of server incoming e-mails) and amount of spam/viruses filtered."),"qpsmtpd",
"--title=".gettext("Incoming qpsmtpd connections spam/virus/e-mails"),
"--start=$start",
"DEF:check_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:AVERAGE","DEF:maxcheck_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:MAX","DEF:mincheck_basicheaders=$rrddir/qpsmtpd.rrd:check_basicheaders:MIN",
"DEF:check_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:AVERAGE","DEF:maxcheck_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:MAX","DEF:mincheck_goodrcptto=$rrddir/qpsmtpd.rrd:check_goodrcptto:MIN",
"DEF:clamav=$rrddir/qpsmtpd.rrd:clamav:AVERAGE","DEF:maxclamav=$rrddir/qpsmtpd.rrd:clamav:MAX","DEF:minclamav=$rrddir/qpsmtpd.rrd:clamav:MIN",
"DEF:karma=$rrddir/qpsmtpd.rrd:karma:AVERAGE","DEF:maxkarma=$rrddir/qpsmtpd.rrd:karma:MAX","DEF:minkarma=$rrddir/qpsmtpd.rrd:karma:MIN",
"DEF:tls_failed=$rrddir/qpsmtpd.rrd:tls_failed:AVERAGE","DEF:maxtls_failed=$rrddir/qpsmtpd.rrd:tls_failed:MAX","DEF:mintls_failed=$rrddir/qpsmtpd.rrd:tls_failed:MIN",
"DEF:auth_failed=$rrddir/qpsmtpd.rrd:auth_failed:AVERAGE","DEF:maxauth_failed=$rrddir/qpsmtpd.rrd:auth_failed:MAX","DEF:minauth_failed=$rrddir/qpsmtpd.rrd:auth_failed:MIN",
"DEF:rhsbl=$rrddir/qpsmtpd.rrd:rhsbl:AVERAGE","DEF:maxrhsbl=$rrddir/qpsmtpd.rrd:rhsbl:MAX","DEF:minrhsbl=$rrddir/qpsmtpd.rrd:rhsbl:MIN",
"DEF:check_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:AVERAGE","DEF:maxcheck_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:MAX","DEF:mincheck_earlytalker=$rrddir/qpsmtpd.rrd:check_earlytalker:MIN",
"DEF:resolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:AVERAGE","DEF:maxresolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:MAX","DEF:minresolvable_fromhost=$rrddir/qpsmtpd.rrd:resolvable_fromhost:MIN",
"DEF:dnsbl=$rrddir/qpsmtpd.rrd:dnsbl:AVERAGE","DEF:maxdnsbl=$rrddir/qpsmtpd.rrd:dnsbl:MAX","DEF:mindnsbl=$rrddir/qpsmtpd.rrd:dnsbl:MIN",
"DEF:fcrdns=$rrddir/qpsmtpd.rrd:fcrdns:AVERAGE","DEF:maxfcrdns=$rrddir/qpsmtpd.rrd:fcrdns:MAX","DEF:minfcrdns=$rrddir/qpsmtpd.rrd:fcrdns:MIN",
"DEF:spf=$rrddir/qpsmtpd.rrd:spf:AVERAGE","DEF:maxspf=$rrddir/qpsmtpd.rrd:spf:MAX","DEF:minspf=$rrddir/qpsmtpd.rrd:spf:MIN",
"DEF:check_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:AVERAGE","DEF:maxcheck_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:MAX","DEF:mincheck_spamhelo=$rrddir/qpsmtpd.rrd:check_spamhelo:MIN",
"DEF:uribl=$rrddir/qpsmtpd.rrd:uribl:AVERAGE","DEF:maxuribl=$rrddir/qpsmtpd.rrd:uribl:MAX","DEF:minuribl=$rrddir/qpsmtpd.rrd:uribl:MIN",
"DEF:dmarc=$rrddir/qpsmtpd.rrd:dmarc:AVERAGE","DEF:maxdmarc=$rrddir/qpsmtpd.rrd:dmarc:MAX","DEF:mindmarc=$rrddir/qpsmtpd.rrd:dmarc:MIN",
"DEF:total_denied=$rrddir/qpsmtpd.rrd:total_denied:AVERAGE","DEF:maxtotal_denied=$rrddir/qpsmtpd.rrd:total_denied:MAX","DEF:mintotal_denied=$rrddir/qpsmtpd.rrd:total_denied:MIN",
"DEF:spam_denied=$rrddir/qpsmtpd.rrd:spam_denied:AVERAGE","DEF:maxspam_denied=$rrddir/qpsmtpd.rrd:spam_denied:MAX","DEF:minspam_denied=$rrddir/qpsmtpd.rrd:spam_denied:MIN",
"DEF:other_denied=$rrddir/qpsmtpd.rrd:other_denied:AVERAGE","DEF:maxother_denied=$rrddir/qpsmtpd.rrd:other_denied:MAX","DEF:minother_denied=$rrddir/qpsmtpd.rrd:other_denied:MIN",
"DEF:spam_queued=$rrddir/qpsmtpd.rrd:spam_queued:AVERAGE","DEF:maxspam_queued=$rrddir/qpsmtpd.rrd:spam_queued:MAX","DEF:minspam_queued=$rrddir/qpsmtpd.rrd:spam_queued:MIN",
"DEF:queued=$rrddir/qpsmtpd.rrd:queued:AVERAGE","DEF:maxqueued=$rrddir/qpsmtpd.rrd:queued:MAX","DEF:minqueued=$rrddir/qpsmtpd.rrd:queued:MIN",
"DEF:total=$rrddir/qpsmtpd.rrd:total:AVERAGE","DEF:maxtotal=$rrddir/qpsmtpd.rrd:total:MAX","DEF:mintotal=$rrddir/qpsmtpd.rrd:total:MIN",
"CDEF:total_accepted=queued,spam_queued,+",
"COMMENT:Last\\t Min\\t Avg\\t Max\\r",
"COMMENT:\\n","COMMENT:".gettext("Total"),"COMMENT:\\u","GPRINT:total:LAST:%4.0lf ","GPRINT:mintotal:MIN:%4.0lf ","GPRINT:total:AVERAGE:%4.0lf ","GPRINT:maxtotal:MAX:%4.0lf \\r",
"COMMENT:".gettext("Total accepted e-mails"),"COMMENT:\\u","GPRINT:total_accepted:LAST:%4.0lf ","GPRINT:total_accepted:MIN:%4.0lf ","GPRINT:total_accepted:AVERAGE:%4.0lf ","GPRINT:total_accepted:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:spam_queued#8fd487:".gettext("Accepted e-mails")."\\: ".gettext("spam queued"),"COMMENT:\\u","GPRINT:spam_queued:LAST:%4.0lf ","GPRINT:minspam_queued:MIN:%4.0lf ","GPRINT:spam_queued:AVERAGE:%4.0lf ","GPRINT:maxspam_queued:MAX:%4.0lf \\r",
"COMMENT:\\n","AREA:queued#1ED408:".gettext("Accepted e-mails")."\\: ".gettext("queued").":STACK","COMMENT:\\u","GPRINT:queued:LAST:%4.0lf ","GPRINT:minqueued:MIN:%4.0lf ","GPRINT:queued:AVERAGE:%4.0lf ","GPRINT:maxqueued:MAX:%4.0lf \\r",
"COMMENT:\\n", "COMMENT:".gettext("Total denied e-mails"),"COMMENT:\\u","GPRINT:total_denied:LAST:%4.0lf ","GPRINT:mintotal_denied:MIN:%4.0lf ","GPRINT:total_denied:AVERAGE:%4.0lf ","GPRINT:maxtotal_denied:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:check_spamhelo#007a7a:".gettext("Denied e-mails")."\\: ".gettext("check_spamhelo").":STACK","COMMENT:\\u","GPRINT:check_spamhelo:LAST:%4.0lf ","GPRINT:mincheck_spamhelo:MIN:%4.0lf ","GPRINT:check_spamhelo:AVERAGE:%4.0lf ","GPRINT:maxcheck_spamhelo:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:other_denied#666666:".gettext("Denied e-mails")."\\: ".gettext("other reasons").":STACK","COMMENT:\\u","GPRINT:other_denied:LAST:%4.0lf ","GPRINT:minother_denied:MIN:%4.0lf ","GPRINT:other_denied:AVERAGE:%4.0lf ","GPRINT:maxother_denied:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:tls_failed#990099:".gettext("Denied e-mails")."\\: ".gettext("tls failed").":STACK","COMMENT:\\u","GPRINT:tls_failed:LAST:%4.0lf ","GPRINT:mintls_failed:MIN:%4.0lf ","GPRINT:tls_failed:AVERAGE:%4.0lf ","GPRINT:maxtls_failed:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:auth_failed#FFA500:".gettext("Denied e-mails")."\\: ".gettext("auth failed").":STACK","COMMENT:\\u","GPRINT:auth_failed:LAST:%4.0lf ","GPRINT:minauth_failed:MIN:%4.0lf ","GPRINT:auth_failed:AVERAGE:%4.0lf ","GPRINT:maxauth_failed:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:spf#00004f:".gettext("Denied e-mails")."\\: ".gettext("spf").":STACK","COMMENT:\\u","GPRINT:spf:LAST:%4.0lf ","GPRINT:minspf:MIN:%4.0lf ","GPRINT:spf:AVERAGE:%4.0lf ","GPRINT:maxspf:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:resolvable_fromhost#ff99ff:".gettext("Denied e-mails")."\\: ".gettext("resolvable_fromhost").":STACK","COMMENT:\\u","GPRINT:resolvable_fromhost:LAST:%4.0lf ","GPRINT:minresolvable_fromhost:MIN:%4.0lf ","GPRINT:resolvable_fromhost:AVERAGE:%4.0lf ","GPRINT:maxresolvable_fromhost:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:karma#ffff00:".gettext("Denied e-mails")."\\: ".gettext("karma").":STACK","COMMENT:\\u","GPRINT:karma:LAST:%4.0lf ","GPRINT:minkarma:MIN:%4.0lf ","GPRINT:karma:AVERAGE:%4.0lf ","GPRINT:maxkarma:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:check_basicheaders#ff00ff:".gettext("Denied e-mails")."\\: ".gettext("check_basicheaders").":STACK","COMMENT:\\u","GPRINT:check_basicheaders:LAST:%4.0lf ","GPRINT:mincheck_basicheaders:MIN:%4.0lf ","GPRINT:check_basicheaders:AVERAGE:%4.0lf ","GPRINT:maxcheck_basicheaders:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:check_goodrcptto#00ffff:".gettext("Denied e-mails")."\\: ".gettext("check_goodrcptto").":STACK","COMMENT:\\u","GPRINT:check_goodrcptto:LAST:%4.0lf ","GPRINT:mincheck_goodrcptto:MIN:%4.0lf ","GPRINT:check_goodrcptto:AVERAGE:%4.0lf ","GPRINT:maxcheck_goodrcptto:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:uribl#4c004c:".gettext("Denied e-mails")."\\: ".gettext("uribl").":STACK","COMMENT:\\u","GPRINT:uribl:LAST:%4.0lf ","GPRINT:minuribl:MIN:%4.0lf ","GPRINT:uribl:AVERAGE:%4.0lf ","GPRINT:maxuribl:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:rhsbl#7f7f7f:".gettext("Denied e-mails")."\\: ".gettext("rhsbl").":STACK","COMMENT:\\u","GPRINT:rhsbl:LAST:%4.0lf ","GPRINT:minrhsbl:MIN:%4.0lf ","GPRINT:rhsbl:AVERAGE:%4.0lf ","GPRINT:maxrhsbl:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:dnsbl#0000ff:".gettext("Denied e-mails")."\\: ".gettext("dnsbl").":STACK","COMMENT:\\u","GPRINT:dnsbl:LAST:%4.0lf ","GPRINT:mindnsbl:MIN:%4.0lf ","GPRINT:dnsbl:AVERAGE:%4.0lf ","GPRINT:maxdnsbl:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:check_earlytalker#7c7cff:".gettext("Denied e-mails")."\\: ".gettext("check_earlytalker").":STACK","COMMENT:\\u","GPRINT:check_earlytalker:LAST:%4.0lf ","GPRINT:mincheck_earlytalker:MIN:%4.0lf ","GPRINT:check_earlytalker:AVERAGE:%4.0lf ","GPRINT:maxcheck_earlytalker:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:fcrdns#827f00:".gettext("Denied e-mails")."\\: ".gettext("fcrdns").":STACK","COMMENT:\\u","GPRINT:fcrdns:LAST:%4.0lf ","GPRINT:minfcrdns:MIN:%4.0lf ","GPRINT:fcrdns:AVERAGE:%4.0lf ","GPRINT:maxfcrdns:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:dmarc#7f0000:".gettext("Denied e-mails")."\\: ".gettext("dmarc").":STACK","COMMENT:\\u","GPRINT:dmarc:LAST:%4.0lf ","GPRINT:mindmarc:MIN:%4.0lf ","GPRINT:dmarc:AVERAGE:%4.0lf ","GPRINT:maxdmarc:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:spam_denied#DAA520:".gettext("Denied e-mails")."\\: ".gettext("spam denied").":STACK","COMMENT:\\u","GPRINT:spam_denied:LAST:%4.0lf ","GPRINT:minspam_denied:MIN:%4.0lf ","GPRINT:spam_denied:AVERAGE:%4.0lf ","GPRINT:maxspam_denied:MAX:%4.0lf \\r",
"COMMENT:\\n", "AREA:clamav#ff0000:".gettext("Denied e-mails")."\\: ".gettext("virus").":STACK","COMMENT:\\u","GPRINT:clamav:LAST:%4.0lf ","GPRINT:minclamav:MIN:%4.0lf ","GPRINT:clamav:AVERAGE:%4.0lf ","GPRINT:maxclamav:MAX:%4.0lf \\r",
"COMMENT:\\n");
}