Advertisement
tomba2k

check_perc.pl

Jan 29th, 2021
2,162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 14.47 KB | None | 0 0
  1. #!/usr/bin/perl
  2. #
  3. # Josh Yost
  4. # written: 07.14.06
  5. # updated: 03.20.07
  6. #
  7. # THE POINT
  8. #   Use the output from SNMP walks to create warning/critical
  9. # signals to Nagios w/ Dell's SNMP Array/Storage Manager information.
  10. #
  11. # CAVEATS
  12. #   Tested using: Net-SNMP 5.2, Perl 5.8.8, Nagios 2.x
  13. #
  14. # NOTE: I have switched to using an absolute path for the snmpwalk
  15. #       system call.  Please adjust '$snmpwalk' as needed for your system.
  16. #
  17. # NOTE: SNMPv3 hasn't been heavily tested.  I'm simply mirroring the
  18. #       options for snmpwalk, so I would assume it works if you have SNMP
  19. #       configured properly.
  20. #
  21. # I do very little sanity checking of input.  I don't see this as
  22. # a problem because a) only authorized users should be able to run this
  23. # script, b) this script isn't SETUID, c) any options a user could pass to
  24. # corrupt the syscall, they could also just run on the cmdline themselves.
  25. #
  26. #
  27. # COPYRIGHT
  28. #   Distributed freely w/ no license & w/ absolutely no warranty of any kind.
  29. #
  30. # VERSIONS
  31. # 1.0.4
  32. #   - fixed system status handling (i'm lazy)
  33. #   - fixed phys-3 (should be 'ONLINE')
  34. #   - added SIG alarm check
  35. #   - added most usable options for SNMP
  36. #   - switched usage to exit UNKNOWN, all status errors to UNKNOWN
  37. #      (I actually read the plugin guidelines ...)
  38. #   - better error handling, a bit more sanity checking, etc.
  39. #   - added more debugging output
  40. #   - switched to Getopt::Long
  41. #
  42. # 1.0.3c
  43. #   - fixed a couple of typos; added -l to force output to lowercase
  44. #   - made BKGRND INIT. & INITIALIZING ok states; added a couple of
  45. #     older, un-documented OID return values I've seen from our boxes
  46. #   - fixed ret value for usage
  47. # 1.0.2
  48. #   - using controller & physical disk names; fixed debug output a bit
  49. #   - re-directing STDERR to STDOUT on syscalls
  50. #   - added -n to always use numbers
  51. #
  52. # TODO
  53. #   Don't use Net::SNMP - the execution time goes from around 0.050 -
  54. #    0.100 sec to around .180 - .220 sec on our box, mostly due to the
  55. #    loading of the Net::SNMP module (as far as I can tell).
  56. #
  57. # BUGS &/OR PATCHES
  58. #   mailto: joshyost@gmail.com
  59.  
  60. use warnings;
  61. use strict;
  62. use Getopt::Long;
  63. use File::Basename;
  64. use lib '/usr/nagios/libexec';
  65. use utils qw ( %ERRORS $TIMEOUT );
  66.  
  67. our $snmpwalk = '/usr/bin/snmpwalk';
  68. our $vers     = '1.0.4';
  69. our $exe      = basename $0;
  70.  
  71. sub usage{
  72.   print "Usage: $exe [-dhlnV] -D glob|phys|log|con -T sm|am -H <host>\n",
  73.     ' ' x length("Usage: $exe "), "[-v 1|2c|3] -C <community> | -u <user>\n",
  74.     ' ' x length("Usage: $exe "), "[-a MD5|SHA][-A <authpass>][-x DES|AES][-X <privpass>]\n",
  75.     ' ' x length("Usage: $exe "), "[-e <secengine>][-E <conengine][-N <context>]\n";
  76.   print "Try '--help' for more information.\n";
  77.   exit $ERRORS{'UNKNOWN'};
  78. }
  79.  
  80. sub VERS{
  81.   print "$exe\t\t$vers\n";
  82.   exit $ERRORS{'OK'};
  83. }
  84.  
  85. sub HELP{
  86.   print "$exe\t\t$vers\n",
  87.         "\n\tThis script will check your Dell hardware for problems. It\n",
  88.     "can check the Controller State, PERC Global State, Logical Disk State,\n",
  89.     "and Physical Disk State.\n",
  90.     "\nPlease Note: these SNMPv3 options haven't been heavily tested, but\n",
  91.     "since I am just mirroring snmpwalk's options, there shouldn't be any\n",
  92.     "problems. If you have issues w/ the syscall, please let me know.\n",
  93.     "\nOPTIONS\n",
  94.     "  -a,--authproto MD5|SHA\n",       "     Set the SNMPv3 auth protocol (defaults to MD5)\n",
  95.     "  -A,--authpass <arg>\n",          "     Set the SNMPv3 auth passphrase\n",
  96.     "  -C,--community <arg>\n",         "     Set the SNMP v1|v2c community string\n",
  97.     "  -d,--debug\n",                   "     Show debugging output\n",
  98.     "  -D,--device glob|phys|log|con\n","     Set the device type that you want to check\n",
  99.     "  -e,--secengine <arg>\n",         "     Set the SNMPv3 security engine ID\n",
  100.     "  -E,--conengine <arg>\n",         "     Set the SNMPv3 context engine ID\n",
  101.     "  -h,--help\n",                    "     Show this help information\n",
  102.     "  -H,--host <host[:port]>\n",      "     Set the target host (& port optionally)\n",
  103.     "  -l,--lower\n",                   "     Force output to lowercase instead of uppercase\n",
  104.     "  -n,--numbers\n",                 "     Always show numbers for controller & physical disk names\n",
  105.     "  -N,--context <arg>\n",           "     Set the SNMP context name\n",
  106.     "  -T,--type am|sm\n",              "     Set the OpenManage storage type used (Array or Storage Managment)\n",
  107.     "  -v,--snmpversion 1|2c|3\n",      "     Set the SNMP version (defaults to 1)\n",
  108.     "  -V,--version\n",                 "     Show version information\n",
  109.     "  -u,--username <arg>\n",          "     Set the SNMPv3 username\n",
  110.     "  -x,--privproto DES|AES\n",       "     Set the SNMPv3 priv protocol (defaults to DES)\n",
  111.     "  -X,--privpass <arg>\n",          "     Set the SNMPv3 privacy passphrase\n",
  112.     "\nCAVEATS\n",
  113.     " - This script depends on having net-snmp's snmpwalk installed.\n",
  114.     " - It also depends on having Dell's OpenManage software and either Dell's\n",
  115.     "    Array Manager or Storage Management installed on the target system.\n",
  116.     " - The executable path is hard-coded to '/usr/bin/snmpwalk.' Please edit the\n",
  117.     "    '\$snmpwalk' variable near the top of the script for your environment.\n",
  118.     " - You may also need to change the 'use lib' path to utils.pm for your system.\n",
  119.     "\nEXAMPLES\n",
  120.     " \$ $exe -D glob -T sm -H host1 -C public\n",
  121.     " \$ $exe -D phys -T am -H host2 -u MD5User -A \"My Passphrase\"\n";
  122.   exit $ERRORS{'OK'};
  123. }
  124.  
  125. $SIG{ALRM} = sub { print "ERROR - Global timeout exceeded\n"; exit $ERRORS{'UNKNOWN'} };
  126.  
  127. #### Variables
  128. Getopt::Long::Configure("bundling");
  129. my %opts;
  130. GetOptions(\%opts, 'authproto|a=s','authpass|A=s',   'community|C=s','debug|d',
  131.                    'device|D=s',   'secengine|e=s',  'conengine|E=s','help|h',
  132.            'host|H=s',     'lower|l',        'numbers|n',    'context|N=s',
  133.            'type|T=s',     'snmpversion|v=s','version|V',    'username|u=s',
  134.            'privproto|x=s','privpass|X=s') || &usage();
  135.  
  136. &HELP()  if defined($opts{help});
  137. &VERS()  if defined($opts{version});
  138.  
  139. my $aproto   = ($opts{authproto} || 'MD5');
  140. my $aphrase  =  $opts{authpass}  if defined ($opts{authpass});
  141. my $pass     =  $opts{community} if defined ($opts{community});
  142. my $DEBUG    = defined ($opts{debug});
  143. my $dev      =  $opts{device}    if defined ($opts{device});
  144. my $sengine  =  $opts{secengine} if defined ($opts{secengine});
  145. my $cengine  =  $opts{conengine} if defined ($opts{conengine});
  146. my $host     =  $opts{host}      if defined ($opts{host});
  147. my $lower    = defined ($opts{lower});
  148. my $numbers  = defined ($opts{numbers});
  149. my $context  =  $opts{context}   if defined ($opts{context});
  150. my $type     =  $opts{type}      if defined ($opts{type});
  151. my $snmpvers = ($opts{snmpversion} || '1');
  152. my $user     =  $opts{username}  if defined ($opts{username});
  153. my $pproto   = ($opts{privproto} || 'DES');
  154. my $pphrase  =  $opts{privpass}  if defined ($opts{privpass});
  155.  
  156. my ($num,$exit,$id,$timeout) = (0,$ERRORS{'OK'},1,$TIMEOUT+5);
  157. my ($out,$oid);
  158.  
  159. #### sanity checks - flesh out input errors
  160. if (!(defined($host) && defined($type) && defined($dev) && (defined($pass) || defined($user)))){
  161.   print "ERROR - must define -D, -H, -T, and either -C or -u.\n";
  162.   &usage();
  163. }
  164. if (! -x $snmpwalk){
  165.   print "ERROR - $snmpwalk not found. Please edit the script for your environment.\n";
  166.   exit $ERRORS{'UNKNOWN'};
  167. }
  168. &usage() if !($type eq 'sm'  || $type eq 'am');
  169. &usage() if !($dev eq 'phys' || $dev eq 'log' || $dev eq 'con' || $dev eq 'glob');
  170. &usage() if !(($aproto eq 'MD5' || $aproto eq 'SHA') && ($pproto eq 'DES' || $pproto eq 'AES'));
  171. &usage() if !($snmpvers eq '1' || $snmpvers eq '2c' || $snmpvers eq '3');
  172. &usage() if (@ARGV);
  173.  
  174. if (defined($user)) { $snmpvers = '3' }
  175.  
  176. #### initialize SNMP output hash
  177. my @names;
  178. # log-50 was seen on OpenManage 2.1
  179. # phys-44, con-43 was seen on OpenManage 1.8
  180. my %perc = ('log-0'  => 'UNKNOWN',        'phys-0'  => 'UNKNOWN',    'con-0'  => 'UNKNOWN',
  181.             'log-1'  => 'READY',          'phys-1'  => 'READY',      'con-1'  => 'READY',
  182.         'log-2'  => 'FAILED',         'phys-2'  => 'FAILED',     'con-2'  => 'FAILED',
  183.         'log-3'  => 'ONLINE',         'phys-3'  => 'ONLINE',     'con-3'  => 'ONLINE',
  184.         'log-4'  => 'OFFLINE',        'phys-4'  => 'OFFLINE',    'con-4'  => 'OFFLINE',
  185.         'log-6'  => 'DEGRADED',       'phys-6'  => 'DEGRADED',   'con-6'  => 'DEGRADED',
  186.         'log-7'  => 'VERIFYING',      'phys-7'  => 'RECOVERING', 'con-43' => 'UNKNOWN',
  187.         'log-15' => 'RESYNCHING',     'phys-11' => 'REMOVED',    'glob-1' => 'CRITICAL',
  188.         'log-24' => 'REBUILDING',     'phys-15' => 'RESYNCHING', 'glob-2' => 'WARNING',
  189.         'log-26' => 'FORMATTING',     'phys-24' => 'REBUILDING', 'glob-3' => 'NORMAL',
  190.         'log-32' => 'RECONSTRUCTING', 'phys-25' => 'NO MEDIA',   'glob-4' => 'UNKNOWN',
  191.         'log-35' => 'INITIALIZING',   'phys-26' => 'FORMATTING',
  192.         'log-36' => 'BKGRND INIT.',   'phys-28' => 'DIAGNOSTICS',
  193.             'log-50' => 'BKGRND INIT.',   'phys-35' => 'INITIALIZING',
  194.                                       'phys-44' => 'PRED. FAILURE');
  195.  
  196. # set oid param
  197. $id = 20 if $type eq 'sm';
  198.  
  199. # set out and oid string
  200. if ($dev eq 'phys'){
  201.   $out = 'Physical Disks -';
  202.   $oid = ".1.3.6.1.4.1.674.10893.1.${id}.130.4.1.4";
  203. }
  204. elsif ($dev eq 'log'){
  205.   $out = 'Logical Disk(s) -';
  206.   $oid = ".1.3.6.1.4.1.674.10893.1.${id}.140.1.1.4";
  207. }
  208. elsif ($dev eq 'con') {
  209.   $out = 'Controller(s) -';
  210.   $oid = ".1.3.6.1.4.1.674.10893.1.${id}.130.1.1.5";
  211. }
  212. else{
  213.   $out = 'PERC Global State -';
  214.   $oid = ".1.3.6.1.4.1.674.10893.1.${id}.2";
  215. }
  216.  
  217. #### Prepare System Call
  218. my $syscall;
  219. if ($snmpvers eq '3' && defined($user)){
  220.   if (defined($pphrase)){
  221.     if (!defined($aphrase)){
  222.       print "ERROR - auth passphrase is not defined.\n";
  223.       exit $ERRORS{'UNKNOWN'};
  224.     }
  225.     print "debug >> using SNMPv3 authPriv\n" if $DEBUG;
  226.     $syscall = "$snmpwalk -v${snmpvers} -u $user -a $aproto -A \"$aphrase\" -x $pproto -X \"$pphrase\" -l authPriv";
  227.   }
  228.   elsif (defined($aphrase)){
  229.     print "debug >> using SNMPv3 authNoPriv\n" if $DEBUG;
  230.     $syscall = "$snmpwalk -v${snmpvers} -u $user -a $aproto -A \"$aphrase\" -l authNoPriv";
  231.   }
  232.   else{
  233.     print "debug >> using SNMPv3 noAuthNoPriv\n" if $DEBUG;
  234.     $syscall = "$snmpwalk -v${snmpvers} -u $user -l noAuthNoPriv";
  235.   }
  236.   $syscall .= " -n \"$context\"" if defined($context);
  237.   $syscall .= " -e $sengine" if defined($sengine);
  238.   $syscall .= " -E $cengine" if defined($cengine);
  239. }
  240. elsif ($snmpvers eq '1' || $snmpvers eq '2c'){
  241.   print "debug >> using SNMPv$snmpvers\n" if $DEBUG;
  242.   $syscall = "$snmpwalk -v${snmpvers} -c \"$pass\"";
  243. }
  244. else{
  245.   print "ERROR - SNMPv3 requires at least the '-u' option.\n";
  246.   &usage();
  247. }
  248.  
  249. print "debug >> syscall - $syscall $host $oid 2>&1\n" if $DEBUG;
  250.  
  251. #### actual initial system call
  252. alarm $timeout;
  253. my @output = `$syscall $host $oid 2>&1`;
  254. my $state  = $?;
  255. print "debug >> exit status - $state\n" if $DEBUG;
  256.  
  257. if ($state != 0){
  258.   print @output;
  259.   exit $ERRORS{'UNKNOWN'};
  260. }
  261. else{
  262.   # test for non-existent OID
  263.   # SNMPv1 will return no lines, v2c & v3 return an error
  264.   if (!@output || $output[0] =~ /No Such Object available/){
  265.     if ($DEBUG){
  266.       print "debug >> @output";
  267.       print "\n" if !@output;           # for cleaner debug output
  268.     }
  269.     print "ERROR - OID is not available on this server (wrong -T opt?).\n";
  270.     exit $ERRORS{'UNKNOWN'};
  271.   }
  272.  
  273.   # grab names of devices
  274.   if (!$numbers && ($dev eq 'phys' || $dev eq 'con')){
  275.     chop $oid; $oid .= '2';
  276.     print "debug >> names syscall - $syscall $host $oid 2>&1\n" if $DEBUG;
  277.  
  278.     my @tmp = `$syscall $host $oid 2>&1`;
  279.     if ($? != 0){
  280.       print "Error running snmpwalk on oid: $oid\n";
  281.       exit $ERRORS{'UNKNOWN'};
  282.     }
  283.     for (@tmp){
  284.       print "debug >> output - $_" if $DEBUG;
  285.       chomp;
  286.  
  287.       my $name;
  288.       if (/STRING: (.*)/){
  289.         $name = $1;
  290.         # I'm sure there's a prettier way to do this, but whatever...
  291.         if ($name =~ /.* (\d+:\d+)/ || $name =~ /^"?(.*? .*?)[ \"]/){
  292.           print "debug >> name   - $1\n" if $DEBUG;
  293.           push @names,$1;
  294.         }
  295.         else{
  296.           print "debug >> name   - $name\n" if $DEBUG;
  297.           push @names,$name;
  298.         }
  299.       }
  300.       else{
  301.         print "SNMP returned unknown output: $_\n";
  302.     exit $ERRORS{'UNKNOWN'};
  303.       }
  304.     }
  305.   }
  306.  
  307.   for (@output){
  308.     $num++;
  309.     print "debug >> output - $_" if $DEBUG;
  310.  
  311.     my $s;          # state of device
  312.     if (/INTEGER:\s+(\d+)/){
  313.       $s = $1;
  314.       print "debug >> num    - |$s|\n" if $DEBUG;
  315.     }
  316.     else{
  317.       print "SNMP returned unknown output: $_\n";
  318.       exit $ERRORS{'UNKNOWN'};
  319.     }
  320.  
  321.     my $key = "$dev-$s";
  322.     if ($DEBUG){
  323.       print "debug >> key    - $key\tvalue - ",
  324.            (defined($perc{$key})) ? $perc{$key} : 'UNDEFINED VALUE',"\n"
  325.     }
  326.     # handle global status separately
  327.     if ($dev eq 'glob'){
  328.       (defined($perc{$key})) ? ($out .= " $perc{$key}")
  329.                              : ($out .= " UNKNOWN VALUE");
  330.       if    (!defined($perc{$key}))     { $exit = $ERRORS{'UNKNOWN'}  }
  331.       elsif ($perc{$key} eq 'CRITICAL') { $exit = $ERRORS{'CRITICAL'} }
  332.       elsif ($perc{$key} eq 'WARNING')  { $exit = $ERRORS{'WARNING'}  }
  333.       elsif ($perc{$key} ne 'NORMAL' )  { $exit = $ERRORS{'UNKNOWN'}  }
  334.       next;
  335.     }
  336.  
  337.     # handle other devices - only display state for physical disks if
  338.     # state is anything other than ready or online
  339.     if (($dev eq 'phys' && (!defined($perc{$key}) || !($perc{$key} eq 'READY' || $perc{$key} eq 'ONLINE')))
  340.          || $dev ne 'phys'){
  341.       (defined($names[$num-1])) ? ($out .= ' ' . $names[$num-1] . ': ')
  342.                                 : ($out .= " #$num: ");
  343.       (defined($perc{$key}))    ? ($out .= "$perc{$key},")
  344.                                 : ($out .= 'UNKNOWN VALUE,');
  345.     }
  346.  
  347.     # set exit status; make sure you don't downgrade status
  348.     if (!defined($perc{$key}) || $perc{$key} eq 'UNKNOWN'){
  349.       $exit = $ERRORS{'UNKNOWN'} if ($exit != $ERRORS{'CRITICAL'})
  350.     }
  351.     elsif ($perc{$key} eq 'FAILED' || $perc{$key} eq 'OFFLINE'){
  352.       $exit = $ERRORS{'CRITICAL'}
  353.     }
  354.     elsif (!($perc{$key} eq 'READY' || $perc{$key} eq 'ONLINE' ||
  355.              $perc{$key} eq 'BKGRND INIT.' || $perc{$key} eq 'INITIALIZING')){
  356.       $exit = $ERRORS{'WARNING'} if ($exit != $ERRORS{'CRITICAL'})
  357.     }
  358.   }
  359.   #### output
  360.   # check physical disk output
  361.   if ($dev eq 'phys' && $out eq 'Physical Disks -'){
  362.     $out .= ' OK';
  363.   }
  364.   else { chop $out if $dev ne 'glob' }         # chop trailing comma
  365.   alarm 0;
  366.   ($lower) ? print "\L$out\n" : print $out,"\n";
  367.   exit $exit;
  368. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement