Skip to content

Commit 7299b0f

Browse files
committed
Initial commit with Kevins demos
1 parent 19b8e05 commit 7299b0f

30 files changed

+1203
-3
lines changed

README.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
1-
# genie_solutions
2-
Genie Solution
1+
# pyATS and Genie Solutions examples
32

4-
Collection of Genie solutions which are ready to use to solve real life problems.
3+
This repository contains several scripts for network health checking using the
4+
[pyATS Framework](https://developer.cisco.com/site/pyats/)
55

6+
These are intended be examples/starting points for solving common network operations
7+
challenges.
68

9+
10+
# Installation / configuration
11+
12+
##### Installation
13+
```
14+
git clone https://github.com/kecorbin/pyats-network-checks
15+
cd pyats-network-checks
16+
python3 -m venv venv
17+
source venv/bin/activate
18+
pip install -r requirements.txt
19+
```
20+
21+
You can visit our [documentation](https://pubhub.devnetcloud.com/media/pyats-packages/docs/genie/cookbooks/genie.html#how-to-install-genie) for more information.
22+
23+
##### Simulation
24+
25+
We've provided a [topology.virl](./topology.virl) file for you to test with.
26+
27+
##### Testbed configuration
28+
29+
We've provided a [default_testbed.yaml](./testedbed.yaml) to go along with the
30+
sample topology. you'll likely need to change it to match your devices
31+
32+
# checks
33+
34+
* #### [bgp_adjacencies](./bgp_adjacencies) - "if a neighbor is configured, it should be established"
35+
36+
* #### [crc_errors](./crc_errors) - "No interface should be accumulating CRC errors"
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/bin/env python
2+
3+
# To get a logger for the script
4+
import logging
5+
import json
6+
# To build the table at the end
7+
from tabulate import tabulate
8+
9+
# Needed for aetest script
10+
from ats import aetest
11+
from ats.log.utils import banner
12+
13+
# Genie Imports
14+
from genie.conf import Genie
15+
from genie.abstract import Lookup
16+
17+
# import the genie libs
18+
from genie.libs import ops # noqa
19+
20+
# Get your logger for your script
21+
log = logging.getLogger(__name__)
22+
23+
24+
###################################################################
25+
# COMMON SETUP SECTION #
26+
###################################################################
27+
28+
class common_setup(aetest.CommonSetup):
29+
""" Common Setup section """
30+
31+
# CommonSetup have subsection.
32+
# You can have 1 to as many subsection as wanted
33+
34+
# Connect to each device in the testbed
35+
@aetest.subsection
36+
def connect(self, testbed):
37+
genie_testbed = Genie.init(testbed)
38+
self.parent.parameters['testbed'] = genie_testbed
39+
device_list = []
40+
for device in genie_testbed.devices.values():
41+
log.info(banner(
42+
"Connect to device '{d}'".format(d=device.name)))
43+
try:
44+
device.connect()
45+
except Exception as e:
46+
self.failed("Failed to establish connection to '{}'".format(
47+
device.name))
48+
49+
device_list.append(device)
50+
51+
# Pass list of devices the to testcases
52+
self.parent.parameters.update(dev=device_list)
53+
54+
55+
###################################################################
56+
# TESTCASES SECTION #
57+
###################################################################
58+
59+
60+
class BGP_Neighbors_Established(aetest.Testcase):
61+
""" This is user Testcases section """
62+
63+
# First test section
64+
@ aetest.test
65+
def learn_bgp(self):
66+
""" Sample test section. Only print """
67+
68+
self.all_bgp_sessions = {}
69+
for dev in self.parent.parameters['dev']:
70+
log.info(banner("Gathering BGP Information from {}".format(
71+
dev.name)))
72+
abstract = Lookup.from_device(dev)
73+
bgp = abstract.ops.bgp.bgp.Bgp(dev)
74+
bgp.learn()
75+
self.all_bgp_sessions[dev.name] = bgp.info
76+
77+
@ aetest.test
78+
def check_bgp(self):
79+
""" Sample test section. Only print """
80+
81+
failed_dict = {}
82+
mega_tabular = []
83+
for device, bgp in self.all_bgp_sessions.items():
84+
# may need to change based on BGP config
85+
default = bgp['instance']['default']['vrf']['default']
86+
neighbors = default['neighbor']
87+
for nbr, props in neighbors.items():
88+
state = props.get('session_state')
89+
if state:
90+
tr = []
91+
tr.append(device)
92+
tr.append(nbr)
93+
tr.append(state)
94+
if state == 'established':
95+
tr.append('Passed')
96+
else:
97+
failed_dict[device] = {}
98+
failed_dict[device][nbr] = props
99+
tr.append('Failed')
100+
101+
mega_tabular.append(tr)
102+
103+
log.info(tabulate(mega_tabular,
104+
headers=['Device', 'Peer',
105+
'State', 'Pass/Fail'],
106+
tablefmt='orgtbl'))
107+
108+
if failed_dict:
109+
log.error(json.dumps(failed_dict, indent=3))
110+
self.failed("Testbed has BGP Neighbors that are not established")
111+
112+
else:
113+
self.passed("All BGP Neighbors are established")
114+
115+
# #####################################################################
116+
# #### COMMON CLEANUP SECTION ###
117+
# #####################################################################
118+
119+
120+
# This is how to create a CommonCleanup
121+
# You can have 0 , or 1 CommonCleanup.
122+
# CommonCleanup can be named whatever you want :)
123+
class common_cleanup(aetest.CommonCleanup):
124+
""" Common Cleanup for Sample Test """
125+
126+
# CommonCleanup follow exactly the same rule as CommonSetup regarding
127+
# subsection
128+
# You can have 1 to as many subsections as wanted
129+
# here is an example of 1 subsection
130+
131+
@aetest.subsection
132+
def clean_everything(self):
133+
""" Common Cleanup Subsection """
134+
log.info("Aetest Common Cleanup ")
135+
136+
137+
if __name__ == '__main__': # pragma: no cover
138+
aetest.main()

bgp_adjacencies/BGP_check_job.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# To run the job:
2+
# easypy CRC_check_job.py -testbed_file <testbed_file.yaml>
3+
# Description: This job file shows the Genie CRC Interface Checker
4+
import os
5+
from ats.easypy import run
6+
7+
8+
# All run() must be inside a main function
9+
def main():
10+
# Find the location of the script in relation to the job file
11+
bgp_tests = os.path.join('./BGP_Neighbors_Established.py')
12+
# Execute the testscript
13+
# run(testscript=testscript)
14+
run(testscript=bgp_tests)

bgp_adjacencies/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Overview
2+
3+
This check connects to all devices defined in the testbed, and parses BGP operational data. The test passes if all BGP neighbors found are in the `established` state.
4+
5+
# Running
6+
7+
```
8+
easypy BGP_check_job.py -html_logs -testbed_file ../default_testbed.yaml
9+
```

bgp_adjacencies/bgp_check.robot

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Execute a Test Case from Robot
2+
# ================================================
3+
4+
*** Settings ***
5+
Library ats.robot.pyATSRobot
6+
7+
*** TestCases ***
8+
9+
Initialize
10+
# select the testbed to use
11+
use testbed "${testbed}"
12+
run testcase "BGP_Neighbors_Established.common_setup"
13+
14+
15+
Verify all BGP Neighbors are established
16+
run testcase "BGP_Neighbors_Established.BGP_Neighbors_Established"

crc_errors/CRC_Count_check.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/bin/env python
2+
3+
# To get a logger for the script
4+
import logging
5+
6+
# To build the table at the end
7+
from tabulate import tabulate
8+
9+
# Needed for aetest script
10+
from ats import aetest
11+
from ats.log.utils import banner
12+
13+
# Genie Imports
14+
from genie.conf import Genie
15+
from genie.abstract import Lookup
16+
17+
# import the genie libs
18+
from genie.libs import ops # noqa
19+
20+
# Get your logger for your script
21+
log = logging.getLogger(__name__)
22+
23+
24+
###################################################################
25+
# COMMON SETUP SECTION #
26+
###################################################################
27+
28+
class common_setup(aetest.CommonSetup):
29+
""" Common Setup section """
30+
31+
# CommonSetup have subsection.
32+
# You can have 1 to as many subsection as wanted
33+
34+
# Connect to each device in the testbed
35+
@aetest.subsection
36+
def connect(self, testbed):
37+
genie_testbed = Genie.init(testbed)
38+
self.parent.parameters['testbed'] = genie_testbed
39+
device_list = []
40+
for device in genie_testbed.devices.values():
41+
log.info(banner(
42+
"Connect to device '{d}'".format(d=device.name)))
43+
try:
44+
device.connect()
45+
except Exception as e:
46+
self.failed("Failed to establish connection to '{}'".format(
47+
device.name))
48+
49+
device_list.append(device)
50+
51+
# Pass list of devices the to testcases
52+
self.parent.parameters.update(dev=device_list)
53+
54+
55+
###################################################################
56+
# TESTCASES SECTION #
57+
###################################################################
58+
59+
# Testcase name : vxlan_consistency_check
60+
class CRC_count_check(aetest.Testcase):
61+
""" This is user Testcases section """
62+
63+
# First test section
64+
@ aetest.test
65+
def learn_interfaces(self):
66+
""" Sample test section. Only print """
67+
68+
self.all_interfaces = {}
69+
for dev in self.parent.parameters['dev']:
70+
log.info(banner("Gathering Interface Information from {}".format(
71+
dev.name)))
72+
abstract = Lookup.from_device(dev)
73+
intf = abstract.ops.interface.interface.Interface(dev)
74+
intf.learn()
75+
self.all_interfaces[dev.name] = intf.info
76+
77+
# Second test section
78+
@ aetest.test
79+
def check_CRC(self):
80+
81+
mega_dict = {}
82+
mega_tabular = []
83+
for device, ints in self.all_interfaces.items():
84+
mega_dict[device] = {}
85+
for name, props in ints.items():
86+
counters = props.get('counters')
87+
if counters:
88+
smaller_tabular = []
89+
if 'in_crc_errors' in counters:
90+
mega_dict[device][name] = counters['in_crc_errors']
91+
smaller_tabular.append(device)
92+
smaller_tabular.append(name)
93+
smaller_tabular.append(str(counters['in_crc_errors']))
94+
if counters['in_crc_errors']:
95+
smaller_tabular.append('Failed')
96+
else:
97+
smaller_tabular.append('Passed')
98+
else:
99+
mega_dict[device][name] = None
100+
smaller_tabular.append(device)
101+
smaller_tabular.append(name)
102+
smaller_tabular.append('N/A')
103+
smaller_tabular.append('N/A')
104+
mega_tabular.append(smaller_tabular)
105+
106+
mega_tabular.append(['-'*sum(len(i) for i in smaller_tabular)])
107+
108+
log.info(tabulate(mega_tabular,
109+
headers=['Device', 'Interface',
110+
'CRC Errors Counter',
111+
'Passed/Failed'],
112+
tablefmt='orgtbl'))
113+
114+
for dev in mega_dict:
115+
for intf in mega_dict[dev]:
116+
if mega_dict[dev][intf]:
117+
self.failed("{d}: {name} CRC ERRORS: {e}".format(
118+
d=dev, name=intf, e=mega_dict[dev][intf]))
119+
120+
self.passed("All devices' interfaces CRC ERRORS Count is: 'Zero'")
121+
122+
# #####################################################################
123+
# #### COMMON CLEANUP SECTION ###
124+
# #####################################################################
125+
126+
127+
# This is how to create a CommonCleanup
128+
# You can have 0 , or 1 CommonCleanup.
129+
# CommonCleanup can be named whatever you want :)
130+
class common_cleanup(aetest.CommonCleanup):
131+
""" Common Cleanup for Sample Test """
132+
133+
# CommonCleanup follow exactly the same rule as CommonSetup regarding
134+
# subsection
135+
# You can have 1 to as many subsections as wanted
136+
# here is an example of 1 subsection
137+
138+
@aetest.subsection
139+
def clean_everything(self):
140+
""" Common Cleanup Subsection """
141+
log.info("Aetest Common Cleanup ")
142+
143+
144+
if __name__ == '__main__': # pragma: no cover
145+
aetest.main()

crc_errors/CRC_check_job.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# To run the job:
2+
# easypy CRC_check_job.py -testbed_file <testbed_file.yaml>
3+
# Description: This job file shows the Genie CRC Interface Checker
4+
import os
5+
from ats.easypy import run
6+
7+
8+
# All run() must be inside a main function
9+
def main():
10+
# Find the location of the script in relation to the job file
11+
testscript = os.path.join('./CRC_Count_check.py')
12+
run(testscript=testscript)

crc_errors/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Overview
2+
3+
This check connects to all devices defined in the testbed, and parses are interface counters
4+
if an interface has CRC errors, the test case fails.
5+
6+
# Running
7+
8+
```
9+
easypy CRC_check_job.py -html_logs -testbed_file ../default_testbed.yaml
10+
```
3.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)