首页 > 解决方案 > easysnmp 停止为单个 IP 地址工作

问题描述

我有一个脚本,它使用 easysnmp get 和 bulkwalk 模块来收集设备上所有 IP 地址的列表,并将它们添加到字典中以进行进一步处理。问题发生在特定的 IP 地址上,而问题似乎不在于终端主机本身。

从一个 python shell 的全新开始,我可以对一个有问题的 IP 进行批量遍历:

>>> from easysnmp import snmp_bulkwalk
>>> snmp_ips = snmp_bulkwalk('ipAdEntIfIndex', hostname='x.x.x.80', version=3, security_username=snmp_user, security_level='auth_with_privacy', auth_protocol='SHA', auth_password=snmp_auth, privacy_protocol='AES128', privacy_password=snmp_priv)     
>>> snmp_ips
[<SNMPVariable value='4010' (oid='ipAdEntIfIndex', oid_index='x.x.x.179', snmp_type='INTEGER')>, <SNMPVariable value='4011' (oid='ipAdEntIfIndex', oid_index='x.x.x.186', snmp_type='INTEGER')>, <SNMPVariable value='20567' (oid='ipAdEntIfIndex', oid_index='x.x.x.80', snmp_type='INTEGER')>, <SNMPVariable value='808' (oid='ipAdEntIfIndex', oid_index='x.x.x.133', snmp_type='INTEGER')>]

如果我只针对这个单个节点运行我的函数,它就可以工作。这是功能:

def get_ints():
    addrs = {}
    for h in nodes['results']:
        # Update all nodes in the dictionary to their FQDN
        if 'foo.com' not in h['SysName']:
            h['SysName'] = h['SysName'] + '.foo.com'
        # Fix random hostname issues
        if '-re' in h['SysName']:
            # This is probably way more complicated than it needs to be. Split the hostname at '-' and combine the two results
            # starting at index 3 of the second half of the split.
            h['SysName'] = h['SysName'].split('-'[::])[0] + h['SysName'].split('-'[::])[1][3:]
        host = h['SysName']
        # Use SNMP to get IP and interface information because screen scraping is slow and painful to reformat.
        # This walks the IF-MIB table and gets the IPs assigned to each interface. 
        print(f'Getting interface info from {host}')
        try:
            snmp_ips = snmp_bulkwalk('ipAdEntIfIndex', hostname=host, version=3, security_username=snmp_user, security_level='auth_with_privacy', auth_protocol='SHA', auth_password=snmp_auth, privacy_protocol='AES128', privacy_password=snmp_priv)
        except:
            print(f'Could not get data from {host}')
        # Iterate through SNMP GET objects and update the addrs table with: { IP : { PTR record : RR value }}
        for x in snmp_ips:
            # We only want to process IPs that fall within specific network ranges
            for n in my_nets:
                if ip_address(x.oid_index) in n:
                    try:
                        addrs[x.oid_index] = gen_rev(x.oid_index, snmp_get('ifName' + '.' + x.value, hostname=host, version=3, security_username=snmp_user, security_level='auth_with_privacy', auth_protocol='SHA', auth_password=snmp_auth, privacy_protocol='AES128', privacy_password=snmp_priv).value.lower(), host)
                    except:
                        pass
    return addrs

这是针对字典中的单个主机运行的函数:

>>> nodes['results'] = [ {'NodeID': 571, 'SysName': 'host80.foo.com', 'IPAddress': 'x.x.x.80' } ]
>>> my_addrs = get_ints()
>>> Getting interface info from host80.foo.com
>>> my_addrs
[<SNMPVariable value='4010' (oid='ipAdEntIfIndex', oid_index='x.x.x.179', snmp_type='INTEGER')>, <SNMPVariable value='4011' (oid='ipAdEntIfIndex', oid_index='x.x.x.186', snmp_type='INTEGER')>, <SNMPVariable value='20567' (oid='ipAdEntIfIndex', oid_index='x.x.x.80', snmp_type='INTEGER')>, <SNMPVariable value='808' (oid='ipAdEntIfIndex', oid_index='x.x.x.133', snmp_type='INTEGER')>]

这是字典中的完整节点集,当函数针对完整集运行时,'host80.foo.com' 失败:

>>> nodes['results'] = [{'NodeID': 14, 'SysName': 'host13.foo.com', 'IPAddress': 'x.x.x.13'}, {'NodeID': 15, 'SysName': 'host14.foo.com', 'IPAddress': 'x.x.x.14'}, {'NodeID': 17, 'SysName': 'hhost16.foo.com', 'IPAddress': 'x.x.x.16'}, {'NodeID': 18, 'SysName': 'host17.foo.com', 'IPAddress': 'x.x.x.17'}, {'NodeID': 571, 'SysName': 'host80.foo.com', 'IPAddress': 'x.x.x.80'}, {'NodeID': 20, 'SysName': 'host19.foo.com', 'IPAddress': 'x.x.x.19'}]
>>> my_addrs = get_ints()
Getting interface info from host13.foo.com
Getting interface info from host14.foo.com
Getting interface info from host16.foo.com
Getting interface info from host17.foo.com
Getting interface info from host19.foo.com
Getting interface info from host80.foo.com
Could not get data from host80.foo.com
...

现在,如果我尝试单独运行 bulkwalk 请求,它将不再有效:

>>> snmp_bulkwalk('ipAdEntIfIndex', hostname='x.x.x.80',version=3, security_username=snmp_user, security_level='auth_with_privacy', auth_protocol='SHA', auth_password=snmp_auth, privacy_protocol='AES128', privacy_password=snmp_priv)    
easysnmp.exceptions.EasySNMPTimeoutError: timed out while connecting to remote host

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/logging/__init__.py", line 1293, in debug
    if self.isEnabledFor(DEBUG):
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/logging/__init__.py", line 1548, in isEnabledFor
    return level >= self.getEffectiveLevel()
SystemError: PyEval_EvalFrameEx returned a result with an error set

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/site-packages/easysnmp/easy.py", line 147, in snmp_bulkwalk
    return session.bulkwalk(oids, non_repeaters, max_repetitions)
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/site-packages/easysnmp/session.py", line 498, in bulkwalk
    interface.bulkwalk(self, non_repeaters, max_repetitions, varlist)
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/logging/__init__.py", line 1293, in debug
    if self.isEnabledFor(DEBUG):
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/logging/__init__.py", line 1548, in isEnabledFor
    return level >= self.getEffectiveLevel()
SystemError: PyEval_EvalFrameEx returned a result with an error set

如果我退出解释器并重新做一遍,结果总是一样的。我还可以在另一个 python shell 中运行独立的 bulkrequest,它工作正常。

我的防火墙上的数据包捕获显示正在发送到设备的请求,但设备发送报告响应而不是获取响应。在有效的会话和无效的会话之间,get 请求和 getbulkrequests 之间似乎没有任何区别。我愿意接受这个问题可能与防火墙有关,但是什么,特别是因为 bulkrequest 同时在另一个 shell 中工作正常?此外,为什么它自己工作,而不是每次针对表中的所有主机运行该函数时?

我尝试一次添加一个导入的模块,以查看这方面是否发生了某些事情,但是在针对字典中的其他主机运行该函数并且无法正常工作之前,我从来没有失败过之后在同一个壳里。

标签: pythoneasysnmp

解决方案


推荐阅读