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