Skip to content

Commit ec91524

Browse files
committedFeb 13, 2020
modernization
1 parent 0eb664d commit ec91524

24 files changed

+396
-379
lines changed
 

‎.gitignore

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
*.egg-info/
24+
.installed.cfg
25+
*.egg
26+
MANIFEST
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*.cover
47+
.hypothesis/
48+
.pytest_cache/
49+
50+
# Translations
51+
*.mo
52+
*.pot
53+
54+
# Django stuff:
55+
*.log
56+
local_settings.py
57+
db.sqlite3
58+
59+
# Flask stuff:
60+
instance/
61+
.webassets-cache
62+
63+
# Scrapy stuff:
64+
.scrapy
65+
66+
# Sphinx documentation
67+
docs/_build/
68+
69+
# PyBuilder
70+
target/
71+
72+
# Jupyter Notebook
73+
.ipynb_checkpoints
74+
75+
# pyenv
76+
.python-version
77+
78+
# celery beat schedule file
79+
celerybeat-schedule
80+
81+
# SageMath parsed files
82+
*.sage.py
83+
84+
# Environments
85+
.env
86+
.venv
87+
env/
88+
venv/
89+
ENV/
90+
env.bak/
91+
venv.bak/
92+
93+
# Spyder project settings
94+
.spyderproject
95+
.spyproject
96+
97+
# Rope project settings
98+
.ropeproject
99+
100+
# mkdocs documentation
101+
/site
102+
103+
# mypy
104+
.mypy_cache/

‎NOTICE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
Copyright (c) 2019 Cisco Systems, Inc. and/or its affiliates
1+
Copyright (c) 2020 Cisco Systems, Inc. and/or its affiliates
22

33
This project includes software developed at Cisco Systems, Inc. and/or its affiliates.

‎README.md

+34-18
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,56 @@
11
[![published](https://static.production.devnetcloud.com/codeexchange/assets/images/devnet-published.svg)](https://developer.cisco.com/codeexchange/github/repo/CiscoTestAutomation/solutions_examples)
22

3-
# pyATS and Genie Solutions examples
3+
# pyATS Solutions Examples
44

5-
This repository contains several scripts for network health checking using the
6-
[pyATS Framework](https://developer.cisco.com/site/pyats/)
5+
This repository contains several NetDevOps scripts build by our user community
6+
using [pyATS Framework](https://developer.cisco.com/pyats/)
77

8-
These are intended be examples/starting points for solving common network operations
9-
challenges.
8+
## Contributions
109

10+
Everyone is welcome to leverage these scripts as starting points on solving
11+
common network operations challenges.
1112

12-
# Installation / configuration
13+
If you have additional thoughts, ideas, or samples you'd like to contribute,
14+
feel free to open a PR and become a member of the development community!
1315

14-
##### Installation
15-
```
16-
git clone https://github.com/CiscoTestAutomation/solutions_examples.git
16+
## Installation
17+
18+
```bash
19+
# first, ensure you have a pyATS virtual environment
20+
# eg:
21+
mkdir -p ~/workspace/pyats
22+
cd ~/workspace/pyats
23+
python3 -m venv .
24+
source bin/activate
25+
pip install --upgrade pip setuptools
26+
pip install pyats[full]
27+
28+
# now, clone this repository
29+
git clone https://github.com/CiscoTestAutomation/solutions_examples
1730
cd solutions_examples
18-
python3 -m venv venv
19-
source venv/bin/activate
31+
32+
# install the common dependencies
2033
pip install -r requirements.txt
34+
35+
# you're good to go!
2136
```
2237

23-
You can visit our [documentation](https://pubhub.devnetcloud.com/media/pyats-packages/docs/genie/cookbooks/genie.html#how-to-install-genie) for more information.
38+
You can visit our [documentation](https://developer.cisco.com/docs/pyats/) for more information.
2439

25-
##### Simulation
40+
## VIRL Simulation
2641

2742
We've provided a [topology.virl](./topology.virl) file for you to test with.
2843

29-
##### Testbed configuration
44+
## Testbed configuration
3045

3146
We've provided a [default_testbed.yaml](./testedbed.yaml) to go along with the
3247
sample topology. you'll likely need to change it to match your devices
3348

34-
# checks
49+
## Notable Examples
50+
51+
* [bgp_adjacencies](./bgp_adjacencies) - "if a neighbor is configured, it should be established"
3552

36-
* #### [bgp_adjacencies](./bgp_adjacencies) - "if a neighbor is configured, it should be established"
53+
* [crc_errors](./crc_errors) - "No interface should be accumulating CRC errors"
3754

38-
* #### [crc_errors](./crc_errors) - "No interface should be accumulating CRC errors"
55+
* [hostname_checker](./hostname_checker) - "Verify devices hostname with Testbed file names"
3956

40-
* #### [hostname_checker](./hostname_checker) - "Verify devices hostname with Testbed file names"

‎bgp_adjacencies/BGP_Neighbors_Established.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from tabulate import tabulate
88

99
# Needed for aetest script
10-
from ats import aetest
11-
from ats.log.utils import banner
10+
from pyats import aetest
11+
from pyats.log.utils import banner
1212

1313
# Genie Imports
1414
from genie.conf import Genie

‎bgp_adjacencies/BGP_check_job.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
# pyats run job BGP_check_job.py --testbed-file <testbed_file.yaml>
33
# Description: This job file checks that all BGP neighbors are in Established state
44
import os
5-
from ats.easypy import run
6-
75

86
# All run() must be inside a main function
9-
def main():
7+
def main(runtime):
108
# Find the location of the script in relation to the job file
11-
bgp_tests = os.path.join('./BGP_Neighbors_Established.py')
9+
bgp_tests = os.path.join(os.path.dirname(__file__),
10+
'BGP_Neighbors_Established.py')
1211
# Execute the testscript
13-
# run(testscript=testscript)
14-
run(testscript=bgp_tests)
12+
runtime.tasks.run(testscript=bgp_tests)

‎bgp_adjacencies/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ This check connects to all devices defined in the testbed, and parses BGP operat
55
# Running
66

77
```
8-
easypy BGP_check_job.py -html_logs -testbed_file ../default_testbed.yaml
8+
pyats run job BGP_check_job.py --html-logs --testbed-file ../default_testbed.yaml
99
```

‎crc_errors/CRC_Count_check.py

-155
This file was deleted.

‎crc_errors/CRC_check_job.py

-12
This file was deleted.

‎crc_errors/README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
This check connects to all devices defined in the testbed, and parses are interface counters
44
if an interface has CRC errors, the test case fails.
55

6-
# Running
6+
## Running
77

88
```
9-
pyats run job CRC_check_job.py --testbed-file ../default_testbed.yaml
10-
```
11-
9+
# run with the provided devnet always-on sandbox
10+
pyats run job job.py --testbed-file ../default_testbed.yaml
1211
13-
# To use the Mock device
14-
pyats run job CRC_check_job.py --testbed-file ../default_testbed.yaml --replay mock
12+
# run with the provided mock devices (does not require real testbed)
13+
pyats run job job.py --testbed-file ../default_testbed.yaml --replay mock
14+
```
Binary file not shown.

‎crc_errors/job.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'''
2+
To run the job:
3+
4+
$ pyats run job job.py --testbed-file <testbed_file.yaml>
5+
6+
Additional CLI Arguments:
7+
--no-parallel-connect: disables parallel device connection
8+
--crc-threshold: max crc interface error before it's called to be a failure
9+
10+
Example:
11+
$ pyats run job job.py --testbed-file ../devnet_sandbox.yaml --crc-threshold 100 --no-parallel-connect
12+
'''
13+
14+
import os
15+
import argparse
16+
17+
# command line argument parser
18+
# see https://pubhub.devnetcloud.com/media/pyats/docs/easypy/jobfile.html#custom-arguments
19+
parser = argparse.ArgumentParser()
20+
parser.add_argument('--no-parallel-connect',
21+
dest = 'p_connect',
22+
action='store_false',
23+
default = True,
24+
help = 'disable connecting to devices in parallel')
25+
parser.add_argument('--crc-threshold',
26+
dest = 'crc_threshold',
27+
default = 0,
28+
type = int,
29+
help = 'threshold at which interface CRC will be considered'
30+
'fail')
31+
32+
def main(runtime):
33+
# parse command line arguments
34+
# only parse arguments we know
35+
args, _ = parser.parse_known_args()
36+
37+
# Find the location of the script in relation to the job file
38+
testscript = os.path.join(os.path.dirname(__file__), 'script.py')
39+
40+
# run script, pass arguments to script as parameters
41+
runtime.tasks.run(testscript=testscript,
42+
**vars(args))

‎crc_errors/script.py

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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 pyats import aetest
11+
from pyats.log.utils import banner
12+
13+
# Genie Imports
14+
from genie.testbed import load
15+
16+
# Get your logger for your script
17+
log = logging.getLogger(__name__)
18+
19+
###################################################################
20+
# COMMON SETUP SECTION #
21+
###################################################################
22+
23+
class common_setup(aetest.CommonSetup):
24+
""" Common Setup section """
25+
26+
# Connect to each device in the testbed
27+
@aetest.subsection
28+
def connect_to_devices(self, testbed, p_connect = True):
29+
30+
# convert from pyATS testbed to genie testbed
31+
# this step will be deprecated soon (and not required)
32+
testbed = self.parent.parameters['testbed'] = load(testbed)
33+
34+
# connect to all devices in testbed in parallel
35+
if p_connect:
36+
testbed.connect()
37+
else:
38+
for device in testbed:
39+
try:
40+
device.connect()
41+
except Exception:
42+
logger.exception('failed to connect to device %s'
43+
% device.name)
44+
45+
log.debug(self.parameters)
46+
47+
@aetest.subsection
48+
def prepare_testcases(self, testbed):
49+
'''
50+
creates a loop over the CRC_count_Check class using device name
51+
as the iterator
52+
'''
53+
# use device name as iterator for clarity in testcase name reporting
54+
aetest.loop.mark(CRC_Count_Check,
55+
device = [d.name for d in testbed])
56+
57+
###################################################################
58+
# TESTCASES SECTION #
59+
###################################################################
60+
class CRC_Count_Check(aetest.Testcase):
61+
'''
62+
Capture Interfaces statistics on the device and tabulate
63+
Also look for CRC Errors. If CRC error exceeds threshold, fail
64+
'''
65+
66+
@aetest.setup
67+
def setup(self, device, testbed):
68+
'''
69+
parameters
70+
----------
71+
device: current device to check crc for (assigned by loop)
72+
testbed: testbed object
73+
'''
74+
75+
log.info(banner("Gathering Interface Information from %s"
76+
% device))
77+
78+
# get device by name (device is a hostname from our loop assignment)
79+
device = testbed.devices[device]
80+
81+
if device.connected:
82+
self.interface_info = device.learn('interface')
83+
else:
84+
self.failed('Cannot learn %s interface information: '
85+
'did not establish connectivity to device'
86+
% device.name)
87+
88+
@aetest.test
89+
def interface_crc_counter_summary(self, device, crc_threshold = 0):
90+
'''
91+
creates and displays the CRC summary table for this device
92+
93+
parameters
94+
----------
95+
device: current device to check crc for (assigned by loop)
96+
crc_threshold: max crc threshold before interface check fails
97+
'''
98+
99+
table_data = []
100+
self.failed_interfaces = {}
101+
102+
for intf, data in self.interface_info.info.items():
103+
counters = data.get('counters')
104+
if counters:
105+
table_row = []
106+
if 'in_crc_errors' in counters:
107+
table_row.append(device)
108+
table_row.append(intf)
109+
table_row.append(str(counters['in_crc_errors']))
110+
if counters['in_crc_errors'] > crc_threshold:
111+
table_row.append('Failed')
112+
self.failed_interfaces[intf] = counters['in_crc_errors']
113+
else:
114+
table_row.append('Passed')
115+
116+
else:
117+
table_row.append(device)
118+
table_row.append(intf)
119+
table_row.append('N/A')
120+
table_row.append('N/A')
121+
table_data.append(table_row)
122+
123+
# display the table
124+
log.info(tabulate(table_data,
125+
headers=['Device', 'Interface',
126+
'CRC Errors Counter',
127+
'Passed/Failed'],
128+
tablefmt='orgtbl'))
129+
130+
131+
# should we pass or fail?
132+
if self.failed_interfaces:
133+
# loop the next test on all interfaces that fail the check
134+
aetest.loop.mark(self.interface_check,
135+
name = self.failed_interfaces.keys())
136+
self.failed('Some interfaces have CRC errors')
137+
else:
138+
# skip the check interface test
139+
# this is a bug current in v20.1 pyats.aetest, pending fix
140+
# aetest.skip.affix(self.interface_check, 'no interface crc errors')
141+
self.passed('No interfaces have CRC errors')
142+
143+
@aetest.test
144+
def interface_check(self, name = None, crc_threshold = 0):
145+
# This test has been marked for loop. intf is the looping argument
146+
# this test will ONLY run if interfaces has errors
147+
148+
# workaround for bug in pyATS v20.1 on skip.affix - using intf check
149+
if name is None:
150+
self.skipped('no interface crc errors')
151+
else:
152+
self.failed('Interface %s has crc errors %s (threshold %s)'
153+
% (name, self.failed_interfaces[name], crc_threshold))
154+
155+
if __name__ == '__main__': # pragma: no cover
156+
aetest.main()

‎devnet_sandbox.yaml

+8-24
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,34 @@
11
testbed:
2-
32
name: devnet_always_on_sandbox
43

54

65
devices:
7-
86
csr1000v:
9-
alias: csr1000v
107
os: iosxe
11-
type: CSR1000v
12-
tacacs:
8+
type: router
9+
credentials:
10+
default:
1311
username: root
14-
passwords:
15-
tacacs: D_Vay!_10&
16-
12+
password: D_Vay!_10&
1713
connections:
18-
defaults:
19-
class: unicon.Unicon
2014
console:
2115
ip: ios-xe-mgmt.cisco.com
2216
protocol: ssh
2317
port: 8181
24-
custom:
25-
abstraction:
26-
order: [os, type]
2718

2819
sbx-n9kv-ao:
2920
alias: nxos
3021
os: nxos
31-
type: Nexus9000v
32-
tacacs:
22+
type: switch
23+
credentials:
24+
default:
3325
username: admin
34-
passwords:
35-
tacacs: Admin_1234!
36-
26+
password: Admin_1234!
3727
connections:
38-
defaults:
39-
class: unicon.Unicon
4028
console:
4129
ip: sbx-nxos-mgmt.cisco.com
4230
protocol: ssh
4331
port: 8181
44-
custom:
45-
abstraction:
46-
order: [os, type]
47-
4832

4933
topology:
5034
csr1000v:

‎local_users/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ users are configured on the device.
77
# Running
88

99
```
10-
easypy local_user_check_job.py -html_logs -testbed_file ../default_testbed.yaml --local_users cisco admin
10+
pyats run job local_user_check_job.py --html-logs--testbed-file ../default_testbed.yaml --local_users cisco admin
1111
```

‎local_users/local_user_check.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/env python
22
import logging
3-
from ats import aetest
4-
from ats.log.utils import banner
3+
from pyats import aetest
4+
from pyats.log.utils import banner
55
from genie.conf import Genie
66
from genie.libs import ops # noqa
77

‎local_users/local_user_check_job.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
# To run the job:
2-
# easypy local_user_check_job.py -testbed_file <testbed_file.yaml> --local_users cisco admin
2+
# pyats run job local_user_check_job.py --testbed-file <testbed_file.yaml> --local_users cisco admin
33
# Description: This job file checks for the existence of known local users
44
import os
5-
from ats.easypy import run
65
import argparse
7-
from ats.datastructures.logic import Or
6+
from pyats.datastructures.logic import Or
87

98

109
# All run() must be inside a main function
11-
def main():
10+
def main(runtime):
1211
parser = argparse.ArgumentParser()
1312
parser.add_argument('--local_users',
1413
dest='expected_local_users',
1514
nargs='+',
1615
default=['cisco'])
1716
args, unknown = parser.parse_known_args()
1817
# Find the location of the script in relation to the job file
19-
local_user_check = os.path.join('./local_user_check.py')
18+
local_user_check = os.path.join(os.path.dirname(__file__), 'local_user_check.py')
2019
# Execute the testscript
21-
run(testscript=local_user_check, taskid="Local User Check", **vars(args),
22-
groups=Or('golden_config', 'bar'))
20+
runtime.tasks.run(testscript=local_user_check,
21+
taskid="Local User Check",
22+
**vars(args),
23+
groups=Or('golden_config', 'bar'))

‎mobile_app/android_job.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
2-
from pyats.easypy import run
3-
def main():
2+
def main(runtime):
43
test_path = os.path.dirname(os.path.abspath(__file__))
54
testscript = os.path.join(test_path, 'pyats_android.py')
6-
run(testscript=testscript)
5+
runtime.tasks.run(testscript=testscript)

‎netchaos/README.md

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ Proof of concept Network Chaos Monkey using Cisco VIRL, pyATS, and Genie
44

55
> Author: Kevin Corbin @kecorbin
66
7-
# Requirements
8-
9-
pyATS requires python3 make sure you've installed the requirements in your virtualenv
10-
11-
```
12-
pip install -r requirements.txt
13-
```
14-
157
# Configuration
168

179
you should only need to modify the [./mapping_datafile.yaml](./mapping_datafile.yaml) to
@@ -26,7 +18,7 @@ make chaos
2618

2719
# Wait not so fast....
2820

29-
If you're scared - maybe start out with a single [Trigger](https://pubhub.devnetcloud.com/media/pyats-packages/docs/genie/genie_libs/#/triggers)
21+
If you're scared - maybe start out with a single [Trigger](https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/)
3022

3123
```
3224
pyats run job network_chaos_monkey.py --testbed-file default_testbed.yaml --html-logs ./TriggerClearIpMroute.html --trigger TriggerClearIpMroute

‎netchaos/network_chaos_monkey.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from ats.datastructures.logic import And, Not, Or
2+
from pyats.datastructures.logic import And, Not, Or
33
from genie.harness.main import gRun
44
import argparse
55

‎netchaos/requirements.txt

-49
This file was deleted.

‎one_big_test_job.py

+18-17
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
# To run the job:
2-
# easypy one_big_test_job.py -testbed_file <testbed_file.yaml> --local_users cisco admin
2+
# pyats run job one_big_test_job.py --testbed-file <testbed_file.yaml> --local_users cisco admin
33

44
# Description: This job file runs multiple testcases from different files
55
# there are various ways and reasons to do so depending on use case
66

77
# For more information refer to the documentation here:
8-
# https://pubhub.devnetcloud.com/media/pyats/docs/aetest/structure.html
8+
# https://pubhub.devnetcloud.com/media/pyats/docs/easypy/jobfile.html#
99

10-
# or here
11-
# https://pubhub.devnetcloud.com/media/pyats/docs/easypy/jobfile.html
1210
import os
13-
from ats.easypy import run, Task
1411
import argparse
1512

13+
HERE = os.path.dirname(__name__)
1614

1715
# All run() must be inside a main function
1816
def main(runtime):
@@ -23,27 +21,30 @@ def main(runtime):
2321
default=['cisco'])
2422
args, unknown = parser.parse_known_args()
2523
# Find the location of the script in relation to the job file
26-
local_user_check = os.path.join('./local_users/local_user_check.py')
24+
local_user_check = os.path.join(HERE, 'local_users', 'local_user_check.py')
2725
# Execute the testscript as task
28-
task_1 = Task(testscript=local_user_check,
29-
runtime=runtime,
30-
taskid='Validate Locally Configured Usernames',
31-
**vars(args))
26+
task_1 = runtime.tasks.Task(testscript=local_user_check,
27+
runtime=runtime,
28+
taskid='Validate Locally Configured Usernames',
29+
**vars(args))
3230
task_1.start()
3331
# wait for a max runtime of 60*5 seconds = 5 minutes
3432
task_1.wait(60*5)
3533

3634
# add another task
37-
bgp_neighbors_check = os.path.join('./bgp_adjacencies/BGP_Neighbors_Established.py')
38-
task_2 = Task(testscript=bgp_neighbors_check,
39-
runtime=runtime,
40-
taskid='Verify BGP neighbors are established',
41-
**vars(args))
35+
bgp_neighbors_check = os.path.join(HERE, 'bgp_adjacencies',
36+
'BGP_Neighbors_Established.py')
37+
task_2 = runtime.tasks.Task(testscript=bgp_neighbors_check,
38+
runtime=runtime,
39+
taskid='Verify BGP neighbors are established',
40+
**vars(args))
4241

4342
task_2.start()
4443
task_2.wait(60*5)
4544

46-
crc_check = os.path.join('./crc_errors_CRC_Count_check.py')
45+
crc_check = os.path.join(HERE, 'crc_errors', 'script.py')
4746

4847
# or simply call run as many times as you'd like
49-
run(testscript=crc_check, taskid="Check all Interfaces for CRC errors", **vars(args))
48+
runtime.tasks.run(testscript=crc_check,
49+
taskid="Check all Interfaces for CRC errors",
50+
**vars(args))

‎profile_custom/Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
before:
2-
-easypy network_ops_profile.py -html_logs . -testbed_file ../default_testbed.yaml
2+
-pyats run job network_ops_profile.py --html-logs. --testbed-file ../default_testbed.yaml
33
-open TaskLog.html
44
after:
5-
-easypy network_ops_profile.py -html_logs . -testbed_file ../default_testbed.yaml --after
5+
-pyats run job network_ops_profile.py --html-logs. --testbed-file ../default_testbed.yaml --after
66
-open TaskLog.html
77

88
clean:

‎profile_custom/snapshot.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ if [ "$#" -ne 1 ]; then
44
exit
55
fi
66
rm -rf archive/ runinfo/
7-
easypy network_ops_profile.py -html_logs . -testbed_file ../default_testbed.yaml
7+
pyats run job network_ops_profile.py --html-logs. --testbed-file ../default_testbed.yaml
88
ARCHIVE_FILE=`find . -name network_ops_profile*.zip`
99
echo $ARCHIVE_FILE
1010
mkdir -p snapshots

‎requirements.txt

+2-62
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,2 @@
1-
asn1crypto==0.24.0
2-
asyncssh==1.15.1
3-
certifi==2018.11.29
4-
cffi==1.11.5
5-
chardet==3.0.4
6-
cryptography==2.5
7-
dill==0.2.9
8-
genie
9-
genie.abstract
10-
genie.conf
11-
genie.examples
12-
genie.harness
13-
genie.libs.conf
14-
genie.libs.filetransferutils
15-
genie.libs.ops
16-
genie.libs.parser
17-
genie.libs.robot
18-
genie.libs.sdk
19-
genie.libs.telemetry
20-
genie.metaparser
21-
genie.ops
22-
genie.parsergen
23-
genie.predcore
24-
genie.telemetry
25-
genie.utils
26-
idna==2.8
27-
Jinja2==2.10
28-
jsonpickle==1.1
29-
junit-xml==1.8
30-
MarkupSafe==1.1.0
31-
netaddr==0.7.19
32-
pathspec==0.5.9
33-
prettytable==0.7.2
34-
psutil==5.5.0
35-
pyats
36-
pyats.aereport
37-
pyats.aetest
38-
pyats.async
39-
pyats.connections
40-
pyats.datastructures
41-
pyats.easypy
42-
pyats.examples
43-
pyats.kleenex
44-
pyats.log
45-
pyats.results
46-
pyats.robot
47-
pyats.tcl
48-
pyats.templates
49-
pyats.topology
50-
pyats.utils
51-
pycparser==2.19
52-
PyYAML==3.13
53-
requests==2.21.0
54-
robotframework==3.1.1
55-
setproctitle==1.1.10
56-
six==1.12.0
57-
tabulate==0.8.3
58-
tqdm==4.30.0
59-
unicon==3.4.7
60-
urllib3==1.24.1
61-
xmltodict==0.11.0
62-
yamllint==1.14.0
1+
2+
tabulate>=0.8.3

0 commit comments

Comments
 (0)
Please sign in to comment.