#!/usr/bin/python """ This modules takes a python dictionary that was generated by libsmi's smidump program, and wraps it in a class (object), and defines some search methods. It is intended to be temporary, only used until a generally useful SMI module is available. The pysmi module is almost working, so this module should have the same methods as that and be easily replaced by it (just import the different module). """ from UserDict import UserDict import string from PYSMI import * from SNMP import OID class SmiValue: def __init__(self, basetype, range=None, value=None): self.basetype = basetype self.range = range self.value = value def __repr__(self): return "%s(%s, range=%s, value=%s)" % (self.__class__.__name__, \ repr(self.basetype), repr(self.range), repr(self.value)) class Enumeration(UserDict): def __getattr__(self, name): if self.data.has_key(name): return self.data[name] else: raise AttributeError def __str__(self): s = ["{"] for key, val in self.data.items(): s.append("%s(%s), " % (key, val)) s.append("}") return string.join(s, "") def __repr__(self): return "%s(%s)" % (self.__class__.__name__, repr(self.data)) class SmiNamedNumber: def __init__(self, name, value): self.name = name self.value = int(value) def __str__(self): return "%s(%s)" % (self.name, self.value) def __repr__(self): return "%s(%s, %d)" % (self.__class__.__name__, repr(self.name), self.value) def __getinitargs__(self): return (self.name, self.value) def __cmp__(self, other): return cmp(self.value, other.value) def __int__(self): # Return the enum as an 'integer' for array indexing etc. return self.value def __long__(self): return long(self.value) def __hash__(self): return self.value class SmiRange: def __init__(self, mini, maxi): self.minValue = long(mini) self.maxValue = long(maxi) def __repr__(self): return "%s(%s, %s)" % (self.__class__.__name__, self.minValue, self.maxValue) class SmiNode: def __init__(self, name, **attributes): self.name = name self.attributes = attributes def __getattr__(self, key): if self.attributes.has_key(key): return self.attributes[key] else: raise AttributeError, "SmiNode: no such attribute: %s" % key def __str__(self): s = [self.__class__.__name__+":"] s.append(" %20s = %s" % ("name", self.name)) for key, val in self.attributes.items(): s.append(" %20s = %s" % (key, val)) return string.join(s, "\n") def __repr__(self): s = ["%s(%s, " % (self.__class__.__name__, repr(self.name))] for key, val in self.attributes.items(): s.append("%s=%s, " % (key, repr(val))) s.append(")") return string.join(s, "") def isWritable(self): return self.access >= 5 def isReadable(self): return self.access >= 4 def _parse_enum(dict): newdict = {} del dict["basetype"] for key, val in dict.items(): newdict[key] = int(val["number"]) return newdict def _parse_value(dict): if dict.has_key("basetype"): try: basetype = BASETYPEMAP[dict["basetype"]] except KeyError: raise ValueError, "Unknown type: %s" % basetype elif dict.has_key("type"): basetype = BASETYPEMAP[dict["type"]] elif dict.has_key("name"): try: basetype = BASETYPEMAP.get(dict["name"]) except KeyError: basetype = TYPEDEFS[dict["name"]].basetype else: basetype = SMI_BASETYPE_UNKNOWN if dict.has_key("range"): rangeval = SmiRange(dict["range"]["min"], dict["range"]["max"]) else: rangeval = None if basetype == SMI_BASETYPE_ENUM : value = Enumeration(_parse_enum(dict)) else: value = None return SmiValue(basetype, rangeval, value) def _parse_node(rawnode): _CONVERTMAP = { "access": ACCESSMAP, "nodetype": NODEKINDMAP, "status": STATUSMAP } newnode = {} for key in rawnode.keys(): cvdict = _CONVERTMAP.get(key, None) if cvdict: newnode[key] = cvdict.get(rawnode[key]) # else: # newnode[key] = rawnode[key] if rawnode.has_key("oid"): newnode["oid"] = OID(rawnode["oid"]) if rawnode.has_key("create"): newnode["create"] = 1 else: newnode["create"] = 0 if rawnode.has_key("syntax"): newnode["value"] = _parse_value(rawnode["syntax"]["type"]) # del newnode["syntax"] if rawnode.has_key("linkage"): newnode["indexes"] = rawnode["linkage"].keys() # if newnode.has_key("moduleName"): # # get rid of the unneeded moduleName # del newnode["moduleName"] # this is an error from the smidump program. I can remove it here. # if newnode.has_key("reference>"): # del newnode["reference>"] return newnode class SmiModule: def __init__(self, rawdict): global TYPEDEFS self.data = {} if rawdict.has_key("typedefs"): self.data["typedefs"] = self._convert_nodes(rawdict["typedefs"]) else: self.data["typedefs"] = {} TYPEDEFS = self.data["typedefs"] if rawdict.has_key("nodes"): self.data["nodes"] = self._convert_nodes(rawdict["nodes"]) else: self.data["nodes"] = {} if rawdict.has_key("notifications"): self.data["notifications"] = self._convert_nodes(rawdict["notifications"]) else: self.data["notifications"] = {} if rawdict.has_key("imports"): self.data["imports"] = rawdict["imports"] else: self.data["imports"] = {} self.data["moduleName"] = rawdict["moduleName"] def _convert_nodes(self, rawdict): new = {} for nn in rawdict.keys(): new[nn] = apply(SmiNode, (nn,), _parse_node(rawdict[nn])) return new def getModule(self): return self.data["moduleName"] def getImports(self): return self.data["imports"] def getType(self, name): return self.data["typedefs"][name] def getTypes(self): return self.data["typedefs"] def getNotifications(self): return self.data["notifications"] def getNotification(self, name): return self.data["notifications"][name] def getNode(self, name): return self.data["nodes"][name] def getNodes(self, statusfilt=None): nodes = self.data["nodes"] if statusfilt: return filter(lambda node, sf=statusfilt: node.status == sf, nodes.values() ) else: return nodes.values() def getNodeByOID(self, oid): nodes = self.data["nodes"] t = filter(lambda node, oid=oid: node.oid == oid, nodes.values() ) if t: return t[0] else: return None def getNodesByType(self, nodetype, statusfilt=SMI_STATUS_CURRENT): nodes = self.data["nodes"] return filter(lambda nm, nt=nodetype, sf=statusfilt: nm.nodetype == nt and nm.status == sf, nodes.values() ) def getScalars(self, statusfilt=SMI_STATUS_CURRENT): return self.getNodesByType(SMI_NODEKIND_SCALAR, statusfilt) def getRows(self, statusfilt=SMI_STATUS_CURRENT): return self.getNodesByType(SMI_NODEKIND_ROW, statusfilt) def getChildren(self, node, statusfilt=SMI_STATUS_CURRENT): # This is slow, due to the way the smidump output is formatted. This has to # scan the whole MIB for each child. nodes = self.data["nodes"] return filter(lambda cnode, node=node, sf=statusfilt: cnode.oid > node.oid and cnode.status == sf, nodes.values() ) def GetModule(name): exec "from mibs.%s import MIB" % name return SmiModule(MIB)