You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySnmp查询可达SNMP代理失败,但snmpget命令行执行成功求助

问题:PySnmp调用SNMP代理时报TypeError参数不匹配错误

我需要实现一个监控SNMP代理的服务端,基于Python编写了基础应用。在同一Docker网络中部署了polinux/snmpd镜像的SNMP代理(固定IP:10.5.0.5),在服务端容器中执行snmpget命令可成功获取目标OID,但通过PySnmp编程调用时失败,核心报错为TypeError: decodeMessageVersion.<locals>.<lambda>() takes 3 positional arguments but 4 were given。

Docker Compose配置

services:
  spm-health-service:
    build:
      context: .
      dockerfile: docker/Dockerfile
    restart: unless-stopped
    env_file:
      - .env
    ports:
      - "4500:4500"
    depends_on:
      - scs-server
      - network-device-identifier

  spm:
    image: polinux/snmpd
    restart: unless-stopped
    privileged: true
    ports:
      - "161:161/udp"
    volumes:
      - ./resources/snmpd-conf/snmpd.conf:/etc/snmp/snmpd.conf
      - ./resources/spm-mib/:/usr/local/share/snmp/mibs/
    networks:
      default:
        ipv4_address: 10.5.0.5

networks:
  default:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

snmpget执行成功结果

$ winpty docker exec -it 627 bash
root@627d241920e3:/app# snmpget -v2c -t 10 -c public 10.5.0.5 .1.3.6.1.2.1.1.3.0
Created directory: /var/lib/snmp/cert_indexes
iso.3.6.1.2.1.1.3.0 = Timeticks: (21437) 0:03:34.37
root@627d241920e3:/app#

Python代码片段

def get_system_uptime(self) -> Union[str, None]:
    """Get system uptime"""
    try:
        result = snmp_get(self.ip, [SYS_UP_TIME], self.snmp_ro_credential)
    except SNMPError as e:
        logging.error(e.message)
        return None
    return result.get(SYS_UP_TIME, None)

# ---

def snmp_get(
    target: str,
    oids: list[str],
    credentials: CommunityData = SNMP_RO_CREDENTIAL,
    port: int = SNMP_DEFAULT_PORT,
) -> dict:
    """SNMP get"""
    handler = getCmd(
        SNMP_ENGINE,
        credentials,
        UdpTransportTarget((target, port), timeout=5, retries=10),
        SNMP_CONTEXT,
        *construct_object_types(oids),
    )
    return fetch(handler)[0]

# ---

def fetch(fetch_handler, count: int = -1) -> list[dict]:
    """Fetch"""
    def convert(_var_binds):
        """Convert"""
        return {str(var_bind[0]): var_bind[1] for var_bind in _var_binds}

    result = []
    while True:
        if count == 0:
            break
        count -= 1
        try:
            error_indication, error_status, error_index, var_binds = next(fetch_handler)
            if error_indication:
                raise SNMPError(f"SNMP error: {error_indication}")
            if error_status:
                raise SNMPError(
                    f"SNMP error: {error_status.prettyPrint()} at \
                        {error_index and var_binds[int(error_index) - 1][0] or '?'}"
                )
            items = convert(var_binds)
            result.append(items)
        except StopIteration:
            break
    return result

报错信息

