Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions ansible/library/bgp_facts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#!/usr/bin/python


DOCUMENTATION = '''
module: bgp_facts
version_added: "2.0"
author: John Arnold (johnar@microsoft.com)
short_description: Retrieve BGP neighbor information from Quagga
description:
- Retrieve BGP neighbor information from Quagga, using the VTYSH command line
- Retrieved facts will be inserted into the 'bgp_neighbors' key
'''

EXAMPLES = '''
- name: Get BGP neighbor information
bgp_facts:
'''

# Example of the source data
'''
BGP neighbor is 10.0.0.61, remote AS 64015, local AS 65100, external link
Description: ARISTA15T0
BGP version 4, remote router ID 0.0.0.0
BGP state = Active
Last read 6d13h16m, hold time is 180, keepalive interval is 60 seconds
Message statistics:
Inq depth is 0
Outq depth is 0
Sent Rcvd
Opens: 1 1
Notifications: 0 0
Updates: 6595 3
Keepalives: 949 948
Route Refresh: 0 0
Capability: 0 0
Total: 7545 952
Minimum time between advertisement runs is 30 seconds

For address family: IPv4 Unicast
Community attribute sent to this neighbor(both)
0 accepted prefixes

Connections established 1; dropped 1
Last reset 6d13h15m, due to
Next connect timer due in 31 seconds
Read thread: off Write thread: off
'''


class BgpModule(object):
def __init__(self):
self.module = AnsibleModule(
argument_spec=dict(
),
supports_check_mode=True)

self.out = None
self.facts = {}

return

def run(self):
"""
Main method of the class
"""
self.collect_neighbors()
self.parse_neighbors()
self.module.exit_json(ansible_facts=self.facts)


def collect_neighbors(self):
"""
Collect bgp neighbors by reading output of 'vtysh' command line tool
"""
try:
rc, self.out, err = self.module.run_command('vtysh -c "show ip bgp neighbors"',
executable='/bin/bash', use_unsafe_shell=True)
except Exception as e:
self.module.fail_json(msg=str(e))

if rc != 0:
self.module.fail_json(msg="Command failed rc=%d, out=%s, err=%s" %
(rc, self.out, err))

return

def parse_neighbors(self):

