Stable update proposal: sitesummary 0.0.35
Ref item 9 on <URL:http://wiki.debian.org/DebianEdu/Meeting/20070813>,
here is a update proposal for the stable release.
I propose to update the version of sitesummary in the stable
repository from 0.0.30 to 0.0.35. This fixes a bug in the collection
of the peername IP address, and add a few featires to list the clients
with a given kernel version or that have not submitted information for
a while. It also fixes a minor bug in the client, collecting locale
specific information the collector can't parse.
There is also a draft nagios config generator, but this is not yet
complete, and only provided to inspire those interested in further
work. It is not used, and will probably need more work to be
complete.
The changes are tested on the skolelinux servers, and the resulting
output can be seen on <URL:http://maintainer.skolelinux.no/sitesummary/>.
Here is the diff -r output between the two versions:
Index: debian/changelog
===================================================================
--- debian/changelog (revision 38710)
+++ debian/changelog (working copy)
@@ -1,3 +1,56 @@
+sitesummary (0.0.35) unstable; urgency=low
+
+ [ Petter Reinholdtsen ]
+ * Recognice nagios2 as a nagios client/server indicator.
+
+ [ Daniel Hess ]
+ * Make get_peerinfo of sitesummary-collector.cgi return the
+ dotted decimal representation of the remote IP address even
+ with webservers that don't set REMOTE_ADDR but passes the
+ filedescriptor of the TCP socket.
+
+ -- Petter Reinholdtsen <pere@debian.org> Mon, 3 Dec 2007 21:25:29 +0100
+
+sitesummary (0.0.34) unstable; urgency=low
+
+ * Prefer REMOTE_ADDR over the output from gethostbyaddr() in
+ get_peerinfo(), to avoid "Bad arg length" problem. Rewrite
+ get_peerinfo() to look ip REMOTE_ADDR in DNS when creating
+ peerinfo.
+
+ -- Petter Reinholdtsen <pere@debian.org> Sun, 2 Dec 2007 19:25:51 +0100
+
+sitesummary (0.0.33) unstable; urgency=low
+
+ * Collect loaded kernel modules, to ease nagios autoconfiguration.
+ * Add >180 days to the agesinceseen-summary list, for really old entries.
+
+ -- Petter Reinholdtsen <pere@debian.org> Sat, 1 Dec 2007 14:13:16 +0100
+
+sitesummary (0.0.32) unstable; urgency=low
+
+ * Collect /proc/mounts and /etc/fstab in system, for use when
+ generating nagios checks for the file systems.
+ * Start on experimental code to generate nagios configuration from
+ the collected sitesummary information.
+ * Fix peername code in the collector.
+ * Set the locale to C when collecting data, to make sure the output
+ format is well known. (Closes: #452899)
+ * Minor cleanup in output.
+
+ -- Petter Reinholdtsen <pere@debian.org> Mon, 26 Nov 2007 09:52:33 +0100
+
+sitesummary (0.0.31) unstable; urgency=low
+
+ * Add -l option to kernelversion-summary and site-summary, to get it
+ to list the individual hosts with the given kernel version and
+ site/sitegroup setting.
+ * New script agesinceseen-summary, listing the hosts that have
+ failed to submit a report in the last few days. It support -l to
+ list the individual hosts.
+
+ -- Petter Reinholdtsen <pere@debian.org> Fri, 23 Nov 2007 22:28:14 +0100
+
sitesummary (0.0.30) unstable; urgency=low
* Change default apache setup to allow everyone read access to
Index: sitesummary-collector.cgi
===================================================================
--- sitesummary-collector.cgi (revision 38710)
+++ sitesummary-collector.cgi (working copy)
@@ -10,6 +10,7 @@
use CGI;
use POSIX qw(strftime);
use Socket;
+use Sys::Syslog;
my $basedir = "/var/lib/sitesummary";
my $handlerdir = "/usr/lib/sitesummary/handler.d";
@@ -17,6 +18,9 @@
$ENV{PATH} = "/bin:/usr/bin";
print "Content-Type: text/plain\n\n";
+
+my ($peeripaddr, $peername) = get_peerinfo(\*STDIN);
+
if (exists $ENV{REQUEST_METHOD} && $ENV{REQUEST_METHOD} ne "POST")
{
print "Sitesummary HTTP-POST submission URL\n";
@@ -62,7 +66,6 @@
EOF
}
-my ($peeripaddr, $peername) = get_peerinfo(\*STDIN);
my $timestamp = strftime("%Y-%m-%dT%H:%M:%S", gmtime());
if ($filename =~ m/.tar.gz$/) {
@@ -76,7 +79,7 @@
# XXX Come up with some unique file name.
my $savefile = "$basedir/tmpstorage/$peeripaddr-$timestamp-$$-$filename";
-open(SITESUMMARY, ">$savefile") or die "Unable to write to $savefile";
+open(SITESUMMARY, ">", $savefile) or die "Unable to write to $savefile";
print SITESUMMARY @entry;
close SITESUMMARY;
@@ -95,10 +98,10 @@
my $eth2mac;
open(IFCONFIG, "system/ifconfig-a") || die "Unable to read ifconfig-a";
while (<IFCONFIG>) {
- chomp;
- $eth0mac = $1 if (m/^eth0\s+Link encap:Ethernet HWaddr (\S+)/);
- $eth1mac = $1 if (m/^eth1\s+Link encap:Ethernet HWaddr (\S+)/);
- $eth2mac = $1 if (m/^eth2\s+Link encap:Ethernet HWaddr (\S+)/);
+ chomp;
+ $eth0mac = $1 if (m/^eth0\s+Link encap:Ethernet HWaddr (\S+)/);
+ $eth1mac = $1 if (m/^eth1\s+Link encap:Ethernet HWaddr (\S+)/);
+ $eth2mac = $1 if (m/^eth2\s+Link encap:Ethernet HWaddr (\S+)/);
}
close (IFCONFIG);
#print STDERR "MAC: $eth0mac\n";
@@ -110,12 +113,12 @@
my ($peeripaddr, $peername, $filename) = @_;
my $dirname;
if ($filename =~ m/(.+).tar.gz$/) {
- $dirname = $1;
- mkdir $dirname;
- chdir $dirname;
- `tar zxf $filename`;
+ $dirname = $1;
+ mkdir $dirname;
+ chdir $dirname;
+ `tar zxf $filename`;
} else {
- die "Unhandled file format '$filename'";
+ die "Unhandled file format '$filename'";
}
open(PEERINFO, ">peerinfo") || die;
@@ -127,37 +130,39 @@
my $status = "new";
if ( -d $newdir ) {
- `rm -r $newdir`;
- my $status = "update";
+ `rm -r $newdir`;
+ my $status = "update";
}
rename $dirname, $newdir || die;
for my $handler (<$handlerdir/*>) {
- `$handler $newdir $status`;
+ `$handler $newdir $status`;
}
}
sub get_peerinfo {
my $sockethandle = shift;
+ my ($peeripstr, $peername) = ("", "");
- # Return something while this function do not work.
- return ("127.0.0.1", "localhost");
-
- # XXX The call to sockaddr_in trigger "Bad arg length for
- # Socket::unpack_sockaddr_in, length is 2, should be 16 at
- # /usr/lib/perl/5.8/Socket.pm line 198." No idea why.
- my ($peerport, $peeripaddr) = sockaddr_in(getpeername($sockethandle));
- if ($peerport) {
- my $peername = gethostbyaddr($peeripaddr, AF_INET);
-
- if ("" eq $peername) {
- syslog('warning', "client without DNS entry connected from \[$peeripaddr\]");
- $peername = "$peeripaddr";
- }
+ if ($ENV{'REMOTE_ADDR'}) { # CGI variable
+ $peeripstr = $ENV{'REMOTE_ADDR'};
+ $peeripstr =~ m/(\d+).(\d+).(\d+).(\d+)/; # Untaint
+ $peeripstr = "$1.$2.$3.$4";
+ $peeripaddr = inet_aton($peeripstr);
+ $peername = gethostbyaddr($peeripaddr, AF_INET);
+ } elsif (my $sockaddr = getpeername($sockethandle)) {
+ my $peerport;
+ ($peerport, $peeripaddr) = sockaddr_in($sockaddr);
+ $peername = gethostbyaddr($peeripaddr, AF_INET);
+ $peeripstr = inet_ntoa($peeripaddr);
} else {
# Running on the command line, use test host
- $peeripaddr = "127.0.0.1";
+ $peeripstr = "127.0.0.1";
$peername = "localhost";
}
- return ($peeripaddr, $peername);
+ if ("" eq $peername) {
+ syslog('warning', "%s", "client without DNS entry connected from \[$peeripstr\]");
+ $peername = "$peeripstr";
+ }
+ return ($peeripstr, $peername);
}
Index: agesinceseen-summary
===================================================================
--- agesinceseen-summary (revision 0)
+++ agesinceseen-summary (revision 39602)
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use SiteSummary;
+use Getopt::Std;
+
+my %agegroup =
+ (
+ 0 => '>0 days',
+ 3 => '>3 days',
+ 7 => '>one week',
+ 14 => '>14 days',
+ 30 => '>30 days',
+ 90 => '>90 days',
+ 180 => '>180 days',
+);
+
+my %agedist;
+my %opts;
+
+sub usage {
+ my $retval = shift;
+ print <<EOF;
+Usage: $0 [-l]
+ -l list hosts with the given age
+EOF
+ exit $retval;
+}
+
+getopt("l", \%opts) || usage(1);
+
+for_all_hosts(\&handle_host);
+
+print_summary();
+
+sub handle_host {
+ my $hostid = shift;
+ my $topdir = get_filepath_current($hostid, "/");
+ my $age = (time() - (stat($topdir))[9]) / (60 * 60 * 24);
+
+ my $thisgroup;
+ for my $group (sort { $a <=> $b; } keys %agegroup) {
+ if ($age > $group) {
+ $thisgroup = $group;
+ }
+ }
+ if (defined $thisgroup) {
+ if (exists $agedist{$thisgroup}) {
+ push @{$agedist{$thisgroup}}, $hostid ;
+ } else {
+ $agedist{$thisgroup} = [$hostid];
+ }
+ }
+}
+
+sub print_summary {
+ printf(" %-20s %5s\n", "hostclass", "count");
+ for my $group (sort { $a <=> $b; } keys %agedist) {
+ printf(" %-20s %5d\n", $agegroup{$group}, scalar @{$agedist{$group}});
+ if (exists $opts{l}) {
+ for my $hostid (sort @{$agedist{$group}}) {
+ my $hostname = get_hostname($hostid);
+ my $site = get_site($hostid) || "";
+ my $sitegroup = get_sitegroup($hostid) || "";
+ printf " %s %s/%s %s\n", $hostname, $site, $sitegroup, $hostid;
+ }
+ print "\n";
+ }
+ }
+}
Index: kernelversion-summary
===================================================================
--- kernelversion-summary (revision 38710)
+++ kernelversion-summary (working copy)
@@ -4,9 +4,22 @@
use warnings;
use SiteSummary;
+use Getopt::Std;
my %kernelvers;
+my %opts;
+sub usage {
+ my $retval = shift;
+ print <<EOF;
+Usage: $0 [-l]
+ -l list hosts using the given kernel versions
+EOF
+ exit $retval;
+}
+
+getopt("l", \%opts) || usage(1);
+
for_all_hosts(\&handle_host);
print_summary();
@@ -15,14 +28,26 @@
my $hostid = shift;
#print "$hostid\n";
for my $kver (get_linux_kernel_ver($hostid)) {
- $kver = "" unless defined $kver;
- $kernelvers{$kver}++;
+ $kver = "" unless defined $kver;
+ if (exists $kernelvers{$kver}) {
+ push @{$kernelvers{$kver}}, $hostid ;
+ } else {
+ $kernelvers{$kver} = [$hostid];
+ }
}
}
sub print_summary {
printf(" %-20s %5s\n", "kernel", "count");
for my $kver (sort keys %kernelvers) {
- printf(" %-20s %5d\n", $kver, $kernelvers{$kver});
+ printf(" %-20s %5d\n", $kver, scalar @{$kernelvers{$kver}});
+ if (exists $opts{l}) {
+ for my $hostid (sort @{$kernelvers{$kver}}) {
+ my $hostname = get_hostname($hostid);
+ my $site = get_site($hostid) || "";
+ my $sitegroup = get_sitegroup($hostid) || "";
+ printf " %s %s/%s %s\n", $hostname, $site, $sitegroup, $hostid;
+ }
+ }
}
}
Index: sitesummary-makewebreport
===================================================================
--- sitesummary-makewebreport (revision 38710)
+++ sitesummary-makewebreport (working copy)
@@ -15,7 +15,12 @@
<pre>
EOF
-for f in site-summary hostclass-summary kernelversion-summary debian_edu-summary ; do
+for f in site-summary \
+ hostclass-summary \
+ kernelversion-summary \
+ agesinceseen-summary \
+ debian_edu-summary ; do
+ echo "$f:"
/usr/lib/sitesummary/$f
echo
done
Index: sitesummary-nodes
===================================================================
--- sitesummary-nodes (revision 38710)
+++ sitesummary-nodes (working copy)
@@ -10,7 +10,7 @@
use Getopt::Std;
my %opts;
-getopts("m", \%opts);
+getopts("mn", \%opts);
my %hostnames;
@@ -18,6 +18,8 @@
if ($opts{'m'}) {
print_munin_list();
+} elsif ($opts{'n'}) { # XXX Nagios config generation do not work yet
+ generate_nagios_config();
} else {
print_list();
}
@@ -34,13 +36,13 @@
}
}
-sub is_munin_client {
- my $hostid = shift;
- # Check debian/dpkg-l for 'ii *munin-node '
+sub is_pkg_installed {
+ my ($hostid, $pkgname) = @_;
+ # Check debian/dpkg-l for 'ii *pkgname '
my $path = get_filepath_current($hostid, "/debian/dpkg-l");
if (open (my $fh, $path)) {
while(<$fh>) {
- if (m/^ii *munin-node /) {
+ if (m/^ii *$pkgname /) {
close($fh);
return 1
}
@@ -50,6 +52,18 @@
return undef;
}
+sub is_munin_client {
+ my $hostid = shift;
+ return is_pkg_installed($hostid, "munin-node");
+}
+
+sub is_nagios_client {
+ my $hostid = shift;
+ return is_pkg_installed($hostid, "nagios-nrpe-server") ||
+ is_pkg_installed($hostid, "nagios-text") ||
+ is_pkg_installed($hostid, "nagios2");
+}
+
sub print_munin_list {
for my $hostname (sort keys %hostnames) {
next unless (is_munin_client($hostnames{$hostname}));
@@ -65,3 +79,100 @@
EOF
}
}
+
+sub generate_nagios_config {
+ for my $hostname (sort keys %hostnames) {
+ my $hostid = $hostnames{$hostname};
+ next unless (is_nagios_client($hostid));
+
+ my $ifconfigpath = get_filepath_current($hostid, "/system/ifconfig-a");
+ my $peerinfopath = get_filepath_current($hostid, "/peerinfo");
+ open (F, "<", $peerinfopath)||die "Unable to read from $peerinfopath";
+ my ($address) = split(/\s+/, scalar <F>);
+ close(F);
+
+ # first, check ping to see if the other checks should be performed
+ print <<EOF;
+##################### $hostname #######################
+define host {
+ host_name $hostname
+ address $address
+}
+define service {
+ use server-service
+ host_name $hostname
+ service_description ping
+ check_command check_ping!100.0,20%!500.0,60%
+}
+EOF
+
+ print <<EOF if is_pkg_installed($hostid, "openssh-server");
+define service {
+ use server-service
+ host_name $hostname
+ service_description ssh
+ check_command check_ssh
+}
+EOF
+
+ my %tcpservices =
+ (
+ 139 => { name => 'samba', package => 'samba' },
+ 631 => { name => 'cups', package => 'cupsys' },
+ 636 => { name => 'ldaps', package => 'slapd' },
+ 3128 => { name => 'squid', package => 'squid' },
+# 10000 => { name => 'webmin', package => 'webmin' },
+ );
+
+ for my $port (sort { $a <=> $b } keys %tcpservices) {
+ next if (exists $tcpservices{$port}->{package} && !
+ is_pkg_installed($hostid,
+ $tcpservices{$port}->{package}));
+ my $servicename = $tcpservices{$port}->{name};
+ print <<EOF;
+define service {
+ use server-service
+ host_name $hostname
+ service_description $servicename
+ check_command check_tcp!$port
+}
+EOF
+ }
+ # check munin if munin-node is installed
+ # check hw and sw raid status
+ # check hardware status
+ # check free swap
+ # check X font server
+ # check LDAP
+ # check DNS
+ # check disk free space
+ my $path = get_filepath_current($hostid, "/system/procmounts");
+ if ( -e $path ) {
+ open (F, "<", $path) || die "unable to read from $path";
+ my %checked;
+ while (<F>) {
+ chomp;
+ my ($dev, $partition, $fs, $opts) = split;
+ next if (exists $checked{$partition});
+ next if ($fs eq "devpts" ||
+ $fs eq "proc" ||
+ $fs eq "rootfs" ||
+ $fs eq "rpc_pipefs" ||
+ $fs eq "sysfs" ||
+ $fs eq "tmpfs");
+
+ $checked{$partition} = 1;
+ my $warn = 10;
+ my $crit = 5;
+ print <<EOF;
+define service {
+ use server-service
+ host_name $hostname
+ service_description Disk $partition
+ check_command check_disk!$warn%!$crit%!$partition
+}
+EOF
+ }
+ }
+ }
+}
Index: sitesummary-client
===================================================================
--- sitesummary-client (revision 38710)
+++ sitesummary-client (working copy)
@@ -8,7 +8,12 @@
set -e
PATH=/sbin:/usr/sbin:/bin:/usr/bin
+export PATH
+# Make sure the output from programs is well known.
+LC_ALL=C
+export LC_ALL
+
# Make sure to store files in a ramfs backed
# storage area on diskless clients, so use /tmp/.
tmpdir=/tmp/sitesummary-$$
Index: site-summary
===================================================================
--- site-summary (revision 38710)
+++ site-summary (working copy)
@@ -4,10 +4,25 @@
use warnings;
use SiteSummary;
+use Getopt::Std;
my %sites;
my %sitegroups;
+my %hostmap;
+my %sitegroupmap;
+my %opts;
+sub usage {
+ my $retval = shift;
+ print <<EOF;
+Usage: $0 [-l]
+ -l list hosts with the given site/sitegroup
+EOF
+ exit $retval;
+}
+
+getopt("l", \%opts) || usage(1);
+
for_all_hosts(\&handle_host);
print_summary();
@@ -16,18 +31,48 @@
my $hostid = shift;
#print "$hostid\n";
for my $site (get_site($hostid)) {
- $site = "" unless defined $site;
- $sites{$site}++;
- $sitegroups{$site}{get_sitegroup($hostid)}++ if get_sitegroup($hostid);
+ $site = "" unless defined $site;
+ $sites{$site}++;
+ my $sitegroup = get_sitegroup($hostid);
+ if ($sitegroup) {
+ $sitegroups{$site}{$sitegroup}++;
+ if (exists $sitegroupmap{$site} && exists $sitegroupmap{$site}{$sitegroup}) {
+ push @{$sitegroupmap{$site}{$sitegroup}}, $hostid ;
+ } else {
+ $sitegroupmap{$site}{$sitegroup} = [$hostid];
+ }
+ } else {
+ if (exists $hostmap{$site}) {
+ push @{$hostmap{$site}}, $hostid ;
+ } else {
+ $hostmap{$site} = [$hostid];
+ }
+ }
}
}
sub print_summary {
printf(" %-20s %5s\n", "site", "count");
for my $site (sort keys %sites) {
- printf(" %-20s %5d\n", $site, $sites{$site});
- for my $sitegroup (sort keys %{$sitegroups{$site}}) {
- printf(" %-18s %5d\n", $sitegroup, $sitegroups{$site}{$sitegroup});
- }
+ printf(" %-20s %5d\n", $site, $sites{$site});
+ if (exists $opts{l}) {
+ for my $hostid (sort @{$hostmap{$site}}) {
+ my $hostname = get_hostname($hostid);
+ my $site = get_site($hostid) || "";
+ my $sitegroup = get_sitegroup($hostid) || "";
+ printf " %s %s/%s %s\n", $hostname, $site, $sitegroup, $hostid;
+ }
+ }
+ for my $sitegroup (sort keys %{$sitegroups{$site}}) {
+ printf(" %-18s %5d\n", $sitegroup, $sitegroups{$site}{$sitegroup});
+ if (exists $opts{l}) {
+ for my $hostid (sort @{$sitegroupmap{$site}{$sitegroup}}) {
+ my $hostname = get_hostname($hostid);
+ my $site = get_site($hostid) || "";
+ my $sitegroup = get_sitegroup($hostid) || "";
+ printf " %s %s/%s %s\n", $hostname, $site, $sitegroup, $hostid;
+ }
+ }
+ }
}
}
Index: collect.d/system
===================================================================
--- collect.d/system (revision 38710)
+++ collect.d/system (working copy)
@@ -26,7 +26,15 @@
lsscsi > lsscsi
fi
+if type lsmod >/dev/null 2>&1; then
+ lsmod > lsmod
+fi
+
uname -smr > uname-smr
uname -n > hostname
ifconfig -a > ifconfig-a
cat /proc/cpuinfo > cpuinfo
+
+# Collect mount points, for nagios configuration
+cp /etc/fstab fstab
+cat /proc/mounts > procmounts
Index: Makefile
===================================================================
--- Makefile (revision 38710)
+++ Makefile (working copy)
@@ -21,6 +21,7 @@
collect.d/siteinfo
SUMMARYSCRIPTS = \
+ agesinceseen-summary \
site-summary \
hostclass-summary \
kernelversion-summary \
Reply to: