]> arthur.barton.de Git - netdata.git/blob - node.d/snmp.node.js
universal node.js shebang; snmp.node.js now appends range id without adding a dot
[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         fixoid: function(oid) {
114                 if(oid.charAt(0) === '.')
115                         return oid.substring(1, oid.length);
116
117                 return oid;
118         },
119
120         process: function(service, callback) {
121                 if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
122                         // this is the first time we see this service
123
124                         if(netdata.options.DEBUG === true)
125                                 netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
126
127                         // build an index of all OIDs
128                         service.snmp_oids_index = {};
129                         for(var c in service.request.charts) {
130                                 // for each chart
131
132                                 if(netdata.options.DEBUG === true)
133                                         netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
134
135                                 for(var d in service.request.charts[c].dimensions) {
136                                         // for each dimension in the chart
137
138                                         var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
139                                         
140                                         if(netdata.options.DEBUG === true)
141                                                 netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid);
142
143                                         // link it to the point we need to set the value to
144                                         service.snmp_oids_index[oid] = service.request.charts[c].dimensions[d];
145
146                                         // and set the value to null
147                                         service.request.charts[c].dimensions[d].value = null;
148                                 }
149                         }
150                         if(netdata.options.DEBUG === true)
151                                 netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
152
153                         // now create the array of OIDs needed by net-snmp
154                         service.snmp_oids = new Array();
155                         for(var o in service.snmp_oids_index)
156                                 service.snmp_oids.push(o);
157
158                         if(netdata.options.DEBUG === true)
159                                 netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
160                 }
161
162                 if(service.snmp_oids.length === 0) {
163                         // no OIDs found for this service
164
165                         if(netdata.options.DEBUG === true)
166                                 service.error('no OIDs to process.');
167
168                         callback(null);
169                         return;
170                 }
171
172                 if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
173                         // no SNMP session has been created for this service
174                         // the SNMP session is just the initialization of NET-SNMP
175
176                         if(netdata.options.DEBUG === true)
177                                 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));
178
179                         // create the SNMP session
180                         service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
181
182                         if(netdata.options.DEBUG === true)
183                                 netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
184
185                         // if we later need traps, this is how to do it:
186                         //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
187                         //      if(error) console.error('trap error: ' + netdata.stringify(error));
188                         //});
189                 }
190
191                 // do it, get the SNMP values for the sessions we need
192                 service.snmp_session.get(service.snmp_oids, function(error, varbinds) {
193                         var ok = 0, failed = 0;
194
195                         if(error) {
196                                 service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
197
198                                 // make all values null
199                                 var len = service.snmp_oids.length;
200                                 while(len--)
201                                         service.snmp_oids_index[service.snmp_oids[len]].value = null;
202                         }
203                         else {
204                                 if(netdata.options.DEBUG === true)
205                                         netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
206
207                                 for(var i = 0; i < varbinds.length; i++) {
208                                         if(net_snmp.isVarbindError(varbinds[i])) {
209                                                 if(netdata.options.DEBUG === true)
210                                                         netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
211
212                                                 service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
213                                                 service.snmp_oids_index[varbinds[i].oid].value = null;
214                                                 failed++;
215                                         }
216                                         else {
217                                                 if(netdata.options.DEBUG === true)
218                                                         netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
219
220                                                 service.snmp_oids_index[varbinds[i].oid].value = varbinds[i].value;
221                                                 ok++;
222                                         }
223                                 }
224
225                                 if(netdata.options.DEBUG === true)
226                                         netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
227                         }
228                         
229                         callback((ok > 0)?{ ok: ok, failed: failed }:null);
230                 });
231         }
232 };
233
234 var snmp = {
235         name: __filename,
236         enable_autodetect: true,
237         update_every: 1,
238         base_priority: 50000,
239
240         charts: {},
241
242         processResponse: function(service, data) {
243                 if(data !== null) {
244                         if(service.added !== true)
245                                 service.commit();
246
247                         for(var c in service.request.charts) {
248                                 var chart = snmp.charts[c];
249
250                                 if(typeof chart === 'undefined') {
251                                         chart = service.chart(c, service.request.charts[c]);
252                                         snmp.charts[c] = chart;
253                                 }
254
255                                 service.begin(chart);
256                                 
257                                 for( var d in service.request.charts[c].dimensions )
258                                         if(service.request.charts[c].dimensions[d].value !== null)
259                                                 service.set(d, service.request.charts[c].dimensions[d].value);
260
261                                 service.end();
262                         }
263                 }
264         },
265
266         // module.serviceExecute()
267         // this function is called only from this module
268         // its purpose is to prepare the request and call
269         // netdata.serviceExecute()
270         serviceExecute: function(conf) {
271                 if(netdata.options.DEBUG === true)
272                         netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
273
274                 var service = netdata.service({
275                         name: conf.hostname,
276                         request: conf,
277                         update_every: conf.update_every,
278                         module: this,
279                         processor: netdata.processors.snmp
280                 });
281
282                 // multiply the charts, if required
283                 for(var c in service.request.charts) {
284                         if(netdata.options.DEBUG === true)
285                                 netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
286
287                         if(typeof service.request.charts[c].update_every === 'undefined')
288                                 service.request.charts[c].update_every = service.update_every;
289
290                         if(typeof service.request.charts[c].multiply_range !== 'undefined') {
291                                 var from = service.request.charts[c].multiply_range[0];
292                                 var to = service.request.charts[c].multiply_range[1];
293                                 var prio = service.request.charts[c].priority || 1;
294
295                                 if(prio < snmp.base_priority) prio += snmp.base_priority;
296
297                                 while(from <= to) {
298                                         var id = c + from.toString();
299                                         var chart = extend(true, {}, service.request.charts[c]);
300                                         chart.title += from.toString();
301                                         chart.priority = prio++;
302                                         for(var d in chart.dimensions) {
303                                                 chart.dimensions[d].oid += from.toString();
304                                         }
305                                         service.request.charts[id] = chart;
306                                         from++;
307                                 }
308
309                                 delete service.request.charts[c];
310                         }
311                 }
312
313                 service.execute(this.processResponse);
314         },
315
316         configure: function(config) {
317                 var added = 0;
318
319                 if(typeof(config.servers) !== 'undefined') {
320                         var len = config.servers.length;
321                         while(len--) {
322                                 if(typeof config.servers[len].update_every === 'undefined')
323                                         config.servers[len].update_every = this.update_every;
324
325                                 this.serviceExecute(config.servers[len]);
326                                 added++;
327                         }
328                 }
329
330                 return added;
331         },
332
333         // module.update()
334         // this is called repeatidly to collect data, by calling
335         // service.execute()
336         update: function(service, callback) {
337                 service.execute(function(serv, data) {
338                         service.module.processResponse(serv, data);
339                         callback();
340                 });
341         },
342 };
343
344 module.exports = snmp;