regex_ip = re.compile(r'^BGP neighbor is (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
regex_remote_as = re.compile(r'.*remote AS (\d+)')
regex_local_as = re.compile(r'.*local AS (\d+)')
regex_desc = re.compile(r'.*Description: (.*)')
regex_stats = re.compile(r'.*(Opens|Notifications|Updates|Keepalives|Route Refresh|Capability|Total):.*')
regex_state = re.compile(r'.*BGP state = (\w+)')
regex_mrai = re.compile(r'.*Minimum time between advertisement runs is (\d{1,4})')
regex_accepted = re.compile(r'.*(\d+) accepted prefixes')
regex_conn_est = re.compile(r'.*Connections established (\d+)')
regex_conn_dropped = re.compile(r'.*Connections established \d+; dropped (\d+)')
regex_routerid = re.compile(r'.*remote router ID (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')

neighbors = {}

try:
split_output = self.out.split("BGP neighbor")

for n in split_output:

# ignore empty rows
if 'BGP' in n:
neighbor = {}
message_stats = {}
n = "BGP neighbor" + n
lines = n.splitlines()

for line in lines:
if regex_ip.match(line): neighbor_ip = regex_ip.match(line).group(1)
if regex_remote_as.match(line): neighbor['remote AS'] = int(regex_remote_as.match(line).group(1))
if regex_local_as.match(line): neighbor['local AS'] = int(regex_local_as.match(line).group(1))
if regex_desc.match(line): neighbor['description'] = regex_desc.match(line).group(1)
if regex_state.match(line): neighbor['state'] = regex_state.match(line).group(1).lower()
if regex_mrai.match(line): neighbor['mrai'] = int(regex_mrai.match(line).group(1))
if regex_accepted.match(line): neighbor['accepted prefixes'] = int(regex_accepted.match(line).group(1))
if regex_conn_est.match(line): neighbor['connections established'] = int(regex_conn_est.match(line).group(1))
if regex_conn_dropped.match(line): neighbor['connections dropped'] = int(regex_conn_dropped.match(line).group(1))
if regex_routerid.match(line): neighbor['remote routerid'] = regex_routerid.match(line).group(1)

if regex_stats.match(line):
key, values = line.split(':')
key = key.lstrip()
sent, rcvd = values.split()
value_dict = {}
value_dict['sent'] = int(sent)
value_dict['rcvd'] = int(rcvd)
message_stats[key] = value_dict

if message_stats:
neighbor['message statistics'] = message_stats

neighbors[neighbor_ip] = neighbor

except Exception as e:
self.module.fail_json(msg=str(e))

self.facts['bgp_neighbors'] = neighbors

return


def main():
bgp = BgpModule()
bgp.run()

return


from ansible.module_utils.basic import *
if __name__ == "__main__":
main()
221 changes: 221 additions & 0 deletions ansible/library/format_bgp_facts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
#!/usr/bin/python


DOCUMENTATION = '''
module: format_bgp_facts
version_added: "2.0"
author: John Arnold (johnar@microsoft.com)
short_description: Format BGP neighbor info from different OSes
description:
- Format BGP neighbor information from FTOS, Arista, Nexus etc.
- Retrieved facts will be inserted into the 'bgp_neighbors' key
'''

EXAMPLES = '''
- name: Format BGP neighbor information
format_bgp_facts: bgp_neighbors="{{ result.stdout }}" hw_sku_class="Force10"
'''

# Example of the source data
'''
BGP neighbor is 10.0.0.61, remote AS 64015, local AS 65100, external link
Description: ARISTA15T0
BGP version 4, remote router ID 0.0.0.0
BGP state = Active
Last read 6d13h16m, hold time is 180, keepalive interval is 60 seconds
Message statistics:
Inq depth is 0
Outq depth is 0
Sent Rcvd
Opens: 1 1
Notifications: 0 0
Updates: 6595 3
Keepalives: 949 948
Route Refresh: 0 0
Capability: 0 0
Total: 7545 952
Minimum time between advertisement runs is 30 seconds

For address family: IPv4 Unicast
Community attribute sent to this neighbor(both)
0 accepted prefixes

Connections established 1; dropped 1
Last reset 6d13h15m, due to
Next connect timer due in 31 seconds
Read thread: off Write thread: off
'''


class BgpModule(object):


def __init__(self):
self.module = AnsibleModule(
argument_spec=dict(
is_sonic=dict(required=False, default=False, type='bool'),
hw_sku_class=dict(required=True, choices=['Force10', 'Nexus']),
bgp_neighbors_string=dict(required=False),
),
supports_check_mode=True)

self.is_sonic = self.module.params['is_sonic']
self.hw_sku_class = self.module.params['hw_sku_class']
if self.module.params['bgp_neighbors_string']: self.bgp_neighbors_string = self.module.params['bgp_neighbors_string']
self.facts = {}

return

def run(self):
"""
Main method of the class
"""

if self.bgp_neighbors_string:
if self.is_sonic:
self.parse_sonic_neighbors()
else:
self.parse_neighbors()

self.module.exit_json(ansible_facts=self.facts)

def parse_sonic_neighbors(self):

regex_ip = re.compile(r'^BGP neighbor is (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
regex_remote_as = re.compile(r'.*remote AS (\d+)')
regex_local_as = re.compile(r'.*local AS (\d+)')
regex_desc = re.compile(r'.*Description: (.*)')
regex_stats = re.compile(r'.*(Opens|Notifications|Updates|Keepalives|Route Refresh|Capability|Total):.*')
regex_state = re.compile(r'.*BGP state = (\w+)')
regex_mrai = re.compile(r'.*Minimum time between advertisement runs is (\d{1,4})')
regex_accepted = re.compile(r'.*(\d+) accepted prefixes')
regex_conn_est = re.compile(r'.*Connections established (\d+)')
regex_conn_dropped = re.compile(r'.*Connections established \d+; dropped (\d+)')
regex_routerid = re.compile(r'.*remote router ID (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')

neighbors = {}

try:
split_output = self.bgp_neighbors_string.split("BGP neighbor")

for n in split_output:

# ignore empty rows
if 'BGP' in n:
neighbor = {}
message_stats = {}
n = "BGP neighbor" + n
lines = n.splitlines()

for line in lines:
if regex_ip.match(line): neighbor_ip = regex_ip.match(line).group(1)
if regex_remote_as.match(line): neighbor['remote AS'] = int(regex_remote_as.match(line).group(1))
if regex_local_as.match(line): neighbor['local AS'] = int(regex_local_as.match(line).group(1))
if regex_desc.match(line): neighbor['description'] = regex_desc.match(line).group(1)
if regex_state.match(line): neighbor['state'] = regex_state.match(line).group(1).lower()
if regex_mrai.match(line): neighbor['mrai'] = int(regex_mrai.match(line).group(1))
if regex_accepted.match(line): neighbor['accepted prefixes'] = int(regex_accepted.match(line).group(1))
if regex_conn_est.match(line): neighbor['connections established'] = int(regex_conn_est.match(line).group(1))
if regex_conn_dropped.match(line): neighbor['connections dropped'] = int(regex_conn_dropped.match(line).group(1))
if regex_routerid.match(line): neighbor['remote routerid'] = regex_routerid.match(line).group(1)

if regex_stats.match(line):
key, values = line.split(':')
key = key.lstrip()
sent, rcvd = values.split()
value_dict = {}
value_dict['sent'] = int(sent)
value_dict['rcvd'] = int(rcvd)
message_stats[key] = value_dict

if message_stats:
neighbor['message statistics'] = message_stats

neighbors[neighbor_ip] = neighbor

except Exception as e:
self.module.fail_json(msg=str(e))

self.facts['bgp_neighbors'] = neighbors

return

def parse_neighbors(self):


regex_ip = re.compile(r'^BGP neighbor is (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
regex_remote_as = re.compile(r'.*remote AS (\d+)')
regex_local_as = re.compile(r'.*local AS (\d+)')
if self.hw_sku_class == "Force10":
regex_desc = re.compile(r'.*Description : (.*)')
regex_stats = re.compile(r'.*(Opens|Notifications|Updates|Keepalives|Route Refresh|Capability|Total):.*')
regex_state = re.compile(r'.*BGP state (\w+)')
elif self.hw_sku_class == "Nexus":
regex_desc = re.compile(r'.*Description\s*:\s*(.*)')
regex_stats = re.compile(r'.*(Opens|Notifications|Updates|Keepalives|Route Refresh|Capability|Total):\s+(\d+)\s+(\d+)')
regex_state = re.compile(r'.*BGP state =?\s*(\w+)')
regex_mrai = re.compile(r'.*Minimum time between advertisement runs is (\d{1,4})')
regex_accepted = re.compile(r'.*Prefixes accepted (\d+)')
regex_conn_est = re.compile(r'.*Connections established (\d+)')
regex_conn_dropped = re.compile(r'.*Connections established \d+; dropped (\d+)')
regex_routerid = re.compile(r'.*remote router ID (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')

neighbors = {}

try:
split_output = self.bgp_neighbors_string.split("BGP neighbor")

for n in split_output:

# ignore empty rows
if 'BGP' in n:
neighbor = {}
message_stats = {}
n = "BGP neighbor" + n
lines = n.splitlines()

for line in lines:
if regex_ip.match(line): neighbor_ip = regex_ip.match(line).group(1)
if regex_remote_as.match(line): neighbor['remote AS'] = int(regex_remote_as.match(line).group(1))
if regex_local_as.match(line): neighbor['local AS'] = int(regex_local_as.match(line).group(1))
if regex_desc.match(line): neighbor['description'] = regex_desc.match(line).group(1)
if regex_state.match(line): neighbor['state'] = regex_state.match(line).group(1).lower()
if regex_mrai.match(line): neighbor['mrai'] = int(regex_mrai.match(line).group(1))
if regex_accepted.match(line): neighbor['accepted prefixes'] = int(regex_accepted.match(line).group(1))
if regex_conn_est.match(line): neighbor['connections established'] = int(regex_conn_est.match(line).group(1))
if regex_conn_dropped.match(line): neighbor['connections dropped'] = int(regex_conn_dropped.match(line).group(1))
if regex_routerid.match(line): neighbor['remote routerid'] = regex_routerid.match(line).group(1)

if regex_stats.match(line):
key, values = line.split(':')
key = key.lstrip()
sent, rcvd = values.split()
value_dict = {}
value_dict['sent'] = int(sent)
value_dict['rcvd'] = int(rcvd)
message_stats[key] = value_dict

if message_stats:
neighbor['message statistics'] = message_stats

neighbors[neighbor_ip] = neighbor

except Exception as e:
self.module.fail_json(msg=str(e))

self.facts['bgp_neighbors'] = neighbors

return



def main():
bgp = BgpModule()
bgp.run()

return


from ansible.module_utils.basic import *
if __name__ == "__main__":
main()
Loading