def _bulkwalk(self, oids, keys=None, index=None, num_base_nodes=0, ret_raw=False, orderby=None, is_hex=False, to_str=True, proc=None, bulk_size=None, timeout=None): ''' :param oids: dict :param keys: 替换snmp oid为字符串 {'1': 'xxx', '2': 'yyy'} :param index: 数字, 返回dict, 以index为key, 会忽略空值 :param num_base_nodes: :param ret_raw: 返回迭代器, 因为有时需要详细的oid, 但tablify返回不带oid for row in raw: print('%s: %r' % row) :param orderby: 排序 :param to_str: 返回str,否则可能转成int或float :param proc: (func, *args), 不使用tablify,proc, 返回(key, value)组成字典 :param timeout: puresnmp的bulkwalk有bug,不能传递timeout :return: ''' # 一些puresnmp版本中bulkwalk不包含timeout,需要检查 d = {'timeout': timeout or self.timeoout} if 'timeout' in getfullargspec(bulkwalk).args else {} raw = bulkwalk(oids=oids.keys(), bulk_size=bulk_size or self.bulk_size, **d, **self.snmp_auth) if proc: func, *args = proc d = OrderedDict() for x in raw: k, v = func(x, *args) d[k] = v return d if ret_raw: # [(k, bytes_decode(v, to_type=to_type)) for k, v in raw] return raw lst = tablify(raw, num_base_nodes=num_base_nodes) if orderby: if isinstance(orderby, str): lst.sort(key=lambda x: x[orderby]) elif hasattr(orderby, '__call__'): lst.sort(key=orderby) if keys: if '0' not in keys: keys['0'] = 'id' _lst = [] for i, x in enumerate(lst): d = {keys.get(k, k): bytes_decode(x[k], to_type='str' if to_str else None, is_hex=is_hex) for k, v in x.items()} _lst.append(d) if not index or index not in keys: return _lst _dict = OrderedDict() _index = keys[index] for i, x in enumerate(_lst): if not x[_index]: continue _dict[x[_index]] = x return _dict else: return [{k: bytes_decode(v, to_type='str' if to_str else None) for k, v in x.items()} for i, x in enumerate(lst)]
def test_get_call_args(self): data = readbytes('dummy.hex') # any dump would do packet = Sequence(Integer(Version.V2C), OctetString('public'), BulkGetRequest(0, 0, 2, ObjectIdentifier(1, 2, 3))) with patch('puresnmp.send') as mck, \ patch('puresnmp.get_request_id') as mck2: mck2.return_value = 0 mck.return_value = data # we need to wrap this in a list to consume the generator. list(bulkwalk('::1', 'public', ['1.2.3'], bulk_size=2)) mck.assert_called_with('::1', 161, bytes(packet), timeout=2)
def test_get_call_args_issue_22(self): data = readbytes('dummy.hex') # any dump would do packet = Sequence(Integer(Version.V2C), OctetString('public'), BulkGetRequest(0, 0, 2, ObjectIdentifier(1, 2, 3))) with patch('puresnmp.send') as mck, \ patch('puresnmp.get_request_id') as mck2: mck2.return_value = 0 mck.return_value = data with self.assertRaisesRegex(TypeError, 'OIDS.*list'): # we need to wrap this in a list to consume the generator. list(bulkwalk('::1', 'public', '1.2.3', bulk_size=2))
def fdb(self, vlanrange): swNumber = int(self.ipaddress.rpartition('.')[2]) if self.vendor == 'cisco': def portnumber(interfacename, quantity): if interfacename[0] == 'F': return int(interfacename.rpartition('/')[2]) elif interfacename[0] == 'G': return int(interfacename.rpartition('/')[2])+quantity dot1dTpFdbPort = ['.1.3.6.1.2.1.17.4.3.1.2'] dot1dBasePortIfIndex = ['.1.3.6.1.2.1.17.1.4.1.2'] vtpVlanState = ['.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1'] oidifName = ['.1.3.6.1.2.1.31.1.1.1.1'] swIfaces = bulkwalk(self.ipaddress, self.community, oidifName) swVlans = set(int(vlan.oid[-1]) for vlan in bulkwalk( self.ipaddress, self.community, vtpVlanState)) & set(vlanrange) swIfNames = {int(i.oid[-1]): i.value.decode('utf-8') for i in swIfaces} swMappings = { int(m.oid[-1]): swIfNames[int(m.value)] for v in swVlans for m in bulkwalk(self.ipaddress, "@".join([self.community, str(v)]), dot1dBasePortIfIndex)} swFDB = ( (swNumber, portnumber(swMappings[m.value], 48), ":".join( ["{:02X}".format(int(octet)) for octet in m.oid[-6:]]), v) for v in swVlans for m in bulkwalk( self.ipaddress, "@".join( [self.community, str(v)]), dot1dTpFdbPort) if swMappings[m.value] not in self.uplinkports) return swFDB elif self.vendor == 'dlink': oiddot1qTpFdbEntry = ['.1.3.6.1.2.1.17.7.1.2.2.1.2'] swFDB = ( (swNumber, int(m.value), ":".join( ["{:02X}".format(int(octet)) for octet in m.oid[-6:]]), int(m.oid[-7])) for m in bulkwalk(self.ipaddress, self.community, oiddot1qTpFdbEntry) if int(m.oid[-7]) in vlanrange if str(m.value) not in self.uplinkports) return swFDB else: return None
def test_bulkwalk(self): response = readbytes_multiple('apiv1/bulkwalk_response.hex') self.transport.send.side_effect = response result = list(snmp.bulkwalk('192.168.1.1', 'private', [ '1.3.6.1.2.1.1.9.1.4'])) expected = [ VarBind(OID('1.3.6.1.2.1.1.9.1.4.1'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.2'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.3'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.4'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.5'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.6'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.7'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.8'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.9'), datetime.timedelta(0)), VarBind(OID('1.3.6.1.2.1.1.9.1.4.10'), datetime.timedelta(0)) ] self.assertEqual(result, expected) self.assertTrue(self.transport.send.called, 'method was not called') expected_types = [(ObjectIdentifier, datetime.timedelta)] * 10 returned_values = [(row.oid, row.value) for row in result] assert_of_types(returned_values, expected_types)
def __process_methods(method, common_parameters, datatype_config): response = None if method == "get": oid = datatype_config["oid"] response = puresnmp.get(**common_parameters, oid=oid) elif method == "multiget": oids = datatype_config["oid"] oids = oids if isinstance(oids, list) else list(oids) response = puresnmp.multiget(**common_parameters, oids=oids) elif method == "getnext": oid = datatype_config["oid"] master_response = puresnmp.getnext(**common_parameters, oid=oid) response = {master_response.oid: master_response.value} elif method == "multigetnext": oids = datatype_config["oid"] oids = oids if isinstance(oids, list) else list(oids) master_response = puresnmp.multigetnext(**common_parameters, oids=oids) response = { binded_var.oid: binded_var.value for binded_var in master_response } elif method == "walk": oid = datatype_config["oid"] response = { binded_var.oid: binded_var.value for binded_var in list( puresnmp.walk(**common_parameters, oid=oid)) } elif method == "multiwalk": oids = datatype_config["oid"] oids = oids if isinstance(oids, list) else list(oids) response = { binded_var.oid: binded_var.value for binded_var in list( puresnmp.multiwalk(**common_parameters, oids=oids)) } elif method == "set": oid = datatype_config["oid"] value = datatype_config["value"] response = puresnmp.set(**common_parameters, oid=oid, value=value) elif method == "multiset": mappings = datatype_config["mappings"] response = puresnmp.multiset(**common_parameters, mappings=mappings) elif method == "bulkget": scalar_oids = datatype_config.get("scalarOid", []) scalar_oids = scalar_oids if isinstance( scalar_oids, list) else list(scalar_oids) repeating_oids = datatype_config.get("repeatingOid", []) repeating_oids = repeating_oids if isinstance( repeating_oids, list) else list(repeating_oids) max_list_size = datatype_config.get("maxListSize", 1) response = puresnmp.bulkget(**common_parameters, scalar_oids=scalar_oids, repeating_oids=repeating_oids, max_list_size=max_list_size)._asdict() elif method == "bulkwalk": oids = datatype_config["oid"] oids = oids if isinstance(oids, list) else list(oids) bulk_size = datatype_config.get("bulkSize", 10) response = { binded_var.oid: binded_var.value for binded_var in list( puresnmp.bulkwalk( **common_parameters, bulk_size=bulk_size, oids=oids)) } elif method == "table": oid = datatype_config["oid"] del common_parameters["timeout"] num_base_nodes = datatype_config.get("numBaseNodes", 0) response = puresnmp.table(**common_parameters, oid=oid, num_base_nodes=num_base_nodes) elif method == "bulktable": oid = datatype_config["oid"] num_base_nodes = datatype_config.get("numBaseNodes", 0) bulk_size = datatype_config.get("bulkSize", 10) response = puresnmp.bulktable(**common_parameters, oid=oid, num_base_nodes=num_base_nodes, bulk_size=bulk_size) else: log.error("Method \"%s\" - Not found", str(method)) return response
def test_bulkwalk(self, mck_rid, mck_send): req1 = readbytes('bulkwalk_request_1.hex') req2 = readbytes('bulkwalk_request_2.hex') req3 = readbytes('bulkwalk_request_3.hex') responses = [ readbytes('bulkwalk_response_1.hex'), readbytes('bulkwalk_response_2.hex'), readbytes('bulkwalk_response_3.hex'), ] mck_send.side_effect = responses request_ids = [1001613222, 1001613223, 1001613224] mck_rid.side_effect = request_ids result = list( bulkwalk('127.0.0.1', 'private', ['1.3.6.1.2.1.2.2'], bulk_size=20)) self.assertEqual(mck_send.mock_calls, [ call('127.0.0.1', 161, req1, timeout=2), call('127.0.0.1', 161, req2, timeout=2), call('127.0.0.1', 161, req3, timeout=2), ]) # TODO (advanced): Type information is lost for timeticks and OIDs expected = [ VarBind('1.3.6.1.2.1.2.2.1.1.1', 1), VarBind('1.3.6.1.2.1.2.2.1.1.10', 10), VarBind('1.3.6.1.2.1.2.2.1.2.1', b"lo"), VarBind('1.3.6.1.2.1.2.2.1.2.10', b"eth0"), VarBind('1.3.6.1.2.1.2.2.1.3.1', 24), VarBind('1.3.6.1.2.1.2.2.1.3.10', 6), VarBind('1.3.6.1.2.1.2.2.1.4.1', 65536), VarBind('1.3.6.1.2.1.2.2.1.4.10', 1500), VarBind('1.3.6.1.2.1.2.2.1.5.1', 10000000), VarBind('1.3.6.1.2.1.2.2.1.5.10', 4294967295), VarBind('1.3.6.1.2.1.2.2.1.6.1', b""), VarBind('1.3.6.1.2.1.2.2.1.6.10', b"\x02\x42\xAC\x11\x00\x02"), VarBind('1.3.6.1.2.1.2.2.1.7.1', 1), VarBind('1.3.6.1.2.1.2.2.1.7.10', 1), VarBind('1.3.6.1.2.1.2.2.1.8.1', 1), VarBind('1.3.6.1.2.1.2.2.1.8.10', 1), VarBind('1.3.6.1.2.1.2.2.1.9.1', timedelta(0)), VarBind('1.3.6.1.2.1.2.2.1.9.10', timedelta(0)), VarBind('1.3.6.1.2.1.2.2.1.10.1', 172), VarBind('1.3.6.1.2.1.2.2.1.10.10', 60558), VarBind('1.3.6.1.2.1.2.2.1.11.1', 2), VarBind('1.3.6.1.2.1.2.2.1.11.10', 564), VarBind('1.3.6.1.2.1.2.2.1.12.1', 0), VarBind('1.3.6.1.2.1.2.2.1.12.10', 0), VarBind('1.3.6.1.2.1.2.2.1.13.1', 0), VarBind('1.3.6.1.2.1.2.2.1.13.10', 0), VarBind('1.3.6.1.2.1.2.2.1.14.1', 0), VarBind('1.3.6.1.2.1.2.2.1.14.10', 0), VarBind('1.3.6.1.2.1.2.2.1.15.1', 0), VarBind('1.3.6.1.2.1.2.2.1.15.10', 0), VarBind('1.3.6.1.2.1.2.2.1.16.1', 172), VarBind('1.3.6.1.2.1.2.2.1.16.10', 44295), VarBind('1.3.6.1.2.1.2.2.1.17.1', 2), VarBind('1.3.6.1.2.1.2.2.1.17.10', 442), VarBind('1.3.6.1.2.1.2.2.1.18.1', 0), VarBind('1.3.6.1.2.1.2.2.1.18.10', 0), VarBind('1.3.6.1.2.1.2.2.1.19.1', 0), VarBind('1.3.6.1.2.1.2.2.1.19.10', 0), VarBind('1.3.6.1.2.1.2.2.1.20.1', 0), VarBind('1.3.6.1.2.1.2.2.1.20.10', 0), VarBind('1.3.6.1.2.1.2.2.1.21.1', 0), VarBind('1.3.6.1.2.1.2.2.1.21.10', 0), VarBind('1.3.6.1.2.1.2.2.1.22.1', '0.0'), # TODO: type info is lost VarBind('1.3.6.1.2.1.2.2.1.22.10', '0.0'), # TODO: type info is lost ] # TODO: Expected types per OID: # 1.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1 # 1.3.6.1.2.1.2.2.1.1.10 = INTEGER: 10 # 1.3.6.1.2.1.2.2.1.2.1 = STRING: "lo" # 1.3.6.1.2.1.2.2.1.2.10 = STRING: "eth0" # 1.3.6.1.2.1.2.2.1.3.1 = INTEGER: 24 # 1.3.6.1.2.1.2.2.1.3.10 = INTEGER: 6 # 1.3.6.1.2.1.2.2.1.4.1 = INTEGER: 65536 # 1.3.6.1.2.1.2.2.1.4.10 = INTEGER: 1500 # 1.3.6.1.2.1.2.2.1.5.1 = Gauge32: 10000000 # 1.3.6.1.2.1.2.2.1.5.10 = Gauge32: 4294967295 # 1.3.6.1.2.1.2.2.1.6.1 = "" # 1.3.6.1.2.1.2.2.1.6.10 = Hex-STRING: 02 42 AC 11 00 02 # 1.3.6.1.2.1.2.2.1.7.1 = INTEGER: 1 # 1.3.6.1.2.1.2.2.1.7.10 = INTEGER: 1 # 1.3.6.1.2.1.2.2.1.8.1 = INTEGER: 1 # 1.3.6.1.2.1.2.2.1.8.10 = INTEGER: 1 # 1.3.6.1.2.1.2.2.1.9.1 = Timeticks: (0) 0:00:00.00 # 1.3.6.1.2.1.2.2.1.9.10 = Timeticks: (0) 0:00:00.00 # 1.3.6.1.2.1.2.2.1.10.1 = Counter32: 172 # 1.3.6.1.2.1.2.2.1.10.10 = Counter32: 60558 # 1.3.6.1.2.1.2.2.1.11.1 = Counter32: 2 # 1.3.6.1.2.1.2.2.1.11.10 = Counter32: 564 # 1.3.6.1.2.1.2.2.1.12.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.12.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.13.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.13.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.14.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.14.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.15.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.15.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.16.1 = Counter32: 172 # 1.3.6.1.2.1.2.2.1.16.10 = Counter32: 44295 # 1.3.6.1.2.1.2.2.1.17.1 = Counter32: 2 # 1.3.6.1.2.1.2.2.1.17.10 = Counter32: 442 # 1.3.6.1.2.1.2.2.1.18.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.18.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.19.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.19.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.20.1 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.20.10 = Counter32: 0 # 1.3.6.1.2.1.2.2.1.21.1 = Gauge32: 0 # 1.3.6.1.2.1.2.2.1.21.10 = Gauge32: 0 # 1.3.6.1.2.1.2.2.1.22.1 = OID: ccitt.0 # 1.3.6.1.2.1.2.2.1.22.10 = OID: ccitt.0 self.assertEqual(result, expected)