Ticket #7167: munin-node

File munin-node, 20.1 KB (added by L.Schmidt <l.openwrt at scarydevilmonastery.net>, 7 years ago)

whole script, 1.0.2b - added volume usage graphs, performance gains. selection of if_ and netstat depends on presence of required executables.

Line 
1#!/bin/sh
2#
3# Simple Bourne Shell script that implements Munin protocoll and
4# some common Linux plugins.
5#
6# For latest version, see http://muninlite.sf.net/
7#
8# Copyright (c) 2007 Rune Nordbøe Skillingstad <rune@skillingstad.no>
9#
10# Licensed under GPLv2 (see LICENSE file for full License)
11#
12# $Id: $
13#
14
15VERSION="1.0.2b"
16# 2010apr10, L.Schmidt (bushmills.openwrt@scarydevilmonastery.net)
17#    added graphs for used/remaining device storage space.
18#    fixed if bug which caused munin_limits to flood admin with error emails
19#    fetch_cpu speedup
20#    netstat if_ if_err_ plugins selection by presence of required netstat and ethtool programs
21#    (busybox version of netstat has no --statistics switch which is used here)
22#    changed many "grep ... | cut ..." against  "awk /.../ {print ..}"  because latter is about 50% faster
23
24
25
26netstat=$(which netstat)
27ethtool=$(which ethtool)
28
29# Remove unwanted plugins from this list
30PLUGINS="df_ cpu load memory processes uptime interrupts irqstats"
31
32# netstat doesn't work with busybox netstat - needs net-tools netstat
33# assume that if /bin/netstat is executable and not a link, that a proper ethtool is installed,
34# in which case plugin netstat is added:
35if [ -x $netstat -a ! -h $netstat ]; then
36   PLUGINS="netstat $PLUGINS"
37fi
38
39# if_ needs ethtool.
40if [ -x $ethtool ]; then
41   PLUGINS="if_err_ if_ $PLUGINS"
42fi
43
44# ===== PLUGINS CODE =====
45
46config_cpu() {
47  extinfo=""
48  if grep '^cpu \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\}' /proc/stat >/dev/null 2>&1; then
49    extinfo="iowait irq softirq"
50  fi
51  NCPU=$(($(grep '^cpu. ' /proc/stat | wc -l) - 1))
52  PERCENT=$(($NCPU * 100))
53  graphlimit=$PERCENT
54  SYSWARNING=$(($PERCENT * 30 / 100))
55  SYSCRITICAL=$(($PERCENT * 50 / 100))
56  USRWARNING=$(($PERCENT * 80 / 100))
57echo "graph_title CPU usage
58graph_order system user nice idle $extinfo
59graph_args --base 1000 -r --lower-limit 0 --upper-limit $graphlimit
60graph_vlabel %
61graph_scale no
62graph_info This graph shows how CPU time is spent.
63graph_category system
64graph_period second
65system.label system
66system.draw AREA
67system.max 5000
68system.min 0
69system.type DERIVE
70system.warning $SYSWARNING
71system.critical $SYSCRITICAL
72system.info CPU time spent by the kernel in system activities
73user.label user
74user.draw STACK
75user.min 0
76user.max 5000
77user.warning $USRWARNING
78user.type DERIVE
79user.info CPU time spent by normal programs and daemons
80nice.label nice
81nice.draw STACK
82nice.min 0
83nice.max 5000
84nice.type DERIVE
85nice.info CPU time spent by nice(1)d programs
86idle.label idle
87idle.draw STACK
88idle.min 0
89idle.max 5000
90idle.type DERIVE
91idle.info Idle CPU time"
92if [ ! -z "$extinfo" ]; then
93echo "iowait.label iowait
94iowait.draw STACK
95iowait.min 0
96iowait.max 5000
97iowait.type DERIVE
98iowait.info CPU time spent waiting for I/O operations to finish
99irq.label irq
100irq.draw STACK
101irq.min 0
102irq.max 5000
103irq.type DERIVE
104irq.info CPU time spent handling interrupts
105softirq.label softirq
106softirq.draw STACK
107softirq.min 0
108softirq.max 5000
109softirq.type DERIVE
110softirq.info CPU time spent handling \"batched\" interrupts"
111fi
112}
113
114fetch_cpu() {
115  extinfo=""
116  if grep '^cpu \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\} \{1,\}[0-9]\{1,\}' /proc/stat >/dev/null 2>&1; then
117    extinfo="iowait irq softirq"
118  fi
119i=0
120for reading in $(grep '^cpu ' /proc/stat | cut -c6-); do
121  let reading$i=$reading
122  i=$((i+1))
123done
124cat << EOF
125user.value $reading0
126nice.value $reading1
127system.value $reading2
128idle.value $reading3
129EOF
130if [ ! -z "$extinfo" ]; then
131cat << EOF
132iowait.value $reading4
133irq.value $reading5
134softirq.value $reading6
135EOF
136fi
137}
138
139# volume passed as $1
140# /dev/volume passed as $2
141config_df() {
142echo "graph_title $1
143graph_vlabel capacity
144graph_category system
145storageused_$1.label used $1
146storageused_$1.draw AREA
147storagefree_$1.label free $1
148storagefree_$1.draw STACK"
149}
150
151fetch_df() {
152   mountpoint=$(grep -m1 ^$2</proc/mounts|cut -d\  -f2)
153   df $mountpoint|grep ^$2|awk "{print \"storageused_$1.value \" \$3*1024 \"\nstoragefree_$1.value \" \$4*1024}"
154}
155
156
157config_if() {
158echo "graph_order down up
159graph_title $1 traffic
160graph_args --base 1000
161graph_vlabel bits in (-) / out (+) per \${graph_period}
162graph_category network
163graph_info This graph shows the traffic of the $INTERFACE network interface. Please note that the traffic is shown in bits per second, not bytes. IMPORTANT: Since the data source for this plugin use 32bit counters, this plugin is really unreliable and unsuitable for most 100Mb (or faster) interfaces, where bursts are expected to exceed 50Mbps. This means that this plugin is usuitable for most production environments. To avoid this problem, use the ip_ plugin instead.
164down.label received
165down.type DERIVE
166down.min 0
167down.graph no
168down.cdef down,8,*
169up.label bps
170up.type DERIVE
171up.min 0
172up.negative down
173up.cdef up,8,*"
174  if $ethtool $1 2> /dev/null | grep -q Speed; then
175    MAX=$(($($ethtool $1 | grep Speed | sed -e 's/[[:space:]]\{1,\}/ /g' -e 's/^ //' -e 's/M.*//' | cut -d\  -f2) * 1000000))
176    echo "up.max $MAX"
177    echo "down.max $MAX"
178  fi
179}
180fetch_if() {
181  IINFO=$(grep "$1:" /proc/net/dev | cut -d: -f2 | sed -e 's/  / /g')
182  echo "down.value" $(echo $IINFO | cut -d\  -f1)
183  echo "up.value" $(echo $IINFO | cut -d\  -f9)
184}
185config_if_err() {
186echo "graph_order rcvd trans
187graph_title $1 errors
188graph_args --base 1000
189graph_vlabel packets in (-) / out (+) per \${graph_period}
190graph_category network
191graph_info This graph shows the amount of errors on the $1 network interface.
192rcvd.label packets
193rcvd.type COUNTER
194rcvd.graph no
195rcvd.warning 1
196trans.label packets
197trans.type COUNTER
198trans.negative rcvd
199trans.warning 1"
200}
201fetch_if_err() {
202  IINFO=$(grep "$1:" /proc/net/dev | cut -d: -f2 | sed -e 's/  / /g')
203  echo "rcvd.value" $(echo $IINFO | cut -d\  -f3)
204  echo "trans.value" $(echo $IINFO | cut -d\  -f11)
205}
206
207config_load() {
208echo "graph_title Load average
209graph_args --base 1000 -l 0
210graph_vlabel load
211graph_scale no
212graph_category system
213load.label load
214load.warning 10
215load.critical 120
216graph_info The load average of the machine describes how many processes are in the run-queue (scheduled to run \"immediately\").
217load.info Average load for the five minutes."
218}
219
220fetch_load() {
221  echo "load.value" $(cut -f2 -d\  /proc/loadavg)
222}
223
224config_memory() {
225  MINFO=$(cat /proc/meminfo | sed 's/ \{1,\}/ /g;')
226  MEMTOTAL=$(echo "$MINFO" | awk '/^MemTotal:/  {print $2}')
227  PAGETABLES=$(echo "$MINFO" | awk '/^PageTables:/ {print $2}')
228  SWAPCACHED=$(echo "$MINFO" | awk '/^SwapCached:/  {print $2}')
229  SWAPTOTAL=$(echo "$MINFO" | awk '/^SwapTotal:/  {print $2}')
230  VMALLOCUSED=$(echo "$MINFO" | awk '/^VmallocUsed:/  {print $2}')
231  SLAB=$(echo "$MINFO" | awk '/^Slab:/  {print $2}')
232  MAPPED=$(echo "$MINFO" | awk '/^Mapped:/  {print $2}')
233  COMMITTEDAS=$(echo "$MINFO" | awk '/^Committed_AS:/  {print $2}')
234  ACTIVE=$(echo "$MINFO" | awk '/^Active:/  {print $2}')
235  INACTIVE=$(echo "$MINFO" | awk '/^Inactive:/  {print $2}')
236  ACTIVEANON=$(echo "$MINFO" | awk '/^ActiveAnon:/  {print $2}')
237  ACTIVECACHE=$(echo "$MINFO" | awk '/^ActiveCache:/  {print $2}')
238  INACTIVE=$(echo "$MINFO" | awk '/^Inactive:/  {print $2}')
239  INACTDIRTY=$(echo "$MINFO" | awk '/^Inact_dirty:/  {print $2}')
240  INACTLAUNDY=$(echo "$MINFO" | awk '/^Inact_laundry:/  {print $2}')
241  INACTCLEAN=$(echo "$MINFO" | awk '/^Inact_clean:/  {print $2}')
242
243  GRAPH_ORDER="apps";
244  test "$PAGETABLES" != "" && GRAPH_ORDER="$GRAPH_ORDER page_tables"
245  test "$SWAPCACHED" != "" && GRAPH_ORDER="$GRAPH_ORDER swap_cache"
246  test "$VMALLOCUSED" != "" && GRAPH_ORDER="$GRAPH_ORDER vmalloc_used"
247  test "$SLAB" != "" && GRAPH_ORDER="$GRAPH_ORDER slab"
248  GRAPH_ORDER="$GRAPH_ORDER cached buffers free swap"
249
250echo "graph_args --base 1024 -l 0 --vertical-label Bytes --upper-limit $MEMTOTAL
251graph_title Memory usage
252graph_category system
253graph_info This graph shows what the machine uses its memory for.
254graph_order $GRAPH_ORDER
255apps.label apps
256apps.draw AREA
257apps.info Memory used by user-space applications.
258buffers.label buffers
259buffers.draw STACK
260buffers.info Block device (e.g. harddisk) cache. Also where \"dirty\" blocks are stored until written.
261swap.label swap
262swap.draw STACK
263swap.info Swap space used.
264cached.label cache
265cached.draw STACK
266cached.info Parked file data (file content) cache.
267free.label unused
268free.draw STACK
269free.info Wasted memory. Memory that is not used for anything at all."
270  if [ "$SLAB" != "" ]; then
271    echo "slab.label slab_cache"
272    echo "slab.draw STACK"
273    echo "slab.info Memory used by the kernel (major users are caches like inode, dentry, etc)."
274  fi
275  if [ "$SWAPCACHED" != "" ]; then
276    echo "swap_cache.label swap_cache"
277    echo "swap_cache.draw STACK"
278    echo "swap_cache.info A piece of memory that keeps track of pages that have been fetched from swap but not yet been modified."
279  fi
280  if [ "$PAGETABLES" != "" ]; then
281    echo "page_tables.label page_tables"
282    echo "page_tables.draw STACK"
283    echo "page_tables.info Memory used to map between virtual and physical memory addresses.\n"
284  fi
285  if [ "$VMALLOCUSED" != "" ]; then
286    echo "vmalloc_used.label vmalloc_used"
287    echo "vmalloc_used.draw STACK"
288    echo "vmalloc_used.info Virtual memory used by the kernel (used when the memory does not have to be physically contigious)."
289  fi
290  if [ "$COMMITTEDAS" != "" ]; then
291    echo "committed.label committed"
292    echo "committed.draw LINE2"
293    echo "committed.warn" $(($SWAPTOTAL + $MEMTOTAL))
294    echo "committed.info The amount of memory that would be used if all the memory that's been allocated were to be used."
295  fi
296  if [ "$MAPPED" != "" ]; then
297    echo "mapped.label mapped"
298    echo "mapped.draw LINE2"
299    echo "mapped.info All mmap()ed pages."
300  fi
301  if [ "$ACTIVE" != "" ]; then
302    echo "active.label active"
303    echo "active.draw LINE2"
304    echo "active.info Memory recently used. Not reclaimed unless absolutely necessary."
305  fi
306  if [ "$ACTIVEANON" != "" ]; then
307    echo "active_anon.label active_anon"
308    echo "active_anon.draw LINE1"
309  fi
310  if [ "$ACTIVECACHE" != "" ]; then
311    echo "active_cache.label active_cache"
312    echo "active_cache.draw LINE1"
313  fi
314  if [ "$INACTIVE" != "" ]; then
315    echo "inactive.label inactive"
316    echo "inactive.draw LINE2"
317    echo "inactive.info Memory not currently used."
318  fi
319  if [ "$INACTDIRTY" != "" ]; then
320    echo "inact_dirty.label inactive_dirty"
321    echo "inact_dirty.draw LINE1"
322    echo "inact_dirty.info Memory not currently used, but in need of being written to disk."
323  fi
324  if [ "$INACTLAUNDRY" != "" ]; then
325    echo "inact_laundry.label inactive_laundry"
326    echo "inact_laundry.draw LINE1"
327  fi
328  if [ "$INACTCLEAN" != "" ]; then
329    echo "inact_clean.label inactive_clean"
330    echo "inact_clean.draw LINE1"
331    echo "inact_clean.info Memory not currently used."
332  fi
333}
334fetch_memory() {
335  MINFO=$(cat /proc/meminfo | sed 's/ \{1,\}/ /g;')
336  MEMTOTAL=$(echo "$MINFO" | awk '/^MemTotal:/  {print $2}')
337  MEMFREE=$(echo "$MINFO" | awk '/^MemFree:/  {print $2}')
338  BUFFERS=$(echo "$MINFO" | awk '/^Buffers:/  {print $2}')
339  CACHED=$(echo "$MINFO" | awk '/^Cached:/  {print $2}')
340  SWAP_TOTAL=$(echo "$MINFO" | awk '/^SwapTotal:/  {print $2}')
341  SWAP_FREE=$(echo "$MINFO" | awk '/^SwapFree:/  {print $2}')
342  MEMTOTAL=$(echo "$MINFO" | awk '/^MemTotal:/  {print $2}')
343  PAGETABLES=$(echo "$MINFO" | awk '/^PageTables:/ {print $2}')
344  SWAPCACHED=$(echo "$MINFO" | awk '/^SwapCached:/  {print $2}')
345  VMALLOCUSED=$(echo "$MINFO" | awk '/^VmallocUsed:/  {print $2}')
346  SLAB=$(echo "$MINFO" | awk '/^Slab:/  {print $2}')
347  MAPPED=$(echo "$MINFO" | awk '/^Mapped:/  {print $2}')
348  COMMITTEDAS=$(echo "$MINFO" | awk '/^Committed_AS:/  {print $2}')
349  ACTIVE=$(echo "$MINFO" | awk '/^Active:/  {print $2}')
350  INACTIVE=$(echo "$MINFO" | awk '/^Inactive:/  {print $2}')
351  ACTIVEANON=$(echo "$MINFO" | awk '/^ActiveAnon:/  {print $2}')
352  ACTIVECACHE=$(echo "$MINFO" | awk '/^ActiveCache:/  {print $2}')
353  INACTIVE=$(echo "$MINFO" | awk '/^Inactive:/  {print $2}')
354  INACTDIRTY=$(echo "$MINFO" | awk '/^Inact_dirty:/  {print $2}')
355  INACTLAUNDY=$(echo "$MINFO" | awk '/^Inact_laundry:/  {print $2}')
356  INACTCLEAN=$(echo "$MINFO" | awk '/^Inact_clean:/  {print $2}')
357  APPS=$(($MEMTOTAL - $MEMFREE - $BUFFERS - $CACHED))
358  SWAP=$(($SWAP_TOTAL - $SWAP_FREE))
359  echo "buffers.value" $(($BUFFERS * 1024))
360  echo "swap.value" $(($SWAP * 1024))
361  echo "cached.value" $(($CACHED * 1024))
362  echo "free.value" $(($MEMFREE * 1024))
363  if [ "$SLAB" != "" ]; then
364    echo "slab.value" $(($SLAB * 1024))
365    APPS=$(($APPS - $SLAB))
366  fi
367  if [ "$SWAPCACHED" != "" ]; then
368    echo "swap_cache.value" $(($SWAPCACHED * 1024))
369    APPS=$(($APPS - $SWAPCACHED))
370  fi
371  if [ "$PAGETABLES" != "" ]; then
372    echo "page_tables.value" $(($PAGETABLES * 1024))
373    APPS=$(($APPS - $PAGETABLES))
374  fi
375  if [ "$VMALLOCUSED" != "" ]; then
376    echo "vmalloc_used.value" $(($VMALLOCUSED * 1024))
377    APPS=$(($APPS - $VMALLOCUSED))
378  fi
379  if [ "$COMMITTEDAS" != "" ]; then
380    echo "committed.value" $(($COMMITTEDAS * 1024))
381  fi
382  if [ "$MAPPED" != "" ]; then
383    echo "mapped.value" $(($MAPPED * 1024))
384  fi
385  if [ "$ACTIVE" != "" ]; then
386    echo "active.value" $(($ACTIVE * 1024))
387  fi
388  if [ "$ACTIVEANON" != "" ]; then
389    echo "active_anon.value" $(($ACTIVEANON * 1024))
390  fi
391  if [ "$ACTIVECACHE" != "" ]; then
392    echo "active_cache.value" $(($ACTIVECACHE * 1024))
393  fi
394  if [ "$INACTIVE" != "" ]; then
395    echo "inactive.value" $(($INACTIVE * 1024))
396  fi
397  if [ "$INACTDIRTY" != "" ]; then
398    echo "inact_dirty.value" $(($INACTDIRTY * 1024))
399  fi
400  if [ "$INACTLAUNDRY" != "" ]; then
401    echo "inact_laundry.value" $(($INACTLAUNDRY * 1024))
402  fi
403  if [ "$INACTCLEAN" != "" ]; then
404    echo "inact_clean.value" $(($INACTCLEAN * 1024))
405  fi
406
407  echo "apps.value" $(($APPS * 1024))
408}
409config_processes() {
410  echo "graph_title Number of Processes"
411  echo "graph_args --base 1000 -l 0 "
412  echo "graph_vlabel number of processes"
413  echo "graph_category processes"
414  echo "graph_info This graph shows the number of processes in the system."
415  echo "processes.label processes"
416  echo "processes.draw LINE2"
417  echo "processes.info The current number of processes."
418}
419fetch_processes() {
420  echo "processes.value" $(echo /proc/[0-9]* | wc -w)
421}
422
423config_netstat() {
424  echo "graph_title Netstat"
425  echo "graph_args -l 0 --base 1000"
426  echo "graph_vlabel active connections"
427  echo "graph_category network"
428  echo "graph_period second"
429  echo "graph_info This graph shows the TCP activity of all the network interfaces combined."
430  echo "active.label active"
431  echo "active.type DERIVE"
432  echo "active.max 50000"
433  echo "active.min 0"
434  echo "active.info The number of active TCP openings per second."
435  echo "passive.label passive"
436  echo "passive.type DERIVE"
437  echo "passive.max 50000"
438  echo "passive.min 0"
439  echo "passive.info The number of passive TCP openings per second."
440  echo "failed.label failed"
441  echo "failed.type DERIVE"
442  echo "failed.max 50000"
443  echo "failed.min 0"
444  echo "failed.info The number of failed TCP connection attempts per second."
445  echo "resets.label resets"
446  echo "resets.type DERIVE"
447  echo "resets.max 50000"
448  echo "resets.min 0"
449  echo "resets.info The number of TCP connection resets."
450  echo "established.label established"
451  echo "established.type GAUGE"
452  echo "established.max 50000"
453  echo "established.info The number of currently open connections."
454}
455
456# doesn't work with busybox netstat - needs net-tools netstat
457fetch_netstat() {
458  NINFO=$($netstat -s 2> /dev/null| sed 's/ \{1,\}/ /g')
459  echo "active.value" $(echo "$NINFO" | awk '/active connections/ {print $1}')
460  echo "passive.value" $(echo "$NINFO" | awk '/passive connection/ {print $1}')
461  echo "failed.value" $(echo "$NINFO" | awk '/failed connection/ {print $1}')
462  echo "resets.value" $(echo "$NINFO" | awk '/connection resets/ {print $1}')
463  echo "established.value" $(echo "$NINFO" | awk '/connections established/ {print $1}')
464}
465
466config_uptime() {
467  echo "graph_title Uptime"
468  echo "graph_args --base 1000 -l 0 "
469  echo "graph_vlabel uptime in days"
470  echo "uptime.label uptime"
471  echo "uptime.draw AREA"
472  echo "uptime.cdef uptime,86400,/"
473}
474fetch_uptime() {
475  echo "uptime.value" $(cut -d\  -f1 /proc/uptime)
476}
477config_interrupts() {
478  echo "graph_title Interrupts & context switches"
479  echo "graph_args --base 1000 -l 0"
480  echo "graph_vlabel interrupts & ctx switches / \${graph_period}"
481  echo "graph_category system"
482  echo "graph_info This graph shows the number of interrupts and context switches on the system. These are typically high on a busy system."
483  echo "intr.info Interrupts are events that alter sequence of instructions executed by a processor. They can come from either hardware (exceptions, NMI, IRQ) or software."
484  echo "ctx.info A context switch occurs when a multitasking operatings system suspends the currently running process, and starts executing another."
485  echo "intr.label interrupts"
486  echo "ctx.label context switches"
487  echo "intr.type DERIVE"
488  echo "ctx.type DERIVE"
489  echo "intr.max 100000"
490  echo "ctx.max 100000"
491  echo "intr.min 0"
492  echo "ctx.min 0"
493}
494
495fetch_interrupts() {
496  IINFO=$(cat /proc/stat)
497  echo "ctx.value" $(echo "$IINFO"  | awk '/^ctxt/  {print $2}')
498  echo "intr.value" $(echo "$IINFO" | awk '/^intr/  {print $2}')
499}
500
501config_irqstats() {
502  echo "graph_title Individual interrupts
503graph_args --base 1000 -l 0;
504graph_vlabel interrupts / \${graph_period}
505graph_category system"
506  CPUS=$(grep 'CPU[0-9]' /proc/interrupts | wc -w)
507  IINFO=$(sed -e 's/ \{1,\}/ /g' -e 's/^ //' /proc/interrupts  | grep '.:')
508  for ID in $(echo "$IINFO" | cut -d: -f1)
509  do
510    IDL=$(echo "$IINFO" | grep "^$ID:")
511    INFO=$(eval "echo \"$IDL\" | cut -d\  -f$((3+$CPUS))-")
512    if [ "$INFO" = "" ]; then
513      echo "i$ID.label $ID"
514    else
515      echo "i$ID.label $INFO"
516      echo "i$ID.info Interrupt $ID, for device(s): $INFO"
517    fi
518    echo "i$ID.type DERIVE"
519    echo "i$ID.min 0"
520  done
521}
522
523fetch_irqstats() {
524  CPUS=$(grep 'CPU[0-9]' /proc/interrupts | wc -w)
525  IINFO=$(sed -e 's/ \{1,\}/ /g' -e 's/^ //' /proc/interrupts  | grep '.:')
526  for ID in $(echo "$IINFO" | cut -d: -f1)
527  do
528    IDL=$(echo "$IINFO" | grep "^$ID:")
529    VALS=$(eval "echo \"$IDL\" | cut -d\  -f2-$((1+$CPUS))")
530    VALUE=0
531    for VAL in $VALS;
532    do
533      VALUE=$(($VALUE + $VAL))
534    done
535    echo "i$ID.value $VALUE"
536  done
537}
538
539# ===== NODE CODE =====
540do_list() {
541  echo $PLUGINS
542}
543
544
545do_nodes() {
546  echo "$HOSTNAME"
547  echo "."
548}
549
550do_config() {
551  if echo "$PLUGINS" | grep "\b$1\b" >/dev/null 2>&1; then
552    config_$1
553  else
554    echo "# Unknown service"
555  fi
556  echo "."
557}
558
559do_fetch() {
560  if echo "$PLUGINS" | grep "\b$1\b" >/dev/null 2>&1; then
561    fetch_$1
562  else
563    echo "# Unknown service"
564  fi
565  echo "."
566}
567
568do_version() {
569  echo "munins node on $HOSTNAME version: $VERSION (munin-lite)"
570}
571
572do_quit() {
573  exit 0
574}
575
576# ===== Runtime config =====
577RES=""
578for PLUG in $PLUGINS
579do
580  if [ "$PLUG" = "if_" ]; then 
581    for INTER in $(grep '^ *\(ppp\|eth\|wlan\|ath\|ra\)[0-9]\{1,\}:' /proc/net/dev | cut -f1 -d: | sed 's/ //g');
582    do
583      RES="$RES if_$INTER"
584      eval "fetch_if_${INTER}() { fetch_if $INTER $@; };"
585      eval "config_if_${INTER}() { config_if $INTER $@; };"
586    done
587  elif [ "$PLUG" = "if_err_" ]; then
588    for INTER in $(grep '^ *\(ppp\|eth\|wlan\|ath\|ra\)[0-9]\{1,\}:' /proc/net/dev | cut -f1 -d: | sed 's/ //g');
589    do
590      RES="$RES if_err_$INTER"
591      eval "fetch_if_err_${INTER}() { fetch_if_err $INTER $@; };"
592      eval "config_if_err_${INTER}() { config_if_err $INTER $@; };"
593    done
594  elif [ "$PLUG" = "netstat" ]; then
595    if $netstat -s >/dev/null 2>&1; then
596      RES="$RES netstat"
597    fi
598  elif [ "$PLUG" = "df_" ]; then
599    for dev in $(   awk '/^\/dev/  {print $1}'</proc/mounts|sort -u); do
600      basedev=$(basename $dev)
601      RES="$RES df_$basedev"
602      eval "fetch_df_${basedev}() { fetch_df $basedev $dev $@; };"
603      eval "config_df_${basedev}() { config_df $basedev $dev $@; };"
604    done
605  else
606    RES="$RES $PLUG";
607  fi
608done
609PLUGINS=$RES
610
611# ===== MAIN LOOP =====
612FUNCTIONS="list nodes config fetch version quit"
613HOSTNAME=$(/sbin/uci get "system.@system[0].hostname" 2>/dev/null || cat /proc/sys/kernel/hostname)
614echo "# munin node at $HOSTNAME"
615while read arg0 arg1
616do
617  arg0=$(echo "$arg0" | xargs)
618  arg1=$(echo "$arg1" | xargs) 
619  if ! echo "$FUNCTIONS" | grep "\b$arg0\b" >/dev/null 2>&1 ; then
620    echo "# Unknown command. Try" $(echo "$FUNCTIONS" | sed -e 's/\( [[:alpha:]]\{1,\}\)/,\1/g' -e 's/,\( [[:alpha:]]\{1,\}\)$/ or\1/')
621    continue
622  fi
623  do_$arg0 $arg1
624done 
625