Code

New plugin to check Citrix Metaframe XP "Program Neighbourhood"
[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 my $VERSION = "0.2";
18 use strict;
19 use DBI;
20 use Getopt::Long;
21 use lib "/usr/local/nagios/libexec";
22 use utils qw(%ERRORS &print_revision &support &usage $TIMEOUT);
25 my $PROGNAME = "check_sybase";
26 my $DEFAULT_CHECKTYPE = "FREESPACE";
27 my $DEFAULT_WARNING   = "25";
28 my $DEFAULT_CRITICAL  = "10";
30 my ($user, $pass, $dbsvr, $dbname, $config, $checktype, $warn, $crit, $timeout,
31     $help, $version);
33 my $options_okay = GetOptions(
34         "U|user=s"      => \$user,
35         "P|pass:s"      => \$pass, # ":" means optional
36         "S|dbsvr=s"     => \$dbsvr,
37         "D|dbname=s"    => \$dbname,
38         "config=s"      => \$config,
39         "checktype=s"   => \$checktype,
40         "w|warning=i"   => \$warn,
41         "c|critical=i"  => \$crit,
42         "t|timeout=i"   => \$timeout,
43         "h|help"        => \$help,
44         "V|version"     => \$version
45 );
48 if (! $options_okay) # Bad option passed
49 {
50         &help;
51         &nunk("Bad command line option passed!");
52 }
54 # Use defaults, if needed
55 $warn = $warn || $DEFAULT_WARNING;
56 $crit = $crit || $DEFAULT_CRITICAL;
57 $checktype = $checktype || $DEFAULT_CHECKTYPE;
58 $timeout = $timeout || $TIMEOUT;
60 if ($help)
61 {
62         &help;
63         &nok;
64 }
66 if ($version)
67 {
68         print_revision($PROGNAME,"\$Revision$VERSION \$");
69         &nok;
70 }
72 if ($config) # Read any of "user", "pass", "dbsvr", "dbname" from config file
73 {
74         &read_config;
75 }
77 # Some more descriptive syntax checks
78 my $syntax_error;
79 $syntax_error .= "No dbsvr given! " unless $dbsvr;
80 $syntax_error .= "No dbname given! " unless $dbname;
81 $syntax_error .= "No user given! " unless $user;
82 $syntax_error .= "Bad checktype given!"
83         unless $checktype =~ m/^CONNECT|FREESPACE$/;
84 &nunk($syntax_error) if $syntax_error;
87 # Just in case of problems, let's not hang Nagios
88 $SIG{'ALRM'} = sub {
89         &nunk("Timeout: no response from dbsvr $dbsvr within $timeout seconds");
90 };
91 alarm($timeout);
94 # Decide on what we are checking
95 if ($checktype eq "CONNECT")
96 {
97         &connect;
98 }
99 elsif ($checktype eq "FREESPACE")
101         &check_space;
104 my $dbh;
105 my $is_connected;
106 sub connect
108         $dbh = DBI->connect("dbi:Sybase:server=$dbsvr;database=$dbname",
109                             $user, $pass)
110                 or &ncrit("Could not connect to '$dbname' on '$dbsvr'");
112         # Report success for a check of type CONNECT
113         &nok("Connect okay") if $checktype ne "FREESPACE";
116 sub disconnect
118         $dbh->disconnect if $is_connected;
119         $is_connected = 0;
122 sub check_space
124         &connect;
126         # Most of this sub based on Michael Peppler's check-space.pl
128         $dbh->{syb_do_proc_status} = 1;
130         my $dbinfo;
132         # First check space in the database
133         my $sth = $dbh->prepare("sp_spaceused")
134                 or &nunk("Failed to call sp_spaceused on '$dbsvr'");
135         $sth->execute
136                 or &nunk("Failed to call sp_spaceused on '$dbsvr'");
137         do {
138                 while(my $d = $sth->fetch)
139                 {
140                         if($d->[0] =~ /$dbname/)
141                         {
142                                 # Grab "database_size"
143                                 $d->[1] =~ s/[^\d.]//g;
144                                 $dbinfo->{size} = $d->[1];
145                         }
146                         else
147                         {
148                                 foreach (@$d)
149                                 {
150                                         s/\D//g;
151                                 }
153                                 # Grab "reserved", "data", "index"
154                                 $dbinfo->{reserved} = $d->[0] / 1024;
155                                 $dbinfo->{data} = $d->[1] / 1024;
156                                 $dbinfo->{index} = $d->[2] / 1024;
157                         }
158                 }
159         } while($sth->{syb_more_results});
161         # Get the actual device usage from sp_helpdb to get the free log space
162         $sth = $dbh->prepare("sp_helpdb $dbname")
163                 or &nunk("Failed to call sp_helpdb $dbname on '$dbsvr'");
164         $sth->execute
165                 or &nunk("Failed to call sp_helpdb $dbname on '$dbsvr'");
166         do {
167                 while(my $d = $sth->fetch)
168                 {
169                         # Look for "usage" column with value "log only"
170                         if($d->[2] && $d->[2] =~ /log only/)
171                         {
172                                 # Grab "size", add it to our log size
173                                 $d->[1] =~ s/[^\d\.]//g;
174                                 $dbinfo->{log} += $d->[1];
175                         }
177                         # Look for "device fragments" column with "log only"
178                         # followed by a number.
179                         if($d->[0] =~ /log only .* (\d+)/)
180                         {
181                                 $dbinfo->{logfree} = $1 / 1024;
182                         }
183                 }
184         } while($sth->{syb_more_results});
186         # Subtract the log size from the database size
187         $dbinfo->{size} -= $dbinfo->{log};
189         # The "reserved" space is free for use by the table that freed it, so 
190         # it is not truly free space. To be safe, our calculation ignores it.
191         my $free = ($dbinfo->{size} - $dbinfo->{reserved}) / $dbinfo->{size};
192         $free = sprintf("%.2f", $free*100);
195         if ($free < $crit)
196         {
197                 &ncrit("Free space is $free%! (critical threshold is $crit%)");
198         }
200         if ($free < $warn)
201         {
202                 &nwarn("Free space is $free%! (warning threshold is $warn%)");
203         }
206         &nok("Free space within thresholds ($free% free)");
209 sub read_config
211         open (CONFIG, "<$config")
212                 or &nunk("Failed to open config file '$config': $!");
213         while (<CONFIG>)
214         {
215                 chomp;
216                 next if m/^#/; # skip comments
217                 next if m/^$/; # skip blanks
219                 # Each case-insensitive argument can be followed by an optional
220                 # colon, then must be followed by whitespace and the value.
221                 # Options in the config file override those given on the 
222                 # command line, but don't rely on this!
224                 if    (m/USER:?\s+(\S+)/i)
225                 {
226                         $user = $1;
227                 }
228                 elsif (m/PASS:?\s+(\S+)/i)
229                 {
230                         $pass = $1;
231                 }
232                 elsif (m/DBSVR:?\s+(\S+)/i)
233                 {
234                         $dbsvr = $1;
235                 }
236                 elsif (m/DBNAME:?\s+(\S+)/i)
237                 {
238                         $dbname = $1;
239                 }
240                 else
241                 {
242                         &nunk("Invalid line $. in config file '$config'");
243                 }
244         }
245         close (CONFIG);
248 sub help
250         print <<_HELP_;
251 Usage: $PROGNAME OPTIONS
252 A nagios plugin that connects to a Sybase database and checks free space.
254 Mandatory arguments to long options are mandatory for short options too.
255   -U, --user            Username to connect to database.
256   -P, --pass            Password to connect to database.
257   -S, --dbsvr           Database server (as in the interfaces file).
258   -D, --dbname          Database name to check.
259   --config=FILE         Config file (see SECURITY below)
260   --checktype=TYPE      Type of check to run (see TYPEs below)
261   -w, --warning         Warning threshold, in percent (default 25)
262   -c, --critical        Critical threshold, in percent (default 10)
263   -t, --timeout         Timeout value, in seconds (default 30)
264   -h, --help            This help message
265   -V, --version         Version information
267 Examples:
268         $PROGNAME -U sa -P secret -S bigbox -D orders
269         $PROGNAME --config=/secure/nagios-sybase.cfg --checktype=CONNECT
271 TYPEs
272  There are two types of checks you can run:
273  --checktype=CONNECT
274     Checks just the connection to the database.
275  --checktype=FREESPACE
276     (Default) Checks both the connection to the database and the free space.
278 SECURITY - Using a config file
279  Since a "ps ax" will reveal your database username and password, you can 
280  instead specify them in a config file. Pass the config file with --config.
281  The format of the file is:
282    USER     value
283    PASS     value
284  You can also specify a DBSVR and DBNAME in the file. Comments (#) and blank
285  lines are ignored. Use whitespace to separate argument and value.
286 _HELP_
292 # Some wrappers..
294 # Returns code 0, OK
295 sub nok
297         my $msg = shift;
298         print "OK: $msg\n" if $msg;
300         &disconnect;
301         exit $ERRORS{OK};
304 # Returns code 1, Warning
305 sub nwarn
307         my $msg = shift;
308         print "WARNING: $msg\n";
310         &disconnect;
311         exit $ERRORS{WARNING};
314 # Returns code 2, Critical
315 sub ncrit
317         my $msg = shift;
318         print "CRITICAL: $msg\n";
320         &disconnect;
321         exit $ERRORS{CRITICAL};
324 # Returns code 3, Unknown
325 sub nunk
327         my $msg = shift;
328         print "ERROR: $msg\n";
330         &disconnect;
331         exit $ERRORS{UNKNOWN};