Code

New version of Simon Bellwoods check_sybase (0.4). Thank you.
[nagiosplug.git] / contrib / check_sybase
1 #!/usr/bin/perl -w
2 # check_sybase
3 # A nagios plugin that connects to a Sybase database and checks free space.
4 #
5 # Copyright 2004 Simon Bellwood, NetMan Network Management and IT Services GmbH
6 # Portions Copyright 2001 Michael Peppler.
7 # License: GPL
8 #
9 # Bugs and feedback to simon.bellwood@nospam.net-man.at
10 # Latest version available from:
11 #       http://www.net-man.at/software/check_sybase-LATEST.zip
12 #
13 # Revision history:
14 # 0.1   01-OCT-2004     Initial version.
15 # 0.2   08-NOV-2004     Initial release.
16 # 0.3   13-JAN-2004     Fixed lib path, improved timeouts.
17 # 0.4   26-JAN-2004     Added loginTimeout.
18 my $VERSION = "0.4";
20 use strict;
21 use DBI;
22 use Getopt::Long;
23 use lib qw( /usr/lib/nagios/plugins/ /usr/local/nagios/libexec/ );
24 use utils qw(%ERRORS &print_revision &support &usage $TIMEOUT);
27 my $PROGNAME = "check_sybase";
28 my $DEFAULT_CHECKTYPE = "FREESPACE";
29 my $DEFAULT_WARNING   = "25";
30 my $DEFAULT_CRITICAL  = "10";
31 my $DEFAULT_TIMEOUT   = "30";
33 my ($user, $pass, $dbsvr, $dbname, $config, $checktype, $warn, $crit, $timeout,
34     $help, $version);
36 my $options_okay = GetOptions(
37         "U|user=s"      => \$user,
38         "P|pass:s"      => \$pass, # ":" means optional
39         "S|dbsvr=s"     => \$dbsvr,
40         "D|dbname=s"    => \$dbname,
41         "config=s"      => \$config,
42         "checktype=s"   => \$checktype,
43         "w|warning=i"   => \$warn,
44         "c|critical=i"  => \$crit,
45         "t|timeout=i"   => \$timeout,
46         "h|help"        => \$help,
47         "V|version"     => \$version
48 );
51 if (! $options_okay) # Bad option passed
52 {
53         &help;
54         &nunk("Bad command line option passed!");
55 }
57 # Use defaults, if needed
58 $warn = $warn || $DEFAULT_WARNING;
59 $crit = $crit || $DEFAULT_CRITICAL;
60 $checktype = $checktype || $DEFAULT_CHECKTYPE;
61 $timeout = $timeout || $TIMEOUT || $DEFAULT_TIMEOUT;
63 if ($help)
64 {
65         &help;
66         &nok;
67 }
69 if ($version)
70 {
71         print_revision($PROGNAME,"\$Revision$VERSION \$");
72         &nok;
73 }
75 if ($config) # Read any of "user", "pass", "dbsvr", "dbname" from config file
76 {
77         &read_config;
78 }
80 # Some more descriptive syntax checks
81 my $syntax_error;
82 $syntax_error .= "No dbsvr given! " unless $dbsvr;
83 $syntax_error .= "No dbname given! " unless $dbname;
84 $syntax_error .= "No user given! " unless $user;
85 $syntax_error .= "Bad checktype given!"
86         unless $checktype =~ m/^CONNECT|FREESPACE$/;
87 &nunk($syntax_error) if $syntax_error;
90 # Just in case of problems, let's not hang Nagios
91 $SIG{'ALRM'} = sub {
92         &nunk("Timeout: no response from dbsvr $dbsvr within $timeout seconds");
93 };
94 alarm($timeout);
97 # Decide on what we are checking
98 if ($checktype eq "CONNECT")
99 {
100         &connect;
102 elsif ($checktype eq "FREESPACE")
104         &check_space;
107 my $dbh;
108 my $is_connected;
109 sub connect
111         $dbh = DBI->connect("dbi:Sybase:server=$dbsvr;database=$dbname;".
112                        "timeout=$timeout,loginTimeout=$timeout", $user, $pass)
113                 or &ncrit("Could not connect to '$dbname' on '$dbsvr'");
115         # Report success for a check of type CONNECT
116         &nok("Connect okay") if $checktype ne "FREESPACE";
119 sub disconnect
121         $dbh->disconnect if $is_connected;
122         $is_connected = 0;
125 sub check_space
127         &connect;
129         # Most of this sub based on Michael Peppler's check-space.pl
131         $dbh->{syb_do_proc_status} = 1;
133         my $dbinfo;
135         # First check space in the database
136         my $sth = $dbh->prepare("sp_spaceused")
137                 or &nunk("Failed to call sp_spaceused on '$dbsvr'");
138         $sth->execute
139                 or &nunk("Failed to call sp_spaceused on '$dbsvr'");
140         do {
141                 while(my $d = $sth->fetch)
142                 {
143                         if($d->[0] =~ /$dbname/)
144                         {
145                                 # Grab "database_size"
146                                 $d->[1] =~ s/[^\d.]//g;
147                                 $dbinfo->{size} = $d->[1];
148                         }
149                         else
150                         {
151                                 foreach (@$d)
152                                 {
153                                         s/\D//g;
154                                 }
156                                 # Grab "reserved", "data", "index"
157                                 $dbinfo->{reserved} = $d->[0] / 1024;
158                                 $dbinfo->{data} = $d->[1] / 1024;
159                                 $dbinfo->{index} = $d->[2] / 1024;
160                         }
161                 }
162         } while($sth->{syb_more_results});
164         # Get the actual device usage from sp_helpdb to get the free log space
165         $sth = $dbh->prepare("sp_helpdb $dbname")
166                 or &nunk("Failed to call sp_helpdb $dbname on '$dbsvr'");
167         $sth->execute
168                 or &nunk("Failed to call sp_helpdb $dbname on '$dbsvr'");
169         do {
170                 while(my $d = $sth->fetch)
171                 {
172                         # Look for "usage" column with value "log only"
173                         if($d->[2] && $d->[2] =~ /log only/)
174                         {
175                                 # Grab "size", add it to our log size
176                                 $d->[1] =~ s/[^\d\.]//g;
177                                 $dbinfo->{log} += $d->[1];
178                         }
180                         # Look for "device fragments" column with "log only"
181                         # followed by a number.
182                         if($d->[0] =~ /log only .* (\d+)/)
183                         {
184                                 $dbinfo->{logfree} = $1 / 1024;
185                         }
186                 }
187         } while($sth->{syb_more_results});
189         # Subtract the log size from the database size
190         $dbinfo->{size} -= $dbinfo->{log};
192         # The "reserved" space is free for use by the table that freed it, so 
193         # it is not truly free space. To be safe, our calculation ignores it.
194         my $free = ($dbinfo->{size} - $dbinfo->{reserved}) / $dbinfo->{size};
195         $free = sprintf("%.2f", $free*100);
198         if ($free < $crit)
199         {
200                 &ncrit("Free space is $free%! (critical threshold is $crit%)");
201         }
203         if ($free < $warn)
204         {
205                 &nwarn("Free space is $free%! (warning threshold is $warn%)");
206         }
209         &nok("Free space within thresholds ($free% free)");
212 sub read_config
214         open (CONFIG, "<$config")
215                 or &nunk("Failed to open config file '$config': $!");
216         while (<CONFIG>)
217         {
218                 chomp;
219                 next if m/^#/; # skip comments
220                 next if m/^$/; # skip blanks
222                 # Each case-insensitive argument can be followed by an optional
223                 # colon, then must be followed by whitespace and the value.
224                 # Options in the config file override those given on the 
225                 # command line, but don't rely on this!
227                 if    (m/USER:?\s+(\S+)/i)
228                 {
229                         $user = $1;
230                 }
231                 elsif (m/PASS:?\s+(\S+)/i)
232                 {
233                         $pass = $1;
234                 }
235                 elsif (m/DBSVR:?\s+(\S+)/i)
236                 {
237                         $dbsvr = $1;
238                 }
239                 elsif (m/DBNAME:?\s+(\S+)/i)
240                 {
241                         $dbname = $1;
242                 }
243                 else
244                 {
245                         &nunk("Invalid line $. in config file '$config'");
246                 }
247         }
248         close (CONFIG);
251 sub help
253         print <<_HELP_;
254 Usage: $PROGNAME OPTIONS
255 A nagios plugin that connects to a Sybase database and checks free space.
257 Mandatory arguments to long options are mandatory for short options too.
258   -U, --user            Username to connect to database.
259   -P, --pass            Password to connect to database.
260   -S, --dbsvr           Database server (as in the interfaces file).
261   -D, --dbname          Database name to check.
262   --config=FILE         Config file (see SECURITY below)
263   --checktype=TYPE      Type of check to run (see TYPEs below)
264   -w, --warning         Warning threshold, in percent (default 25)
265   -c, --critical        Critical threshold, in percent (default 10)
266   -t, --timeout         Timeout value, in seconds (default 30)
267   -h, --help            This help message
268   -V, --version         Version information ($VERSION)
270 Examples:
271         $PROGNAME -U sa -P secret -S bigbox -D orders
272         $PROGNAME --config=/secure/nagios-sybase.cfg --checktype=CONNECT
274 TYPEs
275  There are two types of checks you can run:
276  --checktype=CONNECT
277     Checks just the connection to the database.
278  --checktype=FREESPACE
279     (Default) Checks both the connection to the database and the free space.
281 SECURITY - Using a config file
282  Since a "ps ax" will reveal your database username and password, you can 
283  instead specify them in a config file. Pass the config file with --config.
284  The format of the file is:
285    USER     value
286    PASS     value
287  You can also specify a DBSVR and DBNAME in the file. Comments (#) and blank
288  lines are ignored. Use whitespace to separate argument and value.
289 _HELP_
295 # Some wrappers..
297 # Returns code 0, OK
298 sub nok
300         my $msg = shift;
301         print "OK: $msg\n" if $msg;
303         &disconnect;
304         exit $ERRORS{OK};
307 # Returns code 1, Warning
308 sub nwarn
310         my $msg = shift;
311         print "WARNING: $msg\n";
313         &disconnect;
314         exit $ERRORS{WARNING};
317 # Returns code 2, Critical
318 sub ncrit
320         my $msg = shift;
321         print "CRITICAL: $msg\n";
323         &disconnect;
324         exit $ERRORS{CRITICAL};
327 # Returns code 3, Unknown
328 sub nunk
330         my $msg = shift;
331         print "ERROR: $msg\n";
333         &disconnect;
334         exit $ERRORS{UNKNOWN};