]> arthur.barton.de Git - netdata.git/blob - node.d/snmp.node.js
added a new element on all charts: context, which is the template upon the chart...
[netdata.git] / node.d / snmp.node.js
1 'use strict';
2
3 // This program will connect to one or more SNMP Agents
4
5 // example configuration in /etc/netdata/snmp.conf
6 /*
7 {
8         "enable_autodetect": false,
9         "update_every": 5,
10         "servers": [
11                 {
12                         "hostname": "10.11.12.8",
13                         "community": "public",
14                         "update_every": 10,
15                         "options": { "timeout": 10000 },
16                         "charts": {
17                                 "snmp_switch.bandwidth_port1": {
18                                         "title": "Switch Bandwidth for port 1",
19                                         "units": "kilobits/s",
20                                         "type": "area",
21                                         "priority": 1,
22                                         "dimensions": {
23                                                 "in": {
24                                                         "oid": "1.3.6.1.2.1.2.2.1.10.1",
25                                                         "algorithm": "incremental",
26                                                         "multiplier": 8,
27                                                         "divisor": 1024
28                                                 },
29                                                 "out": {
30                                                         "oid": "1.3.6.1.2.1.2.2.1.16.1",
31                                                         "algorithm": "incremental",
32                                                         "multiplier": -8,
33                                                         "divisor": 1024
34                                                 }
35                                         }
36                                 },
37                                 "snmp_switch.bandwidth_port2": {
38                                         "title": "Switch Bandwidth for port 2",
39                                         "units": "kilobits/s",
40                                         "type": "area",
41                                         "priority": 1,
42                                         "dimensions": {
43                                                 "in": {
44                                                         "oid": "1.3.6.1.2.1.2.2.1.10.2",
45                                                         "algorithm": "incremental",
46                                                         "multiplier": 8,
47                                                         "divisor": 1024
48                                                 },
49                                                 "out": {
50                                                         "oid": "1.3.6.1.2.1.2.2.1.16.2",
51                                                         "algorithm": "incremental",
52                                                         "multiplier": -8,
53                                                         "divisor": 1024
54                                                 }
55                                         }
56                                 }
57                         }
58                 }
59         ]
60 }
61 */
62
63 // You can also give ranges of charts like the following.
64 // This will append 1-24 to id, title, oid (on each dimension)
65 // so that 24 charts will be created.
66 /*
67 {
68         "enable_autodetect": false,
69         "update_every": 10,
70         "servers": [
71                 {
72                         "hostname": "10.11.12.8",
73                         "community": "public",
74                         "update_every": 10,
75                         "options": { "timeout": 20000 },
76                         "charts": {
77                                 "snmp_switch.bandwidth_port": {
78                                         "title": "Switch Bandwidth for port ",
79                                         "units": "kilobits/s",
80                                         "type": "area",
81                                         "priority": 1,
82                                         "multiply_range": [ 1, 24 ],
83                                         "dimensions": {
84                                                 "in": {
85                                                         "oid": "1.3.6.1.2.1.2.2.1.10",
86                                                         "algorithm": "incremental",
87                                                         "multiplier": 8,
88                                                         "divisor": 1024
89                                                 },
90                                                 "out": {
91                                                         "oid": "1.3.6.1.2.1.2.2.1.16",
92                                                         "algorithm": "incremental",
93                                                         "multiplier": -8,
94                                                         "divisor": 1024
95                                                 }
96                                         }
97                                 }
98                         }
99                 }
100         ]
101 }
102 */
103
104 var net_snmp = require('net-snmp');
105 var extend = require('extend');
106 var netdata = require('netdata');
107
108 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
109
110 netdata.processors.snmp = {
111         name: 'snmp',
112
113         process: function(service, callback) {
114                 if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
115                         // this is the first time we see this service
116
117                         if(netdata.options.DEBUG === true)
118                                 netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
119
120                         // build an index of all OIDs
121                         service.snmp_oids_index = {};
122                         for(var c in service.request.charts) {
123                                 // for each chart
124
125                                 if(netdata.options.DEBUG === true)
126                                         netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
127
128                                 for(var d in service.request.charts[c].dimensions) {
129                                         // for each dimension in the chart
130
131                                         if(netdata.options.DEBUG === true)
132                                                 netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + service.request.charts[c].dimensions[d].oid);
133
134                                         // link it to the point we need to set the value to
135                                         service.snmp_oids_index[service.request.charts[c].dimensions[d].oid] = service.request.charts[c].dimensions[d];
136
137                                         // and set the value to null
138                                         service.request.charts[c].dimensions[d].value = null;
139                                 }
140                         }
141                         if(netdata.options.DEBUG === true)
142                                 netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
143
144                         // now create the array of OIDs needed by net-snmp
145                         service.snmp_oids = new Array();
146                         for(var o in service.snmp_oids_index)
147                                 service.snmp_oids.push(o);
148
149                         if(netdata.options.DEBUG === true)
150                                 netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
151                 }
152
153                 if(service.snmp_oids.length === 0) {
154                         // no OIDs found for this service
155
156                         if(netdata.options.DEBUG === true)
157                                 service.error('no OIDs to process.');
158
159                         callback(null);
160                         return;
161                 }
162
163                 if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
164                         // no SNMP session has been created for this service
165                         // the SNMP session is just the initialization of NET-SNMP
166
167                         if(netdata.options.DEBUG === true)
168                                 netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
169
170                         // create the SNMP session
171                         service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
172
173                         if(netdata.options.DEBUG === true)
174                                 netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
175
176                         // if we later need traps, this is how to do it:
177                         //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
178                         //      if(error) console.error('trap error: ' + netdata.stringify(error));
179                         //});
180                 }
181
182                 // do it, get the SNMP values for the sessions we need
183                 service.snmp_session.get(service.snmp_oids, function(error, varbinds) {
184                         var ok = 0, failed = 0;
185
186                         if(error) {
187                                 service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
188
189                                 // make all values null
190                                 var len = service.snmp_oids.length;
191                                 while(len--)
192                                         service.snmp_oids_index[service.snmp_oids[len]].value = null;
193                         }
194                         else {
195                                 if(netdata.options.DEBUG === true)
196                                         netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
197
198                                 for(var i = 0; i < varbinds.length; i++) {
199                                         if(net_snmp.isVarbindError(varbinds[i])) {
200                                                 if(netdata.options.DEBUG === true)
201                                                         netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
202
203                                                 service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
204                                                 service.snmp_oids_index[varbinds[i].oid].value = null;
205                                                 failed++;
206                                         }
207                                         else {
208                                                 if(netdata.options.DEBUG === true)
209                                                         netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
210
211                                                 service.snmp_oids_index[varbinds[i].oid].value = varbinds[i].value;
212                                                 ok++;
213                                         }
214                                 }
215
216                                 if(netdata.options.DEBUG === true)
217                                         netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
218                         }
219                         
220                         callback((ok > 0)?{ ok: ok, failed: failed }:null);
221                 });
222         }
223 };
224
225 var snmp = {
226         name: __filename,
227         enable_autodetect: true,
228         update_every: 1,
229         base_priority: 50000,
230
231         charts: {},
232
233         processResponse: function(service, data) {
234                 if(data !== null) {
235                         if(service.added !== true)
236                                 service.commit();
237
238                         for(var c in service.request.charts) {
239                                 var chart = snmp.charts[c];
240
241                                 if(typeof chart === 'undefined') {
242                                         chart = service.chart(c, service.request.charts[c]);
243                                         snmp.charts[c] = chart;
244                                 }
245
246                                 service.begin(chart);
247                                 
248                                 for( var d in service.request.charts[c].dimensions )
249                                         if(service.request.charts[c].dimensions[d].value !== null)
250                                                 service.set(d, service.request.charts[c].dimensions[d].value);
251
252                                 service.end();
253                         }
254                 }
255         },
256
257         // module.serviceExecute()
258         // this function is called only from this module
259         // its purpose is to prepare the request and call
260         // netdata.serviceExecute()
261         serviceExecute: function(conf) {
262                 if(netdata.options.DEBUG === true)
263                         netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
264
265                 var service = netdata.service({
266                         name: conf.hostname,
267                         request: conf,
268                         update_every: conf.update_every,
269                         module: this,
270                         processor: netdata.processors.snmp
271                 });
272
273                 // multiply the charts, if required
274                 for(var c in service.request.charts) {
275                         if(netdata.options.DEBUG === true)
276                                 netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
277
278                         if(typeof service.request.charts[c].update_every === 'undefined')
279                                 service.request.charts[c].update_every = service.update_every;
280
281                         if(typeof service.request.charts[c].multiply_range !== 'undefined') {
282                                 var from = service.request.charts[c].multiply_range[0];
283                                 var to = service.request.charts[c].multiply_range[1];
284                                 var prio = service.request.charts[c].priority || 1;
285
286                                 if(prio < snmp.base_priority) prio += snmp.base_priority;
287
288                                 while(from <= to) {
289                                         var id = c + from.toString();
290                                         var chart = extend(true, {}, service.request.charts[c]);
291                                         chart.title += from.toString();
292                                         chart.priority = prio++;
293                                         for(var d in chart.dimensions) {
294                                                 chart.dimensions[d].oid += '.' + from.toString();
295                                         }
296                                         service.request.charts[id] = chart;
297                                         from++;
298                                 }
299
300                                 delete service.request.charts[c];
301                         }
302                 }
303
304                 service.execute(this.processResponse);
305         },
306
307         configure: function(config) {
308                 var added = 0;
309
310                 if(typeof(config.servers) !== 'undefined') {
311                         var len = config.servers.length;
312                         while(len--) {
313                                 if(typeof config.servers[len].update_every === 'undefined')
314                                         config.servers[len].update_every = this.update_every;
315
316                                 this.serviceExecute(config.servers[len]);
317                                 added++;
318                         }
319                 }
320
321                 return added;
322         },
323
324         // module.update()
325         // this is called repeatidly to collect data, by calling
326         // service.execute()
327         update: function(service, callback) {
328                 service.execute(function(serv, data) {
329                         service.module.processResponse(serv, data);
330                         callback();
331                 });
332         },
333 };
334
335 module.exports = snmp;