The unified diff between revisions [ea8ef2d2..] and [c1adc84f..] is displayed below. It can also be downloaded as a raw diff.
#
#
# patch "iputils.py"
# from [d10413b7982a049c60d75ad671bae620f8ccd250]
# to [84ec996038ab504ee8b5b18ba8d4f3f3c23e1801]
#
# patch "plugins/basic_snmp.py"
# from [f4361556222d4ff31fc9a0693b384723c24677ed]
# to [fb0fb2d026d99c1259a12ad5003a3a75eeacbc1e]
#
# patch "plugins/cisco_ios.py"
# from [c22b8cbe73befe343ea39b472c8929b7f678276b]
# to [19feaff94350a58fc05c4cc35ae258285a38655c]
#
# patch "yowie.py"
# from [3e57b46eee9446cfb98f258c312df9df5a5cb8a6]
# to [8303d0a3d2730d9b7caf3d9dab5260c25705787d]
#
============================================================
--- iputils.py d10413b7982a049c60d75ad671bae620f8ccd250
+++ iputils.py 84ec996038ab504ee8b5b18ba8d4f3f3c23e1801
@@ -2,8 +2,8 @@
# iputils.py
#
-# Author: Grahame Bowland <grahame@ucs.uwa.edu.au>
-# License: GNU GPL
+# -- FIXME; I wrote this a LONG time ago, it could really do with some cleaning
+# up for efficiency reasons.
import sys
import socket
@@ -16,8 +16,8 @@ class Network:
# is "ip" within our network
c1 = ip & self.mask
c2 = self.address & self.mask
- # 130.95.0.0 & 255.255.255.0 = 130.95.0.0
- # 130.95.2.0 & 255.255.255.0 = 130.95.2.0
+ # 130.95.0.0 & 255.255.255.0 = 130.95.0.0
+ # 130.95.2.0 & 255.255.255.0 = 130.95.2.0
if c1 == c2:
if c1 == 0 and self.address <> ip:
# /32 route and not equal host addresses
@@ -38,19 +38,18 @@ def ip_to_int(str, invert = 0):
if invert:
cval = cval ^ 255
if cval > 255 or cval < 0:
- print "Invalid ip; contains section out of bounds at index %d : %s"\
- % (4-i, str)
+ print "Invalid ip; contains section out of bounds at index %d : %s" % (4-i, str)
rv = rv + (m * cval)
m = m * 256
return rv
def int_to_length(ip_int):
- len = 0
- while ip_int > 0:
- if ip_int % 2: break
- ip_int /= 2
- len += 1
- return 32 - len
+ len = 0
+ while ip_int > 0:
+ if ip_int % 2: break
+ ip_int /= 2
+ len += 1
+ return 32 - len
def network_from_ip(ip, mask):
pip = ip_to_int(ip)
============================================================
--- plugins/basic_snmp.py f4361556222d4ff31fc9a0693b384723c24677ed
+++ plugins/basic_snmp.py fb0fb2d026d99c1259a12ad5003a3a75eeacbc1e
@@ -3,7 +3,9 @@
# basic_snmp : stuff a generic managed switch should support
#
+import re
from goatpy.snmpwrapper import snmpwalk
+from iputils import int_to_length, ip_to_int
plugin_info = {
'description' : '''\
@@ -19,9 +21,9 @@ def ip_arp(table_name, table_io, device)
mac_address = value
yield device.config['zone'], None, mac_address, ip_address
-def ip_routing(hostname, community):
+def ip_routing(table_name, table_io, device):
routes = {}
- for oid, route_type, value in snmpwalk(hostname, community, "2c", "ipRouteTable"):
+ for oid, route_type, value in snmpwalk(device.device_name, device.config['community'], "2c", "ipRouteTable", ssh_dest=device.config.get('ssh')):
row_name = oid[0]
colon = row_name.rfind(':')
if colon <> -1: row_name = row_name[colon+1:]
@@ -42,9 +44,26 @@ def ip_routing(hostname, community):
metric = route.get('ipRouteMetric1')
ifindex = route.get('ipRouteIfIndex')
if ifindex: ifindex = int(ifindex)
- yield route_type, ifindex, False, network, via, metric
+ yield device.config["zone"], route_type, ifindex, False, network, via, metric
+def ip_addresses(table_name, table_io, device):
+ addresses = {}
+ for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", "IP-MIB::ipAddrTable", ssh_dest=device.config.get('ssh')):
+ current_row = tuple(oid[-4:])
+ row_name = oid[-5]
+ colon = row_name.rfind(':')
+ if colon <> -1: row_name = row_name[colon+1:]
+ if not addresses.has_key(current_row): addresses[current_row] = {}
+ addresses[current_row][row_name] = value
+ for row in addresses:
+ ip = addresses[row].get('ipAdEntAddr')
+ netmask = addresses[row].get('ipAdEntNetMask')
+ interface = addresses[row].get('ipAdEntIfIndex')
+ if ip != None and netmask != None: ip = ip + '/' + str(int_to_length(ip_to_int(netmask)))
+ yield device.config['zone'], ip, interface
+
tables = {
+ 'ip_addresses' : ip_addresses,
'ip_arp' : ip_arp,
'ip_routing' : ip_routing,
}
============================================================
--- plugins/cisco_ios.py c22b8cbe73befe343ea39b472c8929b7f678276b
+++ plugins/cisco_ios.py 19feaff94350a58fc05c4cc35ae258285a38655c
@@ -1,15 +1,58 @@
-from basic_snmp import ip_arp, ethernet_forwarding
+from goatpy.snmpwrapper import snmpwalk
+import basic_snmp
+import re
+def adjacency(table_name, table_io, device):
+ def h2i(s):
+ print "h2i called, with argument:", s
+ h = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'A':10,'B':11,'C':12,'D':13,'E':14,'F':15}
+ if len(s) == 1: return h[s[0]]
+ else :return 16*h[s[0]] + h[s[1]]
+ def to_ipaddr(s):
+ if s == None: return s
+ return '.'.join([str(t) for t in map(h2i, s.split(' '))])
+ def to_ascii(s):
+ if s == None: return s
+ asdigits = [h2i(t) for t in s.split(' ')]
+ asdigits = filter(lambda x: x >= 32 and x <= 122, asdigits)
+ return ''.join([chr(t) for t in asdigits])
+ row_to_field = { 4 : 'ip_address', 6 : 'name', 7 : 'remote_port' }
+ table = {}
+ for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", "SNMPv2-SMI::enterprises.9.9.23.1.2.1.1", ssh_dest=device.config.get('ssh')):
+ print oid, type, value
+ id = tuple(oid[-2:])
+ row = int(oid[-3])
+ if not table.has_key(id): table[id] = {}
+ if row_to_field.has_key(row):
+ table[id][row_to_field[row]] = value
+ for row in table:
+ ip = to_ipaddr(table[row].get('ip_address'))
+ name = table[row].get('name')[1:-1]
+ if re.match(r'^(..?)+ ..?$', name):
+ name = to_ascii(name)
+ m = re.match(r'[^A-Za-z0-9]*([A-Za-z0-9]+)', name)
+ if m: name = m.groups()[0]
+ remote_port = table[row].get('remote_port')[1:-1]
+ yield device.config['zone'], ip, name, remote_port
# see: http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a0080094a9b.shtml
def ethernet_forwarding(table_name, table_io, device):
yield device.config['zone'], 1, '00:11:24:c7:dd:41', 'en1'
+def ethernet_vlans(table_name, table_io, device):
+ # walk vtpVlanName
+ for oid, type, value in snmpwalk(device.device_name, device.config['community'], "2c", ".1.3.6.1.4.1.9.9.46.1.3.1.1.4", ssh_dest=device.config.get('ssh')):
+ value = value[1:-1]
+ yield device.config['zone'], int(oid[-1]), value
tables = {
+ 'adjacency' : adjacency,
'ethernet_forwarding' : ethernet_forwarding,
- 'ip_arp' : ip_arp,
+ 'ethernet_vlans' : ethernet_vlans,
+ 'ip_addresses' : basic_snmp.ip_addresses,
+ 'ip_arp' : basic_snmp.ip_arp,
+ 'ip_routing' : basic_snmp.ip_routing
}
def init():
============================================================
--- yowie.py 3e57b46eee9446cfb98f258c312df9df5a5cb8a6
+++ yowie.py 8303d0a3d2730d9b7caf3d9dab5260c25705787d
@@ -1,5 +1,6 @@
#!/usr/bin/env python2.4
+import tempfile
import config
import popen2
import socket
@@ -36,14 +37,22 @@ class TableIO:
yield row
def write(self, header, rows):
- fd = open(self.filename, "w")
- writer = csv.writer(fd)
- writer.writerow(header)
- rowlen = len(header)
- for row in rows:
- if len(row) != rowlen:
- raise Exception("Row has length %d (must be %d)" % (len(row), rowlen))
- writer.writerow(row)
+ # use a temporary file; this avoids annoying problems where an update fails half-way
+ # through and we potentially commit a half-complete version of the file.
+ tmp_fdno, tmp_filename = tempfile.mkstemp(suffix='.csv', prefix='yowie')
+ tmp_fd = os.fdopen(tmp_fdno, "w")
+ try:
+ writer = csv.writer(tmp_fd)
+ writer.writerow(header)
+ rowlen = len(header)
+ for row in rows:
+ if len(row) != rowlen:
+ raise Exception("Row has length %d (must be %d)" % (len(row), rowlen))
+ writer.writerow(row)
+ os.rename(tmp_filename, self.filename)
+ except:
+ os.unlink(tmp_filename)
+ raise
export_funcs = {}
def export_to_drivers(f):