def loadConfig(filename): """Load and parse .yaml configuration file Args: filename (str): Path to system configuration file Returns: dict: representing configuration information Raises: BdsError: if unable to get configuration information """ try: with open(filename) as stream: config = yaml.load(stream) return config['bdsSnmpAdapter'] except Exception as exc: raise error.BdsError( 'Failed to read configuration file %s: %s' % (filename, exc))
def willRaise(): raise error.BdsError()
def __init__(self, args, queue): configDict = loadConfig(args.config) self.moduleLogger = set_logging(configDict, __class__.__name__) self.moduleLogger.info(f'original configDict: {configDict}') self._queue = queue # temp lines for graylog client end # # configDict['usmUserDataMatrix'] = [ usmUserTuple.strip().split(',') # for usmUserTuple in configDict['usmUserTuples'].split(';') if len(usmUserTuple) > 0 ] # self.moduleLogger.debug('configDict['usmUserDataMatrix']: {}'.format(configDict['usmUserDataMatrix'])) # configDict['usmUsers'] = [] self.moduleLogger.info(f'modified configDict: {configDict}') self._snmpEngine = snmp_config.getSnmpEngine( engineId=configDict['snmp'].get('engineId')) engineBoots = snmp_config.setSnmpEngineBoots( self._snmpEngine, configDict.get('stateDir', '.')) self._targets = snmp_config.setTrapTypeForTag(self._snmpEngine, self.TARGETS_TAG) authEntries = {} for snmpVersion, snmpConfigEntries in configDict['snmp'].get( 'versions', {}).items(): snmpVersion = str(snmpVersion) if snmpVersion in ('1', '2c'): for security, snmpConfig in snmpConfigEntries.items(): community = snmpConfig['community'] authLevel = snmp_config.setCommunity( self._snmpEngine, security, community, version=snmpVersion, tag=self.TARGETS_TAG) self.moduleLogger.info( f'Configuring SNMPv{snmpVersion} security name ' f'{security}, community name {community}') authEntries[security] = snmpVersion, authLevel elif snmpVersion == '3': for security, usmCreds in snmpConfigEntries.get('usmUsers', {}).items(): authLevel = snmp_config.setUsmUser( self._snmpEngine, security, usmCreds.get('user'), usmCreds.get('authKey'), usmCreds.get('authProtocol'), usmCreds.get('privKey'), usmCreds.get('privProtocol')) self.moduleLogger.info( f'Configuring SNMPv3 USM security {security}, user ' f'{usmCreds.get("user")}, ' f'auth {usmCreds.get("authKey")}/{usmCreds.get("authProtocol")}, ' f'priv {usmCreds.get("privKey")}/{usmCreds.get("privProtocol")}') authEntries[security] = snmpVersion, authLevel else: raise error.BdsError(f'Unknown SNMP version {snmpVersion}') self._birthday = time.time() snmpTrapTargets = configDict['notificator'].get('snmpTrapTargets', {}).items() for targetId, (targetName, targetConfig) in enumerate(snmpTrapTargets): bind_address = targetConfig.get('bind-address', '0.0.0.0'), 0 security = targetConfig['security-name'] transportDomain = snmp_config.setSnmpTransport( self._snmpEngine, iface=bind_address, iface_num=targetId) transportAddress = (targetConfig['address'], int(targetConfig.get('port', 162))) snmp_config.setTrapTargetAddress( self._snmpEngine, security, transportDomain, transportAddress, tag=self.TARGETS_TAG) snmpVersion, authLevel = authEntries[security] snmp_config.setTrapVersion( self._snmpEngine, security, authLevel, snmpVersion) self.moduleLogger.info( f'Configuring target #{targetId}, transport domain ' f'{transportDomain}, destination {transportAddress}, ' f'bind address {bind_address} using security name {security}') self._configureMibObjects(configDict) self._ntfOrg = ntforg.NotificationOriginator() self._trapCounter = 0 self.moduleLogger.info( f'Running SNMP engine ID {self._snmpEngine}, boots {engineBoots}')
def __init__(self, args, mibController): self.mibController = mibController configDict = loadConfig(args.config) self.moduleLogger = set_logging(configDict, __class__.__name__) self.moduleLogger.debug(f'configDict:{configDict}') self.snmpEngine = snmp_config.getSnmpEngine( engineId=configDict['snmp'].get('engineId')) engineBoots = snmp_config.setSnmpEngineBoots( self.snmpEngine, configDict.get('stateDir', '.')) self.listeningAddress = configDict['responder']['listeningIP'] self.listeningPort = configDict['responder']['listeningPort'] self.birthday = time.time() self.moduleLogger.info( f'Running SNMP engine ID {self.snmpEngine.snmpEngineID.prettyPrint()}, ' f'boots {engineBoots}') # UDP over IPv4 try: snmp_config.setSnmpTransport( self.snmpEngine, (self.listeningAddress, self.listeningPort)) except Exception as exc: self.moduleLogger.error(f'SNMP transport error: {exc}') raise self.moduleLogger.info( f'SnmpEngine UDPv4 listening on {self.listeningAddress} ' f'{self.listeningPort}') for snmpVersion, snmpConfigEntries in configDict['snmp'].get( 'versions', {}).items(): snmpVersion = str(snmpVersion) if snmpVersion in ('1', '2c'): for security, snmpConfig in snmpConfigEntries.items(): community = snmpConfig['community'] snmp_config.setCommunity( self.snmpEngine, security, community, version=snmpVersion) self.moduleLogger.info( f'Configuring SNMPv{snmpVersion} security name ' f'{security}, community name {community}') elif snmpVersion == '3': for security, usmCreds in snmpConfigEntries.get('usmUsers', {}).items(): snmp_config.setUsmUser( self.snmpEngine, security, usmCreds.get('user'), usmCreds.get('authKey'), usmCreds.get('authProtocol'), usmCreds.get('privKey'), usmCreds.get('privProtocol')) self.moduleLogger.info( f'Configuring SNMPv3 USM security {security}, user ' f'{usmCreds.get("user")}, ' f'auth {usmCreds.get("authKey")}/{usmCreds.get("authProtocol")}, ' f'priv {usmCreds.get("privKey")}/{usmCreds.get("privProtocol")}') else: raise error.BdsError('Unknown SNMP version {snmpVersion}') snmpContext = snmp_config.setMibController( self.snmpEngine, mibController) self.moduleLogger.info( f'Configuring SNMP context name "{snmpContext}"') cmdrsp.GetCommandResponder(self.snmpEngine, snmpContext) cmdrsp.NextCommandResponder(self.snmpEngine, snmpContext) cmdrsp.BulkCommandResponder(self.snmpEngine, snmpContext) self.snmpEngine.transportDispatcher.jobStarted(1)
def add(self, mibName, mibSymbol, *indices, value=None, valueFormat=None, code=None): """Add SNMP MIB managed object instance to the OID DB Args: mibName (str): MIB name e.g. SNMPv2-MIB. This MIB must be in MIB search path. mibSymbol (str): MIB symbol name indices (vararg): one or more objects representing indices. Should be `0` for scalars. value: put this value into MIB managed object. This is what SNMP manager will get in response. The `None` sentinel refreshes existing object. valueFormat (string): 'hexValue' to indicate hex `value` initializer. Optional. code (string): compile and use this Python code snippet for getting a value at run time. Optional. Examples: add('SNMPv2-MIB', 'sysDescr', 0, value='hello world') add('SNMPv2-MIB', 'sysDescr', 0, value='10101010', valueFormat='binValue') add('SNMPv2-MIB', 'sysDescr', 0, code='print("hello world")') """ if value is None: objectIdentity = rfc1902.ObjectIdentity( mibName, mibSymbol, *indices).resolveWithMib(self._mibViewController) try: oidDbItem = self._oids[objectIdentity.getOid()] except KeyError: raise error.BdsError( 'Initial value for managed %s::%s object must be ' 'provided' % (mibName, mibSymbol)) else: obj = rfc1902.ObjectType( rfc1902.ObjectIdentity(mibName, mibSymbol, *indices), value) objectIdentity, objectSyntax = obj.resolveWithMib(self._mibViewController) try: representation = {valueFormat if valueFormat else 'value': value} objectSyntax = objectSyntax.clone(**representation) if code: code = compile(code, '<%s::%s>' % (mibName, mibSymbol), 'exec') oidDbItem = OidDbItem( oid=objectIdentity.getOid(), name=objectIdentity.getMibSymbol()[1], value=objectSyntax, code=code ) except Exception as exc: raise error.BdsError( 'Error setting managed object %s (%s) of type %s to value ' '"%s"' % ('::'.join(objectIdentity.getMibSymbol()), objectIdentity.getOid(), objectSyntax, value)) self.moduleLogger.debug( f'{"updating" if oidDbItem.oid in self._oids else "adding"} ' f'{oidDbItem.oid} {"<code>" if code else oidDbItem.value.prettyPrint()}') # put new OID online immediately self._oids[oidDbItem.oid] = oidDbItem self._dirty = True now = time.time() mibObject = mibName, mibSymbol # We update two DBs for some time while use only one, eventually # we drop the older DB and use the newer one. This effectively # expires DB entries that do not get updated for some time. self._mibObjects[mibObject][oidDbItem.oid] = oidDbItem self._candidateMibObjects[mibObject][oidDbItem.oid] = oidDbItem if self._expireBy < now: # put candidate objects online (self._mibObjects[mibObject], self._candidateMibObjects[mibObject]) = ( self._candidateMibObjects[mibObject], self._mibObjects[mibObject]) # prepare new candidate objects dict - drop everything it has, # most importantly, entries that have not been updated # N.B. this only works for tablular SNMP objects self._candidateMibObjects[mibObject].clear() # stale entries expire in two runs of `.add` self._expireBy = now + self.EXPIRE_PERIOD / 2 # drop all online OIDs self._oids.clear() # put recently updated OIDs online for oidItems in self._mibObjects.values(): self._oids.update(oidItems)
def setUsmUser(snmpEngine, security, user, authKey=None, authProtocol=None, privKey=None, privProtocol=None): """Configure SNMP v3 USM user credentials and VACM access. Args: snmpEngine (object): pysnmp `SnmpEngine` class instance security (str): SNMP security name. Used in SNMP engine configuration primarily as an ID for the given SNMP v3 authentication information. user (str): SNMP v3 USM user name authKey (str): SNMP v3 USM authentication key. Must be 8+ characters long, unless no SNMP message authentication is in use. Defaults to `None`. authProtocol (str): Authentication protocol to use. Known values are: 'MD5', 'SHA', 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'NONE'. Defaults to 'NONE'. privKey (str): SNMP v3 USM privacy key. Must be 8+ characters long, unless no SNMP payload encryption is in use. Defaults to `None`. privProtocol (str): SNMP message encryption protocol to use. Known values are: 'DES', '3DES', 'AES', 'AES128', 'AES192', 'AES192BLMT', 'AES256', 'AES256BLMT', 'NONE'. Defaults to 'NONE'. Returns: str: effective SNMP authentication and privacy level. Known values are: 'noAuthNoPriv', 'authNoPriv', 'authPriv'. """ if not authKey: authProtocol = 'NONE' elif not authProtocol: authProtocol = 'MD5' if not privKey: privProtocol = 'NONE' elif not privProtocol: privProtocol = 'DES' authProtocol = AUTH_PROTOCOLS[authProtocol.upper()] privProtocol = PRIV_PROTOCOLS[privProtocol.upper()] if (authProtocol == config.usmNoAuthProtocol and privProtocol != config.usmNoPrivProtocol): raise error.BdsError('SNMP privacy implies enabled authentication') elif (authProtocol == config.usmNoAuthProtocol and privProtocol == config.usmNoPrivProtocol): authLevel = 'noAuthNoPriv' elif privProtocol != config.usmNoPrivProtocol: authLevel = 'authPriv' else: authLevel = 'authNoPriv' config.addV3User( snmpEngine, user, authProtocol, authKey, privProtocol, privKey, securityName=security) config.addVacmUser( snmpEngine, 3, security, authLevel, (1, 3, 6), (1, 3, 6), (1, 3, 6)) return authLevel