Update facts (#101)

* Update facts.py

* Update facts.py

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Update plugins/modules/facts.py

Co-authored-by: Egor Zaitsev <heuels@gmail.com>

* Create 101_update_facts.yml

* Update plugins/modules/facts.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update changelogs/fragments/101_update_facts.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* add test default function

* add test data

* Update routing_ospf_neighbor_print_detail_without-paging

* add test function "Routing"

* added information of version

* Removed extra spaces

* add one more version, "ansible_net_cpu_load"

* remove many blank lines

* remove 'too many blank lines'

* renamed arhitec to arch

* Update facts.py

* Update test_facts.py

* Update test_facts.py

* one more

* remove one route

* Update test_facts.py

* remove one neighbor

Co-authored-by: Egor Zaitsev <heuels@gmail.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
adeptvin1 2020-08-21 21:04:09 +10:00 committed by Felix Fontein
parent cc273e7ec1
commit f1ae008c4d
9 changed files with 519 additions and 2 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- facts - now also collecting data about BGP and OSPF (https://github.com/ansible-collections/community.network/pull/101).

View file

@ -68,6 +68,21 @@ ansible_net_hostname:
description: The configured hostname of the device description: The configured hostname of the device
returned: always returned: always
type: str type: str
ansible_net_arch:
description: The CPU architecture of the device
returned: always
type: str
version_added: 1.2.0
ansible_net_uptime:
description: The uptime of the device
returned: always
type: str
version_added: 1.2.0
ansible_net_cpu_load:
description: Current CPU load
returned: always
type: str
version_added: 1.2.0
# hardware # hardware
ansible_net_spacefree_mb: ansible_net_spacefree_mb:
@ -110,6 +125,38 @@ ansible_net_neighbors:
description: The list of neighbors from the remote device description: The list of neighbors from the remote device
returned: when interfaces is configured returned: when interfaces is configured
type: dict type: dict
# routing
ansible_net_bgp_peer:
description: The dict bgp peer
returned: peer information
type: dict
version_added: 1.2.0
ansible_net_bgp_vpnv4_route:
description: The dict bgp vpnv4 route
returned: vpnv4 route information
type: dict
version_added: 1.2.0
ansible_net_bgp_instance:
description: The dict bgp instance
returned: bgp instance information
type: dict
version_added: 1.2.0
ansible_net_route:
description: The dict routes in all routing table
returned: routes information in all routing table
type: dict
version_added: 1.2.0
ansible_net_ospf_instance:
description: The dict ospf instance
returned: ospf instance information
type: dict
version_added: 1.2.0
ansible_net_ospf_neighbor:
description: The dict ospf neighbor
returned: ospf neighbor information
type: dict
version_added: 1.2.0
""" """
import re import re
@ -148,11 +195,12 @@ class Default(FactsBase):
data = self.responses[0] data = self.responses[0]
if data: if data:
self.facts['hostname'] = self.parse_hostname(data) self.facts['hostname'] = self.parse_hostname(data)
data = self.responses[1] data = self.responses[1]
if data: if data:
self.facts['version'] = self.parse_version(data) self.facts['version'] = self.parse_version(data)
self.facts['arch'] = self.parse_arch(data)
self.facts['uptime'] = self.parse_uptime(data)
self.facts['cpu_load'] = self.parse_cpu_load(data)
data = self.responses[2] data = self.responses[2]
if data: if data:
self.facts['model'] = self.parse_model(data) self.facts['model'] = self.parse_model(data)
@ -173,6 +221,21 @@ class Default(FactsBase):
if match: if match:
return match.group(1) return match.group(1)
def parse_arch(self, data):
match = re.search(r'architecture-name:\s(.*)\s*$', data, re.M)
if match:
return match.group(1)
def parse_uptime(self, data):
match = re.search(r'uptime:\s(.*)\s*$', data, re.M)
if match:
return match.group(1)
def parse_cpu_load(self, data):
match = re.search(r'cpu-load:\s(.*)\s*$', data, re.M)
if match:
return match.group(1)
def parse_serialnum(self, data): def parse_serialnum(self, data):
match = re.search(r'serial-number:\s(.*)\s*$', data, re.M) match = re.search(r'serial-number:\s(.*)\s*$', data, re.M)
if match: if match:
@ -319,11 +382,178 @@ class Interfaces(FactsBase):
yield parsed yield parsed
class Routing(FactsBase):
COMMANDS = [
'/routing bgp peer print detail without-paging',
'/routing bgp vpnv4-route print detail without-paging',
'/routing bgp instance print detail without-paging',
'/ip route print detail without-paging',
'/routing ospf instance print detail without-paging',
'/routing ospf neighbor print detail without-paging'
]
DETAIL_RE = re.compile(r'([\w\d\-]+)=\"?(\w{3}/\d{2}/\d{4}\s\d{2}:\d{2}:\d{2}|[\w\d\-\.:/]+)')
WRAPPED_LINE_RE = re.compile(r'^\s+(?!\d)')
def populate(self):
super(Routing, self).populate()
self.facts['bgp_peer'] = dict()
self.facts['bgp_vpnv4_route'] = dict()
self.facts['bgp_instance'] = dict()
self.facts['route'] = dict()
self.facts['ospf_instance'] = dict()
self.facts['ospf_neighbor'] = dict()
data = self.responses[0]
if data:
peer = self.parse_bgp_peer(data)
self.populate_bgp_peer(peer)
data = self.responses[1]
if data:
vpnv4 = self.parse_vpnv4_route(data)
self.populate_vpnv4_route(vpnv4)
data = self.responses[2]
if data:
instance = self.parse_instance(data)
self.populate_bgp_instance(instance)
data = self.responses[3]
if data:
route = self.parse_route(data)
self.populate_route(route)
data = self.responses[4]
if data:
instance = self.parse_instance(data)
self.populate_ospf_instance(instance)
data = self.responses[5]
if data:
instance = self.parse_ospf_neighbor(data)
self.populate_ospf_neighbor(instance)
def preprocess(self, data):
preprocessed = list()
for line in data.split('\n'):
if len(line) == 0 or line[:5] == 'Flags':
continue
elif not re.match(self.WRAPPED_LINE_RE, line):
preprocessed.append(line)
else:
preprocessed[-1] += line
return preprocessed
def parse_name(self, data):
match = re.search(r'name=.(\S+\b)', data, re.M)
if match:
return match.group(1)
def parse_interface(self, data):
match = re.search(r'interface=([\w\d\-]+)', data, re.M)
if match:
return match.group(1)
def parse_instance_name(self, data):
match = re.search(r'instance=([\w\d\-]+)', data, re.M)
if match:
return match.group(1)
def parse_routing_mark(self, data):
match = re.search(r'routing-mark=([\w\d\-]+)', data, re.M)
if match:
return match.group(1)
else:
match = 'main'
return match
def parse_bgp_peer(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_name(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def parse_instance(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_name(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def parse_vpnv4_route(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_interface(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def parse_route(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_routing_mark(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def parse_ospf_instance(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_name(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def parse_ospf_neighbor(self, data):
facts = dict()
data = self.preprocess(data)
for line in data:
name = self.parse_instance_name(line)
facts[name] = dict()
for (key, value) in re.findall(self.DETAIL_RE, line):
facts[name][key] = value
return facts
def populate_bgp_peer(self, data):
for key, value in iteritems(data):
self.facts['bgp_peer'][key] = value
def populate_vpnv4_route(self, data):
for key, value in iteritems(data):
self.facts['bgp_vpnv4_route'][key] = value
def populate_bgp_instance(self, data):
for key, value in iteritems(data):
self.facts['bgp_instance'][key] = value
def populate_route(self, data):
for key, value in iteritems(data):
self.facts['route'][key] = value
def populate_ospf_instance(self, data):
for key, value in iteritems(data):
self.facts['ospf_instance'][key] = value
def populate_ospf_neighbor(self, data):
for key, value in iteritems(data):
self.facts['ospf_neighbor'][key] = value
FACT_SUBSETS = dict( FACT_SUBSETS = dict(
default=Default, default=Default,
hardware=Hardware, hardware=Hardware,
interfaces=Interfaces, interfaces=Interfaces,
config=Config, config=Config,
routing=Routing,
) )
VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) VALID_SUBSETS = frozenset(FACT_SUBSETS.keys())

View file

@ -0,0 +1,19 @@
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
0 ADC dst-address=10.10.66.0/30 pref-src=10.10.66.1 gateway=bridge1
gateway-status=bridge1 reachable distance=0 scope=10
routing-mark=altegro
2 A S dst-address=0.0.0.0/0 gateway=85.15.75.109
gateway-status=85.15.75.109 reachable via Internet-VTK distance=1
scope=30 target-scope=10
3 ADC dst-address=10.10.1.0/30 pref-src=10.10.1.1 gateway=GRE_TYRMA
gateway-status=GRE_TYRMA reachable distance=0 scope=10
4 DC dst-address=10.10.1.4/30 pref-src=10.10.1.5 gateway=RB2011
gateway-status=RB2011 unreachable distance=255 scope=10
5 ADC dst-address=10.10.2.0/30 pref-src=10.10.2.1 gateway=VLAN_SAT.ROUTER
gateway-status=VLAN_SAT.ROUTER reachable distance=0 scope=10

View file

@ -0,0 +1,10 @@
Flags: * - default, X - disabled
0 *X name="default" as=65530 router-id=0.0.0.0 redistribute-connected=no
redistribute-static=no redistribute-rip=no redistribute-ospf=no
redistribute-other-bgp=no out-filter="" client-to-client-reflection=yes
ignore-as-path-len=no routing-table=""
1 name="MAIN_AS_STARKDV" as=64520 router-id=10.10.50.1
redistribute-connected=no redistribute-static=no redistribute-rip=no
redistribute-ospf=no redistribute-other-bgp=no out-filter=""
client-to-client-reflection=yes ignore-as-path-len=no routing-table=""

View file

@ -0,0 +1,13 @@
Flags: X - disabled, E - established
0 E name="iBGP_BRAS.TYRMA" instance=MAIN_AS_STARKDV remote-address=10.10.100.1
remote-as=64520 tcp-md5-key="" nexthop-choice=default multihop=no
route-reflect=yes hold-time=3m ttl=default in-filter="" out-filter=""
address-families=ip,l2vpn,vpnv4 update-source=LAN_KHV
default-originate=never remove-private-as=no as-override=no passive=no
use-bfd=yes
1 E name="iBGP_BRAS_SAT" instance=MAIN_AS_STARKDV remote-address=10.10.50.230
remote-as=64520 tcp-md5-key="" nexthop-choice=default multihop=no
route-reflect=yes hold-time=3m ttl=default in-filter="" out-filter=""
address-families=ip default-originate=never remove-private-as=no
as-override=no passive=no use-bfd=yes

View file

@ -0,0 +1,7 @@
Flags: L - label-present
0 L route-distinguisher=64520:666 dst-address=10.10.66.8/30 gateway=10.10.100.1
interface=GRE_TYRMA in-label=6136 out-label=6136 bgp-local-pref=100
bgp-origin=incomplete bgp-ext-communities="RT:64520:666"
1 L route-distinguisher=64520:666 dst-address=10.10.66.0/30 interface=bridge1
in-label=1790 bgp-ext-communities="RT:64520:666"

View file

@ -0,0 +1,10 @@
Flags: X - disabled, * - default
0 * name="default" router-id=10.10.50.1 distribute-default=never redistribute-connected=no
redistribute-static=no redistribute-rip=no redistribute-bgp=no redistribute-other-ospf=no
metric-default=1 metric-connected=20 metric-static=20 metric-rip=20 metric-bgp=auto
metric-other-ospf=auto in-filter=ospf-in out-filter=ospf-out
1 name="OSPF_ALTEGRO" router-id=10.10.66.1 distribute-default=never redistribute-connected=no
redistribute-static=no redistribute-rip=no redistribute-bgp=no redistribute-other-ospf=no
metric-default=1 metric-connected=20 metric-static=20 metric-rip=20 metric-bgp=auto
metric-other-ospf=auto in-filter=ospf-in out-filter=ospf-out routing-table=altegro

View file

@ -0,0 +1,3 @@
0 instance=default router-id=10.10.100.1 address=10.10.1.2 interface=GRE_TYRMA priority=1
dr-address=0.0.0.0 backup-dr-address=0.0.0.0 state="Full" state-changes=15 ls-retransmits=0
ls-requests=0 db-summaries=0 adjacency=6h8m46s

View file

@ -64,6 +64,12 @@ class TestRouterosFactsModule(TestRouterosModule):
self.assertEqual( self.assertEqual(
result['ansible_facts']['ansible_net_serialnum'], '1234567890' result['ansible_facts']['ansible_net_serialnum'], '1234567890'
) )
self.assertEqual(
result['ansible_facts']['ansible_net_arch'], 'x86'
)
self.assertEqual(
result['ansible_facts']['ansible_net_uptime'], '3h28m52s'
)
def test_facts_hardware(self): def test_facts_hardware(self):
set_module_args(dict(gather_subset='hardware')) set_module_args(dict(gather_subset='hardware'))
@ -117,3 +123,220 @@ class TestRouterosFactsModule(TestRouterosModule):
result = interfaces.populate_addresses(data=addresses, family='ipv6') result = interfaces.populate_addresses(data=addresses, family='ipv6')
self.assertEqual(result, None) self.assertEqual(result, None)
def test_facts_routing(self):
set_module_args(dict(gather_subset='routing'))
result = self.execute_module()
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['name'], ['iBGP_BRAS.TYRMA']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['instance'], ['MAIN_AS_STARKDV']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remote-address'], ['10.10.100.1']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remote-as'], ['64520']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['nexthop-choice'], ['default']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['multihop'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['route-reflect'], ['yes']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['hold-time'], ['3m']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['ttl'], ['default']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['address-families'], ['ip']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['update-source'], ['LAN_KHV']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['default-originate'], ['never']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['remove-private-as'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['as-override'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['passive'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_peer']['iBGP_BRAS.TYRMA']['use-bfd'], ['yes']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['route-distinguisher'], ['64520:666']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['dst-address'], ['10.10.66.8/30']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['gateway'], ['10.10.100.1']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['interface'], ['GRE_TYRMA']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['in-label'], ['6136']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['out-label'], ['6136']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-local-pref'], ['100']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-origin'], ['incomplete']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_vpnv4_route']['GRE_TYRMA']['bgp-ext-communities'], ['RT:64520:666']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['name'], ['default']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['as'], ['65530']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['router-id'], ['0.0.0.0']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-connected'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-static'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-rip'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-ospf'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['redistribute-other-bgp'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['client-to-client-reflection'], ['yes']
)
self.assertIn(
result['ansible_facts']['ansible_net_bgp_instance']['default']['ignore-as-path-len'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['dst-address'], ['10.10.66.0/30']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['pref-src'], ['10.10.66.1']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['gateway'], ['bridge1']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['gateway-status'], ['bridge1']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['distance'], ['0']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['scope'], ['10']
)
self.assertIn(
result['ansible_facts']['ansible_net_route']['altegro']['routing-mark'], ['altegro']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['name'], ['default']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['router-id'], ['10.10.50.1']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['distribute-default'], ['never']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-connected'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-static'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-rip'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-bgp'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['redistribute-other-ospf'], ['no']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-default'], ['1']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-connected'], ['20']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-static'], ['20']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-rip'], ['20']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-bgp'], ['auto']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['metric-other-ospf'], ['auto']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['in-filter'], ['ospf-in']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_instance']['default']['out-filter'], ['ospf-out']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['instance'], ['default']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['router-id'], ['10.10.100.1']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['address'], ['10.10.1.2']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['interface'], ['GRE_TYRMA']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['priority'], ['1']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['dr-address'], ['0.0.0.0']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['backup-dr-address'], ['0.0.0.0']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['state'], ['Full']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['state-changes'], ['15']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['ls-retransmits'], ['0']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['ls-requests'], ['0']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['db-summaries'], ['0']
)
self.assertIn(
result['ansible_facts']['ansible_net_ospf_neighbor']['default']['adjacency'], ['6h8m46s']
)