Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: modules/nagios/files/check_bandwidth

Issue 12375002: Implement more detailed bandwidth monitoring (Closed)
Patch Set: Created Oct. 1, 2013, 5:30 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | modules/nagios/manifests/client.pp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 import os, re, subprocess, sys 3 import os, re, subprocess, sys, socket, struct, fcntl
4
5 INTERVAL = 5
4 6
5 def format_bandwidth(bits): 7 def format_bandwidth(bits):
6 if bits >= 1000000: 8 if bits >= 1000000:
7 return "%.2f Mbit/s" % (bits / 1000000) 9 return "%.2f Mbit/s" % (bits / 1000000)
8 elif bits >= 1000: 10 elif bits >= 1000:
9 return "%.2f kbit/s" % (bits / 1000) 11 return "%.2f kbit/s" % (bits / 1000)
10 else: 12 else:
11 return "%.2f bit/s" % bits 13 return "%.2f bit/s" % bits
12 14
15 def getmacaddress():
16 # We are calling SIOCGIFHWADDR (0x8927 according to man ioctl_list) here. See
17 # man netdevice for the request structure: it has to start with 16 bytes
18 # containing the interface name, the OS will write 8 bytes after that (2 bytes
19 # family name and 6 bytes actual MAC address).
20 s = socket.socket()
21 return fcntl.ioctl(s.fileno(), 0x8927, struct.pack("24s", "eth0"))[18:24]
22
23 def splitport(hostport):
24 match = re.search(r"\.(d+)$", hostport)
25 if match:
26 return hostport[:match.start()], match.group(1)
27 else:
28 return hostport, "0"
29
30 def readtime(time):
31 hour, minute, second = time.split(":")
32 return int(hour) * 3600 + int(minute) * 60 + float(second)
33
13 if __name__ == "__main__": 34 if __name__ == "__main__":
14 if len(sys.argv) != 3: 35 if len(sys.argv) != 3:
15 script_name = os.path.basename(sys.argv[0]) 36 script_name = os.path.basename(sys.argv[0])
16 print "Usage: %s WARN CRIT" % script_name 37 print "Usage: %s WARN CRIT" % script_name
17 sys.exit(0) 38 sys.exit(0)
18 39
19 (warn, crit) = sys.argv[1:3] 40 (warn, crit) = sys.argv[1:3]
20 warn = int(sys.argv[1]) 41 warn = int(sys.argv[1])
21 crit = int(sys.argv[2]) 42 crit = int(sys.argv[2])
22 43
23 process_output = subprocess.check_output(["bwm-ng", "-I", "eth0", "-t", "5000" , "-c", "1", "-o", "csv"]) 44 process = subprocess.Popen(["tcpdump", "-q", "-n", "-s", "64", "-w", "-"], std out=subprocess.PIPE, stderr=subprocess.PIPE)
24 data = process_output.splitlines()[0].split(";") 45 starttime = None
25 tx = float(data[2]) * 8 46 mac = getmacaddress()
26 rx = float(data[3]) * 8
27 status = "rx %s tx %s" % (format_bandwidth(rx), format_bandwidth(tx))
28 47
29 perfdata = "rx=%i;%i;%i tx=%i;%i;%i" % (rx, warn, crit, tx, warn, crit) 48 total = {"rx": 0, "tx": 0}
49 http = {"rx": 0, "tx": 0}
50 https = {"rx": 0, "tx": 0}
51 ssh = {"rx": 0, "tx": 0}
52 dns = {"rx": 0, "tx": 0}
53 other = {"rx": 0, "tx": 0}
54 other_detailed = {}
30 55
31 output = "%s|%s" % (status, perfdata) 56 # See http://wiki.wireshark.org/Development/LibpcapFileFormat for libpcap form at description
57 magic_number, _, _, _, _, _, _ = struct.unpack("IHHiIII", process.stdout.read( 24))
58 if magic_number != 0xa1b2c3d4:
59 raise Exception("Unexpected format")
60 while True:
61 sec, usec, incl_len, orig_len = struct.unpack("IIII", process.stdout.read(16 ))
62 length = orig_len + 24 # 24 bytes Ethernet overhead not captured by tcpdum p
32 63
64 time = sec + float(usec) / 1000000
65 if starttime == None:
66 starttime = time
67 if time - starttime > INTERVAL:
68 break
69
70 def add_other(description):
71 other[direction] += length
72 other_detailed[description] = other_detailed.get(description, 0) + length
73
74 payload = process.stdout.read(incl_len)
75
76 # Unpack Ethernet frame, http://en.wikipedia.org/wiki/Ethernet_frame#Structu re
77 destination, source, protocol = struct.unpack("!6s6sH", payload[:14])
78 payload = payload[14:]
79 direction = "rx" if destination == mac else "tx"
80 total[direction] += length
81
82 # Check Level 3 protocol
83 if protocol == 0x0800: # IPv4, http://en.wikipedia.org/wiki/Internet_Pro tocol_version_4#Header
84 ihl = ord(payload[0]) & 0xF
85 protocol = ord(payload[9])
86 payload = payload[ihl * 4:]
87 elif protocol == 0x86DD: # IPv6, http://en.wikipedia.org/wiki/IPv6_packet# Fixed_header
88 protocol = ord(payload[6])
89 payload = payload[40:]
90 else:
91 add_other("L3 0x%04X" % protocol)
92 continue
93
94 # Check Level 4 protocol
95 if protocol in (0x06, 0x11): # TCP, UDP
96 # The lower port number should be the real port, the other one will be
97 # the ephemeral port.
98 source_port, destination_port = struct.unpack('!HH', payload[:4])
99 protocol = "TCP" if protocol == 0x06 else "UDP"
100 port = min(source_port, destination_port)
101 else:
102 add_other("L4 0x%02X" % protocol)
103 continue
104
105 if protocol == "TCP" and port == 80:
106 http[direction] += length
107 elif protocol == "TCP" and port == 443:
108 https[direction] += length
109 elif protocol == "TCP" and port == 22:
110 ssh[direction] += length
111 elif port == 53:
112 dns[direction] += length
113 else:
114 add_other("Port %i" % port)
115 continue
116
117 status = []
118 perfdata = []
119 def add_status(id, values):
120 rx = float(values["rx"]) * 8 / INTERVAL
121 tx = float(values["tx"]) * 8 / INTERVAL
122 status.append("%srx %s %stx %s" % (id, format_bandwidth(rx), id, format_band width(tx)))
123 if id == "":
124 perfdata.append("rx=%i;%i;%i tx=%i;%i;%i" % (rx, warn, crit, tx, warn, cri t))
125 else:
126 perfdata.append("%srx=%i %stx=%i" % (id, rx, id, tx))
127
128 add_status("", total)
129 add_status("http_", http)
130 add_status("https_", https)
131 add_status("ssh_", ssh)
132 add_status("dns_", dns)
133 add_status("other_", other)
134 for key in sorted(other_detailed.iterkeys(), key=lambda k: other_detailed[k], reverse=True):
135 status.append("%s %s" % (key, format_bandwidth(float(other_detailed[key]) / INTERVAL)))
136
137 output = "%s|%s" % (", ".join(status), " ".join(perfdata))
138
139 rx = float(total["rx"]) * 8 / INTERVAL
140 tx = float(total["tx"]) * 8 / INTERVAL
33 if rx >= crit or tx >= crit: 141 if rx >= crit or tx >= crit:
34 print "CRITICAL - " + output 142 print "CRITICAL - " + output
35 sys.exit(2) 143 sys.exit(2)
36 144
37 if rx >= warn or tx >= warn: 145 if rx >= warn or tx >= warn:
38 print "WARNING - " + output 146 print "WARNING - " + output
39 sys.exit(1) 147 sys.exit(1)
40 148
41 print "OK - " + output 149 print "OK - " + output
OLDNEW
« no previous file with comments | « no previous file | modules/nagios/manifests/client.pp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld