charlestolley / python-snmp

A user-friendly SNMP library
MIT License
15 stars 3 forks source link

snmpwalk #8

Open allansbo opened 6 months ago

allansbo commented 6 months ago

Hello Charles! Thanks a lot for your great job!

I'm looking for snmpwalk in the documentation. The library doesn't have this method yet, right?

charlestolley commented 6 months ago

Hi, and thank you. You are correct that there is no built-in walk method, (it's on my to-do list), but it's also very simple to write your own. Here's an example:

def walk(manager, root):
    varbind = manager.getNext(root)[0]

    while varbind.name.startswith(root):
        yield varbind
        varbind = manager.getNext(varbind.name)[0]
allansbo commented 6 months ago

Thanks for your help. I will do this.

manutec commented 6 months ago

Hi, I have an issue with startswith method. It always responds me False. I think is caused by self.subidentifiers[:len(prefix)] returns a tuple instead a string.

def startswith(self, prefix: "OBJECT_IDENTIFIER") -> bool:
    return self.subidentifiers[:len(prefix)] == prefix[:]
def startswith(self, prefix: "OBJECT_IDENTIFIER") -> bool:
        oid = str(self)
        return oid[:len(prefix)] == prefix[:]

Is correct? Thank you for your work

charlestolley commented 6 months ago

@manutec from your code, it looks like you are passing the prefix as a string, when you should be passing an OID object:

>>> sysDescr = OID.parse("1.3.6.1.2.1.1.1")
>>> sysDescr.startswith("1.3.6.1.2.1")
False
>>> sysDescr.startswith(OID.parse("1.3.6.1.2.1"))
True
manutec commented 6 months ago

Ok @charlestolley, this has more sense, sorry and thank you

denisbondar commented 6 months ago

@allansbo Maybe the following solution will help you. However, it is designed for only one OID.

def walk_next(
    manager: Union[SNMPv1Manager[Address], SNMPv2cManager[Address], SNMPv3UsmManager[Address]],
    oid: OID,
):
    _oid = oid
    while True:
        result = manager.getNext(_oid)
        if not result[0].name.startswith(oid):
            break

        yield result

        _oid = result[0].name

def walk_bulk(
    manager: Union[SNMPv2cManager[Address], SNMPv3UsmManager[Address]],
    oid: OID,
    max_repetitions: int = 10,
    non_repeaters: int = 0,
):
    _oid = oid
    while True:
        result = []
        bulk_result = manager.getBulk(_oid, maxRepetitions=max_repetitions, nonRepeaters=non_repeaters)
        if not bulk_result[0].name.startswith(oid):
            break

        for bulk_result_row in bulk_result:
            if bulk_result_row.name.startswith(oid):
                result.append(bulk_result_row)

        yield VarBindList(*result)

        _oid = bulk_result[-1].name
        if not _oid.startswith(oid):
            break

Using:

with Engine(SNMPv2c) as engine:
    manager = engine.Manager("10.10.0.185")
    oid = OID.parse("1.3.6.1.2.1.31.1.1.1.1")

    for r in walk_next(manager, oid):
        print(r)

    for r in walk_bulk(manager, oid):
        print(r)
allansbo commented 6 months ago

@denisbondar

It's work fine. Thanks a lot dude.