Search
j0ke.net Open Build Service
>
Projects
>
server:monitoring
>
nagios-plugins-zypper
> check_zypper.pl
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File check_zypper.pl of Package nagios-plugins-zypper (Revision 4)
Currently displaying revision
4
,
show latest
#!/usr/bin/perl -w # nagios: -epn # # check_zypper - nagios plugin # # Copyright (C) 2008, Novell, Inc. # Author: Lars Vogdt # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # * Neither the name of the Novell nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # $Id$ # use strict; use warnings; use Getopt::Long; use vars qw($PROGNAME $VERSION $DEBUG); # cleanup the environment $ENV{'PATH'}='/bin:/usr/bin:/sbin:/usr/sbin:'; $ENV{'BASH_ENV'}=''; $ENV{'ENV'}=''; # constants $PROGNAME="check_zypper"; $VERSION="0.98ß"; $DEBUG = 0; # variables our $zypper="/usr/bin/zypper"; our $zypperopt="--non-interactive --no-gpg-checks xml-updates"; our $sudo="/usr/bin/sudo"; our $refresh_wrapper="/usr/sbin/zypp-refresh-wrapper"; our $use_sudo="unset LANG; "; our $releasefile="/etc/SuSE-release"; our $release="11.0"; our $dist="openSUSE"; our $patchlevel=0; our ($opt_V, $opt_h, $opt_i, $opt_H, $opt_w, $opt_c, $opt_f, $opt_o, $opt_r, $opt_s, $opt_t, $opt_v); our $exitcode=0; our %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4); our %REVERSE=(4=>'DEPENDENT',3=>'UNKNOWN',2=>'CRITICAL',1=>'WARNING',0=>'OK'); our $TIMEOUT=120; our @patchignore=(); our @packageignore=(); $opt_H=""; $opt_w="recommended,optional"; $opt_c="security"; $opt_f="$releasefile"; $opt_t="120"; $opt_v=0; $opt_o=0; $opt_s=0; ####################################################################### # Functions ####################################################################### sub print_myrevision ($$) { my $commandName = shift; my $pluginRevision = shift; print "$commandName v$pluginRevision\n"; } sub mysupport () { print "Please use https://bugzilla.novell.com to submit patches or suggest improvements.\n"; print "Please include version information with all correspondence (when possible,\n"; print "use output from the --version option of the plugin itself).\n"; } sub usage ($) { my $format=shift; printf($format,@_); exit $ERRORS{'UNKNOWN'}; } sub get_distribution($){ my $file=shift || "$releasefile"; open(RELEASE,"<$file") || warn ("Could not open $file\n"); while (<RELEASE>){ if (/^SUSE Linux Enterprise/){ $dist="SLE"; } if (/^VERSION/){ ( $release ) = $_ =~ m/VERSION = (.*)/; } if (/^PATCHLEVEL/){ ( $patchlevel ) = $_ =~ m/PATCHLEVEL = (.*)/; } } close(RELEASE); print STDERR "INFO: $dist,$release,$patchlevel\n" if ($DEBUG); return($dist,$release,$patchlevel); } sub print_usage () { print "This plugin checks for software updates on systems that use package\n"; print "management systems based on the zypper command found in openSUSE.\n\n"; print "It checks for security, recommended and optional patches and also for\n"; print "optional package updates.\n\n"; print "You can define the status by patch category. Use a commata to list more\n"; print "than one category to a state. Possible values are recommended,optional,security\n"; print "and packages\n\n"; print "If you like to know the names of available patches and packages, use\n"; print "the \"-v\" option.\n\n"; print "Usage:\n"; print " $PROGNAME [-w <category>] [-c <category>] [-t <timeout>] [-v]\n"; print " $PROGNAME [-h | --help]\n"; print " $PROGNAME [-V | --version]\n"; print "\n\nOptions:\n"; print " -c, --critical\n"; print " A patch with this category result in critical status.\n"; print " Default: $opt_c\n"; print " -f, --releasefile\n"; print " Use the given file to get informations about the distribution.\n"; print " Default: $releasefile\n"; print " -h, --help\n"; print " Print detailed help screen\n"; print " -i, --ignore <file>\n"; print " Ignore patches/packages that are mentioned in <file>\n"; print " Just list one patch/package per line - example:\n\n"; print " patch:libtiff-devel\n"; print " # comment\n"; print " package:libtiff3\n"; print " package:libtiff-devel\n\n"; print " -o, --ignore_outdated\n"; print " Don't warn if a repository is outdated.\n"; print " -r, --refresh_repos\n"; print " Tries to refresh the repositories before checking for updates.\n"; print " Note: this maybe needs an entry in /etc/sudoers like:\n"; print " nagios ALL = NOPASSWD: /usr/bin/zypper ref\n"; print " (and additional lines for the \'-s\' Option) if no check-zypp-wrapper is available.\n"; print " -s, --use_sudo\n"; print " Zypper needs root privileges on some distributions (known: 10.1 and SLE10).\n"; print " You can enable the script to use $sudo to start zypper.\n"; print " But don't forget to enable nopasswd sudo for the user starting $PROGNAME\n"; print " Via lines like the two below on in /etc/sudoers:\n"; print " nagios ALL = NOPASSWD: /usr/bin/zypper sl, \\ \n"; print " /usr/bin/zypper $zypperopt\n"; print " -t, --timeout\n"; print " Just in case of problems, let's not hang Nagios and define a timeout.\n"; print " Default value is: $opt_t seconds\n"; print " -v, --verbose_output\n"; print " Print more information (useful only with Nagios v3.x).\n"; print " -w, --warning\n"; print " A patch with this category result in warning status.\n"; print " Default: $opt_w\n"; print "\n"; print " -V, --version\n"; print " Print version information\n"; } sub print_help { my $exit=shift || undef; print "Copyright (c) 2009, Novell, Inc.\n\n"; print_usage(); print "\n"; mysupport(); exit $exit if (defined($exit)); } sub check_zypper(){ if ( -x "$zypper" ){ print STDERR "INFO: Trying $use_sudo $zypper sl 2>/dev/null 1>&2\n" if ( $DEBUG ); return (system("$use_sudo $zypper sl 2>/dev/null 1>&2")); } else { return 1; } } sub refresh_zypper(){ if ( -x $refresh_wrapper ){ print STDERR "Trying: $refresh_wrapper 2>/dev/null 1>&2\n" if ( $DEBUG ); return (system("$refresh_wrapper 2>/dev/null 1>&2")); } if ( -x "$zypper" ){ print STDERR "Trying: $sudo $zypper ref 2>/dev/null 1>&2\n" if ( $DEBUG ); my $res=system("$sudo $zypper ref 2>/dev/null 1>&2"); if (( "$release" eq "10.2" ) || ("$dist" eq "SLE")){ return 0 if ( $res ); } else { return $res } } else { return 1; } } sub check_errorcode($){ my $status=shift || ""; my $level=0; my $returnvalue="OK"; $returnvalue="WARNING" if ("$opt_w" =~ /$status/); $returnvalue="CRITICAL" if ("$opt_c" =~ /$status/); $level=$ERRORS{"$returnvalue"}; $exitcode=$level if ( $level gt $exitcode); $returnvalue=$REVERSE{"$exitcode"}; return "$returnvalue"; } sub check(){ my ($status,$ret_str,$error); my $secstr=""; my $recstr=""; my $optstr=""; my $pacstr=""; my $seccount=0; my $reccount=0; my $optcount=0; my $paccount=0; my $update_avail=0; my %packagelist; print STDERR "INFO: Trying $use_sudo $zypper $zypperopt\n" if ($DEBUG); if (open (FH, "$use_sudo $zypper $zypperopt 2>&1 |")) { while(<FH>){ chomp; my $category="unknown"; print STDERR "LINE: $_\n" if ($DEBUG); # error handling return("UNKNOWN: $_","UNKNOWN") if (/not found on medium/); return("UNKNOWN: $_","UNKNOWN") if (/I\/O error: Can't provide/); return("UNKNOWN: $_","UNKNOWN") if (/Error message:/); return("UNKNOWN: $_","UNKNOWN") if (/A ZYpp transaction is already in progress./); return("UNKNOWN: $_","UNKNOWN") if (/System management is locked/); if ((/out-of-date/)&&(!$opt_o)){ $error="WARNING"; $exitcode=1; $ret_str="WARNING: At least one of your Repositories is out of date. Please run \"zypper refresh\" as root to update it. "; $ret_str.="\n" if ($opt_v); } if (( "$release" eq "10.2" ) || ("$dist" eq "SLE") ){ my ($url,$name,$version,$category,$status)=split('\s*\|\s*',$_,5); # just for reference - perhaps we need the variables later if (defined($name)){ if (grep {/$name/} @patchignore){ print STDERR "WARNING: ignoring $name as it is in \@patchignore\n" if ($DEBUG); next; } } if (/\|\s*optional\s*\|\s*Needed/) { $category="optional"; $optcount++; } if (/\|\s*recommended\s*\|\s*Needed/){ $category="recommended"; $reccount++; } if (/\|\s*security\s*\|\s*Needed/){ $category="security"; $seccount++; } $packagelist{"$category"}{"$name"}{'category'}="$category" if defined($category); $packagelist{"$category"}{"$name"}{'status'}="$status" if defined($status); $packagelist{"$category"}{"$name"}{'name'}="$name" if defined($name); } else { if (/<update /){ my ($name)=$_=~/name="(.*?)"/; if (/kind="patch"/){ # line contains patch if (grep {/$name/} @patchignore){ print STDERR "WARNING: ignoring $name as it is in \@patchignore\n" if ($DEBUG); next; } if (/category="security"/){ $seccount++; $category="security"; } if (/category="recommended"/){ $reccount++; $category="recommended"; } if (/category="optional"/){ $optcount++; $category="optional"; } } elsif (/kind="package"/) { if (grep {/$name/} @packageignore){ print STDERR "WARNING: ignoring $name as it is in \@packageignore\n" if ($DEBUG); next; } $paccount++; $category="package"; } $packagelist{"$category"}{"$name"}{'category'}="$category"; $packagelist{"$category"}{"$name"}{'name'}="$name"; $packagelist{"$category"}{"$name"}{'status'}="Needed"; } } } if ($DEBUG){ print STDERR "INFO: Packages (paccount): $paccount\n"; print STDERR "INFO: Optional (optcount): $optcount\n"; print STDERR "INFO: Recommended (reccount): $reccount\n"; print STDERR "INFO: Security (seccount): $seccount\n"; use Data::Dumper; print STDERR Data::Dumper->Dump([\%packagelist]); } if ("$paccount" ne "0"){ $update_avail=1; $error=check_errorcode("packages"); $pacstr="$paccount package update(s);"; } if ("$optcount" ne "0"){ $update_avail=1; $error=check_errorcode("optional"); $optstr="$optcount optinal update(s);"; } if ("$reccount" ne "0"){ $update_avail=1; $error=check_errorcode("recommended"); $recstr="$reccount recommended update(s);"; } if ("$seccount" ne "0"){ $update_avail=1; $error=check_errorcode("security"); $secstr="$seccount security update(s);"; } if ( $update_avail ){ $ret_str.="$error : $secstr $recstr $optstr $pacstr "; my @packagelist=(); if ( $opt_v ){ foreach my $cat ('security','recommended','optional','package'){ for my $key (sort(keys %packagelist)){ if ( "$key" eq "$cat"){ for my $name (sort(keys %{$packagelist{$key}})){ if ( "$cat" eq "package"){ push @packagelist, $packagelist{$key}{$name}{'name'}; } else { $ret_str.="\n$cat patch: ".$packagelist{$key}{$name}{'name'}; } } } } } $ret_str.="\npackages: ".join(' ',@packagelist) if @packagelist; $ret_str.="\nIgnored Patches : ".join(' ',@patchignore)." " if @patchignore; $ret_str.="\nIgnored Packages: ".join(' ',@packageignore)." " if @packageignore; } } else { $error="OK"; $ret_str="OK: no updates available "; if ( $opt_v ){ $ret_str.="\nIgnored Patches : ".join(' ',@patchignore)." " if @patchignore; $ret_str.="\nIgnored Packages: ".join(' ',@packageignore)." " if @packageignore; } } $ret_str.="| security=".$seccount.";recommended=".$reccount.";optional=".$optcount.";packages=".$paccount.";\n"; } close(FH); return("$ret_str","$error"); } ####################################################################### # Main ####################################################################### Getopt::Long::Configure('bundling'); GetOptions( "V" => \$opt_V, "version" => \$opt_V, "h" => \$opt_h, "help" => \$opt_h, "i=s" => \$opt_i, "ignore=s" => \$opt_i, "H=s" => \$opt_H, "hostname" => \$opt_H, "w=s" => \$opt_w, "warning=s" => \$opt_w, "c=s" => \$opt_c, "critical=s" => \$opt_c, "f=s" => \$opt_f, "releasefile=s" => \$opt_f, "o" => \$opt_o, "ignore_outdated" => \$opt_o, "r" => \$opt_r, "refresh_repos" => \$opt_r, "t=i" => \$opt_t, "timeout=i" => \$opt_t, "v" => \$opt_v, "verbose_output" => \$opt_v, "s" => \$opt_s, "use_sudo" => \$opt_s) or print_help(2); $TIMEOUT=$opt_t if ($opt_t); # Just in case of problems, let's not hang Nagios $SIG{'ALRM'} = sub { print "UNKNOWN - Plugin timed out\n"; exit $ERRORS{"UNKNOWN"}; }; alarm($TIMEOUT); if ($opt_V) { print_myrevision($PROGNAME,"$VERSION"); exit $ERRORS{'OK'}; } if (! $opt_H) { $opt_H=$ENV{'HOSTNAME'}; } ($dist,$release,$patchlevel)=get_distribution("$opt_f"); if ("$release" eq "10.2"){ $zypperopt="--non-interactive --no-gpg-checks list-updates"; } if (("$release" eq "11.1") || (("$dist" eq "SLE") && ("$release" eq "11"))){ $zypperopt="--xmlout list-updates -t package -t patch" } if ("$dist" eq "SLE"){ if (("$release" eq "10") && ($patchlevel gt 0)){ $zypperopt="--non-interactive --no-gpg-checks --terse list-updates"; } else { print "UNKNOWN - SLE $release is currently not supported\n"; exit $ERRORS{"UNKNOWN"}; } } $use_sudo.="$sudo" if ($opt_s); if ($opt_h) { print_help(); exit $ERRORS{'OK'}; } if ($opt_i){ if (! -r "$opt_i" ){ print "Updates CRITICAL - can't find file '$opt_i' - perhaps you should not use option '-i'?\n"; exit $ERRORS{"CRITICAL"}; } else { open(IGNORES,"<$opt_i") or die "Could not open $opt_i: $!\n"; print "INFO: Ignoring the following patches/packages:\n" if ($DEBUG); while(<IGNORES>){ next if /^#/; next if /^\s*$/; chomp; if (/^patch:/){ my ($foo,$toadd)=split(':', $_, 2 ); $foo=~ s/\s*//; print "INFO: + Patch : $toadd\n" if ($DEBUG); push @patchignore,$toadd; } elsif (/^package:/){ my ($foo,$toadd)=split(':', $_, 2 ); $foo=~ s/\s*//; print "INFO: + Package: $toadd\n" if ($DEBUG); push @packageignore,$toadd; } } close(IGNORES); } } if ($opt_r){ if ( refresh_zypper() ){ print "Updates UNKNWON - system does not allow to refresh the repositories\n"; exit $ERRORS{"UNKNOWN"}; } } alarm(0); if ( check_zypper() ){ print "Updates UNKNOWN - system does not allow to execute zypper\n"; exit $ERRORS{"UNKNOWN"}; } else { my ($ret_str,$error)=check(); print "Updates $ret_str"; print STDERR "INFO: Exit-Code: ".$exitcode."\n" if ($DEBUG); exit $exitcode; }