- Initial PySMI integration. Original ASN.1 MIBs could now be parsed, stored

at a local pysnmp MIBs repository and loaded into SNMP Engine.
- smi.MibBuilder will now raise more specific exceptions (MibLoadError,
  MibNotFoundError) on MIB loading problems rather than more generic
  SmiError.
- MibBuilder.addMibSources() convenience method added.
pull/45/head
elie 2015-05-17 21:01:43 +00:00
parent fce2a8a445
commit 087522e567
5 changed files with 154 additions and 65 deletions

View File

@ -3,6 +3,8 @@ Revision 4.2.6rc2
- Critical error fixed in key localization procedure for AES192/AES256/3DES
cyphers. Previous versions might never worked properly in this respect.
- Initial PySMI integration. Original ASN.1 MIBs could now be parsed, stored
at a local pysnmp MIBs repository and loaded into SNMP Engine.
- Major rewrite of native SNMPv3 CommandGenerator and NotificationOriginator
applications towards the following goals:
* avoid bonding with particular SNMP engine instance to promote single
@ -80,8 +82,10 @@ Revision 4.2.6rc2
- Parts of SMIv1 remnant MIBs (RFC1213-MIB, RFC1158-MIB) added to provide
complete compatibility with SMIv1. Symbols defined in these MIBs only
present in SMIv1 so they can't be substituted with their SMIv2 analogues.
- Optional configuration/MIB directory added to MIB search path
(~/,pysnmp/mibs) at MibBuilder.
- MibBuilder.addMibSources() convenience method added.
- The smi.MibBuilder() will now raise more specific exceptions (MibLoadError,
MibNotFoundError) on MIB loading problems rather than more generic
SmiError.
- Fix to authoritative engine side snmpEngineID discovery procedure:
respond with notInTimeWindows rather then with unsupportedSecurityLevel
at time synchronization phase.

View File

@ -1,21 +1,23 @@
# SNMP manager-side MIB management
from pysnmp.smi import builder, view, error
from pysnmp.smi import builder, view, compiler, error
# Create MIB loader/builder
mibBuilder = builder.MibBuilder()
# Optionally set an alternative path to compiled MIBs
#print('Setting MIB sources...')
#mibSources = mibBuilder.getMibSources() + (
# builder.DirMibSource('/opt/pysnmp_mibs'),
# )
#mibBuilder.setMibSources(*mibSources)
#print(mibBuilder.getMibSources())
# Optionally attach PySMI MIB compiler (if installed)
#print('Attaching MIB compiler...'),
#compiler.addMibCompiler(mibBuilder, sources=['/usr/share/snmp/mibs'])
#print('done')
# Optionally set an alternative path to compiled MIBs
print('Setting MIB sources...')
mibBuilder.addMibSources(builder.DirMibSource('/opt/pysnmp_mibs'))
print(mibBuilder.getMibSources())
print('done')
print('Loading MIB modules...'),
mibBuilder.loadModules(
'SNMPv2-MIB', 'SNMP-FRAMEWORK-MIB', 'SNMP-COMMUNITY-MIB'
'SNMPv2-MIB', 'SNMP-FRAMEWORK-MIB', 'SNMP-COMMUNITY-MIB', 'IP-MIB'
)
print('done')

View File

