check_snmp_temperature 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. #!/usr/bin/perl
  2. #
  3. # ============================== SUMMARY =====================================
  4. #
  5. # Program : check_snmp_temperature.pl
  6. # Version : 0.41
  7. # Date : Mar 23, 2012
  8. # Author : William Leibzon - william@leibzon.org
  9. # Summary : This is a nagios plugin that checks temperature sensors
  10. # using SNMP. Dell, HP, Cisco and other types are supported
  11. # and for other systems OIDs can be easily specified too
  12. # Licence : GPL - summary below, text at http://www.fsf.org/licenses/gpl.txt
  13. #
  14. # =========================== PROGRAM LICENSE =================================
  15. #
  16. # This program is free software; you can redistribute it and/or modify
  17. # it under the terms of the GNU General Public License as published by
  18. # the Free Software Foundation; either version 2 of the License, or
  19. # (at your option) any later version.
  20. #
  21. # This program is distributed in the hope that it will be useful,
  22. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. # GNU General Public License for more details.
  25. #
  26. # You should have received a copy of the GNU General Public License
  27. # along with this program; if not, write to the Free Software
  28. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. #
  30. # ===================== INFORMATION ABOUT THIS PLUGIN =========================
  31. #
  32. # This Temperature check plugin that retreives temperature sensor values from
  33. # SNMP and can issue alerts if selected parameters are above given number
  34. # It also returns performance data for further nagios 2.0 post-processing
  35. #
  36. # This program is written and maintained by:
  37. # William Leibzon - william(at)leibzon.org
  38. # It is partially based on check_snmp_* plugins by:
  39. # Patrick Proy (patrick at proy.org)
  40. #
  41. # ============================= SETUP NOTES ====================================
  42. #
  43. # Make sure to check and if necessary adjust the the path to utils.pm
  44. # Make sure you have Net::SNMP perl module installed
  45. #
  46. # If you want to check Dell servers, HP server, Juniper routers or
  47. # Cisco Switches/Routers (cisco 7500, 5500, 2948) then you may skip
  48. # much of the configuration hassles and use pre-programmed settings
  49. # by using "--type" (or -T) parameter, you do still need to specify
  50. # though if you want output as C or F with '-o' option (see examples).
  51. # The plugin currently does not support finding critical & warning
  52. # thresholds which most systems also report in SNMP, so actual thresholds
  53. # you will need to specify as well.
  54. #
  55. # NOTE: If you've previously used 0.2x version of this plugin to
  56. # check HP equipment, beware that 0.3 version has "incompatible"
  57. # change in that it returns human-readable sensor names rather
  58. # then using HP locale ids to enumerate sensors. If you need
  59. # old behavior then instead of using '-T hp' as parameter
  60. # use '-N 1.3.6.1.4.1.232.6.2.6.8.1.3 -D 1.3.6.1.4.1.232.6.2.6.8.1.4'
  61. #
  62. # If you're using some other device then you need to check documentation to
  63. # figure out correct parameters for this plugin, then specify base temperature
  64. # sensor names table OID with '-N' and values table OID with '-D. You also need
  65. # to specify what base sensor temperature data type is with "-i" (see below).
  66. #
  67. # The way plugin works is to walk the snmp tree from base names OID and find
  68. # all the sensor names. Then it compares names given with '-a' (names are
  69. # seperated by ',') to those found in the snmp tree (in '-a' you're expected
  70. # to specify one word which would be found in the full sensor name and
  71. # is unique for thaqt `sensor) and uses OID ending (i.e. part of OID after
  72. # the base) and adds it to base value table OID to create OID to be retrieved
  73. # (similar to how you find ethernet statistics OIDs based on name of the
  74. # interface and in fact many of SNMP parameters are like that).
  75. #
  76. # Note: If you don't know temperature sensor names on your system do:
  77. # check_snmp_temperature -v -A '*' ...
  78. # (using '-v' option forces debugging output that should further help)
  79. #
  80. # If your system does not have table with sensor names you can still use
  81. # this plugin if you know exact temperature data OIDs. Then you specify list
  82. # of names sensors should be known by with '-n' option and list of data OIDs
  83. # with '-d' option (this can also be useful if you want to avoid having plugin
  84. # do snmp table walk each time as retrieving specific list of OIDs is faster).
  85. # You will still need to specify what is likely the same sensor names you
  86. # you put in '-n' with '-a' or '-A' option.
  87. #
  88. # Request: If you have an new type of device and as per above you figured
  89. # out SNMP parameters that work, please send me email with this
  90. # information so that I can add it as a new system type.
  91. #
  92. # The values retrieved are compared to specified warning and critical values,
  93. # but first the temperature has to be converted from base measurement units to
  94. # measurement units you want. These units are Celsius (C) or Fahrenheit (F)
  95. # or Kelvin (K) with input measurement unit specified with '-i' and output
  96. # specified with '-o'. For input you sometimes have situation where sensor
  97. # reports 10xRealValue, i.e. 33.5C is reported as 335 - this is supported
  98. # too and then input type is specified as '-i 10C'.
  99. #
  100. # Warning and critical values are specified with '-w' and '-c' and each
  101. # one must have exact same number of values (separated by ',') as number
  102. # of sensor names specified with '-a'. Any values you dont want to compare
  103. # you specify as 0 or just not specify (i.e. -w ',50,'). In some cases you
  104. # might not get data for specific sensor and want to substitute default
  105. # value - this is supported with '-u' option (note that default values
  106. # is in fact compared against -w and -c).
  107. #
  108. # Additionally if you want performance output then use '-f' option to get all
  109. # the sensors specified in '-a' or specify particular list of sensors for
  110. # performance data with '-A' (this list can include names not found in '-a').
  111. # A special option of -A '*' will allow to get data from all sensors found
  112. # and is this very useful to find what sensors you have with manual run.
  113. #
  114. # ========================= SETUP EXAMPLES ==================================
  115. #
  116. # define command {
  117. # command_name check_cisco_temperature
  118. # command_line $USER1$/check_snmp_temperature.pl -f -H $HOSTADDRESS$ --type=cisco1 -o F -C $ARG1$ -a $ARG2$ -w $ARG3$ -c $ARG4$
  119. # }
  120. #
  121. # define service{
  122. # use std-service
  123. # hostgroup_name cs2948
  124. # service_description Temperature
  125. # check_command check_cisco_temperature!foo!Chassis!160!190
  126. # }
  127. #
  128. # define command{
  129. # command_name check_dell_temperature
  130. # command_line $USER1$/check_snmp_temperature.pl -H $HOSTADDRESS$ -C public \
  131. # -N .1.3.6.1.4.1.674.10892.1.700.20.1.8 \
  132. # -D .1.3.6.1.4.1.674.10892.1.700.20.1.6 -i 10C -o F -u 0 \
  133. # -a ARG1$ -w $ARG2$ -c $ARG3$ -f
  134. # }
  135. #
  136. # define service {
  137. # use std-service
  138. # hostgroup_name dell_1750
  139. # service_description Temperature
  140. # check_command check_dell_temperature!CPU,Ambient,Bottom!110,90,0!135,110,0
  141. # }
  142. #
  143. # For some dell systems with all sensors enabled you can replace the above with:
  144. # check_command check_temperature!'CPU,PROC_1,PROC_2,Ambient,Bottom,BMC Planar,BMC Riser'!110,120,120,90,90,105,105!135,140,140,110,110,125,125
  145. #
  146. # ==================== CHANGES/RELEASE, TODO ==================================
  147. #
  148. # 0.1 - ??? 2006 : Simple plugin where temperature table OIDs were to be
  149. # specified directly as parameter. Was used for checking Dell
  150. # 0.2 - Aug 2006 : Support multiple types of equipment by using config
  151. # hash/array and --type parameter
  152. # 0.21 - Dec 2006 : Added support for Juniper and HP
  153. # 0.22 - Dec 2006 : Added quick hack to interpret 0 value as "dont' check" threshold
  154. # 0.23 - Dec 2007 : Bug Fixes (especially one involving F as input format)
  155. # 0.3 - Jan 2008 : Added '-n' and '-d' options to specify exact list of
  156. # sensor names and oids.
  157. # Also when you specify 'hp' type, the plugin will now
  158. # provide human-readable sensor names rather then purely
  159. # an id of their sensor locale (this is basicly special
  160. # hack just for HP since I don't know anyone else who
  161. # hard-coded sensor names by ids into SNMP MIB).
  162. # 0.31 - Feb 2008 : Bug fix due to report by Michael Timmers. The issue
  163. # was with sensor list that contains a name which matches
  164. # by regex with some other later sensor name. In this
  165. # case it was Juniper with "Routing Engine" which was
  166. # followed by "Routing Engine PCMCIA Card 0" sensor.
  167. # 0.32 - May 2008 : Minor bug fixes. Added baytech pdu SNMP OIDs
  168. # 0.33 - Aug 2008 : Full SNMPv3 support (contrib patch by Nicolas Deffayet)
  169. # 0.34 - Dec 2011 : Bug and small documentation fixes
  170. # 0.35 - Jan 2012 : Added reporting warning and critical threshold to
  171. # performance output (as 'name=temperature;warn;crit'
  172. # based on what become nagios standard for this info)
  173. # Documentation history and todo updates (added 0.1 & 0.2
  174. # versions from below info to above), updated on todo
  175. # 0.36 - Jan 2012 : If data is missing return "UNKNOWN"
  176. # Added linux 'lmsensors' as type of device
  177. # In order to suppot this you need lmsensors package
  178. # and snmpd compiled as:
  179. # --with-mib-modules="ucd-snmp/lmSensors ucd-snmp/diskio"
  180. # 0.40 (beta) - Mar 2012 :
  181. # Imported newest code from check_mysqld 0.93 to support full nagios
  182. # threshold specification (including ranges) as well as reporting
  183. # of warn/crit threshold in performance data. This changes internal
  184. # processing significantly and it needs to be tested more.
  185. # 0.41 - Mar 23, 2013: Fixed bug in parse_threshold function, reported by Charlie Langrall
  186. # official release of 0.4 code branch
  187. #
  188. # TODO and older revision history:
  189. # -- TODO ON TODO --> since most of below is done, it should be cleaned up sometime later
  190. #
  191. # 1. [DONE - Aug 2006] To support multiple types of equipment add config
  192. # array/hash and --type parameter
  193. # 2. More plugin types for various other equipment need to be added ...
  194. # [DONE - Dec 2006] - added Juniper & HP
  195. # 3. [DONE - Mar 2012] Need to update warn & crit parameters parsing code so
  196. # it would support both low and high values with '<' and '>' prefixed and
  197. # using '~' for don't check rather then 0
  198. # [DONE - Dec 2006] - added quick hack to interpret empty values
  199. # (i.e. -w ",90,") as dont check instead of specifying '0' directly
  200. # Note: Low temperature value checks are rarely needed for network
  201. # equipment so this is not high priority right now and will
  202. # be done together with #4 most likely as part of some general
  203. # library that would be shared with check_snmp_table and quite
  204. # likely other plugins where multiple "attributes" are specified
  205. # 4. [DONE - Mar 2012] Add threshold specification in nagios plugin spec compatible way
  206. # as was done with check_mysqld 0.9 which uses code similar to this check
  207. # Add specifying of WARN & CRIT after actual value ';' in the perf output
  208. # [DONE - Dec 2011] - added WARN & CRIT to perf, threshold spec still on todo
  209. # 5. Support specifying table OIDs for temperature threshold values.
  210. # I'll do it only after adding optional file caching so these values
  211. # can be retrieved about once every day rather then for each check.
  212. # 6. Support directly querying lmsensors on linux system without SNMP
  213. # plugin would then be renamed to check_temperature similar to check_netint
  214. #
  215. # ========================== START OF PROGRAM CODE ============================
  216. use strict;
  217. use Getopt::Long;
  218. use Data::Dumper;
  219. # Nagios specific
  220. our $TIMEOUT = 30;
  221. our %ERRORS;
  222. eval 'use utils qw(%ERRORS $TIMEOUT)';
  223. if ($@) {
  224. $TIMEOUT = 30;
  225. %ERRORS = ('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
  226. }
  227. our $no_snmp=0;
  228. eval 'use Net::SNMP';
  229. if ($@) {
  230. $no_snmp=1;
  231. }
  232. # Below is hash array for several types of equipment, format here is that
  233. # key is name you can specify in "--type" and data for that key is 3-value
  234. # array with 1st value sensor names table OID (-N option), 2nd is sensor
  235. # data table OID (-D option) and 3rd is type of temperature reading (-i)
  236. # Additionally instead of specifying sensor names table OID and sensor data
  237. # root table OID, the first two arguments to array can be "" and then 4th and
  238. # 5th argument should be arrays first with list of sensor names and 2nd with
  239. # list of OIDs for data to be retrieved (see below for how its done for Alteon)
  240. my %system_types = ( "dell" => [ "1.3.6.1.4.1.674.10892.1.700.20.1.8", "1.3.6.1.4.1.674.10892.1.700.20.1.6", "10C" ],
  241. "cisco1" => [ "1.3.6.1.4.1.9.9.13.1.3.1.2", "1.3.6.1.4.1.9.9.13.1.3.1.3", "C" ],
  242. "cisco" => [ "1.3.6.1.4.1.9.9.13.1.3.1.2", "1.3.6.1.4.1.9.9.13.1.3.1.3", "C" ], # same as cisco 1 for now, this may change
  243. "juniper" => [ "1.3.6.1.4.1.2636.3.1.13.1.5", "1.3.6.1.4.1.2636.3.1.13.1.7", "C" ], # somebody verify it, dont have juniper right now
  244. "hp" => [ "1.3.6.1.4.1.232.6.2.6.8.1.3", "1.3.6.1.4.1.232.6.2.6.8.1.4", "C" ],
  245. "alteon" => [ "", "", "C", ['RearLeftSensor', 'RearMiddleSensor', 'FrontMiddleSensor', 'FrontRightSensor'], ['1.3.6.1.4.1.1872.2.1.1.6.0','1.3.6.1.4.1.1872.2.1.1.7.0','1.3.6.1.4.1.1872.2.1.1.8.0','1.3.6.1.4.1.1872.2.1.1.9.0'] ], # why do they need to make these alteons so proprietory and hard to deal with?
  246. "baytech" => [ "1.3.6.1.4.1.4779.1.3.5.2.1.2", "1.3.6.1.4.1.4779.1.3.5.2.1.8", "10C" ], # baytech pdu
  247. "lmsensors" => [ "1.3.6.1.4.1.2021.13.16.2.1.2", "1.3.6.1.4.1.2021.13.16.2.1.3", "1000C" ], #linux with lmsensors
  248. "linux" => [ "1.3.6.1.4.1.2021.13.16.2.1.2", "1.3.6.1.4.1.2021.13.16.2.1.3", "1000C" ],
  249. );
  250. # APC OID for the temperature is .1.3.6.1.4.1.318.1.1.2.1.1.0
  251. # APC OID for the humidity is .1.3.6.1.4.1.318.1.1.2.1.2.0
  252. # Cisco fans: .1.3.6.1.4.1.9.9.13.1.4.1.3
  253. # HP switch temperature : .1.3.6.1.4.1.11.2.14.11.1.2.6.1.4.4
  254. # HP switch fan: .1.3.6.1.4.1.11.2.14.11.1.2.6.1.4.1
  255. my $Version='0.40';
  256. my $o_host= undef; # hostname
  257. my $o_community= undef; # community
  258. my $o_port= 161; # SNMP port
  259. my $o_help= undef; # help option
  260. my $o_verb= undef; # verbose mode
  261. my $o_version= undef; # version info option
  262. my $o_octets= 5000;
  263. my $o_warn= undef; # warning level option
  264. my @o_warnL= (); # array for above list
  265. my $o_crit= undef; # Critical level option
  266. my @o_critL= (); # array for above list
  267. my $o_perf= undef; # Performance data option
  268. my $o_timeout= 15; # Default 15s Timeout
  269. my $o_version2= undef; # use snmp v2c
  270. # SNMPv3 specific
  271. my $o_login= undef; # Login for snmpv3
  272. my $o_passwd= undef; # Pass for snmpv3
  273. my $v3protocols=undef; # V3 protocol list.
  274. my $o_authproto='md5'; # Auth protocol
  275. my $o_privproto='des'; # Priv protocol
  276. my $o_privpass= undef; # priv password
  277. my $o_attr= undef; # What attribute(s) to check (specify more then one separated by '.')
  278. my @o_attrL= (); # array for above list
  279. my $o_perfattr= undef; # List of attributes to only provide values in performance data but no checking
  280. my @o_perfattrL=(); # array for above list
  281. my $o_ounit= 'C'; # Output Temperature Measurement Units - can be 'C', 'F' or 'K'
  282. my $o_iunit= 'C'; # Incoming Temperature Measurement Units - can prefix with number if its n*temp
  283. my $oid_names= undef; # OID for base of sensor attribute names
  284. my $oid_data= undef; # OID for base of actual data for those attributes found when walking name base
  285. my $o_names= undef; # List of sensor names (as opposed to specifying names table)
  286. my $o_unkdef= undef; # Default value to report for unknown attributes
  287. my $o_type= undef; # Type of system to check (predefined values for $oid_names, $oid_data, $oid_iunit)
  288. my $o_sensornames=undef; # Option specifying list of sensor names that then go into @ar_sensornames array
  289. my $o_sensoroids=undef; # Option specifying list of sensor oids that then go into @ar_sensoroids array
  290. my @ar_sensornames=(); # List of sensor names if specified in the sensor_types array
  291. my @ar_sensoroids=(); # List of sensor data oids if specified in sensor_types array
  292. # This is hack for HP based on cpqHeTemperatureLocale OID from cpqhlth.mib to map reported locale id to real name
  293. my %hp_locale = ( 1=> ['OTHER',1], 2=> ['UNKNOWN',1], 3=> ['System', 1], 4=> ['SystemBoard',1], 5=> ['ioBoard',1],
  294. 6=> ['CPU',1], 7=> ['Memory',1], 8=> ['Storage',1], 9=> ['RemovableMedia',1],
  295. 10=> ['PowerSupply',1], 11=> ['Ambient',1], 12=> ['Chassis',1], 13=> ['BridgeCard',1] );
  296. sub print_version { print "$0: $Version\n" };
  297. sub print_usage {
  298. print "Usage: $0 [-v] -H <host> -C <snmp_community> [-2] | (-l login -x passwd [-X pass -L <authp>,<privp>]) [-p <port>] [-t <timeout>] -T dell|hp|cisco1|juniper|alteon|lmsensors | [-N <oid_attribnames> -D <oid_attribdata>] | [-n <list of sensor names> -d <list of sensor oids>] [-a <attributes to check> -w <warn levels> -c <crit levels> [-f]] [-A <attributes for perfdata>] [-o <out_temp_unit: C|F|K>] [-i <in_temp_unit>] [-u <unknown_default>] [-V]\n";
  299. }
  300. # Return true if arg is a number
  301. sub isnum {
  302. my $num = shift;
  303. if ( $num =~ /^(\d+\.?\d*)|(^\.\d+)$/ ) { return 1 ;}
  304. return 0;
  305. }
  306. # function used when checking data against critical and warn values
  307. sub check_threshold {
  308. my ($attrib, $data, $th_array, $o_ounit) = @_;
  309. my $mod = $th_array->[0];
  310. my $lv1 = $th_array->[1];
  311. my $lv2 = $th_array->[2];
  312. # verb("debug check_threshold: $mod : ".(defined($lv1)?$lv1:'')." : ".(defined($lv2)?$lv2:''));
  313. return "" if !defined($lv1) || ($mod eq '' && $lv1 eq '');
  314. return " " . $attrib . " Temperature is " . $data . $o_ounit . " = " . $lv1.$o_ounit if $mod eq '=' && $data eq $lv1;
  315. return " " . $attrib . " Temperature is " . $data . $o_ounit . " != " . $lv1.$o_ounit if $mod eq '!' && $data ne $lv1;
  316. return " " . $attrib . " Temperature is " . $data . $o_ounit . " > " . $lv1.$o_ounit if $mod eq '>' && $data>$lv1;
  317. return " " . $attrib . " Temperature is " . $data . $o_ounit . " > " . $lv2.$o_ounit if $mod eq ':' && $data>$lv2;
  318. return " " . $attrib . " Temperature is " . $data . $o_ounit . " >= ". $lv1.$o_ounit if $mod eq '>=' && $data>=$lv1;
  319. return " " . $attrib . " Temperature is " . $data . $o_ounit . " < " . $lv1.$o_ounit if ($mod eq '<' || $mod eq ':') && $data<$lv1;
  320. return " " . $attrib . " Temperature is " . $data . $o_ounit . " <= " . $lv1.$o_ounit if $mod eq '<=' && $data<=$lv1;
  321. return " " . $attrib . " Temperature is " . $data . $o_ounit ." in range ". $lv1.$o_ounit."..".$lv2.$o_ounit if $mod eq '@' && $data>=$lv1 && $data<=$lv2;
  322. return "";
  323. }
  324. # function called when parsing threshold options data
  325. sub parse_threshold {
  326. my $thin = shift;
  327. # link to an array that holds processed threshold data
  328. # array: 1st is type of check, 2nd is value2, 3rd is value2, 4th is option, 5th is nagios spec string representation for perf out
  329. my $th_array = [ '', undef, undef, '', '' ];
  330. my $th = $thin;
  331. my $at = '';
  332. # take 3 ways to specify that there is no threshold
  333. return $th_array if ($th eq '0' || $th eq '~' || $th eq '');
  334. $at = $1 if $th =~ s/^(\^?[@|>|<|=|!]?~?)//; # check mostly for my own threshold format
  335. $th_array->[3]='^' if $at =~ s/\^//; # deal with ^ option
  336. $at =~ s/~//; # ignore ~ if it was entered
  337. if ($th =~ /^\:([-|+]?\d+\.?\d*)/) { # :number format per nagios spec
  338. $th_array->[1]=$1;
  339. $th_array->[0]=($at !~ /@/)?'>':'<=';
  340. $th_array->[5]=($at !~ /@/)?('~:'.$th_array->[1]):($th_array->[1].':');
  341. }
  342. elsif ($th =~ /([-|+]?\d+\.?\d*)\:$/) { # number: format per nagios spec
  343. $th_array->[1]=$1;
  344. $th_array->[0]=($at !~ /@/)?'<':'>=';
  345. $th_array->[5]=($at !~ /@/)?'':'@';
  346. $th_array->[5].=$th_array->[1].':';
  347. }
  348. elsif ($th =~ /([-|+]?\d+\.?\d*)\:([-|+]?\d+\.?\d*)/) { # nagios range format
  349. $th_array->[1]=$1;
  350. $th_array->[2]=$2;
  351. if ($th_array->[1] > $th_array->[2]) {
  352. print "Incorrect format in '$thin' - in range specification first number must be smaller then 2nd\n";
  353. print_usage();
  354. exit $ERRORS{"UNKNOWN"};
  355. }
  356. $th_array->[0]=($at !~ /@/)?':':'@';
  357. $th_array->[5]=($at !~ /@/)?'':'@';
  358. $th_array->[5].=$th_array->[1].':'.$th_array->[2];
  359. }
  360. if (!defined($th_array->[1])) {
  361. $th_array->[0] = ($at eq '@')?'<=':$at;
  362. $th_array->[1] = $th;
  363. $th_array->[5] = '~:'.$th_array->[1] if ($th_array->[0] eq '>' || $th_array->[0] eq '>=');
  364. $th_array->[5] = $th_array->[1].':' if ($th_array->[0] eq '<' || $th_array->[0] eq '<=');
  365. $th_array->[5] = '@'.$th_array->[1].':'.$th_array->[1] if $th_array->[0] eq '=';
  366. $th_array->[5] = $th_array->[1].':'.$th_array->[1] if $th_array->[0] eq '!';
  367. }
  368. if ($th_array->[0] =~ /[>|<]/ && !isnum($th_array->[1])) {
  369. print "Numeric value required when '>' or '<' are used !\n";
  370. print_usage();
  371. exit $ERRORS{"UNKNOWN"};
  372. }
  373. # verb("debug parse_threshold: $th_array->[0] and $th_array->[1]");
  374. $th_array->[0] = '=' if !$th_array->[0] && !isnum($th_array->[1]) && $th_array->[1] ne '';
  375. if (!$th_array->[0] && isnum($th_array->[1])) { # this is just the number by itself, becomes 0:number check per nagios guidelines
  376. $th_array->[2]=$th_array->[1];
  377. $th_array->[1]=0;
  378. $th_array->[0]=':';
  379. $th_array->[5]=$th_array->[2];
  380. }
  381. return $th_array;
  382. }
  383. # this function checks that for numeric data warn threshold is within range of critical threshold
  384. # where within range depends on actual threshold spec and normally just means less
  385. sub threshold_specok {
  386. my ($warn_thar,$crit_thar) = @_;
  387. return 0 if (defined($warn_thar->[1]) && !isnum($warn_thar->[1])) || (defined($crit_thar->[1]) && !isnum($crit_thar->[1]));
  388. return 1 if defined($warn_thar) && defined($warn_thar->[1]) &&
  389. defined($crit_thar) && defined($crit_thar->[1]) &&
  390. isnum($warn_thar->[1]) && isnum($crit_thar->[1]) &&
  391. $warn_thar->[0] eq $crit_thar->[0] &&
  392. (!defined($warn_thar->[3]) || $warn_thar->[3] !~ /\^/) &&
  393. (!defined($crit_thar->[3]) || $crit_thar->[3] !~ /\^/) &&
  394. (($warn_thar->[1]>$crit_thar->[1] && ($warn_thar->[0] =~ />/ || $warn_thar->[0] eq '@')) ||
  395. ($warn_thar->[1]<$crit_thar->[1] && ($warn_thar->[0] =~ /</ || $warn_thar->[0] eq ':')) ||
  396. ($warn_thar->[0] eq ':' && $warn_thar->[2]>=$crit_thar->[2]) ||
  397. ($warn_thar->[0] eq '@' && $warn_thar->[2]<=$crit_thar->[2]));
  398. return 0; # return with 0 means specs check out and are ok
  399. }
  400. sub help {
  401. print "\nSNMP Temperature Monitor for Nagios version ",$Version,"\n";
  402. print " by William Leibzon - william(at)leibzon.org\n\n";
  403. print_usage();
  404. print <<EOD;
  405. -v, --verbose
  406. print extra debugging information
  407. -h, --help
  408. print this help message
  409. -H, --hostname=HOST
  410. name or IP address of host to check
  411. -C, --community=COMMUNITY NAME
  412. community name for the host's SNMP agent (implies v 1 protocol)
  413. -2, --v2c
  414. Use snmp v2c
  415. -l, --login=LOGIN ; -x, --passwd=PASSWD
  416. Login and auth password for snmpv3 authentication
  417. If no priv password exists, implies AuthNoPriv
  418. -X, --privpass=PASSWD
  419. Priv password for snmpv3 (AuthPriv protocol)
  420. -L, --protocols=<authproto>,<privproto>
  421. <authproto> : Authentication protocol (md5|sha : default md5)
  422. <privproto> : Priv protocole (des|aes : default des)
  423. -P, --port=PORT
  424. SNMP port (Default 161)
  425. -w, --warn=INT[,INT[,INT[..]]]
  426. Warning temperature level(s). The number of values listed here must exactly match number
  427. of sensors listed with '-a'. The values specifify threshold for when Nagios should send
  428. WARNING alert. All values are numbers and can have the following prefix modifiers:
  429. > - warn if data is above this value (default for numeric values)
  430. < - warn if data is below this value (must be followed by number)
  431. = - warn if data is equal to this value (default for non-numeric values)
  432. ! - warn if data is not equal to this value
  433. ~ - do not check this data (must not be followed by number or ':')
  434. ^ - this disables check that warning < critical
  435. Threshold values can also be specified as range in two forms:
  436. num1:num2 - warn if data is outside range i.e. if data<num1 or data>num2
  437. \@num1:num2 - warn if data is in range i.e. data>=num1 && data<=num2
  438. -c, --crit=INT[,INT[,INT[..]]]
  439. Critical temperature level(s) (if more then one attribute is checked, must have multiple values)
  440. The format is the same as with warning threshold levels.
  441. -f, --perfdata
  442. Perfparse compatible output
  443. -t, --timeout=INTEGER
  444. timeout for SNMP in seconds (Default: 5)
  445. -V, --version
  446. prints version number
  447. -N, --oidtable_attribnames=OID_STRING
  448. Base table OID to walk through to find names of those attributes supported and from that corresponding data OIDs
  449. -D, --oidtable_attribdata=OID_STRING
  450. Base table OID for sensor attribute data, one number is added to that to make up full attribute OID
  451. -n, --sensor_names=STRING[,STRING[..]]
  452. List of sensor names when -N is not used and sensors are specified with exeact oids
  453. -d, --sensor_oids=OID_STRING[,OID_STRING[..]]
  454. List of exact data OIDs for sensors specified with -n (specify this when -N and -D are not used)
  455. -a, --attributes=STRING[,STRING[..]]
  456. Which attribute(s) to check. This is used as regex to check if attribute is found in sensor names.
  457. As an example for Dell the attribute names to use are: PROC_1, PROC_2, Ambient, Planar, Riser
  458. -A, --perf_attributes=STRING[,STRING[..]]
  459. Which attribute(s) to add to as part of performance data output. These names can be different then the
  460. ones listed in '-a' to only output attributes in perf data but not check. Special value of '*' gets them all.
  461. -f, --perfparse
  462. Used only with '-a'. Causes to output data not only in main status line but also as perfparse output
  463. -o --out_temp_unit=C|F|K
  464. What temperature measurement units are used for output and warning/critical - 'C', 'F' or 'K' - default is 'C'
  465. -i --in_temp_unit=[num]C|F|K
  466. What temperature measurement reported by data OID - format is <num>C|F|K (default is 'C')
  467. where num is used if data is num*realdata, i.e. if reported data of 330 means 33C, then it is: -i 10C
  468. -u, --unknown_default=INT
  469. If attribute is not found then report the output as this number (i.e. -u 0)
  470. -T, --type=dell|hp|cisco1|juniper|alteon|lmsensors
  471. This allows to use pre-defined system type to set Base, Data OIDs and incoming temperature measurement type
  472. Currently support systems types are: dell, hp, cisco1 (7500, 5500, 2948, etc), juniper, alteon, lmsensors (linux using lmsensors package if snmp is compiled to support it)
  473. EOD
  474. }
  475. # For verbose output - don't use it right now
  476. sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }
  477. # Get the alarm signal (just in case snmp timout screws up)
  478. $SIG{'ALRM'} = sub {
  479. print ("ERROR: Alarm signal (Nagios time-out)\n");
  480. exit $ERRORS{"UNKNOWN"};
  481. };
  482. # converts temperature from input format unit into output format units
  483. sub convert_temp {
  484. my ($temp, $in_unit, $out_unit) = @_;
  485. my $in_mult = 1;
  486. my $ctemp = undef;
  487. $in_mult = $1 if $in_unit =~ /(\d+)\w/;
  488. $in_unit =~ s/\d+//;
  489. # exit quickly avoiding conversion to and from C if both units are the same
  490. return $temp / $in_mult if ($in_unit eq $out_unit);
  491. # if units are not the same, we convert to/from C
  492. $ctemp = $temp / $in_mult if $in_unit eq 'C';
  493. $ctemp = ($temp / $in_mult - 32) / 1.8 if $in_unit eq 'F';
  494. $ctemp = $temp / $in_mult - 273.15 if $in_unit eq 'K';
  495. $ctemp = $temp / $in_mult if !defined($ctemp);
  496. return $ctemp if $out_unit eq "C";
  497. return $ctemp * 1.8 + 32 if $out_unit eq "F";
  498. return $ctemp + 273.15 if $out_unit eq "K";
  499. return $ctemp; # should not get here
  500. }
  501. sub check_options {
  502. Getopt::Long::Configure ("bundling");
  503. GetOptions(
  504. 'v' => \$o_verb, 'verbose' => \$o_verb,
  505. 'h' => \$o_help, 'help' => \$o_help,
  506. 'H:s' => \$o_host, 'hostname:s' => \$o_host,
  507. 'P:i' => \$o_port, 'port:i' => \$o_port,
  508. 'C:s' => \$o_community, 'community:s' => \$o_community,
  509. 'l:s' => \$o_login, 'login:s' => \$o_login,
  510. 'x:s' => \$o_passwd, 'passwd:s' => \$o_passwd,
  511. 'X:s' => \$o_privpass, 'privpass:s' => \$o_privpass,
  512. 'L:s' => \$v3protocols, 'protocols:s' => \$v3protocols,
  513. 't:i' => \$o_timeout, 'timeout:i' => \$o_timeout,
  514. 'V' => \$o_version, 'version' => \$o_version,
  515. '2' => \$o_version2, 'v2c' => \$o_version2,
  516. 'c:s' => \$o_crit, 'critical:s' => \$o_crit,
  517. 'w:s' => \$o_warn, 'warn:s' => \$o_warn,
  518. 'f' => \$o_perf, 'perfparse' => \$o_perf,
  519. 'a:s' => \$o_attr, 'attributes:s' => \$o_attr,
  520. 'A:s' => \$o_perfattr, 'perf_attributes:s' => \$o_perfattr,
  521. 'o:s' => \$o_ounit, 'out_temp_unit:s' => \$o_ounit,
  522. 'i:s' => \$o_iunit, 'in_temp_unit:s' => \$o_iunit,
  523. 'u:i' => \$o_unkdef, 'unknown_default:i' => \$o_unkdef,
  524. 'N:s' => \$oid_names, 'oid_attribnames:s' => \$oid_names, 'oidtable_attribnames:s' => \$oid_names,
  525. 'D:s' => \$oid_data, 'oid_attribdata:s' => \$oid_data, 'oidtable_attribdata:s' => \$oid_data,
  526. 'n:s' => \$o_sensornames, 'sensor_names:s' => \$o_sensornames,
  527. 'd:s' => \$o_sensoroids, 'sensor_oids:s' => \$o_sensoroids,
  528. 'T:s' => \$o_type, 'type:s' => \$o_type
  529. );
  530. if (defined($o_help) ) { help(); exit $ERRORS{"UNKNOWN"}; }
  531. if (defined($o_version)) { print_version(); exit $ERRORS{"UNKNOWN"}; }
  532. if ($no_snmp) {
  533. print "Can't locate Net/SNMP.pm\n"; print_usage(); exit $ERRORS{"UNKNOWN"};
  534. }
  535. if (! defined($o_host)) { # check host and filter
  536. print "No host defined!\n";print_usage(); exit $ERRORS{"UNKNOWN"};
  537. }
  538. # check snmp information
  539. if ( !defined($o_community) && (!defined($o_login) || !defined($o_passwd)) )
  540. { print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
  541. if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2)) )
  542. { print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
  543. if (defined ($v3protocols)) {
  544. if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
  545. my @v3proto=split(/,/,$v3protocols);
  546. if ((defined ($v3proto[0])) && ($v3proto[0] ne "")) {$o_authproto=$v3proto[0]; } # Auth protocol
  547. if (defined ($v3proto[1])) {$o_privproto=$v3proto[1]; } # Priv protocol
  548. if ((defined ($v3proto[1])) && (!defined($o_privpass))) {
  549. print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}}
  550. }
  551. $o_ounit =~ tr/[a-z]/[A-Z]/;
  552. if ($o_ounit ne 'C' && $o_ounit ne 'F' && $o_ounit ne 'K')
  553. { print "Invalid output measurement unit specified!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; }
  554. $o_iunit =~ tr/[a-z]/[A-Z]/;
  555. if ($o_iunit !~ /\d*[C|K|F]/)
  556. { print "Invalid input measurement unit specified!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; }
  557. if (defined ($o_type)) {
  558. if (defined($oid_names) || defined($oid_data) || defined($o_sensornames) || defined($o_sensoroids))
  559. { print "Please either specify specify system type (-T) OR base SNMP OIDs for name (-N) and data (-D) tables OR exact list of sensor names (-n) and data OIDs (-d) !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; }
  560. if (defined($system_types{$o_type})) {
  561. $oid_names = $system_types{$o_type}[0];
  562. $oid_data = $system_types{$o_type}[1];
  563. $o_iunit = $system_types{$o_type}[2];
  564. @ar_sensornames= @{$system_types{$o_type}[3]} if defined($system_types{$o_type}[3]) && !$oid_names;
  565. @ar_sensoroids= @{$system_types{$o_type}[4]} if defined($system_types{$o_type}[4]) && !$oid_data;
  566. }
  567. else { print "Unknown system type $o_type !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; }
  568. }
  569. if (defined($o_sensornames) && defined($o_sensoroids)) {
  570. if (defined($oid_names) || defined($oid_data)) {
  571. print "You can not combine -n / -d options with -N / -D\n"; print_usage(); exit $ERRORS{"UNKNOWN"};
  572. }
  573. else {
  574. @ar_sensornames = split(/,/, $o_sensornames);
  575. @ar_sensoroids = split(/,/, $o_sensoroids);
  576. if (scalar(@ar_sensornames) != scalar(@ar_sensoroids)) {
  577. printf "Number of sensor names specified at -n (%d) must be equal to number of data OIDs specified with -d (%d)\n",
  578. scalar(@ar_sensornames), scalar(@ar_sensoroids);
  579. print_usage();
  580. exit $ERRORS{"UNKNOWN"};
  581. }
  582. }
  583. }
  584. if (scalar(@ar_sensornames)==0 && scalar(@ar_sensoroids)==0 && !(defined($oid_names) && defined($oid_data)))
  585. { print "Specify system type (-T) OR base SNMP OIDs for names (-N) and data (-D) tables OR exact list of sensor names (-n) and data OIDs (-d) !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; }
  586. # below code is common for number of my plugins, including check_snmp_?, netstat, etc
  587. # it is mostly compliant with nagios threshold specification (except use of '~')
  588. # and adds number of additional format options using '>','<','!','=' prefixes
  589. my (@ar_warnLv,@ar_critLv);
  590. if (defined($o_perfattr)) {
  591. @o_perfattrL=split(/,/ ,$o_perfattr);
  592. }
  593. if (defined($o_warn) || defined($o_crit) || defined($o_attr)) {
  594. if (defined($o_attr)) {
  595. @o_attrL=split(/,/, $o_attr);
  596. if (defined($o_warn)) {
  597. $o_warn.="~" if $o_warn =~ /,$/;
  598. @ar_warnLv=split( /,/ , lc $o_warn );
  599. }
  600. if (defined($o_crit)) {
  601. $o_crit.="~" if $o_crit =~ /,$/;
  602. @ar_critLv=split( /,/ , lc $o_crit );
  603. }
  604. }
  605. else {
  606. print "Specifying warning and critical levels requires '-a' parameter with list of STATUS variables\n";
  607. print_usage();
  608. exit $ERRORS{"UNKNOWN"};
  609. }
  610. if (scalar(@ar_warnLv)!=scalar(@o_attrL) || scalar(@ar_critLv)!=scalar(@o_attrL)) {
  611. printf "Number of specified warning levels (%d) and critical levels (%d) must be equal to the number of attributes specified at '-a' (%d). If you need to ignore some attribute do it as ',,'\n", scalar(@ar_warnLv), scalar(@ar_critLv), scalar(@o_attrL);
  612. verb("Warning Levels: ".join(",",@ar_warnLv));
  613. verb("Critical Levels: ".join(",",@ar_critLv));
  614. print_usage();
  615. exit $ERRORS{"UNKNOWN"};
  616. }
  617. for (my $i=0; $i<scalar(@o_attrL); $i++) {
  618. $o_warnL[$i] = parse_threshold($ar_warnLv[$i]);
  619. $o_critL[$i] = parse_threshold($ar_critLv[$i]);
  620. if (threshold_specok($o_warnL[$i],$o_critL[$i])) {
  621. print "Numeric value required for warning and critical thresholds!\n";
  622. print "And warning must be less then critical (or greater then when '<' is used)\n";
  623. print "(to override warning<critical check prefix warning value with ^)\n";
  624. print_usage();
  625. exit $ERRORS{"UNKNOWN"};
  626. }
  627. }
  628. }
  629. if (scalar(@o_attrL)==0 && scalar(@o_perfattrL)==0) {
  630. print "You must specify list of attributes with either '-a' or '-A'\n";
  631. print_usage();
  632. exit $ERRORS{"UNKNOWN"};
  633. }
  634. }
  635. ########## MAIN #######
  636. check_options();
  637. # Check global timeout if something goes wrong
  638. if (defined($TIMEOUT)) {
  639. verb("Alarm at $TIMEOUT");
  640. alarm($TIMEOUT);
  641. } else {
  642. verb("no global timeout defined : $o_timeout + 10");
  643. alarm ($o_timeout+10);
  644. }
  645. # Connect to host
  646. my ($session,$error);
  647. if ( defined($o_login) && defined($o_passwd)) {
  648. # SNMPv3 login
  649. verb("SNMPv3 login");
  650. if (!defined ($o_privpass)) {
  651. verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto");
  652. ($session, $error) = Net::SNMP->session(
  653. -hostname => $o_host,
  654. -version => '3',
  655. -username => $o_login,
  656. -authpassword => $o_passwd,
  657. -authprotocol => $o_authproto,
  658. -timeout => $o_timeout
  659. );
  660. } else {
  661. verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto");
  662. ($session, $error) = Net::SNMP->session(
  663. -hostname => $o_host,
  664. -version => '3',
  665. -username => $o_login,
  666. -authpassword => $o_passwd,
  667. -authprotocol => $o_authproto,
  668. -privpassword => $o_privpass,
  669. -privprotocol => $o_privproto,
  670. -timeout => $o_timeout
  671. );
  672. }
  673. } else {
  674. if (defined ($o_version2)) {
  675. # SNMPv2 Login
  676. verb("SNMP v2c login");
  677. ($session, $error) = Net::SNMP->session(
  678. -hostname => $o_host,
  679. -version => '2',
  680. -community => $o_community,
  681. -maxmsgsize => $o_octets || 10000,
  682. -port => $o_port || 161,
  683. -timeout => $o_timeout
  684. );
  685. } else {
  686. # SNMPV1 login
  687. verb("SNMP v1 login");
  688. ($session, $error) = Net::SNMP->session(
  689. -version => '1',
  690. -hostname => $o_host,
  691. -community => $o_community,
  692. -port => $o_port || 161,
  693. -timeout => $o_timeout
  694. );
  695. }
  696. }
  697. if (!defined($session)) {
  698. printf("ERROR opening session: %s.\n", $error);
  699. exit $ERRORS{"UNKNOWN"};
  700. }
  701. # next part of the code builds list of attributes to be retrieved
  702. my $i;
  703. my $oid;
  704. my $line;
  705. my $attr;
  706. my @varlist = ();
  707. my %dataresults;
  708. my $result;
  709. for ($i=0;$i<scalar(@o_attrL);$i++) {
  710. $dataresults{$o_attrL[$i]} = ["check", undef, undef, 0, 0];
  711. }
  712. if (defined($o_perfattr) && $o_perfattr ne '*') {
  713. for ($i=0;$i<scalar(@o_perfattrL);$i++) {
  714. $dataresults{$o_perfattrL[$i]} = ["perf", undef, undef, 0, 0];
  715. }
  716. }
  717. if (scalar(@ar_sensornames)==0) {
  718. verb("Retrieving SNMP table $oid_names to find sensor attribute names");
  719. $result = $session->get_table( -baseoid => $oid_names );
  720. # $result = $session->get_request( -varbindlist => [$oid_names] );
  721. if (!defined($result)) {
  722. printf("ERROR: Problem retrieving OID %s table: %s.\n", $oid_names, $session->error);
  723. $session->close();
  724. exit $ERRORS{"UNKNOWN"};
  725. }
  726. L1: foreach $oid (Net::SNMP::oid_lex_sort(keys %{$result})) {
  727. $line=$result->{$oid};
  728. verb("got $oid : $line");
  729. # special hack for HP
  730. if (defined($o_type) && $o_type eq 'hp' && exists($hp_locale{$line})) {
  731. $line = $hp_locale{$result->{$oid}}[0] ."_". $hp_locale{$result->{$oid}}[1];
  732. $hp_locale{$result->{$oid}}[1]++;
  733. verb("HP hack: interpreting ".$result->{$oid}." as $line");
  734. }
  735. if (defined($o_perfattr) && $o_perfattr eq '*') {
  736. $oid =~ s/$oid_names/$oid_data/;
  737. $dataresults{$line} = ["perf", $oid, undef, 0, 0];
  738. unshift(@varlist,$oid);
  739. verb("match found based on -A '*', now set to retrieve $oid");
  740. }
  741. foreach $attr (keys %dataresults) {
  742. if ($line =~ /$attr/ && !defined($dataresults{$attr}[1])) {
  743. $oid =~ s/$oid_names/$oid_data/;
  744. $dataresults{$attr}[1] = $oid;
  745. unshift(@varlist,$oid) if !defined($varlist[0]) || $varlist[0] ne $oid;
  746. verb("match found for $attr, now set to retrieve $oid");
  747. next L1;
  748. }
  749. }
  750. }
  751. }
  752. else {
  753. my $i;
  754. for ($i=0;$i<scalar(@ar_sensornames);$i++) {
  755. $line=$ar_sensornames[$i];
  756. $oid=$ar_sensoroids[$i];
  757. if (defined($o_perfattr) && $o_perfattr eq '*') {
  758. $dataresults{$line} = ["perf", $oid, undef, 0, 0];
  759. unshift(@varlist,$oid);
  760. verb("match found based on -A '*', now set to retrieve $oid");
  761. }
  762. L2: foreach $attr (keys %dataresults) {
  763. if ($line =~ /$attr/ && !defined($dataresults{$attr}[1])) {
  764. $dataresults{$attr}[1] = $oid;
  765. unshift(@varlist,$oid) if !defined($varlist[0]) || $varlist[0] ne $oid;
  766. verb("match found for $attr, now set to retrieve $oid");
  767. next L2;
  768. }
  769. }
  770. }
  771. }
  772. # now we actually retrieve the attributes
  773. my $statuscode = "OK";
  774. my $statusinfo = "";
  775. my $statusdata = "";
  776. my $perfdata = "";
  777. my $chk = "";
  778. verb("Getting SNMP data for oids" . join(" ",@varlist));
  779. $result = $session->get_request(
  780. -Varbindlist => \@varlist
  781. );
  782. if (!defined($result)) {
  783. printf("ERROR: Can not retrieve OID(s) %s: %s.\n", join(" ",@varlist), $session->error);
  784. $session->close();
  785. exit $ERRORS{"UNKNOWN"};
  786. }
  787. else {
  788. foreach $attr (keys %dataresults) {
  789. if (defined($dataresults{$attr}[1]) && defined($$result{$dataresults{$attr}[1]})) {
  790. $dataresults{$attr}[2]=convert_temp($$result{$dataresults{$attr}[1]},$o_iunit,$o_ounit);
  791. verb("got $dataresults{$attr}[1] : $attr = $dataresults{$attr}[2]");
  792. }
  793. else {
  794. if (defined($o_unkdef)) {
  795. $dataresults{$attr}[2]=$o_unkdef;
  796. verb("could not find snmp data for $attr, setting to to default value $o_unkdef");
  797. }
  798. else {
  799. verb("could not find snmp data for $attr");
  800. }
  801. }
  802. }
  803. }
  804. # loop to check if warning & critical attributes are ok
  805. for ($i=0;$i<scalar(@o_attrL);$i++) {
  806. if (defined($dataresults{$o_attrL[$i]}[2])) {
  807. if ($chk = check_threshold($o_attrL[$i],$dataresults{$o_attrL[$i]}[2],$o_critL[$i],$o_ounit)) {
  808. $dataresults{$o_attrL[$i]}[3]++;
  809. $statuscode = "CRITICAL";
  810. $statusinfo .= $chk;
  811. }
  812. elsif ($chk = check_threshold($o_attrL[$i],$dataresults{$o_attrL[$i]}[2],$o_warnL[$i],$o_ounit)) {
  813. $dataresults{$o_attrL[$i]}[3]++;
  814. $statuscode="WARNING" if $statuscode eq "OK";
  815. $statusinfo .= $chk;
  816. }
  817. if ($dataresults{$o_attrL[$i]}[3]==0) {
  818. $dataresults{$o_attrL[$i]}[3]++;
  819. $statusdata .= "," if ($statusdata);
  820. $statusdata .= " " . $o_attrL[$i] . " Temperature is " . $dataresults{$o_attrL[$i]}[2] . $o_ounit;
  821. }
  822. if (defined($o_perf) && $dataresults{$o_attrL[$i]}[4]==0 &&
  823. defined($o_warnL[$i][5]) && defined($o_critL[$i][5])) {
  824. $dataresults{$o_attrL[$i]}[4]++;
  825. $perfdata .= " " . $o_attrL[$i] . "=" . $dataresults{$o_attrL[$i]}[2];
  826. $perfdata .= ';' if $o_warnL[$i][5] ne '' || $o_critL[$i][5] ne '';
  827. $perfdata .= $o_warnL[$i][5] if $o_warnL[$i][5] ne '';
  828. $perfdata .= ';'.$o_critL[$i][5] if $o_critL[$i][5] ne '';
  829. }
  830. }
  831. else {
  832. $statusdata .= "," if ($statusdata);
  833. $statusdata .= " $o_attrL[$i] data is missing";
  834. $statuscode = "UNKNOWN" if $statuscode eq "OK";
  835. }
  836. }
  837. # add data for performance-only attributes
  838. if (defined($o_perfattr) && $o_perfattr eq '*') {
  839. foreach $attr (keys %dataresults) {
  840. if ($dataresults{$attr}[0] eq "perf" && defined($dataresults{$attr}[2]) && $dataresults{$attr}[4]==0) {
  841. $dataresults{$attr}[4]++;
  842. $perfdata .= " " . $attr . "=" . $dataresults{$attr}[2];
  843. }
  844. }
  845. }
  846. else {
  847. for ($i=0;$i<scalar(@o_perfattrL);$i++) {
  848. if (defined($dataresults{$o_perfattrL[$i]}[2]) && $dataresults{$o_perfattrL[$i]}[4]==0) {
  849. $dataresults{$o_perfattrL[$i]}[4]++;
  850. $perfdata .= " " . $o_perfattrL[$i] . "=" . $dataresults{$o_perfattrL[$i]}[2];
  851. }
  852. }
  853. }
  854. $session->close;
  855. print $statuscode . $statusinfo;
  856. print " -".$statusdata if $statusdata;
  857. print " |".$perfdata if $perfdata;
  858. print "\n";
  859. exit $ERRORS{$statuscode};