Below is the file 'netinfo.py' from this revision. You can also download the file.

#!/usr/bin/python

import ConfigParser
import sys
import os
import pickle
import time
import sets
import traceback
from pyPgSQL import libpq
from iputils import int_to_length, ip_to_int

# netinfo.py
#
# Parses its configuration file and updates
# the information on configured network devices.
#
# These are then serialised for access by applications
# that do something interesting with the data.
#
# Copyright (C) 2004 Grahame Bowland.
# grahame@angrygoats.net

def notify(str):
	sys.stderr.write("%s\n" % (str))

class PluginLibrary:
	def __init__(self, config):
		self.config = config
		orig_path = None
		self.plugins = {}
		if self.config.has_option('locations', 'plugin_path'):
			orig_path = sys.path
			self.plugin_path = self.config.get('locations', 'plugin_path')
			sys.path.insert(0, self.plugin_path)
		if self.config.has_section('plugins'):
			for option in self.config.options('plugins'):
				self.do_load_plugin(option)
		if orig_path: sys.path = orig_path
	def do_load_plugin(self, plugin_name):
		mod = __import__('%s' % plugin_name, globals(), locals(), [''])
		if not self.plugins.has_key(mod.export['type']): self.plugins[mod.export['type']] = []
		self.plugins[mod.export['type']].append(mod)
		notify("Plugin loaded: " + mod.export['name'] + " version " + mod.export['version'] + " (" + mod.export['type'] + ")")

def update(connection, plugins, config):
	def run_sql(command_list):
		map(connection.query, command_list)
	def update_host(hostname):
		def determine_plugin():
			for plugin in plugins:
				if plugin.suits(hostname, community): return plugin
			return None
		def q(s):
			if s == None: return "NULL"
			else: return libpq.PgQuoteString(s)
		def update_start():
			notify("[%s] update_start" % (hostname))
			yield "BEGIN"
			yield "DELETE FROM devices WHERE hostname=%s" % (q(hostname))
			yield "INSERT INTO devices (hostname,update_started) VALUES (%s,now())" % (q(hostname))
			yield "COMMIT"
		def update_stop(success):
			notify("[%s] update_start" % (hostname))
			yield "BEGIN"
			yield "UPDATE devices SET update_stopped=now(),update_succeeded=%s WHERE hostname=%s" % (q(str(success)), q(hostname))
			yield "COMMIT"
		def update_arp():
			notify("[%s] update_arp" % (hostname))
			yield 'BEGIN'
			yield 'DELETE FROM arp WHERE hostname=%s' % (q(hostname))
			for ip_address, mac_address in mod.arp(hostname, community):
				yield "INSERT INTO arp (hostname,mac_address,ip_address) VALUES (%s,%s,%s)" % (q(hostname), q(mac_address), q(ip_address))
			yield 'COMMIT'
		def update_addresses():
			notify("[%s] update_addresses" % (hostname))
			yield 'BEGIN'
			yield 'DELETE FROM addresses WHERE hostname=%s' % (q(hostname))
			for ip_address, interface_id in mod.addresses(hostname, community):
				yield "INSERT INTO addresses (hostname,ip_address,interface_id) VALUES (%s,%s,%s)" % (q(hostname), q(ip_address), q(interface_id))
			yield 'COMMIT'
		def update_vlans(vlans):
			notify("[%s] update_vlans" % (hostname))
			yield "BEGIN"
			yield "DELETE FROM vlans WHERE hostname=%s" % (q(hostname))
			for id, description in mod.vlans(hostname, community):
				vlans.add(id)
				yield "INSERT INTO vlans (hostname,vlan_id,description) VALUES (%s,%d,%s)" % (q(hostname), id, q(description))
			yield "COMMIT"
			# these VLANs should be excluded from any ethernet/IP scans (reserved for non-ethernet use)
			exclude = sets.Set((1002,1003,1004,1005))
			vlans -= exclude
		def update_forwarding(vlans):
			for vlan in vlans:
				notify("[%s] update_forwarding: vlan %d" % (hostname, vlan))
				yield "BEGIN"
				yield "DELETE FROM forwarding WHERE hostname=%s and vlan_id=%s" % (q(hostname), vlan)
				for mac_address, ifindex in mod.forwarding(hostname, community, vlan):
					yield "INSERT INTO forwarding (hostname,vlan_id,mac_address,interface_id) VALUES (%s,%d,%s,%d)" % (q(hostname), vlan, q(mac_address), ifindex)
				yield "COMMIT"
		def update_adjacency():
			notify("[%s] update_adjacency" % (hostname))
			yield "BEGIN"
			yield "DELETE FROM adjacency WHERE hostname=%s" % (q(hostname))
			for ip_address, name, remote_port in mod.adjacency(hostname, community):
				yield "INSERT INTO adjacency (hostname, adjacent_hostname, adjacent_interface_description, ip_address) VALUES (%s,%s,%s,%s)" % (q(hostname), q(name), q(remote_port), q(ip_address))
			yield "COMMIT"
		def update_routing():
			notify("[%s] update_routing" % (hostname))
			yield "BEGIN"
			yield "DELETE FROM routing WHERE hostname=%s" % (q(hostname))
			for type, ifindex, is_null, network, via, metric in mod.routing(hostname, community):
				yield "INSERT INTO routing (hostname,route_type,interface_id,is_null_route,network,via,metric) VALUES (%s,%s,%s,%s,%s,%s,%s)" % (q(hostname), q(type), q(str(ifindex)), q(str(is_null)), q(network), q(via), q(metric))
			yield "COMMIT"
		def update_interfaces():
			notify("[%s] update_interfaces" % (hostname))
			yield "BEGIN"
			yield "DELETE FROM interfaces WHERE hostname=%s" % (q(hostname))
			yield "COMMIT"
		try:
			run_sql(update_start())
			community = config.get('devices', hostname)
			mod = determine_plugin()
			if not mod:
				notify("no suitable plugin found for %" % (hostname))
				return
			notify("[%s] using plugin %s" % (hostname, mod.export['name']))
			vlans = sets.Set()
			run_sql(update_addresses())
			run_sql(update_adjacency())
			run_sql(update_arp())
			run_sql(update_routing())
			run_sql(update_vlans(vlans))
			run_sql(update_forwarding(vlans))
			#run_sql(update_interfaces())
			run_sql(update_stop(True))
		except:
			t,v,tr = sys.exc_info()
                        err_data = '\n'.join(traceback.format_exception(t, v, tr))
			notify("Exception updating %s:%s\n(sending ABORT)" % (hostname, err_data))
			connection.query("ABORT")
			run_sql(update_stop(False))
	for hostname in config.options('devices'):
		try: update_host(hostname)
		except:
			t,v,tr = sys.exc_info()
                        err_data = '\n'.join(traceback.format_exception(t, v, tr))
			notify("Exception updating (in loop) %s:%s\n(sending ABORT)" % (hostname, err_data))

if __name__ == '__main__':
	config = ConfigParser.ConfigParser()
	config.read("netinfo.cfg")
	cnx = libpq.PQconnectdb("dbname=netinfo")
	if config.has_option('locations', 'empty_path'): os.environ['MIBDIR'] = 'empty_path'
	pl = PluginLibrary(config)
	update(cnx, pl.plugins['provider'], config)