1 /*
2 * File: check_brocade_temp.c
3 * Copyright: (c) 2006 by Peter Gritsch
4 * Email: s4nag@no-where.at
5 *
6 * This file is part of SNMP4Nagios.
7 *
8 * SNMP4Nagios is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * SNMP4Nagios is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with SNMP4Nagios; if not, write to the
20 *
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA
23 */
24
25 #if HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include "globals.h"
30 #include "nagiosif.h"
31 #if(WITH_RRD)
32 #include "rrdif.h"
33 #endif /* WITH_RRD */
34 #include "snmpif.h"
35 #include "syslogif.h"
36 #include "strutils.h"
37 #include "utilities.h"
38
39
40 /* data type for storing scan results */
41 typedef struct
42 {
43 int index; /* sensor index */
44 int v2; /* found swSensorType and it is temperature (1) */
45 int v3; /* found swSensorStatus and it is not absent (6) */
46 int v4; /* found swSensorValue */
47 int v5; /* found swSensorInfo */
48 char* info; /* information about the sensor */
49 } tScanRes;
50
51 /* data type for storing data */
52 typedef struct
53 {
54 int type; /* type of the sensor */
55 int stat; /* state of the sensor */
56 int tempC; /* current temperature in deg C */
57 } tDataSet;
58
59
60 /*
61 * SNMP base OID
62 * SW-MIB::swSensorType.1 = .1.3.6.1.4.1.1588.2.1.1.1.1.22.1.2.1
63 * SW-MIB::swSensorStatus.1 = .1.3.6.1.4.1.1588.2.1.1.1.1.22.1.3.1
64 * SW-MIB::swSensorValue.1 = .1.3.6.1.4.1.1588.2.1.1.1.1.22.1.4.1
65 * SW-MIB::swSensorInfo.1 = .1.3.6.1.4.1.1588.2.1.1.1.1.22.1.5.1
66 */
67 oid baseOID[] = { 1, 3, 6, 1, 4, 1, 1588, 2, 1, 1, 1, 1, 22, 1 };
68 size_t baseOIDLen = 14;
69
70 /* scan results */
71 tScanRes* scanRes = NULL;
72 int scanResLen = 0;
73
74 /* results of the SNMP queries */
75 tDataSet v;
76
77
SetGlobals()78 void SetGlobals ()
79 {
80 /* progName is set by ReadArgs() */
81 srvName = "check_brocade_temp";
82 progVersion = "0.2";
83 helpIndexP = "-i INDEX";
84 helpThresP = NULL;
85 helpPurpose =
86 "Checks the status of a temperature sensor of a Brocade SAN"
87 " Switch.";
88 /* community is set by ReadArgs() */
89 /* commFile is set by ReadArgs() */
90 #if(WITH_RRD)
91 rrdStep = 5 * 60;
92 rrdHBeat = 11 * 60;
93 #endif /* WITH_RRD */
94 supportsPerfLog = TRUE;
95 hasIndexParam = TRUE;
96 hasAddInfParam = TRUE;
97 }
98
HelpSpecificParams()99 void HelpSpecificParams ()
100 {
101 printf (
102 "-i, --index INTEGER\n"
103 " Index of the temperature sensor which should be checked\n"
104 "\n"
105 );
106 }
107
HelpExplain()108 void HelpExplain ()
109 {
110 printf (
111 "The plugin checks if the SAN switch considers the temperature of the\n"
112 "sensor as within the nominal range. If the sensor is outside this\n"
113 "range, a critical will be generated. If the sensor is unknown, faulty\n"
114 "or absent, a warning will be generated.\n"
115 "\n"
116 );
117 }
118
HelpPerformanceData()119 void HelpPerformanceData ()
120 {
121 printf (
122 "Native performance data is provided in the format:\n"
123 "<addInf>;<tempC>\n"
124 "where\n"
125 " addInf ... additional information.\n"
126 " tempC ... current temperature in degree Celsius.\n"
127 "\n"
128 );
129 printf (
130 "Nagios Plugins compatible performance data is provided in the format:\n"
131 "'current temperature'=<tempC>\n"
132 "\n"
133 "Note: Nagios Plugin performance data format does not allow Degree\n"
134 "Centigrade as unit of measurement.\n"
135 "\n"
136 );
137 }
138
ChkOptSpecificParams(int argc,char ** argv,int * i)139 int ChkOptSpecificParams ( int argc, char** argv, int* i )
140 {
141 return FALSE;
142 }
143
ScanResIndex(int aIndex)144 int ScanResIndex ( int aIndex )
145 {
146 int retVal = 0;
147 int found = FALSE;
148
149 while ( ( retVal < scanResLen ) && !found )
150 {
151 found = ( scanRes [retVal].index == aIndex );
152 if ( !found ) retVal++;
153 }
154 if ( !found ) retVal = -1;
155 return retVal;
156 }
157
SnmpWalkHandleVariable(netsnmp_variable_list * aVar)158 void SnmpWalkHandleVariable ( netsnmp_variable_list* aVar )
159 {
160 if ( aVar->name_length == 16 )
161 {
162 if ( OidCmp ( aVar->name, baseOID, baseOIDLen ) == 0 )
163 {
164 int index;
165
166 switch ( aVar->name [14] )
167 {
168 case 2: /* swSensorType */
169 index = scanResLen;
170 scanResLen++;
171 scanRes = realloc ( scanRes,
172 sizeof ( tScanRes ) * scanResLen );
173 if ( scanRes == NULL ) ErrorMalloc ();
174 scanRes [index].index = aVar->name [15];
175 if ( ( aVar->type == ASN_INTEGER ) )
176 {
177 scanRes [index].v2 = ( *(aVar->val.integer) == 1 );
178 }
179 else
180 {
181 scanRes [index].v2 = FALSE;
182 }
183 scanRes [index].v3 = FALSE;
184 scanRes [index].v4 = FALSE;
185 scanRes [index].v5 = FALSE;
186 scanRes [index].info = NULL;
187 break;
188 case 3: /* swSensorStatus */
189 index = ScanResIndex ( aVar->name [15] );
190 if ( ( aVar->type == ASN_INTEGER ) )
191 {
192 scanRes [index].v3 = ( *(aVar->val.integer) != 6 );
193 } /* else nothing to do */
194 break;
195 case 4: /* swSensorValue */
196 {
197 index = ScanResIndex ( aVar->name [15] );
198 scanRes [index].v4 = ( aVar->type == ASN_INTEGER );
199 }
200 break;
201 case 5: /* swSensorInfo */
202 index = ScanResIndex ( aVar->name [15] );
203 scanRes [index].v5 = ( aVar->type == ASN_OCTET_STR );
204 scanRes [index].info = VarListStrDup ( aVar );
205 break;
206 default:
207 /* don't care */
208 break;
209 }
210 } else Log ( LOG_CRIT, "Unexpected OID while scanning services" );
211 } else Log ( LOG_CRIT, "Wrong length while scanning services" );
212 }
213
ScanServices()214 int ScanServices ()
215 {
216 int i;
217 int retVal = STATE_UNKNOWN;
218
219 SnmpWalk ( baseOID, baseOIDLen );
220 for ( i = 0; i < scanResLen; i++ )
221 {
222 if ( scanRes [i].v2 && scanRes [i].v3 && scanRes [i].v4 &&
223 scanRes [i].v5 )
224 {
225 retVal = STATE_OK;
226 printf ( "OK index: %i ; info: %s\n",
227 scanRes [i].index, scanRes [i].info );
228 free ( scanRes [i].info );
229 }
230 }
231 if ( retVal == STATE_UNKNOWN ) printf ( "FAILED\n" );
232 return retVal;
233 }
234
ReadVals()235 void ReadVals ()
236 {
237 struct snmp_session sess1;
238 struct snmp_session* sess2;
239 oid o_type [16];
240 oid o_stat [16];
241 oid o_tempC [16];
242 size_t oidLen;
243
244 OidCpy ( o_type, &oidLen, baseOID, &baseOIDLen );
245 OidCpy ( o_stat, &oidLen, baseOID, &baseOIDLen );
246 OidCpy ( o_tempC, &oidLen, baseOID, &baseOIDLen );
247 o_type [14] = 2; o_type [15] = idx;
248 o_stat [14] = 3; o_stat [15] = idx;
249 o_tempC [14] = 4; o_tempC [15] = idx;
250 oidLen = 16;
251 ConfigureSession1 ( &sess1 );
252 sess2 = snmp_open ( &sess1 );
253 if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
254 v.type = ReadInteger ( sess2, o_type, oidLen );
255 v.stat = ReadInteger ( sess2, o_stat, oidLen );
256 v.tempC = ReadInteger ( sess2, o_tempC, oidLen );
257 free ( sess1.peername );
258 free ( sess1.community );
259 snmp_close_sessions ();
260 }
261
262 #if(WITH_RRD)
CreateDataFile(const char * aRRDFPath)263 void CreateDataFile ( const char* aRRDFPath )
264 {
265 int i = 0;
266 char* params[1024]; /* Now that should be enough! */
267 params [i++] = StrDup ( "JUNK" );
268 params [i++] = StrDup ( aRRDFPath );
269 params [i++] = StrDup ( "-s" );
270 params [i++] = IntToStr ( rrdStep );
271 params [i++] = CreateDSStr ( "tempC", GAUGE, rrdHBeat, "-20", "150" );
272 params [i++] = RRA_MAX_25H_5M;
273 params [i++] = RRA_AVG_25H_5M;
274 params [i++] = RRA_MAX_8D_15M;
275 params [i++] = RRA_AVG_8D_15M;
276 params [i++] = RRA_MAX_32D_1H;
277 params [i++] = RRA_AVG_32D_1H;
278 params [i++] = RRA_MAX_367D_4H;
279 params [i++] = RRA_AVG_367D_4H;
280 RRDCreate ( i, params, aRRDFPath );
281 while ( i > 0 ) free ( params [--i] );
282 }
283
ParseData(const char * aData)284 void ParseData ( const char* aData )
285 {
286 int chk;
287 char buf[1024];
288
289 chk = sscanf ( aData, "%1023s;%i", buf, &(v.tempC) );
290 if ( chk != 2 )
291 {
292 char msg[1024];
293 snprintf ( msg, 1024,
294 "Could not parse performance data: %s.\n", aData );
295 Error ( LOG_ERR, msg );
296 }
297 addInf = StrDup ( buf );
298 }
299
WriteData(const char * aRRDFPath)300 void WriteData ( const char* aRRDFPath )
301 {
302 int i = 0;
303 char* params[1024]; /* Now that should be enough! */
304 char* ts = UIntToStr ( GetTimestamp () );
305 char* tempC = IntToStr ( v.tempC );
306
307 params [i++] = StrDup ( "JUNK" );
308 params [i++] = StrDup ( aRRDFPath );
309 params [i++] = StrDup ( "-t" );
310 params [i++] = StrDup ( "tempC" );
311 params [i++] = StrConcat ( 3, ts, ":", tempC );
312 RRDUpdate ( i, params, aRRDFPath );
313 while ( i > 0 ) free ( params [--i] );
314 free ( tempC );
315 free ( ts );
316 }
317
PlotDataTemp(tFN * aFN,int aTiming,int aNow)318 void PlotDataTemp ( tFN* aFN, int aTiming, int aNow )
319 {
320 tPP* pp = PPInit ();
321 int i = 0;
322 char* title = NULL;
323 char* vLabel = "[deg C]";
324 char* params[1024]; /* Now that should be enough! */
325
326 FNSetPNGData ( aFN, NULL, aTiming );
327 PPAddPlot ( pp, "temperature", "deg C", FALSE );
328 title = StrConcat ( 4, hostName, " temperature ", addInf, "" );
329 i = PlotStdParams ( params, aFN, title, vLabel,
330 aTiming, aNow - rrdHBeat, 1000, PLOT_SI_NONE, 0, 100, FALSE );
331 params [i++] = CreateDEF ( "tempCM", aFN, "tempC", MAX );
332 params [i++] = CreateDEF ( "tempCA", aFN, "tempC", AVG );
333 params [i++] = CreatePlot ( PLOT_AREA, "tempCM", C_GAUGE1_MAX, pp, 0, MAX, FALSE );
334 params [i++] = CreatePlot ( PLOT_LINE2, "tempCA", C_GAUGE1_AVG, pp, 0, AVG, TRUE );
335 i = PlotPrintParams ( i, params, pp, 0, "tempCA", "tempCA", "tempCM", "tempCM", "%4.1lf" );
336 RRDGraph ( i, params, aFN, pp );
337 while ( i > 0 ) free ( params [--i] );
338 free ( title );
339 PPDone ( pp );
340 FNUnsetPNGData ( aFN );
341 }
342
PlotPerfData()343 void PlotPerfData ()
344 {
345 int now = time ( NULL );
346 tFN* fn = FNInit ();
347
348 PlotDataTemp ( fn, PLOT_24H_5M, now );
349 PlotDataTemp ( fn, PLOT_7D_15M, now );
350 PlotDataTemp ( fn, PLOT_31D_60M, now );
351 PlotDataTemp ( fn, PLOT_366D_4H, now );
352 FNDone ( fn );
353 }
354 #endif /* WITH_RRD */
355
CheckData()356 int CheckData ()
357 {
358 int retVal = STATE_OK;
359 char* stat = NULL;
360
361 ReadVals ();
362 if ( v.type == 1 )
363 {
364 switch ( v.stat )
365 {
366 case 1: retVal = STATE_WARNING; stat = "'unknown'"; break;
367 case 2: retVal = STATE_WARNING; stat = "'faulty'"; break;
368 case 3: retVal = STATE_CRITICAL; stat = "'below minimum'"; break;
369 case 4: retVal = STATE_OK; stat = "'nominal'"; break;
370 case 5: retVal = STATE_CRITICAL; stat = "'above maximum'"; break;
371 case 6: retVal = STATE_WARNING; stat = "'absent'"; break;
372 default: retVal = STATE_UNKNOWN; stat = "invalid"; break;
373 }
374 PrintExit ( retVal );
375 printf ( " - temperature is %s, %i deg C", stat, v.tempC );
376 if ( npPerfData )
377 {
378 printf ( "|'current temperature'=%i\n", v.tempC );
379 }
380 else
381 {
382 printf ( "|%s;%i\n", addInf, v.tempC );
383 }
384 }
385 else
386 {
387 retVal = STATE_UNKNOWN;
388 v.tempC = -1;
389 PrintExit ( retVal );
390 printf ( " - not a temperature sensor\n" );
391 }
392 return ( retVal );
393 }
394
main(int argc,char ** argv)395 int main ( int argc, char** argv )
396 {
397 int retVal = STATE_OK;
398
399 SetGlobals ();
400 ReadArgs ( argc, argv );
401 if ( scanServices ) retVal = ScanServices ();
402 else
403 {
404 if ( checkData ) retVal = CheckData ();
405 #if(WITH_RRD)
406 if ( logPerfData ) LogPerfData ();
407 if ( plotPerfData ) PlotPerfData ();
408 #endif /* WITH_RRD */
409 }
410 if ( hostName != NULL ) free ( hostName );
411 if ( hostAddr != NULL ) free ( hostAddr );
412 if ( progName != NULL ) free ( progName );
413 return ( retVal );
414 }
415