diff --git a/puresnmp/api/pythonic.py b/puresnmp/api/pythonic.py index 35c8d8f..f1fd368 100644 --- a/puresnmp/api/pythonic.py +++ b/puresnmp/api/pythonic.py @@ -114,8 +114,9 @@ def values(self): return output -def get(ip, community, oid, port=161, timeout=2, version=Version.V2C): - # type: (str, str, str, int, int, int) -> PyType +def get(ip, community, oid, port=161, timeout=2, version=Version.V2C, + retries=None): + # type: (str, str, str, int, int, int, int) -> PyType """ Delegates to :py:func:`~puresnmp.api.raw.get` but returns simple Python types. @@ -123,15 +124,17 @@ def get(ip, community, oid, port=161, timeout=2, version=Version.V2C): See the "raw" equivalent for detailed documentation & examples. """ raw_value = raw.get( - ip, community, oid, port, timeout=timeout, version=version + ip, community, oid, port, timeout=timeout, version=version, + retries=retries, ) return raw_value.pythonize() # type: ignore def multiget( - ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None ): - # type: (str, str, List[str], int, int, int) -> List[PyType] + # type: (str, str, List[str], int, int, int, int) -> List[PyType] """ Delegates to :py:func:`~puresnmp.api.raw.multiget` but returns simple Python types. @@ -139,16 +142,18 @@ def multiget( See the "raw" equivalent for detailed documentation & examples. """ raw_output = raw.multiget( - ip, community, oids, port, timeout, version=version + ip, community, oids, port, timeout, version=version, + retries=retries, ) pythonized = [value.pythonize() for value in raw_output] return pythonized def getnext( - ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, str, int, int, int) -> VarBind + # type: (str, str, str, int, int, int, int) -> VarBind """ Delegates to :py:func:`~puresnmp.api.raw.getnext` but returns simple Python types. @@ -156,15 +161,17 @@ def getnext( See the "raw" equivalent for detailed documentation & examples. """ result = multigetnext( - ip, community, [oid], port, timeout=timeout, version=version + ip, community, [oid], port, timeout=timeout, version=version, + retries=retries, ) return result[0] def multigetnext( - ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], int, int, int) -> List[VarBind] + # type: (str, str, List[str], int, int, int, int) -> List[VarBind] """ Delegates to :py:func:`~puresnmp.api.raw.multigetnext` but returns simple Python types. @@ -172,7 +179,8 @@ def multigetnext( See the "raw" equivalent for detailed documentation & examples. """ raw_output = raw.multigetnext( - ip, community, oids, port, timeout, version=version + ip, community, oids, port, timeout, version=version, + retries=retries, ) pythonized = [ VarBind(oid, value.pythonize()) for oid, value in raw_output # type: ignore @@ -181,9 +189,10 @@ def multigetnext( def walk( - ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, str, int, int, int) -> TWalkResponse + # type: (str, str, str, int, int, int, int) -> TWalkResponse """ Delegates to :py:func:`~puresnmp.api.raw.walk` but returns simple Python types. @@ -191,7 +200,8 @@ def walk( See the "raw" equivalent for detailed documentation & examples. """ - raw_result = raw.walk(ip, community, oid, port, timeout, version=version) + raw_result = raw.walk(ip, community, oid, port, timeout, version=version, + retries=retries,) for raw_oid, raw_value in raw_result: yield VarBind(raw_oid, raw_value.pythonize()) # type: ignore @@ -204,6 +214,7 @@ def multiwalk( timeout: int = DEFAULT_TIMEOUT, fetcher: raw.TFetcher = multigetnext, version: int = Version.V2C, + retries=None, ) -> TWalkResponse: """ Delegates to :py:func:`~puresnmp.api.raw.multiwalk` but returns simple @@ -212,7 +223,8 @@ def multiwalk( See the "raw" equivalent for detailed documentation & examples. """ raw_output = raw.multiwalk( - ip, community, oids, port, timeout, fetcher, version=version + ip, community, oids, port, timeout, fetcher, version=version, + retries=retries, ) for oid, value in raw_output: if isinstance(value, Type): @@ -228,8 +240,9 @@ def set( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): # pylint: disable=redefined-builtin - # type: (str, str, str, Type[T], int, int, int) -> T + # type: (str, str, str, Type[T], int, int, int, int) -> T """ Delegates to :py:func:`~puresnmp.api.raw.set` but returns simple Python types. @@ -238,7 +251,8 @@ def set( """ result = multiset( - ip, community, [(oid, value)], port, timeout=timeout, version=version + ip, community, [(oid, value)], port, timeout=timeout, version=version, + retries=retries, ) return result[oid.lstrip(".")] # type: ignore @@ -250,8 +264,9 @@ def multiset( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[Tuple[str, raw.T]], int, int, int) -> Dict[str, PyType] + # type: (str, str, List[Tuple[str, raw.T]], int, int, int, int) -> Dict[str, PyType] """ Delegates to :py:func:`~puresnmp.api.raw.multiset` but returns simple Python types. @@ -260,7 +275,8 @@ def multiset( """ raw_output = raw.multiset( - ip, community, mappings, port, timeout, version=version + ip, community, mappings, port, timeout, version=version, + retries=retries, ) pythonized = { str(oid): value.pythonize() for oid, value in raw_output.items() @@ -277,8 +293,9 @@ def bulkget( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], List[str], int, int, int, int) -> BulkResult + # type: (str, str, List[str], List[str], int, int, int, int, int) -> BulkResult # pylint: disable=unused-argument """ Delegates to :py:func:`~puresnmp.api.raw.mulkget` but returns simple @@ -296,6 +313,7 @@ def bulkget( port=port, timeout=timeout, version=version, + retries=retries, ) pythonized_scalars = { oid: value.pythonize() for oid, value in raw_output.scalars.items() @@ -314,8 +332,9 @@ def bulkwalk( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], int, int, int, int) -> TWalkResponse + # type: (str, str, List[str], int, int, int, int, int) -> TWalkResponse """ Delegates to :py:func:`~puresnmp.api.raw.bulkwalk` but returns simple Python types. @@ -333,13 +352,15 @@ def bulkwalk( ), timeout=timeout, version=version, + retries=retries, ) for oid, value in result: yield VarBind(oid, value) -def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C): - # type: (str, str, str, int, int) -> List[Dict[str, Any]] +def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C, + timeout=DEFAULT_TIMEOUT, retries=None,): + # type: (str, str, str, int, int, int, int, int) -> List[Dict[str, Any]] """ Fetches a table from the SNMP agent. Each value will be converted to a pure-python type. @@ -364,6 +385,8 @@ def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C): port=port, num_base_nodes=num_base_nodes, version=version, + timeout=timeout, + retries=retries, ) output = [] for row in tmp: @@ -374,8 +397,9 @@ def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C): return output -def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10): - # type: (str, str, str, int, int, int) -> List[Dict[str, Any]] +def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10, + timeout=DEFAULT_TIMEOUT, retries=None,): + # type: (str, str, str, int, int, int, int, int) -> List[Dict[str, Any]] """ Fetch an SNMP table using "bulk" requests converting the values into pure Python types. @@ -392,7 +416,8 @@ def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10): DeprecationWarning, stacklevel=2, ) - tmp = raw.bulktable(ip, community, oid, port=port, bulk_size=bulk_size) + tmp = raw.bulktable(ip, community, oid, port=port, bulk_size=bulk_size, + timeout=timeout, retries=retries,) output = [] for row in tmp: index = row.pop("0") diff --git a/puresnmp/api/raw.py b/puresnmp/api/raw.py index c2e8faf..997520b 100644 --- a/puresnmp/api/raw.py +++ b/puresnmp/api/raw.py @@ -59,9 +59,10 @@ def get( - ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None ): - # type: ( str, str, str, int, int, int ) -> Type[PyType] + # type: ( str, str, str, int, int, int, int ) -> Type[PyType] """ Executes a simple SNMP GET request and returns a pure Python data structure. @@ -72,15 +73,17 @@ def get( 'non-functional example' """ result = multiget( - ip, community, [oid], port, timeout=timeout, version=version + ip, community, [oid], port, timeout=timeout, version=version, + retries=retries ) return result[0] def multiget( - ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None ): - # type: ( str, str, List[str], int, int, int) -> List[Type[PyType]] + # type: ( str, str, List[str], int, int, int, int ) -> List[Type[PyType]] """ Executes an SNMP GET request with multiple OIDs and returns a list of pure Python objects. The order of the output items is the same order as the OIDs @@ -91,7 +94,7 @@ def multiget( >>> multiget('192.168.1.1', 'private', ['1.2.3.4', '1.2.3.5']) ['non-functional example', 'second value'] """ - transport = Transport(timeout=timeout) + transport = Transport(timeout=timeout, retries=retries) parsed_oids = [OID(oid) for oid in oids] @@ -116,9 +119,10 @@ def multiget( def getnext( - ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oid, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None ): - # type: (str, str, str, int, int, int) -> VarBind + # type: (str, str, str, int, int, int, int) -> VarBind """ Executes a single SNMP GETNEXT request (used inside *walk*). @@ -128,15 +132,17 @@ def getnext( VarBind(ObjectIdentifier(1, 2, 3, 0), 'non-functional example') """ result = multigetnext( - ip, community, [oid], port, timeout=timeout, version=version + ip, community, [oid], port, timeout=timeout, version=version, + retries=retries ) return result[0] def multigetnext( - ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C + ip, community, oids, port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None ): - # type: (str, str, List[str], int, int, int) -> List[VarBind] + # type: (str, str, List[str], int, int, int, int) -> List[VarBind] """ Executes a single multi-oid GETNEXT request. @@ -151,7 +157,7 @@ def multigetnext( VarBind(ObjectIdentifier(1, 2, 4, 0), 'second value') ] """ - transport = Transport(timeout=timeout) + transport = Transport(timeout=timeout, retries=retries) request = GetNextRequest(transport.get_request_id(), *oids) packet = Sequence(Integer(version), OctetString(community), request) response = transport.send(ip, port, to_bytes(packet)) @@ -191,8 +197,9 @@ def walk( timeout=DEFAULT_TIMEOUT, errors=ERRORS_STRICT, version=Version.V2C, + retries=None ): - # type: (str, str, str, int, int, str, int) -> TWalkResponse + # type: (str, str, str, int, int, str, int, int) -> TWalkResponse """ Executes a sequence of SNMP GETNEXT requests and returns a generator over :py:class:`~puresnmp.pdu.VarBind` instances. @@ -225,6 +232,7 @@ def walk( timeout=timeout, errors=errors, version=version, + retries=retries, ) return gen @@ -238,8 +246,9 @@ def multiwalk( fetcher=multigetnext, errors=ERRORS_STRICT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], int, int, TFetcher, str, int) -> TWalkResponse + # type: (str, str, List[str], int, int, TFetcher, str, int, int) -> TWalkResponse """ Executes a sequence of SNMP GETNEXT requests and returns a generator over :py:class:`~puresnmp.pdu.VarBind` instances. @@ -255,7 +264,7 @@ def multiwalk( """ LOG.debug("Walking on %d OIDs using %s", len(oids), fetcher.__name__) - varbinds = fetcher(ip, community, oids, port, timeout, version) + varbinds = fetcher(ip, community, oids, port, timeout, version, retries=retries) requested_oids = [OID(oid) for oid in oids] grouped_oids = group_varbinds(varbinds, requested_oids) unfinished_oids = get_unfinished_walk_oids(grouped_oids) @@ -288,7 +297,8 @@ def multiwalk( next_fetches_str = [str(_) for _ in next_fetches] try: varbinds = fetcher( - ip, community, next_fetches_str, port, timeout, version + ip, community, next_fetches_str, port, timeout, version, + retries=retries, ) except NoSuchOID: # Reached end of OID tree, finish iteration @@ -333,8 +343,9 @@ def set( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): # pylint: disable=redefined-builtin - # type: (str, str, str, T, int, int, int) -> T + # type: (str, str, str, T, int, int, int, int) -> T """ Executes a simple SNMP SET request. The result is returned as pure Python data structure. The value must be a subclass of @@ -348,7 +359,8 @@ def set( """ result = multiset( - ip, community, [(oid, value)], port, timeout=timeout, version=version + ip, community, [(oid, value)], port, timeout=timeout, version=version, + retries=retries, ) return result[oid.lstrip(".")] @@ -360,8 +372,9 @@ def multiset( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[Tuple[str, T]], int, int, int) -> Dict[str, T] + # type: (str, str, List[Tuple[str, T]], int, int, int, int) -> Dict[str, T] """ Executes an SNMP SET request on multiple OIDs. The result is returned as pure Python data structure. @@ -374,7 +387,7 @@ def multiset( ... ('2.3.4', OctetString(b'bar'))]) {'1.2.3': b'foo', '2.3.4': b'bar'} """ - transport = Transport(timeout=timeout) + transport = Transport(timeout=timeout, retries=retries) if any([not isinstance(v, Type) for k, v in mappings]): raise TypeError( @@ -408,8 +421,9 @@ def bulkget( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], List[str], int, int, int, int) -> BulkResult + # type: (str, str, List[str], List[str], int, int, int, int, int) -> BulkResult # pylint: disable=unused-argument, too-many-locals """ Runs a "bulk" get operation and returns a :py:class:`~.BulkResult` @@ -474,7 +488,7 @@ def bulkget( ('1.3.6.1.2.1.4.8.0', b'\x00'), ('1.3.6.1.2.1.5.10.0', b'\x00')])) """ - transport = Transport(timeout=timeout) + transport = Transport(timeout=timeout, retries=retries) scalar_oids = scalar_oids or [] # protect against empty values repeating_oids = repeating_oids or [] # protect against empty values @@ -542,8 +556,9 @@ def fetcher( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], int, int, int) -> List[VarBind] + # type: (str, str, List[str], int, int, int, int) -> List[VarBind] """ Executes a SNMP BulkGet request. """ @@ -556,6 +571,7 @@ def fetcher( port=port, timeout=timeout, version=version, + retries=retries, ) return [VarBind(OID(k), v) for k, v in result.listing.items()] @@ -571,8 +587,9 @@ def bulkwalk( port=161, timeout=DEFAULT_TIMEOUT, version=Version.V2C, + retries=None, ): - # type: (str, str, List[str], int, int, int, int) -> TWalkResponse + # type: (str, str, List[str], int, int, int, int, int) -> TWalkResponse """ More efficient implementation of :py:func:`~.walk`. It uses :py:func:`~.bulkget` under the hood instead of :py:func:`~.getnext`. @@ -620,13 +637,15 @@ def bulkwalk( fetcher=_bulkwalk_fetcher(bulk_size), timeout=timeout, version=version, + retries=retries, ) for oid, value in result: yield VarBind(oid, value) -def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C): - # type: (str, str, str, int, int) -> List[Dict[str, Any]] +def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C, + timeout=DEFAULT_TIMEOUT, retries=None): + # type: (str, str, str, int, int, int, int, int) -> List[Dict[str, Any]] """ Fetch an SNMP table @@ -651,15 +670,17 @@ def table(ip, community, oid, port=161, num_base_nodes=0, version=Version.V2C): parsed_oid = OID(oid) num_base_nodes = len(parsed_oid) + 1 - varbinds = walk(ip, community, oid, port=port, version=version) + varbinds = walk(ip, community, oid, port=port, version=version, + timeout=timeout, retries=retries) for varbind in varbinds: tmp.append(varbind) as_table = tablify(tmp, num_base_nodes=num_base_nodes) # type: ignore return as_table -def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10): - # type: (str, str, str, int, int, int) -> List[Dict[str, Any]] +def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10, + timeout=DEFAULT_TIMEOUT, retries=None): + # type: (str, str, str, int, int, int, int, int) -> List[Dict[str, Any]] """ Fetch an SNMP table using "bulk" requests. @@ -672,7 +693,8 @@ def bulktable(ip, community, oid, port=161, num_base_nodes=0, bulk_size=10): parsed_oid = OID(oid) num_base_nodes = len(parsed_oid) + 1 - varbinds = bulkwalk(ip, community, [oid], port=port, bulk_size=bulk_size) + varbinds = bulkwalk(ip, community, [oid], port=port, bulk_size=bulk_size, + timeout=timeout, retries=retries) for varbind in varbinds: tmp.append(varbind) as_table = tablify(tmp, num_base_nodes=num_base_nodes) # type: ignore diff --git a/puresnmp/transport.py b/puresnmp/transport.py index 9bd5ff9..0602151 100644 --- a/puresnmp/transport.py +++ b/puresnmp/transport.py @@ -60,7 +60,7 @@ def __init__(self, timeout=2, retries=None, buffer_size=None): self.retries = retries or RETRIES self.buffer_size = buffer_size or BUFFER_SIZE - def send(self, ip, port, packet, timeout=2): # pragma: no cover + def send(self, ip, port, packet, timeout=None): # pragma: no cover # type: ( str, int, bytes, int ) -> bytes """ Opens a TCP connection to *ip:port*, sends a packet with *bytes* and