@ -200,17 +200,7 @@ class MibBuilder:
defaultCoreMibs = os.pathsep.join(
('pysnmp.smi.mibs.instances', 'pysnmp.smi.mibs')
)
if sys.platform[:3] == 'win':
defaultMiscMibs = os.pathsep.join(
( os.path.join(os.path.expanduser("~"),
'PySNMP Configuration', 'mibs'),
'pysnmp_mibs' )
)
else:
defaultMiscMibs = os.pathsep.join(
( os.path.join(os.path.expanduser("~"), '.pysnmp', 'mibs'),
'pysnmp_mibs' )
)
defaultMiscMibs = 'pysnmp_mibs'
moduleID = 'PYSNMP_MODULE_ID'
def __init__(self):
self.lastBuildId = self._autoName = 0
@ -229,13 +219,29 @@ class MibBuilder:
self.mibSymbols = {}
self.__modSeen = {}
self.__modPathsSeen = {}
self.__mibCompiler = None
self.setMibSources(*sources)
# MIB compiler management
def getMibCompiler(self):
return self.__mibCompiler
def setMibCompiler(self, mibCompiler, destDir):
self.addMibSources(DirMibSource(destDir))
self.__mibCompiler = mibCompiler
return self
# MIB modules management
def addMibSources(self, *mibSources):
self.__mibSources.extend([ s.init() for s in mibSources ])
debug.logger & debug.flagBld and debug.logger('addMibSources: new MIB sources %s' % (self.__mibSources,))
def setMibSources(self, *mibSources):
self.__mibSources = [ s.init() for s in mibSources ]
debug.logger & debug.flagBld and debug.logger('setMibPath: new MIB sources %s' % (self.__mibSources,))
debug.logger & debug.flagBld and debug.logger('setMibSources: new MIB sources %s' % (self.__mibSources,))
def getMibSources(self): return tuple(self.__mibSources)
@ -254,6 +260,49 @@ class MibBuilder:
)
return paths
def loadModule(self, modName, **userCtx):
for mibSource in self.__mibSources:
debug.logger & debug.flagBld and debug.logger('loadModule: trying %s at %s' % (modName, mibSource))
try:
modData, sfx = mibSource.read(modName)
except IOError:
debug.logger & debug.flagBld and debug.logger('loadModule: read %s from %s failed: %s' % (modName, mibSource, sys.exc_info()[1]))
continue
modPath = mibSource.fullPath(modName, sfx)
if modPath in self.__modPathsSeen:
debug.logger & debug.flagBld and debug.logger('loadModule: seen %s' % modPath)
break
else:
self.__modPathsSeen[modPath] = 1
debug.logger & debug.flagBld and debug.logger('loadModule: evaluating %s' % modPath)
g = { 'mibBuilder': self,
'userCtx': userCtx }
try:
exec(modData, g)
except Exception:
del self.__modPathsSeen[modPath]
raise error.MibLoadError(
'MIB module \"%s\" load error: %s' % (modPath, traceback.format_exception(*sys.exc_info()))
)
self.__modSeen[modName] = modPath
debug.logger & debug.flagBld and debug.logger('loadModule: loaded %s' % modPath)
break
if modName not in self.__modSeen:
raise error.MibNotFoundError(
'MIB file \"%s\" not found in search path (%s)' % (modName and modName + ".py[co]", ', '.join([str(x) for x in self.__mibSources]))
)
return self
def loadModules(self, *modNames, **userCtx):
# Build a list of available modules
if not modNames:
@ -263,50 +312,19 @@ class MibBuilder:
modNames[modName] = None
modNames = list(modNames.keys())
if not modNames:
raise error.SmiError(
raise error.MibNotFoundError(
'No MIB module to load at %s' % (self,)
)
)
for modName in modNames:
for mibSource in self.__mibSources:
debug.logger & debug.flagBld and debug.logger('loadModules: trying %s at %s' % (modName, mibSource))
try:
modData, sfx = mibSource.read(modName)
except IOError:
debug.logger & debug.flagBld and debug.logger('loadModules: read %s from %s failed: %s' % (modName, mibSource, sys.exc_info()[1]))
continue
modPath = mibSource.fullPath(modName, sfx)
if modPath in self.__modPathsSeen:
debug.logger & debug.flagBld and debug.logger('loadModules: seen %s' % modPath)
break
else:
self.__modPathsSeen[modPath] = 1
debug.logger & debug.flagBld and debug.logger('loadModules: evaluating %s' % modPath)
g = { 'mibBuilder': self,
'userCtx': userCtx }
try:
exec(modData, g)
except Exception:
del self.__modPathsSeen[modPath]
raise error.SmiError(
'MIB module \"%s\" load error: %s' % (modPath, traceback.format_exception(*sys.exc_info()))
)
self.__modSeen[modName] = modPath
debug.logger & debug.flagBld and debug.logger('loadModules: loaded %s' % modPath)
break
if modName not in self.__modSeen:
raise error.SmiError(
'MIB file \"%s\" not found in search path (%s)' % (modName and modName + ".py[co]", ', '.join([str(x) for x in self.__mibSources]))
)
try:
self.loadModule(modName, **userCtx)
except error.MibNotFoundError:
if self.__mibCompiler:
debug.logger & debug.flagBld and debug.logger('loadModules: calling MIB compiler for %s' % modName)
self.__mibCompiler.compile(modName)
# in case this missing MIB becomes available
self.loadModule(modName, **userCtx)
return self

View File

@ -0,0 +1,62 @@
#
# Attach PySMI MIB compiler to PySNMP MIB builder and configure
# both accordingly.
#
import os
import sys
try:
from pysmi.reader.url import getReadersFromUrls
from pysmi.searcher.pypackage import PyPackageSearcher
from pysmi.searcher.stub import StubSearcher
from pysmi.borrower.pyfile import PyFileBorrower
from pysmi.writer.pyfile import PyFileWriter
from pysmi.parser.smi import parserFactory
from pysmi.parser.dialect import smiV1Relaxed
from pysmi.codegen.pysnmp import PySnmpCodeGen, baseMibs
from pysmi.compiler import MibCompiler
except ImportError:
from pysnmp.smi import error
def addMibCompiler(mibBuilder,
sources=defaultSources,
destination=defaultDest,
borrowers=defaultBorrowers):
raise error.SmiError('MIB compiler not available (pysmi not installed)')
else:
defaultSources = [ 'file:///usr/share/snmp/mibs' ]
if sys.platform[:3] == 'win':
defaultDest = os.path.join(os.path.expanduser("~"),
'PySNMP Configuration', 'mibs')
else:
defaultDest = os.path.join(os.path.expanduser("~"), '.pysnmp', 'mibs')
defaultBorrowers = []
def addMibCompiler(mibBuilder,
sources=defaultSources,
destination=defaultDest,
borrowers=defaultBorrowers):
compiler = MibCompiler(
parserFactory(**smiV1Relaxed)(),
PySnmpCodeGen(),
PyFileWriter(destination)
)
compiler.addSources(*getReadersFromUrls(*sources))
compiler.addSearchers(
StubSearcher(*baseMibs) # XXX
)
compiler.addSearchers(
*[ PyPackageSearcher(x.fullPath()) for x in mibBuilder.getMibSources() ]
)
compiler.addBorrowers(
*[ PyFileBorrower(x) for x in getReadersFromUrls(*borrowers, originalMatching=False, lowcaseMatching=False) ]
)
mibBuilder.setMibCompiler(compiler, destination)

View File

@ -2,6 +2,9 @@ from pyasn1.error import PyAsn1Error
from pysnmp.error import PySnmpError
class SmiError(PySnmpError, PyAsn1Error): pass
class MibLoadError(SmiError): pass
class MibNotFoundError(MibLoadError): pass
class MibOperationError(SmiError):
def __init__(self, **kwargs): self.__outArgs = kwargs
def __str__(self): return '%s(%s)' % (