The Manager Interface

Note

The classes described in this section do not correspond to specific class implementations. Instead, they describe the abstract interfaces of the various Manager objects returned by the Engine.Manager() and AsyncEngine.Manager() factory methods.

class SnmpManager

This class describes the common interface for SNMPv3Manager, SNMPv2cManager, and SNMPv1Manager objects. Each Manager object is pre-configured to communicate with a specific remote machine (see the Engine.Manager() address parameter). Code written for this interface should not need to differentiate between SNMPv3 and SNMPv2c machines. SNMPv1 machines will behave almost the same, but where an SNMPv2c or SNMPv3 response would contain a NoSuchObject, NoSuchInstance, or EndOfMibView object, an SNMPv1 response will simply have an error-status of noSuchName, triggering a NoSuchName exception. An application wishing to support all three protocols must properly handle both of these cases.

get(*oids, timeout=10.0, refreshPeriod=1.0, wait=None) snmp.smi.VarBindList | RequestHandle

Send an SNMP Get request containing the provided list of OIDs.

Each item in the oids argument list may be either an snmp.smi.OID, or a string containing the representation of the OID (e.g. "1.3.6.1.2.1.1.1.0", or ".1.3.6.1.2.1.1.1.0").

Non-Blocking Requests

The default behavior (asterisk) for this method is to block until a response is received, and then return the contents of the response in a VarBindList. However, when called with wait=False, it will not wait for a response, and instead return a RequestHandle corresponding to the request. You can then call the RequestHandle.wait() method to await the response and retrieve its contents. For illustration, here are two equivalent ways to make a Get request and await the response:

vblist = manager.get("1.3.6.1.2.1.1.1.0", wait=True)
vblist = manager.get("1.3.6.1.2.1.1.1.0", wait=False).wait()

This feature makes it possible to send requests to several machines in parallel

handle1 = manager1.get("1.3.6.1.2.1.1.1.0", wait=False)
handle2 = manager2.get("1.3.6.1.2.1.1.1.0", wait=False)
handle3 = manager3.get("1.3.6.1.2.1.1.1.0", wait=False)

vblist1 = handle1.wait()
vblist2 = handle2.wait()
vblist3 = handle3.wait()

rather than one after another.

vblist1 = manager1.get("1.3.6.1.2.1.1.1.0", wait=True)
vblist2 = manager2.get("1.3.6.1.2.1.1.1.0", wait=True)
vblist3 = manager3.get("1.3.6.1.2.1.1.1.0", wait=True)

In the first case, all three requests are sent at the same time, allowing the remote agents to process and respond to them in parallel. The second case is about three times slower, because each request is sent only after the manager receives the response to the previous request.

Warning

The default argument for wait is actually not True, it’s None. True is the default in the sense that it’s the default for the autowait parameter to the Engine() constructor, which sets the default for the autowait parameter to the Engine.Manager() method. However, a Manager created with autowait=False will use the wait=False behavior by default.

No Response?

Since SNMP operates on an “unreliable” transport (UDP), there is always a possibility of messages getting lost in transit. It is also possible that the machine, or the agent that should be running on the machine, is down, or doesn’t even exist. While waiting for a response, the Manager (or the RequestHandle) will re-send the request every refreshPeriod seconds. If it does not receive a response within timeout seconds, it will give up and raise a Timeout exception.

Be aware that the Engine uses a cooperative multitasking strategy, rather than a preemptive strategy, to maintain many requests at once. It can re-send a request even while waiting for a response to a different request (including requests belonging to other Managers, so long as they were created by the same Engine), but it will not preempt your application code. This means that in the following example, the Manager will only ever send the request once.

handle = manager.get("1.3.6.1.2.1.1.1.0", refreshPeriod=0.5, timeout=2.5, wait=False)
time.sleep(3.0)
vblist = handle.wait()

The refreshPeriod is always measured from the time of the most recent message. The timeout is measured from the time of the request, and not from the time at which you call wait(). In this next example, if the request is made at time 0.0s, and if there is no response, then the request will be re-sent at time 1.5s, and 2.5s, and then raise a Timeout at 3.0s.

handle = manager.get("1.3.6.1.2.1.1.1.0", refreshPeriod=1.0, timeout=3.0, wait=False)
time.sleep(1.5)
vblist = handle.wait()

Finally, in this example, the request will time out before it ever considers re-sending.

vblist = manager.get("1.3.6.1.2.1.1.1.0", refreshPeriod=1.5, timeout=1.0, wait=True)

Exceptions

This method (or the wait() method of a corresponding RequestHandle) raises the following exceptions:

snmp.Timeout: No response within timeout seconds (more details above).

snmp.ErrorResponse: Indicates a nonzero error-status in the ResponsePDU.

snmp.NoSuchName: A sub-type of snmp.ErrorResponse, this exception indicates an error-status of noSuchName. Unlike other error-status values, noSuchName sometimes comes up in the normal operation of SNMPv1, so it is convenient to be able to handle it in a separate except block from the more general snmp.ErrorResponse type.

