3 # $Id: nagios-check-apt-updates 352 2008-05-20 21:36:54Z weasel $
5 # nagios check for debian (security) updates,
6 # based on net-snmp glue to security updates via apt-get.
7 # Copyright (C) 2004 SILVER SERVER Gmbh
8 # Copyright (C) 2004, 2005, 2006, 2007, 2008 Peter Palfrader
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # This program is distributed in the hope that it will be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 # General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 $ENV{'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin';
33 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
35 my $APT = '/usr/bin/apt-get';
38 sub do_check($$$$$$) {
39 my ($pre_command, $timeout, $noupdate, $name, $updates_security, $updates_other) = @_;
45 print STDERR "Running $APT update in $name\n" if $VERBOSE;
46 @command = ($APT, 'update');
47 unshift @command, @$pre_command;
49 $pid = open3(\*STDIN, $fh, $fh, @command) or die ("Cannot run $APT update in $name: $!\n");
50 local $SIG{ALRM} = sub { die "Timeout for apt-get update.\n" };
56 if ($CHILD_ERROR) { # program failed
57 die("$APT update returned with non-zero exit code in $name: ".($CHILD_ERROR / 256)."\n");
61 print STDERR "Running $APT --simulate upgrade in $name\n" if $VERBOSE;
62 @command = ($APT, qw{--simulate upgrade});
63 unshift @command, @$pre_command;
65 $pid = open2($fh, \*STDIN, @command) or die ("Cannot run $APT --simulate upgrade | sort -u in $name: $!\n");
66 local $SIG{ALRM} = sub { die "Timeout for apt-get --simulate upgrade.\n" };
72 if ($CHILD_ERROR) { # program failed
73 die("$APT --simulate upgrade | sort -u returned with non-zero exit code in $name: ".($CHILD_ERROR / 256)."\n");
76 @lines = sort {$a cmp $b} @lines;
78 @lines = grep {!$uniq{$_}++} @lines;
80 print STDERR "Processing information for $name\n" if $VERBOSE;
81 for my $line (@lines) {
82 if ($line =~ m/^Inst\s+(\S+)\s+/) {
84 if ($line =~ m/^Inst\s+\S+\s+.*security/i) {
85 push @$updates_security, $package.($name ne '/' ? "($name)" : '');
87 push @$updates_other, $package.($name ne '/' ? "($name)" : '');
95 my $VERSION = '0.0.3 - $Rev: 352 $';
105 $params->{'chroots'} = [];
106 $params->{'vservers'} = [];
107 $params->{'timeout'} = 20;
108 Getopt::Long::config('bundling');
110 '--help' => \$params->{'help'},
111 '--version' => \$params->{'version'},
112 '--sudo' => \$params->{'sudo'},
113 '--noupdate' => \$params->{'noupdate'},
114 '--nosudo' => \$params->{'nosudo'},
115 '--verbose' => \$params->{'verbose'},
116 '--warnifupdates' => \$params->{'warnifupdates'},
117 '--timeout=i' => \$params->{'timeout'},
118 '--chroot=s' => $params->{'chroots'},
119 '--vserver=s' => $params->{'vservers'}
121 die ("Usage: $PROGRAM_NAME [--help|--version] [--sudo|--nosudo] [--timeout=<timeout>] [--verbose]\n");
123 if ($params->{'help'}) {
124 print "nagios-check-apt-updates $VERSION\n";
125 print "Usage: $PROGRAM_NAME [--help|--version] [--sudo|--nosudo] [--verbose]\n";
126 print "Reports packages to upgrade, updating the list if necessary.\n";
128 print " --help Print this short help.\n";
129 print " --version Report version number.\n";
130 print " --sudo Use sudo to call apt-get (default).\n";
131 print " --noupdate Do not run apt-get update first.\n";
132 print " --nosudo Do not use sudo to call apt-get.\n";
133 print " --warnifupdates Exit with a WARNING status if any updates are available.\n";
134 print " --timeout=<timeout> Timeout in seconds for each of the two apt-get runs.\n";
135 print " --verbose Be a little verbose.\n";
136 print " --chroot=<path> Run check in path.\n";
137 print " --vserver=<vserver> Run check in vserver.\n";
139 print "Note that for --sudo (default) you will need entries in /etc/sudoers like these:\n";
140 print "nagios ALL=(ALL) NOPASSWD: /usr/bin/apt-get update\n";
141 print "nagios ALL=(ALL) NOPASSWD: /usr/bin/apt-get --simulate upgrade\n";
142 print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/chroot /chroot-ia32 /usr/bin/apt-get update\n";
143 print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/chroot /chroot-ia32 /usr/bin/apt-get --simulate upgrade\n";
144 print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/vserver phpserver exec /usr/bin/apt-get update\n";
145 print "nagios ALL=(ALL) NOPASSWD: /usr/sbin/vserver phpserver exec /usr/bin/apt-get --simulate upgrade\n";
149 if ($params->{'version'}) {
150 print "nagios-check-apt-updates $VERSION\n";
151 print "nagios check for availability of debian (security) updates\n";
152 print "Copyright (c) 2004 SILVER SERVER Gmbh\n";
153 print "Copyright (c) 2004,2005 Peter Palfrader <peter\@palfrader.org>\n";
156 if ($params->{'sudo'} && $params->{'nosudo'}) {
157 die ("$PROGRAM_NAME: --sudo and --nosudo are mutually exclusive.\n");
159 if ($params->{'sudo'}) {
162 if ($params->{'nosudo'}) {
165 if (scalar @{$params->{'chroots'}} == 0 && scalar @{$params->{'vservers'}} == 0) {
166 $params->{'chroots'} = ['/'];
168 $VERBOSE = $params->{'verbose'};
171 $SIG{'__DIE__'} = sub {
177 my @updates_security;
181 # Make sure chroot paths are nice;
183 for my $root (@{$params->{'chroots'}}) {
184 if ($root =~ m#^(/[a-zA-Z0-9/.-]*)$#) {
187 die ("Chroot path $root is not nice.\n");
190 for my $root (@chroots) {
191 my @pre_command = ();
192 unshift @pre_command, 'chroot', $root if ($root ne '/');
193 unshift @pre_command, 'sudo' if $use_sudo;
194 do_check(\@pre_command, $params->{'timeout'}, $params->{'noupdate'}, $root, \@updates_security, \@updates_other);
197 # Make sure vserver names are nice;
199 for my $vserver (@{$params->{'vservers'}}) {
200 if ($vserver =~ m#^([a-zA-Z0-9.-]+)$#) {
203 die ("Vserver name $vserver is not nice.\n");
206 for my $vserver (@vservers) {
207 my @pre_command = ();
208 unshift @pre_command, '/usr/sbin/vserver', $vserver, 'exec';
209 unshift @pre_command, 'sudo' if $use_sudo;
210 do_check(\@pre_command, $params->{'timeout'}, $params->{'noupdate'}, $vserver, \@updates_security, \@updates_other);
219 if (@updates_security) {
220 $updateinfo .= 'Security updates ('.(scalar @updates_security).'): '.join(', ', @updates_security)."; ";
223 if (@updates_other) {
224 $updateinfo .= 'Other Updates ('.(scalar @updates_other).'): '.join(', ', @updates_other)."; ";
225 $exit = $WARNING if ($params->{'warnifupdates'} and $exit == $OK);
227 $updateinfo = 'No updates available' unless defined $updateinfo;
230 print $updateinfo,"\n";