I need an SNMP server that can monitor an SNMP agent. For this purpose, I wrote a basic Python application, and I run an SNMP agent (polinux/snmpd image based), on the same network, the agent has a fixed IP address. When I run the SNMP get query from the server container, I get the desired OIB, but when I want to do the same programmatically using PySnmp, it just doesn't work. I have tried in a lots of ways but without success.
Do you have any idea?
My docker compose file:
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
My command and result when I enter bash shell of "spm-health-service":
$ 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#
My Python code:
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
- - - - - - - - - -
The exception I get:
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
The issue was with Pipfile
, the logs indicated some dependency issues and conflicts. I do not remember why but at some point the allow_prereleases
flag was set to true in the file. When I set it to false and recreated the Pipfile.lock, the error gone away.