Short description for repo.or.cz.
[snmpsar.git] / snmpsar.sh
blob58905332c30c9709b64e85d4a7b0201418950ed0
1 #!/bin/bash
3 # vi: set softtabstop=4 shiftwidth=4 tabstop=8 expandtab:
5 # Creates logfiles to track the nexthop for a list of dynamic routes.
7 usage()
9 echo "usage: $0 -d logdir -s snmpconffile host1 [host2 [...]]" 1>&2
10 exit 1
13 hosts=
14 outdir=
15 snmpconf=
17 while getopts "d:s:" option
19 case "$option" in
20 d) outdir=$OPTARG ;;
21 s) snmpconf=$OPTARG ;;
22 *) usage ;;
23 esac
24 done
26 shift $((OPTIND-1))
27 hosts="$@"
29 if [ -n "$hosts" ] && [ -n "$outdir" ] && [ -n "$snmpconf" ]
30 then
32 else
33 echo "Missing parameters." 1>&2
34 usage
37 snmpargs=$(cat "$snmpconf") || {
38 echo "Can't read SNMP argument file '$snmpconf'." 1>&2
39 exit 1
42 if [ ! -d "$outdir" ]
43 then
44 echo "Output directory '$outdir' does not exist." 1>&2
45 exit 1
48 filestamp="$(date +%Y-%m-%d)"
49 timestamp="$(date +%H:%M:%S/%s)"
51 get()
53 local host=$1
54 local oid=$2
56 # -Ov: display value only, not OID name
57 # -Oq: display value only, not type
58 val=$(snmpget -Ov -Oq $snmpargs "$host" "$oid" 2>/dev/null) || return 1
60 [ -n "$val" ] || return 1
62 echo "$val" | grep -qi "No Such" && return 1
64 echo "$val"
65 return 0
68 logcpu()
70 local file="$1"
71 local timestamp="$2"
72 local h="$3"
74 # linux: 100 - UCD-SNMP-MIB::ssCpuIdle.0
75 # cisco vpn cpu: alGeneralGaugeCpuUtil (1.3.6.1.4.1.3076.2.1.2.25.1.2.0)
76 # cisco cpu: cpmCPUTotal5minRev (1.3.6.1.4.1.9.9.109.1.1.1.1.8)
77 # or older version cpmCPUTotal5min (1.3.6.1.4.1.9.9.109.1.1.1.1.5)
79 idle=$(get "$h" "UCD-SNMP-MIB::ssCpuIdle.0") &&
80 cpu=$((100 - idle))
81 } ||
82 cpu=$(get "$h" 1.3.6.1.4.1.3076.2.1.2.25.1.2.0) ||
83 cpu=$(get "$h" .1.3.6.1.4.1.9.9.109.1.1.1.1.8) ||
84 cpu=$(get "$h" .1.3.6.1.4.1.9.9.109.1.1.1.1.5)
86 [ -n "$cpu" ] || return 1
88 [ -f "$file" ] || echo -e "\t\t\tcpu%" > "$file"
89 echo -e "$timestamp:\t$(printf "% 3d" "$cpu")" >> "$file"
92 # Converts a file full of counts to a file full of deltas.
93 makedeltas()
95 local last="$1"
96 local current="$2"
98 # if both datasets exist and are not empty
99 if [ -s "$last" ] && [ -s "$current" ]
100 then
101 # paste the common lines together using join, then subtract
102 # corresponding fields
103 join "$last" "$current" |
104 awk '{
105 printf "%s ", $1
106 numfields = (NF-1)/2
107 for (i = 0; i < numfields; ++i) {
108 printf "%s ", ($(i+2+numfields) - $(i+2))
110 print ""
115 # Converts a file full of rates to a file full of deltas.
116 # Takes input from a pipe.
117 # Leaves the first field untouched (line label).
118 makerates()
120 local last="$1"
121 local current="$2"
123 t1=$(date -r "$last" +%s 2>/dev/null) || return 1
124 t2=$(date -r "$current" +%s 2>/dev/null) || return 1
126 if ! [ "$t1" -lt "$t2" ] # time running backwards
127 then
129 else
130 awk -v tdelta="$((t2 - t1))" '{
131 printf "%s", $1
132 for (i = 2; i <= NF; ++i) {
133 printf " %.2f", ($(i) / tdelta)
135 print ""
140 dorates()
142 local last="$1"
143 local current="$2"
145 makedeltas "$last" "$current" |
146 makerates "$last" "$current" |
147 (echo ; sed -e "s,^,$timestamp\t," -e 's, ,\t,g')
149 mv "$file.current" "$file.last"
153 lognet()
155 local file="$1"
156 local timestamp="$2"
157 local h="$3"
159 tmp=$(mktemp "$file.XXXXXX")
161 # Cisco VPN3030 needs -CB
162 if snmptable $snmpargs -Cf '|' -CB "$h" IF-MIB::ifTable > "$tmp" &&
163 [ "$(wc -l "$tmp" | awk '{print $1}')" -gt 3 ]
164 then
166 else
167 rm -f "$tmp"
168 return 1
171 [ -f "$file" ] || echo -e "\t\t\tIFACE\trxpck/s\ttxpck/s\trxbyt/s\ttxbyt/s\trxerr/s\ttxerr/s" > "$file"
173 # SNMP table: IF-MIB::ifTable
175 # ifIndex|ifDescr|ifType|ifMtu|ifSpeed|ifPhysAddress|ifAdminStatus|ifOperStatus|ifLastChange|ifInOctets|ifInUcastPkts|ifInNUcastPkts|ifInDiscards|ifInErrors|ifInUnknownProtos|ifOutOctets|ifOutUcastPkts|ifOutNUcastPkts|ifOutDiscards|ifOutErrors|ifOutQLen|ifSpecific
176 # 1|eth0|ethernetCsmacd|1500|100000000|0:40:63:e7:17:44|up|up|0:0:00:00.00|11969685|99653|0|0|0|0|34327404|375360|0|0|0|0|SNMPv2-SMI::zeroDotZero
177 awk -F'|' '
178 FNR == 1 || FNR == 2 { next }
179 FNR == 3 {
180 # build field name to column mapping
181 split($0, a)
182 for (field in a) {
183 fields[a[field]] = field
185 next
188 split($0, a)
189 desc = a[fields["ifDescr"]]
190 gsub("[^a-zA-Z0-9._-]", "", desc) # sanitize
191 desc = substr(desc, 0, 7)
193 # Handle duplicate descriptions (e.g. cisco vpn3000)
194 if (desc in ifdupe) {
195 desc = substr(desc, 0, 4) "[" a[fields["ifIndex"]] "]"
197 ifdupe[desc]++
199 print desc, \
200 (a[fields["ifInUcastPkts"]] + a[fields["ifInNUcastPkts"]]), \
201 (a[fields["ifOutUcastPkts"]] + a[fields["ifOutNUcastPkts"]]), \
202 a[fields["ifInOctets"]], a[fields["ifOutOctets"]], \
203 a[fields["ifInErrors"]], a[fields["ifOutErrors"]]
205 ' "$tmp" | grep -v -e ^shaper | sort > "$file.current"
207 dorates "$file.last" "$file.current" >> "$file"
209 rm -f "$tmp"
213 log_cisco_tunnelcount()
215 local file="$1"
216 local timestamp="$2"
217 local h="$3"
219 active=$(get "$h" .1.3.6.1.4.1.9.9.171.1.2.1.1.0) || return 1
220 prev=$(get "$h" .1.3.6.1.4.1.9.9.171.1.2.1.2.0) || return 1
221 total=$((active + prev))
223 totaldelta=0
224 if [ -f "$file.lasttotal" ]
225 then
226 prev=$(cat "$file.lasttotal")
227 totaldelta=$((total - prev))
229 echo "$total" > "$file.lasttotal"
231 [ -f "$file" ] || echo -e "\t\t\tactive\tsince last period" > "$file"
232 echo -e "$timestamp:\t$(printf "% 3d\t% 3d" "$active" "$totaldelta")" \
233 >> "$file"
237 for h in $hosts
239 # If h=tcp:some.ip.addr, convert the ':' to a '.'
240 fileh=$(echo "$h" | tr ':' '.' | tr -cd 'a-zA-Z0-9._-')
241 basename="$outdir/snmpsar.$filestamp.$fileh"
242 logcpu "$basename.cpu" "$timestamp" "$h"
243 lognet "$basename.net" "$timestamp" "$h"
245 log_cisco_tunnelcount "$basename.cisco_tunnelcount" "$timestamp" "$h"
246 done