snmp.ImproperResponse: In order to guarantee that the returned VarBindList contains the expected variables in the expected order, the Manager checks the variables in the response against the OIDs in the original request. If there is any discrepancy, it will raise an ImproperResponse exception, which will still give you access to the VarBindList via the variableBindings attribute.

Exception: In some cases, this method may raise an exception that is meant to get the attention of a human, rather than being handled automatically. These exceptions often relate to incorrect SNMPv3 security credentials, but not always. If crashes are unacceptable in your application, then you can catch all these exceptions with a generic except Exception block. This block should log or otherwise report to a human, any exceptions it catches, along with some information to help identify which Manager object (and thereby which machine) the exception came from.

getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, wait=None) snmp.smi.VarBindList | RequestHandle

Send an SNMP GetBulk request containing the provided list of OIDs.

Aside from the addition of the nonRepeaters and maxRepetitions parameters, the usage and behavior of this method is exactly the same as the get() method.

Multiple GetNext Requests In One

The GetBulk request is essentially an enhanced version of the GetNext request. With the maxRepetitions argument, you can request the results of several successive GetNext requests, combined into a single response. For example, this code snippet requests the ifDescr, ifType, and ifOperStatus for the first two rows in a machine’s ifTable.

vblist = manager.getBulk(ifDescr, ifType, ifOperStatus, maxRepetitions=2)
print(vblist)

Here is the response I got from my printer:

1.3.6.1.2.1.2.2.1.2.1: OctetString(b'NC-8200h')
1.3.6.1.2.1.2.2.1.3.1: Integer32(7)
1.3.6.1.2.1.2.2.1.8.1: Integer32(1)
1.3.6.1.2.1.2.2.1.2.2: OctetString(b'SoftwareLoopBack')
1.3.6.1.2.1.2.2.1.3.2: Integer32(24)
1.3.6.1.2.1.2.2.1.8.2: Integer32(1)

This response contains two “repetitions” of the query. The first three variables show that "NC-2800h" is an iso88023Csmacd(7) interface, which is currently up(1) (the ifType an ifOperStatus values are enumerated in IANAifType-MIB and IF-MIB, respectively). The next three variables would be found in the response to a GetNext request that used the OIDs of the first three variables. They tell of a "SoftwareLoopBack" interface of type softwareLoopback(24) which is currently up(1) as well.

A successful response is required, according to the protocol, to contain at least one repetition (unless maxRepetitions is zero). It should contain the full number of repetitions, if possible, but this is not guaranteed. This method additionally guarantees that the returned VarBindList will not contain any partial repetitions (i.e. if three OIDs are requested, the number of variables in the response will be a multiple of three). If a response does not meet this guarantee, the call will raise an ImproperResponse exception. In this case, the VarBindList is still available via the exception object’s variableBindings attribute.

Non-Repeated OIDs

It is also possible to include single queries in the same GetBulk request as repeated queries. When the nonRepeaters is non-zero, then the first nonRepeaters OIDs in the request are excluded from the repetition.

One way to use this feature might be to attach a timestamp to the data in the response, such as in this example.

vblist = manager.getBulk(
   sysUpTime,
   ifDescr,
   ifInOctets,
   nonRepeaters=1,
   maxRepetitions=2,
)
print(vblist)

As you can see, the response includes sysUpTime.0 in the first slot, but the successor to this variable is not included in the second repetition of the query.

1.3.6.1.2.1.1.3.0: TimeTicks(95500355)
1.3.6.1.2.1.2.2.1.2.1: OctetString(b'NC-8200h')
1.3.6.1.2.1.2.2.1.10.1: Counter32(206469550)
1.3.6.1.2.1.2.2.1.2.2: OctetString(b'SoftwareLoopBack')
1.3.6.1.2.1.2.2.1.10.2: Counter32(64)
getNext(*oids, timeout=10.0, refreshPeriod=1.0, wait=None) snmp.smi.VarBindList | RequestHandle

Send an SNMP GetNext request containing the provided list of OIDs.

The usage and behavior of this method is exactly the same as the get() method.

set(*varbinds, timeout=10.0, refreshPeriod=1.0, wait=None) snmp.smi.VarBindList | RequestHandle

Send an SNMP Set request containing the provided list of VarBinds.

Each item in the varbinds argument list may be either a snmp.smi.VarBind, or a tuple containing first the OID (either as an snmp.smi.OID, or as a string) and then the requested value for the variable, as an snmp.smi type.

Aside from the varbinds argument, the usage and behavior of this method is exactly the same as the get() method.

class RequestHandle
wait() snmp.smi.VarBindList

See SnmpManager.get().

class RequestPoller

Similar to the standard library Polling Objects, a RequestPoller can monitor several RequestHandles and tell you when they are ready to be wait()ed on.

