fixes functions and adds cli support

- implements cli
- fixes get_bgp_neighbors #44
- fixes get_lldp_neighbors(multiple neighbors)
This commit is contained in:
Marcos Buzo 2021-08-12 20:07:54 +02:00
parent a5d3b94663
commit 72ed825c1d
1 changed files with 110 additions and 82 deletions

View File

@ -472,12 +472,14 @@ class VyOSDriver(NetworkDriver):
""" """
output = self.device.send_command("show ip bgp summary") output = self.device.send_command("show ip bgp summary")
output = output.split("\n") match = re.search(
r"bgp router identifier (\d+\.\d+\.\d+\.\d+), local as number (\d+) vrf-id (\d+)",
match = re.search(r".* router identifier (\d+\.\d+\.\d+\.\d+), local AS number (\d+)", output,
output[0]) re.MULTILINE | re.IGNORECASE
)
if not match: if not match:
return {} return {}
router_id = match.group(1) router_id = match.group(1)
local_as = int(match.group(2)) local_as = int(match.group(2))
@ -485,73 +487,84 @@ class VyOSDriver(NetworkDriver):
bgp_neighbor_data["global"] = dict() bgp_neighbor_data["global"] = dict()
bgp_neighbor_data["global"]["router_id"] = router_id bgp_neighbor_data["global"]["router_id"] = router_id
bgp_neighbor_data["global"]["peers"] = {} bgp_neighbor_data["global"]["peers"] = {}
re_neighbor = re.compile(
'^([\w\d:\.]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\w+)'
)
for bgp_line in output.split("\n"):
match = re_neighbor.search(bgp_line)
if not match:
continue
peer_id = match.group(1)
bgp_version = match.group(2)
remote_as = match.group(3)
msg_rcvd = match.group(4)
msg_sent = match.group(5)
table_version = match.group(6)
in_queue = match.group(7)
out_queue = match.group(8)
up_time = match.group(9)
state_prefix = match.group(10)
# delete the header and empty element is_enabled = "(Admin)" not in state_prefix
bgp_info = [i.strip() for i in output[6:-2] if i]
received_prefixes = None
for i in bgp_info: try:
if len(i) > 0: state_prefix = int(state_prefix)
peer_id, bgp_version, remote_as, msg_rcvd, msg_sent, table_version, \ received_prefixes = int(state_prefix)
in_queue, out_queue, up_time, state_prefix = i.split() is_up = True
except ValueError:
state_prefix = -1
received_prefixes = -1
is_up = False
is_enabled = "(Admin)" not in state_prefix if bgp_version == "4":
address_family = "ipv4"
elif bgp_version == "6":
address_family = "ipv6"
else:
raise ValueError("BGP neighbor parsing failed")
received_prefixes = None """
'show ip bgp neighbors 192.168.1.1' output example:
BGP neighbor is 192.168.1.1, remote AS 64519, local AS 64520, external link
BGP version 4, remote router ID 192.168.1.1
For address family: IPv4 Unicast
~~~
Community attribute sent to this neighbor(both)
1 accepted prefixes
~~~
"""
bgp_detail = self.device.send_command("show ip bgp neighbors %s" % peer_id)
try: match_rid = re.search(r"remote router ID (\d+\.\d+\.\d+\.\d+).*", bgp_detail)
state_prefix = int(state_prefix) remote_rid = match_rid.group(1)
received_prefixes = int(state_prefix)
is_up = True
except ValueError:
state_prefix = -1
received_prefixes = -1
is_up = False
if bgp_version == "4": match_prefix_accepted = re.search(r"(\d+) accepted prefixes", bgp_detail)
address_family = "ipv4" accepted_prefixes = match_prefix_accepted.group(1)
elif bgp_version == "6":
address_family = "ipv6"
else:
raise ValueError("BGP neighbor parsing failed")
""" bgp_neighbor_data["global"]["peers"].setdefault(peer_id, {})
'show ip bgp neighbors 192.168.1.1' output example: peer_dict = {
BGP neighbor is 192.168.1.1, remote AS 64519, local AS 64520, external link "description": "",
BGP version 4, remote router ID 192.168.1.1 "is_enabled": bool(is_enabled),
For address family: IPv4 Unicast "local_as": int(local_as),
~~~ "is_up": bool(is_up),
Community attribute sent to this neighbor(both) "remote_id": remote_rid,
1 accepted prefixes "uptime": int(self._bgp_time_conversion(up_time)),
~~~ "remote_as": int(remote_as)
""" }
bgp_detail = self.device.send_command("show ip bgp neighbors %s" % peer_id)
match_rid = re.search(r"remote router ID (\d+\.\d+\.\d+\.\d+).*", bgp_detail) af_dict = dict()
remote_rid = match_rid.group(1) af_dict[address_family] = {
"sent_prefixes": int(-1),
"accepted_prefixes": int(accepted_prefixes),
"received_prefixes": int(received_prefixes)
}
match_prefix_accepted = re.search(r"(\d+) accepted prefixes", bgp_detail) peer_dict["address_family"] = af_dict
accepted_prefixes = match_prefix_accepted.group(1) bgp_neighbor_data["global"]["peers"][peer_id] = peer_dict
bgp_neighbor_data["global"]["peers"].setdefault(peer_id, {})
peer_dict = {
"description": "",
"is_enabled": bool(is_enabled),
"local_as": int(local_as),
"is_up": bool(is_up),
"remote_id": remote_rid,
"uptime": int(self._bgp_time_conversion(up_time)),
"remote_as": int(remote_as)
}
af_dict = dict()
af_dict[address_family] = {
"sent_prefixes": int(-1),
"accepted_prefixes": int(accepted_prefixes),
"received_prefixes": int(received_prefixes)
}
peer_dict["address_family"] = af_dict
bgp_neighbor_data["global"]["peers"][peer_id] = peer_dict
return bgp_neighbor_data return bgp_neighbor_data
@ -586,27 +599,28 @@ class VyOSDriver(NetworkDriver):
return uptime return uptime
def get_lldp_neighbors(self): def get_lldp_neighbors(self):
# Multiple neighbors per port are not implemented ret = []
# The show lldp neighbors commands lists port descriptions, not IDs
output = self.device.send_command("show lldp neighbors detail") output = self.device.send_command("show lldp neighbors detail")
pattern = r'''(?s)Interface: +(?P<interface>\S+), [^\n]+ regex = '{},.+?{}.+?{}'.format(
.+? "Interface:\s+(\S+)",
+SysName: +(?P<hostname>\S+) "SysName:\s+(\S+)",
.+? "PortID:\s+ifname (\S+)"
+PortID: +ifname (?P<port>\S+)''' )
re_lldp = re.compile(
def _get_interface(match): regex,
return [ re.MULTILINE|re.DOTALL
{ )
'hostname': match.group('hostname'), match = re_lldp.findall(output)
'port': match.group('port'), if not match:
} return []
]
for ocurrence in match:
return { ret.append({
match.group('interface'): _get_interface(match) 'hostname' : ocurrence[0],
for match in re.finditer(pattern, output) 'port' : ocurrence[1],
} 'interface' : ocurrence[2]
})
return ret
def get_interfaces_counters(self): def get_interfaces_counters(self):
# 'rx_unicast_packet', 'rx_broadcast_packets', 'tx_unicast_packets', # 'rx_unicast_packet', 'rx_broadcast_packets', 'tx_unicast_packets',
@ -958,3 +972,17 @@ class VyOSDriver(NetworkDriver):
config = config[:config.rfind('\n')] config = config[:config.rfind('\n')]
self.device.exit_config_mode() self.device.exit_config_mode()
return config return config
def cli(self, commands):
cli_output = {}
if not isinstance(commands, list):
raise TypeError("Please enter a valid list of commands!")
for command in commands:
try:
cli_output[command] = self.device.send_command(command)
except Exception:
cli_output[command] = 'error running command'
return cli_output