easysnmp перестает работать для одного IP-адреса - PullRequest
0 голосов
/ 16 марта 2019

У меня есть скрипт, использующий модули easysnmp get и bulkwalk для сбора списка всех IP-адресов на устройстве и добавления их в словарь для дальнейшей обработки. Проблема возникает с конкретными IP-адресами, и проблема, похоже, не связана с самими конечными хостами.

С самого начала запуска оболочки Python я могу выполнить массовый переход на одном из проблемных 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
...

Теперь, если я попытаюсь выполнить только запрос массового просмотра, он больше не работает:

>>> 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, и он отлично работает.

Захваты пакетов на моем брандмауэре показывают, что запрос отправляется на устройство, но вместо получения ответа устройство отправляет ответ в виде отчета. Кажется, нет никакой разницы между запросами get и getbulkrequests между сеансами, которые работают, и сеансами, которые не работают. Я согласен с тем, что проблема может быть связана с брандмауэром, но что, тем более, что массовый запрос отлично работает в другой оболочке в то же время? Кроме того, почему он работает сам по себе, а не когда функция запускается на всех хостах в таблице, каждый раз?

Я пытался добавлять импортированные модули по одному за раз, чтобы увидеть, происходит ли что-то на этом фронте, но у меня никогда не происходит сбоя, пока функция не будет запущена для остальных узлов в словаре и впоследствии не будет работать вообще в той же оболочке.

...