Use the Engine.poll() method to create a RequestPoller object.

__bool__() bool

Return True if there are one or more handles registered, and False if there are none. The wait() method automatically unregisters handles as it returns them, so this feature allows you to detect when all handles have been returned.

poller = engine.poll(*handles)

while poller:
    ready = poller.wait()
    for handle in ready:
        print(handle.wait())
register(handle: RequestHandle)

Register a handle for monitoring by the wait() method.

wait(timeout: float = None) List[RequestHandle]

Return the list of handles that are ready, or block until one becomes ready.

If a handle is “ready”, then its RequestHandle.wait() method will return immediately, or raise an exception.

Each RequestHandle is automatically unregistered after it is returned.

If timeout is not None, and no handles become ready within timeout seconds, then the call will return an empty list.

class SNMPv3Manager
get(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList | RequestHandle

This method extends SnmpManager.get() with some SNMPv3-specific parameters.

As explained in the snmp.Engine.Manager() section, each SNMPv3 Manager object is configured with a default user and security level. You can override these defaults for a particular request using the user and securityLevel parameters. The user must be a str, and the securityLevel must be one of the following: snmp.noAuthNoPriv, snmp.authNoPriv, or snmp.authPriv. Remember that before you can make an authNoPriv or authPriv request, you must configure the authentication and privacy protocol(s) and password(s) for the user by calling Engine.addUser().

The context argument is not worth explaining, because I’m not even sure anyone even uses it. The default context is not configurable for the same reason. If you do use it, and want the default to be configurable, feel free to file a GitHub issue or email me about it.

getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, wait=None, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList | RequestHandle

See SnmpManager.getBulk() and get().

getNext(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList | RequestHandle

See SnmpManager.getNext() and get().

set(*varbinds, timeout=10.0, refreshPeriod=1.0, wait=None, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList | RequestHandle

See SnmpManager.set() and get().

class SNMPv2cManager
get(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

This method extends SnmpManager.get() by adding the community parameter.

As explained in the snmp.Engine.Manager() section, each SNMPv2c Manager object is configured with a default community name. The community parameter allows you to use a different community name for an individual request. The argument type is bytes (a str will not work)

getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

See SnmpManager.getBulk() and get().

getNext(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

See SnmpManager.getNext() and get().

set(*varbinds, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

See SnmpManager.set() and get().

class SNMPv1Manager
get(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

This method extends SnmpManager.get() by adding the community parameter.

As explained in the snmp.Engine.Manager() section, each SNMPv1 Manager object is configured with a default community name. The community parameter allows you to use a different community name for an individual request. The argument type is bytes (a str will not work)

getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

This method simulates a GetBulk request (which is not defined in SNMPv1) using a GetNext request. The response will never contain more than repetition for any OID in the request.

getNext(*oids, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

See SnmpManager.getNext() and get().

set(*varbinds, timeout=10.0, refreshPeriod=1.0, wait=None, community=None) snmp.smi.VarBindList | RequestHandle

See SnmpManager.set() and get().

class AsyncSNMPv3Manager

New in version 1.2.

An async version of SNMPv3Manager, created with AsyncEngine.Manager().

async get(*oids, timeout=10.0, refreshPeriod=1.0, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList

See SNMPv3Manager.get(). Note that this method does not support the wait parameter.

async getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList

See SNMPv3Manager.getBulk(). Note that this method does not support the wait parameter.

async getNext(*oids, timeout=10.0, refreshPeriod=1.0, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList

See SNMPv3Manager.getNext(). Note that this method does not support the wait parameter.

async set(*varbinds, timeout=10.0, refreshPeriod=1.0, user=None, securityLevel=None, context=b'') snmp.smi.VarBindList

See SNMPv3Manager.set(). Note that this method does not support the wait parameter.

class AsyncSNMPv2cManager

New in version 1.2.

An async version of SNMPv2cManager, created with AsyncEngine.Manager().

async get(*oids, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv2cManager.get(). Note that this method does not support the wait parameter.

async getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv2cManager.getBulk(). Note that this method does not support the wait parameter.

async getNext(*oids, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv2cManager.getNext(). Note that this method does not support the wait parameter.

async set(*varbinds, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv2cManager.set(). Note that this method does not support the wait parameter.

class AsyncSNMPv1Manager

New in version 1.2.

An async version of SNMPv1Manager, created with AsyncEngine.Manager().

async get(*oids, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv1Manager.get(). Note that this method does not support the wait parameter.

async getBulk(*oids, nonRepeaters=0, maxRepetitions=1, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv1Manager.getBulk(). Note that this method does not support the wait parameter.

async getNext(*oids, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv1Manager.getNext(). Note that this method does not support the wait parameter.

async set(*varbinds, timeout=10.0, refreshPeriod=1.0, community=None) snmp.smi.VarBindList

See SNMPv1Manager.set(). Note that this method does not support the wait parameter.