4
0

check_sybase 8.6 KB

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