# # This file is part of pysnmp software. # # Copyright (c) 2005-2019, Ilya Etingof # License: http://snmplabs.com/pysnmp/license.html # from pysnmp import debug from pysnmp.proto import rfc1902 from pysnmp.proto import rfc1905 from pysnmp.proto.api import v2c from pysnmp.smi.builder import ZipMibSource from pysnmp.smi.compiler import addMibCompiler from pysnmp.smi.error import SmiError from pyasn1.error import PyAsn1Error from pyasn1.type.base import AbstractSimpleAsn1Item __all__ = ['ObjectIdentity', 'ObjectType', 'NotificationType'] class ObjectIdentity(object): """Create an object representing MIB variable ID. At the protocol level, MIB variable is only identified by an OID. However, when interacting with humans, MIB variable can also be referred to by its MIB name. The *ObjectIdentity* class supports various forms of MIB variable identification, providing automatic conversion from one to others. At the same time *ObjectIdentity* objects behave like :py:obj:`tuples` of py:obj:`int` sub-OIDs. See :RFC:`1902#section-2` for more information on OBJECT-IDENTITY SMI definitions. Parameters ---------- args initial MIB variable identity. Recognized variants: * single :py:obj:`tuple` or integers representing OID * single :py:obj:`str` representing OID in dot-separated integers form * single :py:obj:`str` representing MIB variable in dot-separated labels form * single :py:obj:`str` representing MIB name. First variable defined in MIB is assumed. * pair of :py:obj:`str` representing MIB name and variable name * pair of :py:obj:`str` representing MIB name and variable name followed by an arbitrary number of :py:obj:`str` and/or :py:obj:`int` values representing MIB variable instance identification. Other parameters ---------------- kwargs MIB resolution options(object): * whenever only MIB name is given, resolve into last variable defined in MIB if last=True. Otherwise resolves to first variable (default). Notes ----- Actual conversion between MIB variable representation formats occurs upon :py:meth:`~pysnmp.smi.rfc1902.ObjectIdentity.resolveWithMib` invocation. Examples -------- >>> from pysnmp.smi.rfc1902 import ObjectIdentity >>> ObjectIdentity((1, 3, 6, 1, 2, 1, 1, 1, 0)) ObjectIdentity((1, 3, 6, 1, 2, 1, 1, 1, 0)) >>> ObjectIdentity('1.3.6.1.2.1.1.1.0') ObjectIdentity('1.3.6.1.2.1.1.1.0') >>> ObjectIdentity('iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0') ObjectIdentity('iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0') >>> ObjectIdentity('SNMPv2-MIB', 'system') ObjectIdentity('SNMPv2-MIB', 'system') >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0) ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0) >>> ObjectIdentity('IP-MIB', 'ipAdEntAddr', '127.0.0.1', 123) ObjectIdentity('IP-MIB', 'ipAdEntAddr', '127.0.0.1', 123) """ ST_DIRTY, ST_CLEAN = 1, 2 def __init__(self, *args, **kwargs): self._args = args self._kwargs = kwargs self._mibSourcesToAdd = None self._modNamesToLoad = None self._asn1SourcesToAdd = None self._asn1SourcesOptions = None self._state = self.ST_DIRTY self._indices = () self._oid = () self._label = () self._modName = self._symName = '' self._mibNode = None def getMibSymbol(self): """Returns MIB variable symbolic identification. Returns ------- str MIB module name str MIB variable symbolic name : :py:class:`~pysnmp.proto.rfc1902.ObjectName` class instance representing MIB variable instance index. Raises ------ SmiError If MIB variable conversion has not been performed. Examples -------- >>> objectIdentity = ObjectIdentity('1.3.6.1.2.1.1.1.0') >>> objectIdentity.resolveWithMib(mibViewController) >>> objectIdentity.getMibSymbol() ('SNMPv2-MIB', 'sysDescr', (0,)) >>> """ if self._state & self.ST_CLEAN: return self._modName, self._symName, self._indices else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def getOid(self): """Returns OID identifying MIB variable. Returns ------- : :py:class:`~pysnmp.proto.rfc1902.ObjectName` full OID identifying MIB variable including possible index part. Raises ------ SmiError If MIB variable conversion has not been performed. Examples -------- >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0) >>> objectIdentity.resolveWithMib(mibViewController) >>> objectIdentity.getOid() ObjectName('1.3.6.1.2.1.1.1.0') >>> """ if self._state & self.ST_CLEAN: return self._oid else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def getLabel(self): """Returns symbolic path to this MIB variable. Meaning a sequence of symbolic identifications for each of parent MIB objects in MIB tree. Returns ------- tuple sequence of names of nodes in a MIB tree from the top of the tree towards this MIB variable. Raises ------ SmiError If MIB variable conversion has not been performed. Notes ----- Returned sequence may not contain full path to this MIB variable if some symbols are now known at the moment of MIB look up. Examples -------- >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0) >>> objectIdentity.resolveWithMib(mibViewController) >>> objectIdentity.getOid() ('iso', 'org', 'dod', 'internet', 'mgmt', 'mib-2', 'system', 'sysDescr') >>> """ if self._state & self.ST_CLEAN: return self._label else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def getMibNode(self): if self._state & self.ST_CLEAN: return self._mibNode else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def isFullyResolved(self): return self._state & self.ST_CLEAN # # A gateway to MIBs manipulation routines # def addAsn1MibSource(self, *asn1Sources, **kwargs): """Adds path to a repository to search ASN.1 MIB files. Parameters ---------- *asn1Sources : one or more URL in form of :py:obj:`str` identifying local or remote ASN.1 MIB repositories. Path must include the *@mib@* component which will be replaced with MIB module name at the time of search. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Notes ----- Please refer to :py:class:`~pysmi.reader.localfile.FileReader`, :py:class:`~pysmi.reader.httpclient.HttpReader` and :py:class:`~pysmi.reader.ftpclient.FtpReader` classes for in-depth information on ASN.1 MIB lookup. Examples -------- >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').addAsn1Source('http://mibs.snmplabs.com/asn1/@mib@') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self._asn1SourcesToAdd is None: self._asn1SourcesToAdd = asn1Sources else: self._asn1SourcesToAdd += asn1Sources if self._asn1SourcesOptions: self._asn1SourcesOptions.update(kwargs) else: self._asn1SourcesOptions = kwargs return self def addMibSource(self, *mibSources): """Adds path to repository to search PySNMP MIB files. Parameters ---------- *mibSources : one or more paths to search or Python package names to import and search for PySNMP MIB modules. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Notes ----- Normally, ASN.1-to-Python MIB modules conversion is performed automatically through PySNMP/PySMI interaction. ASN1 MIB modules could also be manually compiled into Python via the `mibdump.py `_ tool. Examples -------- >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').addMibSource('/opt/pysnmp/mibs', 'pysnmp_mibs') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self._mibSourcesToAdd is None: self._mibSourcesToAdd = mibSources else: self._mibSourcesToAdd += mibSources return self # provides deferred MIBs load def loadMibs(self, *modNames): """Schedules search and load of given MIB modules. Parameters ---------- *modNames: one or more MIB module names to load up and use for MIB variables resolution purposes. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Examples -------- >>> ObjectIdentity('SNMPv2-MIB', 'sysDescr').loadMibs('IF-MIB', 'TCP-MIB') ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self._modNamesToLoad is None: self._modNamesToLoad = modNames else: self._modNamesToLoad += modNames return self # this would eventually be called by an entity which posses a # reference to MibViewController def resolveWithMib(self, mibViewController): """Perform MIB variable ID conversion. Parameters ---------- mibViewController : :py:class:`~pysnmp.smi.view.MibViewController` class instance representing MIB browsing functionality. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Raises ------ SmiError In case of fatal MIB hanling errora Notes ----- Calling this method might cause the following sequence of events (exact details depends on many factors): * ASN.1 MIB file downloaded and handed over to :py:class:`~pysmi.compiler.MibCompiler` for conversion into Python MIB module (based on pysnmp classes) * Python MIB module is imported by SNMP engine, internal indices created * :py:class:`~pysnmp.smi.view.MibViewController` looks up the rest of MIB identification information based on whatever information is already available, :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` class instance gets updated and ready for further use. Examples -------- >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> objectIdentity.resolveWithMib(mibViewController) ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self._mibSourcesToAdd is not None: debug.logger & debug.FLAG_MIB and debug.logger( 'adding MIB sources %s' % ', '.join(self._mibSourcesToAdd)) mibViewController.mibBuilder.addMibSources( *[ZipMibSource(x) for x in self._mibSourcesToAdd]) self._mibSourcesToAdd = None if self._asn1SourcesToAdd is None: addMibCompiler( mibViewController.mibBuilder, ifAvailable=True, ifNotAdded=True) else: debug.logger & debug.FLAG_MIB and debug.logger( 'adding MIB compiler with source paths ' '%s' % ', '.join(self._asn1SourcesToAdd)) addMibCompiler( mibViewController.mibBuilder, sources=self._asn1SourcesToAdd, searchers=self._asn1SourcesOptions.get('searchers'), borrowers=self._asn1SourcesOptions.get('borrowers'), destination=self._asn1SourcesOptions.get('destination'), ifAvailable=self._asn1SourcesOptions.get('ifAvailable'), ifNotAdded=self._asn1SourcesOptions.get('ifNotAdded') ) self._asn1SourcesToAdd = self._asn1SourcesOptions = None if self._modNamesToLoad is not None: debug.logger & debug.FLAG_MIB and debug.logger( 'loading MIB modules %s' % ', '.join(self._modNamesToLoad)) mibViewController.mibBuilder.loadModules(*self._modNamesToLoad) self._modNamesToLoad = None if self._state & self.ST_CLEAN: return self MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibScalar', 'MibTableColumn') self._indices = () if isinstance(self._args[0], ObjectIdentity): self._args[0].resolveWithMib(mibViewController) if len(self._args) == 1: # OID or label or MIB module debug.logger & debug.FLAG_MIB and debug.logger( 'resolving %s as OID or label' % self._args) try: # pyasn1 ObjectIdentifier or sequence of ints or string OID self._oid = rfc1902.ObjectName(self._args[0]) # OID except PyAsn1Error: # sequence of sub-OIDs and labels if isinstance(self._args[0], (list, tuple)): prefix, label, suffix = mibViewController.getNodeName( self._args[0]) # string label elif '.' in self._args[0]: prefix, label, suffix = mibViewController.getNodeNameByOid( tuple(self._args[0].split('.'))) # MIB module name else: modName = self._args[0] mibViewController.mibBuilder.loadModules(modName) if self._kwargs.get('last'): (prefix, label, suffix) = mibViewController.getLastNodeName(modName) else: (prefix, label, suffix) = mibViewController.getFirstNodeName(modName) if suffix: try: suffix = tuple(int(x) for x in suffix) except ValueError: raise SmiError( 'Unknown object name component %r' % (suffix,)) self._oid = rfc1902.ObjectName(prefix + suffix) else: prefix, label, suffix = mibViewController.getNodeNameByOid( self._oid) debug.logger & debug.FLAG_MIB and debug.logger( 'resolved %r into prefix %r and suffix ' '%r' % (self._args, prefix, suffix)) modName, symName, _ = mibViewController.getNodeLocation(prefix) self._modName = modName self._symName = symName self._label = label mibNode, = mibViewController.mibBuilder.importSymbols( modName, symName) self._mibNode = mibNode debug.logger & debug.FLAG_MIB and debug.logger( 'resolved prefix %r into MIB node %r' % (prefix, mibNode)) if isinstance(mibNode, MibTableColumn): # table column if suffix: rowModName, rowSymName, _ = mibViewController.getNodeLocation( mibNode.name[:-1] ) rowNode, = mibViewController.mibBuilder.importSymbols( rowModName, rowSymName ) self._indices = rowNode.getIndicesFromInstId(suffix) elif isinstance(mibNode, MibScalar): # scalar if suffix: self._indices = (rfc1902.ObjectName(suffix),) else: if suffix: self._indices = (rfc1902.ObjectName(suffix),) self._state |= self.ST_CLEAN debug.logger & debug.FLAG_MIB and debug.logger( 'resolved indices are %r' % (self._indices,)) return self elif len(self._args) > 1: # MIB, symbol[, index, index ...] # MIB, symbol, index, index if self._args[0] and self._args[1]: self._modName = self._args[0] self._symName = self._args[1] # MIB, '' elif self._args[0]: mibViewController.mibBuilder.loadModules(self._args[0]) if self._kwargs.get('last'): (prefix, label, suffix) = mibViewController.getLastNodeName(self._args[0]) else: (prefix, label, suffix) = mibViewController.getFirstNodeName(self._args[0]) (self._modName, self._symName, _) = mibViewController.getNodeLocation(prefix) # '', symbol, index, index else: (prefix, label, suffix) = mibViewController.getNodeName(self._args[1:]) (self._modName, self._symName, _) = mibViewController.getNodeLocation(prefix) mibNode, = mibViewController.mibBuilder.importSymbols( self._modName, self._symName) self._mibNode = mibNode self._oid = rfc1902.ObjectName(mibNode.getName()) (prefix, label, suffix) = mibViewController.getNodeNameByOid( self._oid) self._label = label debug.logger & debug.FLAG_MIB and debug.logger( 'resolved %r into prefix %r and suffix ' '%r' % (self._args, prefix, suffix)) if isinstance(mibNode, MibTableColumn): # table rowModName, rowSymName, _ = mibViewController.getNodeLocation( mibNode.name[:-1]) rowNode, = mibViewController.mibBuilder.importSymbols( rowModName, rowSymName) if self._args[2:]: try: instIds = rowNode.getInstIdFromIndices(*self._args[2:]) self._oid += instIds self._indices = rowNode.getIndicesFromInstId(instIds) except PyAsn1Error as exc: raise SmiError( 'Instance index %r to OID conversion failure ' 'at object %r: ' '%s' % (self._args[2:], mibNode.getLabel(), exc)) elif self._args[2:]: # any other kind of MIB node with indices if self._args[2:]: instId = rfc1902.ObjectName( '.'.join(str(x) for x in self._args[2:])) self._oid += instId self._indices = (instId,) self._state |= self.ST_CLEAN debug.logger & debug.FLAG_MIB and debug.logger( 'resolved indices are %r' % (self._indices,)) return self else: raise SmiError('Non-OID, label or MIB symbol') def prettyPrint(self): if self._state & self.ST_CLEAN: s = rfc1902.OctetString() return '%s::%s%s%s' % ( self._modName, self._symName, self._indices and '.' or '', '.'.join((x.isSuperTypeOf(s, matchConstraints=False) and '"%s"' % x.prettyPrint() or x.prettyPrint()) for x in self._indices)) else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(repr(x) for x in self._args)) # Redirect some attrs access to the OID object to behave alike def __str__(self): if self._state & self.ST_CLEAN: return str(self._oid) else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __eq__(self, other): if self._state & self.ST_CLEAN: return self._oid == other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __ne__(self, other): if self._state & self.ST_CLEAN: return self._oid != other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __lt__(self, other): if self._state & self.ST_CLEAN: return self._oid < other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __le__(self, other): if self._state & self.ST_CLEAN: return self._oid <= other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __gt__(self, other): if self._state & self.ST_CLEAN: return self._oid > other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __ge__(self, other): if self._state & self.ST_CLEAN: return self._oid > other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __nonzero__(self): if self._state & self.ST_CLEAN: return self._oid != 0 else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __bool__(self): if self._state & self.ST_CLEAN: return bool(self._oid) else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __getitem__(self, i): if self._state & self.ST_CLEAN: return self._oid[i] else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __len__(self): if self._state & self.ST_CLEAN: return len(self._oid) else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __add__(self, other): if self._state & self.ST_CLEAN: return self._oid + other else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __radd__(self, other): if self._state & self.ST_CLEAN: return other + self._oid else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __hash__(self): if self._state & self.ST_CLEAN: return hash(self._oid) else: raise SmiError('%s object not properly ' 'initialized' % self.__class__.__name__) def __getattr__(self, attr): if self._state & self.ST_CLEAN: if attr in ('asTuple', 'clone', 'subtype', 'isPrefixOf', 'isSameTypeWith', 'isSuperTypeOf', 'getTagSet', 'getEffectiveTagSet', 'getTagMap', 'tagSet', 'index'): return getattr(self._oid, attr) raise AttributeError(attr) else: raise SmiError( '%s object not properly initialized for accessing ' '%s' % (self.__class__.__name__, attr)) class ObjectType(object): """Create an object representing MIB variable. Instances of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class are containers incorporating :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` class instance (identifying MIB variable) and optional value belonging to one of SNMP types (:RFC:`1902`). Typical MIB variable is defined like this (from *SNMPv2-MIB.txt*): .. code-block:: bash sysDescr OBJECT-TYPE SYNTAX DisplayString (SIZE (0..255)) MAX-ACCESS read-only STATUS current DESCRIPTION "A textual description of the entity. This value should..." ::= { system 1 } Corresponding ObjectType instantiation would look like this: .. code-block:: python ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr'), 'Linux i386 box') In order to behave like SNMP variable-binding (:RFC:`1157#section-4.1.1`), :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects also support sequence protocol addressing `objectIdentity` as its 0-th element and `objectSyntax` as 1-st. See :RFC:`1902#section-2` for more information on OBJECT-TYPE SMI definitions. Parameters ---------- objectIdentity : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` Class instance representing MIB variable identification. objectSyntax : Represents a value associated with this MIB variable. Values of built-in Python types will be automatically converted into SNMP object as specified in OBJECT-TYPE->SYNTAX field. Notes ----- Actual conversion between MIB variable representation formats occurs upon :py:meth:`~pysnmp.smi.rfc1902.ObjectType.resolveWithMib` invocation. Examples -------- >>> from pysnmp.smi.rfc1902 import * >>> ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0')) ObjectType(ObjectIdentity('1.3.6.1.2.1.1.1.0'), Null('')) >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386') """ ST_DIRTY, ST_CLEAM = 1, 2 def __init__(self, objectIdentity, objectSyntax=rfc1905.unSpecified): if not isinstance(objectIdentity, ObjectIdentity): raise SmiError( 'initializer should be ObjectIdentity instance, ' 'not %r' % (objectIdentity,)) self._args = [objectIdentity, objectSyntax] self._state = self.ST_DIRTY def __getitem__(self, i): if self._state & self.ST_CLEAM: return self._args[i] else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def __str__(self): return self.prettyPrint() def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join([repr(x) for x in self._args])) def isFullyResolved(self): return self._state & self.ST_CLEAM def addAsn1MibSource(self, *asn1Sources, **kwargs): """Adds path to a repository to search ASN.1 MIB files. Parameters ---------- *asn1Sources : one or more URL in form of :py:obj:`str` identifying local or remote ASN.1 MIB repositories. Path must include the *@mib@* component which will be replaced with MIB module name at the time of search. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectType` reference to itself Notes ----- Please refer to :py:class:`~pysmi.reader.localfile.FileReader`, :py:class:`~pysmi.reader.httpclient.HttpReader` and :py:class:`~pysmi.reader.ftpclient.FtpReader` classes for in-depth information on ASN.1 MIB lookup. Examples -------- >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')).addAsn1Source('http://mibs.snmplabs.com/asn1/@mib@') ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')) >>> """ self._args[0].addAsn1MibSource(*asn1Sources, **kwargs) return self def addMibSource(self, *mibSources): """Adds path to repository to search PySNMP MIB files. Parameters ---------- *mibSources : one or more paths to search or Python package names to import and search for PySNMP MIB modules. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectType` reference to itself Notes ----- Normally, ASN.1-to-Python MIB modules conversion is performed automatically through PySNMP/PySMI interaction. ASN1 MIB modules could also be manually compiled into Python via the `mibdump.py `_ tool. Examples -------- >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')).addMibSource('/opt/pysnmp/mibs', 'pysnmp_mibs') ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')) >>> """ self._args[0].addMibSource(*mibSources) return self def loadMibs(self, *modNames): """Schedules search and load of given MIB modules. Parameters ---------- *modNames: one or more MIB module names to load up and use for MIB variables resolution purposes. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectType` reference to itself Examples -------- >>> ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')).loadMibs('IF-MIB', 'TCP-MIB') ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr')) >>> """ self._args[0].loadMibs(*modNames) return self def resolveWithMib(self, mibViewController, ignoreErrors=True): """Perform MIB variable ID and associated value conversion. Parameters ---------- mibViewController : :py:class:`~pysnmp.smi.view.MibViewController` class instance representing MIB browsing functionality. Other Parameters ---------------- ignoreErrors: :py:class:`bool` If `True` (default), ignore MIB object name or value casting failures if possible. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectType` reference to itself Raises ------ SmiError In case of fatal MIB hanling errora Notes ----- Calling this method involves :py:meth:`~pysnmp.smi.rfc1902.ObjectIdentity.resolveWithMib` method invocation. Examples -------- >>> from pysmi.hlapi import varbinds >>> mibViewController = varbinds.AbstractVarBinds.getMibViewController( engine ) >>> objectType = ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr'), 'Linux i386') >>> objectType.resolveWithMib(mibViewController) ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr'), DisplayString('Linux i386')) >>> str(objectType) 'SNMPv2-MIB::sysDescr."0" = Linux i386' >>> """ if self._state & self.ST_CLEAM: return self self._args[0].resolveWithMib(mibViewController) MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibScalar', 'MibTableColumn') if not isinstance(self._args[0].getMibNode(), (MibScalar, MibTableColumn)): if (ignoreErrors and not isinstance(self._args[1], AbstractSimpleAsn1Item)): raise SmiError('MIB object %r is not OBJECT-TYPE ' '(MIB not loaded?)' % (self._args[0],)) self._state |= self.ST_CLEAM return self if isinstance(self._args[1], (rfc1905.UnSpecified, rfc1905.NoSuchObject, rfc1905.NoSuchInstance, rfc1905.EndOfMibView)): self._state |= self.ST_CLEAM return self syntax = self._args[0].getMibNode().getSyntax() try: self._args[1] = syntax.clone(self._args[1]) except PyAsn1Error as exc: err = ('MIB object %r having type %r failed to cast value ' '%r: %s' % (self.__args[0].prettyPrint(), self.__args[0].getMibNode().getSyntax().__class__.__name__, self.__args[1], sys.exc_info()[1])) debug.logger & debug.FLAG_MIB and debug.logger(err) if (not ignoreErrors or not isinstance(self.__args[1], AbstractSimpleAsn1Item)): raise SmiError(err) if rfc1902.ObjectIdentifier().isSuperTypeOf( self._args[1], matchConstraints=False): self._args[1] = ObjectIdentity( self._args[1]).resolveWithMib(mibViewController) self._state |= self.ST_CLEAM debug.logger & debug.FLAG_MIB and debug.logger( 'resolved %r syntax is %r' % (self._args[0], self._args[1])) return self def prettyPrint(self): if self._state & self.ST_CLEAM: return '%s = %s' % (self._args[0].prettyPrint(), self._args[1].prettyPrint()) else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) class NotificationType(object): """Create an object representing SNMP Notification. Instances of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class are containers incorporating :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` class instance (identifying particular notification) and a collection of MIB variables IDs that *NotificationOriginator* should gather and put into notification message. Typical notification is defined like this (from *IF-MIB.txt*): .. code-block:: bash linkDown NOTIFICATION-TYPE OBJECTS { ifIndex, ifAdminStatus, ifOperStatus } STATUS current DESCRIPTION "A linkDown trap signifies that the SNMP entity..." ::= { snmpTraps 3 } Corresponding NotificationType instantiation would look like this: .. code-block:: python NotificationType(ObjectIdentity('IF-MIB', 'linkDown')) To retain similarity with SNMP variable-bindings, :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects behave like a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances. See :RFC:`1902#section-2` for more information on NOTIFICATION-TYPE SMI definitions. Parameters ---------- objectIdentity: :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` Class instance representing MIB notification type identification. instanceIndex: :py:class:`~pysnmp.proto.rfc1902.ObjectName` Trailing part of MIB variables OID identification that represents concrete instance of a MIB variable. When notification is prepared, `instanceIndex` is appended to each MIB variable identification listed in NOTIFICATION-TYPE->OBJECTS clause. objects: dict Dictionary-like object that may return values by OID key. The `objects` dictionary is consulted when notification is being prepared. OIDs are taken from MIB variables listed in NOTIFICATION-TYPE->OBJECTS with `instanceIndex` part appended. Notes ----- Actual notification type and MIB variables look up occurs upon :py:meth:`~pysnmp.smi.rfc1902.NotificationType.resolveWithMib` invocation. Examples -------- >>> from pysnmp.smi.rfc1902 import * >>> NotificationType(ObjectIdentity('1.3.6.1.6.3.1.1.5.3')) NotificationType(ObjectIdentity('1.3.6.1.6.3.1.1.5.3'), (), {}) >>> NotificationType(ObjectIdentity('IP-MIB', 'linkDown'), ObjectName('3.5')) NotificationType(ObjectIdentity('1.3.6.1.6.3.1.1.5.3'), ObjectName('3.5'), {}) """ ST_DIRTY, ST_CLEAN = 1, 2 def __init__(self, objectIdentity, instanceIndex=(), objects={}): if not isinstance(objectIdentity, ObjectIdentity): raise SmiError( 'initializer should be ObjectIdentity instance, not ' '%r' % (objectIdentity,)) self._objectIdentity = objectIdentity self._instanceIndex = instanceIndex self._objects = objects self._varBinds = [] self._additionalVarBinds = [] self._state = self.ST_DIRTY def __getitem__(self, i): if self._state & self.ST_CLEAN: return self._varBinds[i] else: raise SmiError( '%s object not fully initialized' % self.__class__.__name__) def __repr__(self): return '%s(%r, %r, %r)' % ( self.__class__.__name__, self._objectIdentity, self._instanceIndex, self._objects) def addVarBinds(self, *varBinds): """Appends variable-binding to notification. Parameters ---------- *varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` One or more :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.NotificationType` reference to itself Notes ----- This method can be used to add custom variable-bindings to notification message in addition to MIB variables specified in NOTIFICATION-TYPE->OBJECTS clause. Examples -------- >>> nt = NotificationType(ObjectIdentity('IP-MIB', 'linkDown')) >>> nt.addVarBinds(ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))) NotificationType(ObjectIdentity('IP-MIB', 'linkDown'), (), {}) >>> """ debug.logger & debug.FLAG_MIB and debug.logger( 'additional var-binds: %r' % (varBinds,)) if self._state & self.ST_CLEAN: raise SmiError( '%s object is already sealed' % self.__class__.__name__) else: self._additionalVarBinds.extend(varBinds) return self def addAsn1MibSource(self, *asn1Sources, **kwargs): """Adds path to a repository to search ASN.1 MIB files. Parameters ---------- *asn1Sources : one or more URL in form of :py:obj:`str` identifying local or remote ASN.1 MIB repositories. Path must include the *@mib@* component which will be replaced with MIB module name at the time of search. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.NotificationType` reference to itself Notes ----- Please refer to :py:class:`~pysmi.reader.localfile.FileReader`, :py:class:`~pysmi.reader.httpclient.HttpReader` and :py:class:`~pysmi.reader.ftpclient.FtpReader` classes for in-depth information on ASN.1 MIB lookup. Examples -------- >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).addAsn1Source('http://mibs.snmplabs.com/asn1/@mib@') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> """ self._objectIdentity.addAsn1MibSource(*asn1Sources, **kwargs) return self def addMibSource(self, *mibSources): """Adds path to repository to search PySNMP MIB files. Parameters ---------- *mibSources : one or more paths to search or Python package names to import and search for PySNMP MIB modules. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.NotificationType` reference to itself Notes ----- Normally, ASN.1-to-Python MIB modules conversion is performed automatically through PySNMP/PySMI interaction. ASN1 MIB modules could also be manually compiled into Python via the `mibdump.py `_ tool. Examples -------- >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).addMibSource('/opt/pysnmp/mibs', 'pysnmp_mibs') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> """ self._objectIdentity.addMibSource(*mibSources) return self def loadMibs(self, *modNames): """Schedules search and load of given MIB modules. Parameters ---------- *modNames: one or more MIB module names to load up and use for MIB variables resolution purposes. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.NotificationType` reference to itself Examples -------- >>> NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}).loadMibs('IF-MIB', 'TCP-MIB') NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> """ self._objectIdentity.loadMibs(*modNames) return self def isFullyResolved(self): return self._state & self.ST_CLEAN def resolveWithMib(self, mibViewController): """Perform MIB variable ID conversion and notification objects expansion. Parameters ---------- mibViewController : :py:class:`~pysnmp.smi.view.MibViewController` class instance representing MIB browsing functionality. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.NotificationType` reference to itself Raises ------ SmiError In case of fatal MIB hanling errora Notes ----- Calling this method might cause the following sequence of events (exact details depends on many factors): * :py:meth:`pysnmp.smi.rfc1902.ObjectIdentity.resolveWithMib` is called * MIB variables names are read from NOTIFICATION-TYPE->OBJECTS clause, :py:class:`~pysnmp.smi.rfc1902.ObjectType` instances are created from MIB variable OID and `indexInstance` suffix. * `objects` dictionary is queried for each MIB variable OID, acquired values are added to corresponding MIB variable Examples -------- >>> notificationType = NotificationType(ObjectIdentity('IF-MIB', 'linkDown')) >>> notificationType.resolveWithMib(mibViewController) NotificationType(ObjectIdentity('IF-MIB', 'linkDown'), (), {}) >>> """ if self._state & self.ST_CLEAN: return self self._objectIdentity.resolveWithMib(mibViewController) self._varBinds.append( ObjectType(ObjectIdentity(v2c.apiTrapPDU.snmpTrapOID), self._objectIdentity).resolveWithMib(mibViewController)) SmiNotificationType, = mibViewController.mibBuilder.importSymbols( 'SNMPv2-SMI', 'NotificationType') mibNode = self._objectIdentity.getMibNode() varBindsLocation = {} if isinstance(mibNode, SmiNotificationType): for notificationObject in mibNode.getObjects(): objectIdentity = ObjectIdentity( *notificationObject + self._instanceIndex) objectIdentity.resolveWithMib(mibViewController) objectType = ObjectType( objectIdentity, self._objects.get( notificationObject, rfc1905.unSpecified)) objectType.resolveWithMib(mibViewController) self._varBinds.append(objectType) varBindsLocation[objectIdentity] = len(self._varBinds) - 1 else: debug.logger & debug.FLAG_MIB and debug.logger( 'WARNING: MIB object %r is not NOTIFICATION-TYPE (MIB not ' 'loaded?)' % (self._objectIdentity,)) for varBinds in self._additionalVarBinds: if not isinstance(varBinds, ObjectType): varBinds = ObjectType(ObjectIdentity(varBinds[0]), varBinds[1]) varBinds.resolveWithMib(mibViewController) if varBinds[0] in varBindsLocation: self._varBinds[varBindsLocation[varBinds[0]]] = varBinds else: self._varBinds.append(varBinds) self._additionalVarBinds = [] self._state |= self.ST_CLEAN debug.logger & debug.FLAG_MIB and debug.logger( 'resolved %r into %r' % (self._objectIdentity, self._varBinds)) return self def prettyPrint(self): if self._state & self.ST_CLEAN: return ' '.join('%s = %s' % (x[0].prettyPrint(), x[1].prettyPrint()) for x in self._varBinds) raise SmiError( '%s object not fully initialized' % self.__class__.__name__)