spm-health-service-spm-health-service-1         | 2022-11-14 10:53:58,729 [INFO]: [get_spms_from_network_mapping] - line 32 | Query for 10.5.0.5
spm-health-service-spm-health-service-1         | 2022-11-14 10:53:58,792 [ERROR]: [get_spms_from_network_mapping] - line 36 | poll error: Traceback (most recent call last):
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/carrier/asyncore/dispatch.py", line 45, in runDispatcher
spm-health-service-spm-health-service-1         |     loop(timeout or self.getTimerResolution(),
spm-health-service-spm-health-service-1         | ;  File "/usr/local/lib/python3.11/asyncore.py", line 212, in loop
spm-health-service-spm-health-service-1         |     poll_fun(timeout, map)
spm-health-service-spm-health-service-1         | ;  File "/usr/local/lib/python3.11/asyncore.py", line 193, in poll2
spm-health-service-spm-health-service-1         |     readwrite(obj, flags)
spm-health-service-spm-health-service-1         | ;  File "/usr/local/lib/python3.11/asyncore.py", line 128, in readwrite
spm-health-service-spm-health-service-1         |     obj.handle_error()
spm-health-service-spm-health-service-1         | ;  File "/usr/local/lib/python3.11/asyncore.py", line 113, in readwrite
spm-health-service-spm-health-service-1         |     obj.handle_read_event()
spm-health-service-spm-health-service-1         | ;  File "/usr/local/lib/python3.11/asyncore.py", line 425, in handle_read_event
spm-health-service-spm-health-service-1         |     self.handle_read()
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/carrier/asyncore/dgram/base.py", line 170, in handle_read
spm-health-service-spm-health-service-1         |     self._cbFun(self, transportAddress, incomingMessage)
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/carrier/base.py", line 84, in _cbFun
spm-health-service-spm-health-service-1         |     self.__recvCallables[recvId](
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/entity/engine.py", line 151, in __receiveMessageCbFun
spm-health-service-spm-health-service-1         |     self.msgAndPduDsp.receiveMessage(
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/proto/rfc3412.py", line 291, in receiveMessage
spm-health-service-spm-health-service-1         |     msgVersion = verdec.decodeMessageVersion(wholeMsg)
spm-health-service-spm-health-service-1         |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pysnmp/proto/api/verdec.py", line 15, in decodeMessageVersion
spm-health-service-spm-health-service-1         |     seq, wholeMsg = decoder.decode(
spm-health-service-spm-health-service-1         |                     ^^^^^^^^^^^^^^^
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pyasn1/codec/ber/decoder.py", line 2003, in __call__
spm-health-service-spm-health-service-1         |     for asn1Object in streamingDecoder:
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pyasn1/codec/ber/decoder.py", line 1918, in __iter__
spm-health-service-spm-health-service-1         |     for asn1Object in self._singleItemDecoder(
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pyasn1/codec/ber/decoder.py", line 1778, in __call__
spm-health-service-spm-health-service-1         |     for value in concreteDecoder.valueDecoder(
spm-health-service-spm-health-service-1         | ;  File "/root/.local/share/virtualenvs/app-4PlAip0Q/lib/python3.11/site-packages/pyasn1/codec/ber/decoder.py", line 654, in valueDecoder
spm-health-service-spm-health-service-1         |     for chunk in substrateFun(asn1Object, substrate, length, options):
spm-health-service-spm-health-service-1         |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
spm-health-service-spm-health-service-1         | ;TypeError: decodeMessageVersion.<locals>.<lambda>() takes 3 positional arguments but 4 were given
spm-health-service-spm-health-service-1         | caused by <class 'TypeError'>: decodeMessageVersion.<locals>.<lambda>() takes 3 positional arguments but 4 were given

问题原因与解决方案

原因

这个错误是PySnmp与PyASN1版本不兼容导致的:PyASN1 0.5.x版本对解码函数的API做了修改,增加了一个参数,但旧版本的PySnmp(如4.4.x系列)中的decodeMessageVersion函数仍使用旧的参数调用方式,从而引发参数不匹配的TypeError。

解决方案

有两种可行的修复方式:

  1. 固定PyASN1到兼容版本:在项目依赖中指定pyasn1<0.5.0,比如在requirements.txt中添加:
    pyasn1>=0.4.8,<0.5.0
    
  2. 升级PySnmp到兼容版本:将PySnmp升级到支持PyASN1 0.5.x的版本,比如升级到pysnmp>=4.4.12(需确认版本兼容性)。

验证

修改依赖版本后,重新构建Docker镜像并启动服务,再次测试PySnmp的SNMP调用,确认是否能正常获取OID数据。

内容的提问来源于stack exchange,提问作者Balint Laszlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:25:59