root/snmp__areca_

Revision 11, 6.6 kB (checked in by ixs, 15 years ago)

Added thresholds

  • Property svn:executable set to *
Line 
1 #!/usr/bin/python
2
3 # Copyright (C) 2009 Andreas Thienemann <andreas@bawue.net>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Library General Public License as published by
7 # the Free Software Foundation; version 2 only
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Library General Public License for more details.
13 #
14 # You should have received a copy of the GNU Library General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #
18
19 #
20 # Munin Plugin to get Temperature, Voltage or Fanspeed from Areca Controllers
21 # via SNMP.
22 #
23 # Parameters:
24 #
25 #       config   (required)
26 #       autoconf (optional - only used by munin-config)
27 #
28
29 # Magic markers (optional - only used by munin-config and some
30 # installation scripts):
31
32 import pprint
33 import time
34 import sys
35 import re
36 import os
37 from pysnmp import v1, v2c, role, asn1
38
39 request_conf = {
40         "volt" : {
41                 "label"  : "Voltages",
42                 "vlabel" : "Volt",
43                 "graph"  : "--base 1000 --logarithmic",
44                 "oid"    : ".1.3.6.1.4.1.18928.1.2.2.1.8"
45         },
46         "fan"  : {
47                 "label"  : "Fans",
48                 "vlabel" : "RPM",
49                 "graph"  : "--base 1000 -l 0",
50                 "oid"    : ".1.3.6.1.4.1.18928.1.2.2.1.9"
51         },
52         "temp" : {
53                 "label"  : "Temperatures",
54                 "vlabel" : "Celsius",
55                 "graph"  : "--base 1000 -l 0",
56                 "oid"   : ".1.3.6.1.4.1.18928.1.2.2.1.10"
57         }
58 }
59
60 # Sanity check and parsing of the commandline
61 host = None
62 port = 161
63 request = None
64 try:
65         match = re.search("^(?:|.*\/)snmp_([^_]+)_areca_(.+)$", sys.argv[0])
66         host = match.group(1)
67         request =  match.group(2)
68         match = re.search("^([^:]+):(\d+)$", host)
69         if match is not None:
70                 host = match.group(1)
71                 port = match.group(2)
72 except:
73         pass
74
75 if host is None or request is None:
76         print "# Error: Incorrect filename. Cannot parse host or request."
77         sys.exit(1)
78
79 # Parse env variables
80 if os.getenv("community") is not None:
81         community = os.getenv("community")
82 else:
83         community = "public"
84 if os.getenv("version") is not None:
85         version = os.getenv("version")
86 else:
87         version = "1"
88
89
90 def get_data():
91         # Fetch the data
92         results = snmpwalk(request_conf[request]["oid"])
93
94         # parse data
95         vals = []
96         for i in range(0, len(results)):
97                 idx, res = results[i][0].split(request_conf[request]["oid"])[1].split(".")[1:], results[i][1]
98                 if idx[1] == '1':
99                         vals.append([])
100                         vals[int(idx[2])-1].append(res)
101                 if idx[1] == '2':
102                         vals[int(idx[2])-1].append(res)
103                 if idx[1] == '3':
104                         if request == "volt":
105                                 res = float(res)/1000
106                         vals[int(idx[2])-1].append(res)
107
108         return vals
109
110 def snmpwalk(root):
111
112         # Create SNMP manager object
113         client = role.manager((host, port))
114
115         # Create a SNMP request&response objects from protocol version
116         # specific module.
117         try:
118                 req = eval('v' + version).GETREQUEST()
119                 nextReq = eval('v' + version).GETNEXTREQUEST()
120                 rsp = eval('v' + version).GETRESPONSE()
121
122         except (NameError, AttributeError):
123                 print '# Unsupported SNMP protocol version: %s\n%s' % (version, usage)
124                 sys.exit(-1)
125
126         # Store tables headers
127         head_oids = [root]
128
129         encoded_oids = map(asn1.OBJECTID().encode, head_oids)
130
131         result = [];
132
133         while 1:
134
135                 # Encode OIDs, encode SNMP request message and try to send
136                 # it to SNMP agent and receive a response
137                 (answer, src) = client.send_and_receive(req.encode(community=community, encoded_oids=encoded_oids))
138
139                 # Decode SNMP response
140                 rsp.decode(answer)
141        
142                 # Make sure response matches request (request IDs, communities, etc)
143                 if req != rsp:
144                         raise 'Unmatched response: %s vs %s' % (str(req), str(rsp))
145
146                 # Decode BER encoded Object IDs.
147                 oids = map(lambda x: x[0], map(asn1.OBJECTID().decode, rsp['encoded_oids']))
148
149                 # Decode BER encoded values associated with Object IDs.
150                 vals = map(lambda x: x[0](), map(asn1.decode, rsp['encoded_vals']))
151
152                 # Check for remote SNMP agent failure
153                 if rsp['error_status']:
154                         # SNMP agent reports 'no such name' when walk is over
155                         if rsp['error_status'] == 2:
156                                 # Switch over to GETNEXT req on error
157                                 # XXX what if one of multiple vars fails?
158                                 if not (req is nextReq):
159                                         req = nextReq
160                                         continue
161                                 # One of the tables exceeded
162                                 for l in oids, vals, head_oids:
163                                         del l[rsp['error_index']-1]
164                         else:
165                                 raise 'SNMP error #' + str(rsp['error_status']) + ' for OID #' + str(rsp['error_index'])
166
167                 # Exclude completed OIDs
168                 while 1:
169                         for idx in range(len(head_oids)):
170                                 if not asn1.OBJECTID(head_oids[idx]).isaprefix(oids[idx]):
171                                         # One of the tables exceeded
172                                         for l in oids, vals, head_oids:
173                                                 del l[idx]
174                                         break
175                         else:
176                                 break
177
178                 if not head_oids:
179                         return result
180
181                 # Print out results
182                 for (oid, val) in map(None, oids, vals):
183                         result.append((oid, str(val)))
184                         # print oid + ' ---> ' + str(val)
185
186                 # BER encode next SNMP Object IDs to query
187                 encoded_oids = map(asn1.OBJECTID().encode, oids)
188
189                 # Update request object
190                 req['request_id'] = req['request_id'] + 1
191
192                 # Switch over GETNEXT PDU for if not done
193                 if not (req is nextReq):
194                         req = nextReq
195
196         raise "error"
197
198
199 def print_config():
200         print "graph_title " + request_conf[request]["label"]
201         print "graph_vlabel " + request_conf[request]["vlabel"]
202         print "graph_args " + request_conf[request]["graph"]
203         print "graph_category sensors"
204         print "host_name", host
205         for dataset in get_data():
206                 if request == "volt":
207                         if dataset[1] == "Battery Status":
208                                 continue
209                         else:
210                                 print request + dataset[0] + ".label", dataset[1]
211                                 ref_val = float(dataset[1].split()[-1][:-1])
212                                 print request + dataset[0] + ".warning", str(ref_val * 0.95) + ":" + str(ref_val * 1.05)
213                                 print request + dataset[0] + ".critical", str(ref_val * 0.80) + ":" + str(ref_val * 1.20)
214                 if request == "temp":
215                         print request + dataset[0] + ".label", dataset[1]
216                         if dataset[1].startswith("CPU"):
217                                 print request + dataset[0] + ".warning", 55
218                                 print request + dataset[0] + ".critical", 60
219                         if dataset[1].startswith("System"):
220                                 print request + dataset[0] + ".warning", 40
221                                 print request + dataset[0] + ".critical", 45
222                 if request == "fan":
223                         print request + dataset[0] + ".label", dataset[1]
224                         print request + dataset[0] + ".warning", 2400
225                         print request + dataset[0] + ".critical", 2000
226
227         sys.exit(0)
228
229
230 if "config" in sys.argv[1:]:
231         print_config()
232 elif "snmpconf" in sys.argv[1:]:
233         print "require 1.3.6.1.4.1.18928.1.2.2.1.8.1.1"
234         sys.exit(0)
235 else:
236         for dataset in get_data():
237                 # Filter Battery Status (255 == Not installed)
238                 if request == "volt" and dataset[1] == "Battery Status":
239                         continue
240                 print request + dataset[0] + ".value", dataset[2]
241         sys.exit(0)
Note: See TracBrowser for help on using the browser.