def parse_metric_tags(self, metric_tags): # type: (List[Dict[str, Any]]) -> Tuple[List[Any], List[ParsedMetricTag]] """Parse configuration for global metric_tags.""" oids = [] parsed_metric_tags = [] for tag in metric_tags: if not ('symbol' in tag and 'tag' in tag): raise ConfigurationError( "A metric tag needs to specify a symbol and a tag: {}". format(tag)) if not ('OID' in tag or 'MIB' in tag): raise ConfigurationError( "A metric tag needs to specify an OID or a MIB: {}".format( tag)) symbol = tag['symbol'] tag_name = tag['tag'] if 'MIB' in tag: mib = tag['MIB'] identity = hlapi.ObjectIdentity(mib, symbol) else: oid = tag['OID'] identity = hlapi.ObjectIdentity(oid) self._resolver.register(to_oid_tuple(oid), symbol) object_type = hlapi.ObjectType(identity) oids.append(object_type) parsed_metric_tags.append(ParsedMetricTag(tag_name, symbol)) return oids, parsed_metric_tags
def get_node(conn): node = {} name = SnmpApi.ObjectType( SnmpApi.ObjectIdentity('SNMPv2-MIB', 'sysName', 0)) descr = SnmpApi.ObjectType( SnmpApi.ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)) errorIndication, errorStatus, errorIndex, varBinds = next( SnmpApi.getCmd(conn['snmpEng'], conn['community'], conn['target'], conn['context'], name, descr)) if errorIndication: print(errorIndication) elif errorStatus: print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) else: for varBind in varBinds: (oid, value) = [x.prettyPrint() for x in varBind] if value is None: continue if re.search('sysName', oid): node['name'] = value elif re.search('sysDescr', oid): node['descr'] = value return node
def extract_symbol(mib, symbol): if isinstance(symbol, dict): symbol_oid = symbol['OID'] symbol = symbol['name'] self._resolver.register(to_oid_tuple(symbol_oid), symbol) identity = hlapi.ObjectIdentity(symbol_oid) else: identity = hlapi.ObjectIdentity(mib, symbol) return identity, symbol
def parse_metrics(metrics, enforce_constraints, warning): """Parse configuration and returns data to be used for SNMP queries. `raw_oids` is a list of SNMP numerical OIDs to query. `table_oids` is a dictionnary of SNMP tables to symbols to query. `mibs_to_load` contains the relevant MIBs used for querying. """ raw_oids = [] table_oids = {} mibs_to_load = set() # Check the metrics completely defined for metric in metrics: if 'MIB' in metric: if not ('table' in metric or 'symbol' in metric): raise ConfigurationError('When specifying a MIB, you must specify either table or symbol') if not enforce_constraints: # We need this only if we don't enforce constraints to be able to lookup MIBs manually mibs_to_load.add(metric['MIB']) if 'symbol' in metric: to_query = metric['symbol'] try: table_oids[hlapi.ObjectType(hlapi.ObjectIdentity(metric['MIB'], to_query))] = [] except Exception as e: warning("Can't generate MIB object for variable : %s\nException: %s", metric, e) elif 'symbols' not in metric: raise ConfigurationError('When specifying a table, you must specify a list of symbols') else: symbols = [] table_oids[hlapi.ObjectType(hlapi.ObjectIdentity(metric['MIB'], metric['table']))] = symbols for symbol in metric['symbols']: try: symbols.append(hlapi.ObjectType(hlapi.ObjectIdentity(metric['MIB'], symbol))) except Exception as e: warning("Can't generate MIB object for variable : %s\nException: %s", metric, e) if 'metric_tags' in metric: for metric_tag in metric['metric_tags']: if not ('tag' in metric_tag and ('index' in metric_tag or 'column' in metric_tag)): raise ConfigurationError( 'When specifying metric tags, you must specify a tag, and an index or column' ) if 'column' in metric_tag: # In case it's a column, we need to query it as well try: symbols.append( hlapi.ObjectType(hlapi.ObjectIdentity(metric['MIB'], metric_tag.get('column'))) ) except Exception as e: warning("Can't generate MIB object for variable : %s\nException: %s", metric, e) elif 'OID' in metric: raw_oids.append(hlapi.ObjectType(hlapi.ObjectIdentity(metric['OID']))) else: raise ConfigurationError('Unsupported metric in config file: {}'.format(metric)) return table_oids, raw_oids, mibs_to_load
def get_ifs(conn): ifs = {} iftype = SnmpApi.ObjectType(SnmpApi.ObjectIdentity('IF-MIB', 'ifType')) ifname = SnmpApi.ObjectType(SnmpApi.ObjectIdentity('IF-MIB', 'ifName')) ifdescr = SnmpApi.ObjectType(SnmpApi.ObjectIdentity('IF-MIB', 'ifDescr')) ifalias = SnmpApi.ObjectType(SnmpApi.ObjectIdentity('IF-MIB', 'ifAlias')) for (errorIndication, errorStatus, errorIndex, varBinds) in SnmpApi.nextCmd(conn['snmpEng'], conn['community'], conn['target'], conn['context'], iftype, ifname, ifdescr, ifalias, lexicographicMode=False): if errorIndication: print(errorIndication) continue elif errorStatus: print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) continue for varBind in varBinds: (oid, value) = [x.prettyPrint() for x in varBind] if value is None: continue index = (oid.split('.'))[-1] if index not in ifs: ifs[index] = {} if re.search('ifType', oid): label = 'ifType' elif re.search('ifName', oid): label = 'ifName' elif re.search('ifDescr', oid): label = 'ifDescr' elif re.search('ifAlias', oid): label = 'ifAlias' else: continue ifs[index][label] = value return ifs
def set(oid, value, host, port=161, community='private', timeout=0, retries=0, snmp_ver=2): try: for (err_i, err_st, err_idx, vals) in snmp_engine.setCmd( snmp_engine.SnmpEngine(), snmp_engine.CommunityData(community, mpModel=snmp_ver - 1), snmp_engine.UdpTransportTarget((host, port), timeout=timeout, retries=retries), snmp_engine.ContextData(), snmp_engine.ObjectType(snmp_engine.ObjectIdentity(oid), value)): if err_i or err_st: logging.debug('snmp error: %s' % err_i) return None else: return True except: log_traceback() return False
def resolve_oid(self, oid): """Resolve an OID to a name and its indexes. This first tries to do manual resolution using `self._resolver`, then falls back to MIB resolution if that fails. In the first case it also tries to resolve indexes to name if that applies, using `self._index_resolver`. """ oid_tuple = oid.asTuple() prefix, resolved = self._resolver.match(oid_tuple) if resolved is not None: index_resolver = self._index_resolver.get(resolved) indexes = oid_tuple[len(prefix):] if index_resolver: new_indexes = [] for i, index in enumerate(indexes, 1): if i in index_resolver: new_indexes.append(index_resolver[i][index]) else: new_indexes.append(index) indexes = new_indexes return resolved, tuple(str(index) for index in indexes) result_oid = oid if not self._enforce_constraints: # if enforce_constraints is false, then MIB resolution has not been done yet # so we need to do it manually. We have to specify the mibs that we will need # to resolve the name. oid_to_resolve = hlapi.ObjectIdentity(oid_tuple) result_oid = oid_to_resolve.resolveWithMib( self._mib_view_controller) _, metric, indexes = result_oid.getMibSymbol() return metric, tuple(index.prettyPrint() for index in indexes)
def snmpWalk(snmpVersion, community, host, port, oid): logging.info('New Walk Query [v:%d, %s, %s, %d, %s]', snmpVersion, community, host, port, oid) generator = snmp.nextCmd(snmp.SnmpEngine(), snmp.CommunityData(community, mpModel=snmpVersion), snmp.UdpTransportTarget((host, port)), snmp.ContextData(), snmp.ObjectType(snmp.ObjectIdentity(oid)), lexicographicMode=False) results = dict() for errorIndication, errorStatus, errorIndex, varBinds in generator: if errorIndication: logging.error(errorIndication) raise Exception('SnmpWalk ErrorIndication.') if errorStatus: logging.error( '%s at %s', errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?') raise Exception('SnmpWalk ErrorStatus.') for name, value in varBinds: results[str(name)] = str(value) return results
def _autodetect(self): from pysnmp import hlapi for (errorIndication, errorStatus, errorIndex, varBindTable) in hlapi.getCmd( hlapi.SnmpEngine(), hlapi.CommunityData('public'), hlapi.UdpTransportTarget((self.hostname, 161)), hlapi.ContextData(), hlapi.ObjectType( hlapi.ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))): if errorIndication: Exception("snmp error {}".format(errorIndication)) elif errorStatus: Exception("snmp error {}".format(errorStatus)) else: sysDescr = str(varBindTable[0][1]) if sysDescr.startswith("HPE OfficeConnect Switch 1820 24G J9980A,"): self._get_fdb = self._get_fdb_dot1q elif sysDescr.startswith("HP 1810-24G,"): self._get_fdb = self._get_fdb_dot1d else: Exception("unsupported switch {}".format(sysDescr)) self.logger.debug("autodetected switch{}: {} {}".format( sysDescr, self._get_ports, self._get_fdb))
def snmpWalk(snmpVersion, community, host, port, oid): generator = snmp.nextCmd(snmp.SnmpEngine(), snmp.CommunityData(community, mpModel=snmpVersion), snmp.UdpTransportTarget((host, port)), snmp.ContextData(), snmp.ObjectType(snmp.ObjectIdentity(oid)), lexicographicMode=False) results = dict() for errorIndication, errorStatus, errorIndex, varBinds in generator: if errorIndication: print(errorIndication) continue if errorStatus: print('%s at %s', errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?') continue for name, value in varBinds: results[str(name)] = str(value) return results
def get(self, oid): """Use PySNMP to perform an SNMP GET operation on a single object. :param oid: The OID of the object to get. :raises: SNMPFailure if an SNMP request fails. :returns: The value of the requested object. """ try: snmp_gen = snmp.getCmd(self.snmp_engine, self._get_auth(), self._get_transport(), self._get_context(), snmp.ObjectType(snmp.ObjectIdentity(oid))) except snmp_error.PySnmpError as e: raise exception.SNMPFailure(operation="GET", error=e) error_indication, error_status, error_index, var_binds = next(snmp_gen) if error_indication: # SNMP engine-level error. raise exception.SNMPFailure(operation="GET", error=error_indication) if error_status: # SNMP PDU error. raise exception.SNMPFailure(operation="GET", error=error_status.prettyPrint()) # We only expect a single value back name, val = var_binds[0] return val
def check_table(self, config, table_oids): """ Perform a snmpwalk on the domain specified by the oids, on the device configured in instance. Returns a dictionary: dict[oid/metric_name][row index] = value In case of scalar objects, the row index is just 0 """ results = defaultdict(dict) enforce_constraints = config.enforce_constraints oids = [] bulk_oids = [] # Use bulk for SNMP version > 1 and there are enough symbols bulk_limit = config.bulk_threshold if config.auth_data.mpModel else 0 for table, symbols in table_oids.items(): if not symbols: # No table to browse, just one symbol oids.append(table) elif len(symbols) < bulk_limit: oids.extend(symbols) else: bulk_oids.append(table) all_binds, error = self.fetch_oids(config, oids, enforce_constraints=enforce_constraints) for oid in bulk_oids: try: self.log.debug('Running SNMP command getBulk on OID %r', oid) binds_iterator = config.call_cmd( hlapi.bulkCmd, self._NON_REPEATERS, self._MAX_REPETITIONS, oid, lookupMib=enforce_constraints, ignoreNonIncreasingOid=self.ignore_nonincreasing_oid, lexicographicMode=False, ) binds, error = self._consume_binds_iterator(binds_iterator, config) all_binds.extend(binds) except PySnmpError as e: message = 'Failed to collect some metrics: {}'.format(e) if not error: error = message self.warning(message) for result_oid, value in all_binds: if not enforce_constraints: # if enforce_constraints is false, then MIB resolution has not been done yet # so we need to do it manually. We have to specify the mibs that we will need # to resolve the name. oid_to_resolve = hlapi.ObjectIdentity(result_oid.asTuple()).loadMibs(*config.mibs_to_load) result_oid = oid_to_resolve.resolveWithMib(config.mib_view_controller) _, metric, indexes = result_oid.getMibSymbol() results[metric][indexes] = value self.log.debug('Raw results: %s', results) # Freeze the result results.default_factory = None return results, error
def snmpGet(snmpVersion, community, host, port, oids): logging.info('New Get Query [v:%d, %s, %s, %d, %s]', snmpVersion, community, host, port, oids) objectTypes = [snmp.ObjectType(snmp.ObjectIdentity(oid)) for oid in oids] errorIndication, errorStatus, errorIndex, varBinds = next( snmp.getCmd(snmp.SnmpEngine(), snmp.CommunityData(community, mpModel=snmpVersion), snmp.UdpTransportTarget((host, port)), snmp.ContextData(), *objectTypes)) if errorIndication: logging.error(errorIndication) return None if errorStatus: logging.error('%s at %s', errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?') return None results = [(str(name), str(value)) for name, value in varBinds] return dict(results)
def set_oid_value(oid, value, host="localhost", port=1024): """Helper function to set snmp oid value of a device""" error_indicator, error_status, error_idx, var_binds = next( hlapi.setCmd( hlapi.SnmpEngine(), hlapi.CommunityData("private", mpModel=0), hlapi.UdpTransportTarget((host, port)), hlapi.ContextData(), hlapi.ObjectType(hlapi.ObjectIdentity(oid), value), lookupMib=False, ) ) if error_indicator: print(error_indicator) elif error_status: print( "%s at %s" % ( error_status.prettyPrint(), error_idx and var_binds[int(error_idx) - 1][0] or "?", ) ) else: v_bind = var_binds[0] return v_bind[1] return None
def set(self, oid, value): """Use PySNMP to perform an SNMP SET operation on a single object. :param oid: The OID of the object to set. :param value: The value of the object to set. :raises: SNMPFailure if an SNMP request fails. """ try: snmp_gen = snmp.setCmd(self.snmp_engine, self._get_auth(write_mode=True), self._get_transport(), self._get_context(), snmp.ObjectType( snmp.ObjectIdentity(oid), value)) except snmp_error.PySnmpError as e: raise exception.SNMPFailure(operation="SET", error=e) error_indication, error_status, error_index, var_binds = next(snmp_gen) if error_indication: # SNMP engine-level error. raise exception.SNMPFailure(operation="SET", error=error_indication) if error_status: # SNMP PDU error. raise exception.SNMPFailure(operation="SET", error=error_status.prettyPrint())
def _get_fdb_dot1q(self): """Fetch the forwarding database via SNMP using the Q-BRIDGE-MIB Returns: Dict[List[str]]: ports and their values """ from pysnmp import hlapi ports = {} for (errorIndication, errorStatus, errorIndex, varBindTable) in hlapi.bulkCmd( hlapi.SnmpEngine(), hlapi.CommunityData('public'), hlapi.UdpTransportTarget((self.hostname, 161)), hlapi.ContextData(), 0, 50, hlapi.ObjectType( hlapi.ObjectIdentity('Q-BRIDGE-MIB', 'dot1qTpFdbPort')), lexicographicMode=False): if errorIndication: Exception("snmp error {}".format(errorIndication)) elif errorStatus: Exception("snmp error {}".format(errorStatus)) else: for varBinds in varBindTable: key, val = varBinds if not val: continue mac = key.getMibSymbol()[-1][1].prettyPrint() interface = str(int(val)) ports.setdefault(interface, []).append(mac) return ports
def construct_value_pairs(list_of_pairs): pairs = [] for key, value in list_of_pairs.items(): pairs.append(hlapi.ObjectType(hlapi.ObjectIdentity(key), value)) return pairs
def construct_object_types(list_of_oids): object_types = [] for oid in list_of_oids: object_types.append(hlapi.ObjectType(hlapi.ObjectIdentity(oid))) return object_types
def fetch_oids(self, config, oids, enforce_constraints): # UPDATE: We used to perform only a snmpgetnext command to fetch metric values. # It returns the wrong value when the OID passeed is referring to a specific leaf. # For example: # snmpgetnext -v2c -c public localhost:11111 1.3.6.1.2.1.25.4.2.1.7.222 # iso.3.6.1.2.1.25.4.2.1.7.224 = INTEGER: 2 # SOLUTION: perform a snmpget command and fallback with snmpgetnext if not found error = None first_oid = 0 all_binds = [] while first_oid < len(oids): try: oids_batch = oids[first_oid:first_oid + self.oid_batch_size] self.log.debug('Running SNMP command get on OIDS %s', oids_batch) error_indication, error_status, _, var_binds = next( config.call_cmd(hlapi.getCmd, *oids_batch, lookupMib=enforce_constraints)) self.log.debug('Returned vars: %s', var_binds) self.raise_on_error_indication(error_indication, config.ip_address) missing_results = [] for var in var_binds: result_oid, value = var if reply_invalid(value): oid_tuple = result_oid.asTuple() missing_results.append( hlapi.ObjectType(hlapi.ObjectIdentity(oid_tuple))) else: all_binds.append(var) if missing_results: # If we didn't catch the metric using snmpget, try snmpnext # Don't walk through the entire MIB, stop at end of table self.log.debug('Running SNMP command getNext on OIDS %s', missing_results) binds_iterator = config.call_cmd( hlapi.nextCmd, *missing_results, lookupMib=enforce_constraints, ignoreNonIncreasingOid=self.ignore_nonincreasing_oid, lexicographicMode=False) binds, error = self._consume_binds_iterator( binds_iterator, config) all_binds.extend(binds) except PySnmpError as e: message = 'Failed to collect some metrics: {}'.format(e) if not error: error = message self.warning(message) # if we fail move onto next batch first_oid += self.oid_batch_size return all_binds, error
def get_table_symbols(mib, table): key = (mib, table) if key in table_oids: return table_oids[key][1] table_object = hlapi.ObjectType(hlapi.ObjectIdentity(mib, table)) symbols = [] table_oids[key] = (table_object, symbols) return symbols
def fetch_sysobject_oid(self, config): """Return the sysObjectID of the instance.""" # Reference sysObjectID directly, see http://oidref.com/1.3.6.1.2.1.1.2 oid = hlapi.ObjectType(hlapi.ObjectIdentity((1, 3, 6, 1, 2, 1, 1, 2))) self.log.debug('Running SNMP command on OID %r', oid) error_indication, _, _, var_binds = next(config.call_cmd(hlapi.nextCmd, oid, lookupMib=False)) self.raise_on_error_indication(error_indication, config.ip_address) self.log.debug('Returned vars: %s', var_binds) return var_binds[0][1].prettyPrint()
def construct_object_types_from_named_oid(list_of_oid_name_tuplets): object_types = [] for oid in list_of_oid_name_tuplets: addr = [] for x in oid: addr.append(x) object_types.append( hlapi.ObjectType(hlapi.ObjectIdentity(*addr).addMibSource('.'))) return object_types
def find_router_type(host, port): oid = '.1.3.6.1.2.1.1.1.0' #import pysnmp.hlapi as ph g = ph.getCmd( ph.SnmpEngine(), ph.CommunityData('otauB9v1kYRO'), ph.UdpTransportTarget((host, port)), ph.ContextData(), ph.ObjectType(ph.ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))) nextg = next(g) print(nextg)
def common(): """PySNMP Tutorial Common Operations Example""" engine = hlapi.SnmpEngine() community = hlapi.CommunityData("public", mpModel=1) # SNMPv2c target = hlapi.UdpTransportTarget(("192.168.0.59", 161)) context = hlapi.ContextData() # object_id = hlapi.ObjectIdentity( # "iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0" # ) sysDescr = hlapi.ObjectType( hlapi.ObjectIdentity("SNMPv2-MIB", "sysDescr", 0)) sysUpTime = hlapi.ObjectType( hlapi.ObjectIdentity("SNMPv2-MIB", "sysUpTime", 0)) ifInOctets = hlapi.ObjectType( hlapi.ObjectIdentity("IF-MIB", "ifInOctets", 1)) command = hlapi.getCmd(engine, community, target, context, sysDescr, sysUpTime, ifInOctets) _old_print_results(command)
def set(self, oid, value): identify = hlapi.ObjectType(hlapi.ObjectIdentity(oid), hlapi.Integer(value)) g = hlapi.setCmd(self.engine, self.community, self.transport, self.context, identify, lookupMib=False) next(g)
def get_by_oid(self, oid): res = hlapi.getCmd( hlapi.SnmpEngine(), self.auth_data, hlapi.UdpTransportTarget(self.target), hlapi.ContextData(), hlapi.ObjectType(hlapi.ObjectIdentity(oid)), ) res = next(res) err_indication, err_status, err_index, var_binds = res return var_binds[0]
def set_one(target, oid, value, credentials, port=161, engine=hlapi.SnmpEngine(), context=hlapi.ContextData()): handler = hlapi.setCmd(engine, credentials, hlapi.UdpTransportTarget((target, port)), context, hlapi.ObjectType(hlapi.ObjectIdentity(oid), value)) return fetch(handler, 1)[0]
def construct_object_types(list_of_oids): """ Build a SNMP payload object from oids for get requests inputs: list_of_oids (list(str)) outputs: SNMP payload for Get requests """ object_types = [] for oid in list_of_oids: object_types.append(hlapi.ObjectType(hlapi.ObjectIdentity(oid).addMibSource('./mibs'))) return object_types
def _construct_object_types(self, list_of_oids): #oid 실제 구별할 값 찾기 object_types = [] for oid in list_of_oids: try: object_types.append(hlapi.ObjectType( hlapi.ObjectIdentity(oid))) except Exception as e: print('> _construct_object_types : ', e) traceback.print_exc(file=sys.stdout) continue return object_types
def get(self, oid): g = hlapi.getCmd(self.engine, self.community, self.transport, self.context, hlapi.ObjectType(hlapi.ObjectIdentity(oid)), lookupMib=False) error_indication, error_status, _, res = next(g) if error_indication or error_status: raise ExecutionError("Failed to get SNMP value") return res[0][1]