├── .gitignore
├── .virlrc
├── LICENSE
├── README.md
├── Vagrantfile
├── config_mgmt
└── ansible
│ └── demo_setup
├── csv_config_gen
├── .gitignore
├── config_render_01.py
├── config_render_02.py
├── switch-ports.csv
└── switchport-interface-template.j2
├── data_manipulation
├── csv
│ ├── add_router.py
│ ├── csv_example.csv
│ └── csv_example.py
├── json
│ ├── json_example.json
│ └── json_example.py
├── xml
│ ├── xml_example.py
│ └── xml_example.xml
├── yaml
│ ├── yaml_example.py
│ └── yaml_example.yaml
└── yang
│ ├── cisco-xe-ietf-ip-deviation.yang
│ ├── ietf-inet-types.yang
│ ├── ietf-interfaces.yang
│ ├── ietf-ip.yang
│ ├── ietf-ipv4-unicast-routing.yang
│ ├── ietf-routing.yang
│ └── pyang-examples.sh
├── device_apis
├── cli
│ ├── netmiko_example1.py
│ ├── netmiko_example1a.py
│ ├── netmiko_example2.py
│ └── netmiko_example3.py
├── device_info.py
├── netconf
│ ├── netconf-ssh-example.md
│ ├── netconf_example1.py
│ ├── netconf_example1a.py
│ ├── netconf_example2.py
│ └── netconf_example3.py
├── rest
│ ├── restconf_example1.py
│ ├── restconf_example1a.py
│ ├── restconf_example2.py
│ └── restconf_example3.py
└── snmp
│ └── pysnmp_example1.py
├── lab.md
├── network_testing
└── pyats
│ ├── default_testbed.yaml
│ └── pyats-example1.py
├── python_code_tips
├── README.md
├── command_line_tool_example
│ └── argparse_example.py
├── exception_handling
│ ├── with_try.py
│ └── without_try.py
├── functions_example
│ ├── functions-after.py
│ └── functions-before.py
├── misc
│ └── example1.py
├── modules_example
│ ├── dnac_functions.py
│ ├── dnac_resources.py
│ ├── modules_after.py
│ └── modules_before.py
├── objects_example
│ ├── dnac
│ │ ├── DNAC.py
│ │ └── __init__.py
│ └── host_troubleshooting.py
└── packages_example
│ ├── dnac
│ ├── __init__.py
│ ├── dnac_functions.py
│ └── dnac_resources.py
│ └── host_troubleshooting.py
├── requirements-win.txt
├── requirements.txt
├── setup
├── ansible.cfg
├── configs
│ └── README.md
├── group_vars
│ ├── access.yaml
│ ├── all.yaml
│ ├── core.yaml
│ └── distribution.yaml
├── host_vars
│ ├── access1.yaml
│ ├── core1.yaml
│ ├── core2.yaml
│ ├── dist1.yaml
│ └── dist2.yaml
├── network_deploy.yaml
└── roles
│ ├── network_enable_api
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ ├── ios.yml
│ │ ├── main.yml
│ │ └── nxos.yml
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ ├── network_inspect
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ ├── ios.yml
│ │ ├── main.yml
│ │ └── nxos.yml
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ ├── network_interface
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ ├── hsrp_nxapi.yml
│ │ ├── l3_netconf.yml
│ │ ├── l3_nxapi.yml
│ │ ├── main.yml
│ │ └── portchannel_nxapi.yml
│ ├── templates
│ │ └── ietf_interface_template.j2
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ ├── network_ospf
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ ├── main.yml
│ │ ├── netconf.yml
│ │ └── nxapi.yml
│ ├── templates
│ │ ├── Cisco-IOS-XE_ospf.j2
│ │ └── ned_ospf.j2
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ ├── network_vlan
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ ├── main.yml
│ │ └── nxapi.yml
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ └── network_vpc
│ ├── README.md
│ ├── defaults
│ └── main.yml
│ ├── handlers
│ └── main.yml
│ ├── meta
│ └── main.yml
│ ├── tasks
│ ├── main.yml
│ └── nxapi.yml
│ ├── tests
│ ├── inventory
│ └── test.yml
│ └── vars
│ └── main.yml
├── topology.virl
├── vagrant_device_config.xml
└── vagrant_device_setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .virl/
2 | scratch*
3 | *.retry
4 | default_inventory.yaml
5 | .vagrant/
6 | setup/configs/*.xml
7 |
8 |
9 |
10 | # Byte-compiled / optimized / DLL files
11 | __pycache__/
12 | *.py[cod]
13 | *$py.class
14 |
15 | # C extensions
16 | *.so
17 |
18 | # Distribution / packaging
19 | .Python
20 | build/
21 | develop-eggs/
22 | dist/
23 | downloads/
24 | eggs/
25 | .eggs/
26 | lib/
27 | lib64/
28 | parts/
29 | sdist/
30 | var/
31 | wheels/
32 | *.egg-info/
33 | .installed.cfg
34 | *.egg
35 | MANIFEST
36 |
37 | # PyInstaller
38 | # Usually these files are written by a python script from a template
39 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
40 | *.manifest
41 | *.spec
42 |
43 | # Installer logs
44 | pip-log.txt
45 | pip-delete-this-directory.txt
46 |
47 | # Unit test / coverage reports
48 | htmlcov/
49 | .tox/
50 | .coverage
51 | .coverage.*
52 | .cache
53 | nosetests.xml
54 | coverage.xml
55 | *.cover
56 | .hypothesis/
57 | .pytest_cache/
58 |
59 | # Translations
60 | *.mo
61 | *.pot
62 |
63 | # Django stuff:
64 | *.log
65 | local_settings.py
66 | db.sqlite3
67 |
68 | # Flask stuff:
69 | instance/
70 | .webassets-cache
71 |
72 | # Scrapy stuff:
73 | .scrapy
74 |
75 | # Sphinx documentation
76 | docs/_build/
77 |
78 | # PyBuilder
79 | target/
80 |
81 | # Jupyter Notebook
82 | .ipynb_checkpoints
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # celery beat schedule file
88 | celerybeat-schedule
89 |
90 | # SageMath parsed files
91 | *.sage.py
92 |
93 | # Environments
94 | .env
95 | .venv
96 | env/
97 | venv/
98 | ENV/
99 | env.bak/
100 | venv.bak/
101 |
102 | # Spyder project settings
103 | .spyderproject
104 | .spyproject
105 |
106 | # Rope project settings
107 | .ropeproject
108 |
109 | # mkdocs documentation
110 | /site
111 |
112 | # mypy
113 | .mypy_cache/
114 |
--------------------------------------------------------------------------------
/.virlrc:
--------------------------------------------------------------------------------
1 | VIRL_HOST=10.10.20.160
2 | VIRL_USERNAME=guest
3 | VIRL_PASSWORD=guest
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Hank Preston
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Useful Python Libraries for Network Engineers
2 | Collection of scripts and examples of Python code, libraries, and utilities for working with Network Devices.
3 |
4 | > The code in this repository is used in a demonstrations, talks, and labs as part of [Cisco DevNet](https://developer.cisco.com) and specifically [NetDevOps Live!](https://developer.cisco.com/netdevops/live).
5 |
6 | # Hands On Lab
7 | Included in this repo is a short hands on lab guide that walks through many of the libraries discussed and used through the examples. You can [view the lab guide here](lab.md).
8 |
9 | # Setting Up to Run Examples
10 | ## Clone and Prep the Environment
11 | 1. Clone the code repo
12 |
13 | ```bash
14 | git clone https://github.com/hpreston/python_networking
15 | cd python_networking
16 | ```
17 |
18 | 1. Setup Python Virtual Environment.
19 |
20 | ```bash
21 | # MacOS or Linux
22 | python3.6 -m venv venv
23 | source venv/bin/activate
24 | pip install -r requirements.txt
25 | ```
26 |
27 | * *Note: If on Linux, you will need to install the Python3.6 development files. On CentOS this is done with `yum install -y python36u-devel`*
28 |
29 | ```bash
30 | # Windows - recommendation to use git-bash terminal
31 | py -3 -m venv venv
32 | source venv/Scripts/activate
33 | pip install -r requirements-win.txt
34 | ```
35 |
36 | * *Note: Creation and activation of a venv in Windows is slightly different. Also Ansible and pyATS aren't currently supported on Windows so the `requirements-win.txt` doesn't contain those libraries.*
37 |
38 |
39 | ## Infrastructure Resources
40 | The example scripts for `data_manipulation` require nothing other than the files in this repository and the Python libraries installed with `pip install` above.
41 |
42 | The example scripts for `device_apis` & `network_testing` leverage DevNet Always On Sandboxes that are publicly available, with no VPN connection needed. The details for these infrastructure are included in the scripts.
43 |
44 | > There is also a `Vagrantfile` included in the repo that can be used to spin up a local IOS XE device to use for the API examples. You'll need to have Vagrant and a box already available. You can find details on obtaining and using Vagrant boxes for Cisco devices at [github.com/hpreston/vagrant_net_prog](https://github.com/hpreston/vagrant_net_prog). If you do do this, the following line would need to be changed in the code examples.
45 | >
46 | > `from device_info import ios_xe1 as device` -> `from device_info import vagrant_iosxe as device`
47 |
48 | ## Infrastructure for Configuration Management Demonstrations
49 | The configuration management scripts in this repository are written to target a sample network topology built as Core > Dist > Access with IOS XE devices in the Core, and NX-OS devices for Dist and Access. The demo network can be run with Cisco VIRL or CML, and the [`topology.virl`](topology.virl) file in the repo has the details. If you do not have your own VIRL server, you can reserve a free [DevNet Multi-IOS VIRL Sandbox](https://devnetsandbox.cisco.com/RM/Diagram/Index/6b023525-4e7f-4755-81ae-05ac500d464a?diagramType=Topology) to use.
50 |
51 | 1. After connecting to the Sandbox with VPN, start the development network. This single line command will start the simulation, wait to completely start, and then lay down an initial configuration with Ansible.
52 |
53 | ```bash
54 | virl up --provision \
55 | && virl generate ansible -o setup/default_inventory.yaml \
56 | && cd setup \
57 | && ansible-playbook network_deploy.yaml \
58 | && cd ../
59 | ```
60 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | Vagrant.configure("2") do |config|
5 |
6 | # Create IOS XE Node
7 | config.vm.define "iosxe1" do |node|
8 | node.vm.box = "iosxe/16.09.01"
9 |
10 | # nic_type: "virtio" needed for IOS XE 16.7+
11 | node.vm.network :private_network, virtualbox__intnet: "link1", auto_config: false, nic_type: "virtio"
12 | node.vm.network :private_network, virtualbox__intnet: "link2", auto_config: false, nic_type: "virtio"
13 |
14 | node.vm.network :forwarded_port, protocol: 'udp', guest: 161, host: 2227, id: 'snmp', auto_correct: true
15 |
16 | # Vagrant 2.1.0 or higher
17 | # node.trigger.after :up do |trigger|
18 | # trigger.info = "Running baseline script"
19 | # trigger.run = {path: "vagrant_device_setup.py"}
20 | # end
21 |
22 | end
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/config_mgmt/ansible/demo_setup:
--------------------------------------------------------------------------------
1 | ../../setup/
--------------------------------------------------------------------------------
/csv_config_gen/.gitignore:
--------------------------------------------------------------------------------
1 | interface_configs.txt
2 |
--------------------------------------------------------------------------------
/csv_config_gen/config_render_01.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Demo script showing how to create network configurations by combining data from CSV files with Jinja templates.
4 | """
5 |
6 | import csv
7 | from jinja2 import Template
8 |
9 | source_file = "switch-ports.csv"
10 | interface_template_file = "switchport-interface-template.j2"
11 |
12 | # String that will hold final full configuration of all interfaces
13 | interface_configs = ""
14 |
15 | # Open up the Jinja template file (as text) and then create a Jinja Template Object
16 | with open(interface_template_file) as f:
17 | interface_template = Template(f.read(), keep_trailing_newline=True)
18 |
19 | # Open up the CSV file containing the data
20 | with open(source_file) as f:
21 | # Use DictReader to access data from CSV
22 | reader = csv.DictReader(f)
23 | # For each row in the CSV, generate an interface configuration using the jinja template
24 | for row in reader:
25 | interface_config = interface_template.render(
26 | interface = row["Interface"],
27 | vlan = row["VLAN"],
28 | server = row["Server"],
29 | link = row["Link"],
30 | purpose = row["Purpose"]
31 | )
32 |
33 | # Append this interface configuration to the full configuration
34 | interface_configs += interface_config
35 |
36 | # Save the final configuraiton to a file
37 | with open("interface_configs.txt", "w") as f:
38 | f.write(interface_configs)
39 |
--------------------------------------------------------------------------------
/csv_config_gen/config_render_02.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Demo script showing how to create network configurations by combining data from CSV files with Jinja templates.
4 | """
5 |
6 | import csv
7 | from jinja2 import Template
8 | from netmiko import ConnectHandler
9 |
10 | source_file = "switch-ports.csv"
11 | interface_template_file = "switchport-interface-template.j2"
12 |
13 | # DevNet Sandbox Nexus 9000 switch to send configuration to
14 | device = {
15 | "address": "sbx-nxos-mgmt.cisco.com",
16 | "device_type": "cisco_nxos",
17 | "ssh_port": 8181,
18 | "username": "admin",
19 | "password": "Admin_1234!"
20 | }
21 |
22 |
23 | # String that will hold final full configuration of all interfaces
24 | interface_configs = ""
25 |
26 | # Open up the Jinja template file (as text) and then create a Jinja Template Object
27 | with open(interface_template_file) as f:
28 | interface_template = Template(f.read(), keep_trailing_newline=True)
29 |
30 | # Open up the CSV file containing the data
31 | with open(source_file) as f:
32 | # Use DictReader to access data from CSV
33 | reader = csv.DictReader(f)
34 | # For each row in the CSV, generate an interface configuration using the jinja template
35 | for row in reader:
36 | interface_config = interface_template.render(
37 | interface = row["Interface"],
38 | vlan = row["VLAN"],
39 | server = row["Server"],
40 | link = row["Link"],
41 | purpose = row["Purpose"]
42 | )
43 |
44 | # Append this interface configuration to the full configuration
45 | interface_configs += interface_config
46 |
47 | # Save the final configuraiton to a file
48 | with open("interface_configs.txt", "w") as f:
49 | f.write(interface_configs)
50 |
51 | # Use Netmiko to connect to the device and send the configuration
52 | with ConnectHandler(ip = device["address"],
53 | port = device["ssh_port"],
54 | username = device["username"],
55 | password = device["password"],
56 | device_type = device["device_type"]) as ch:
57 |
58 | config_set = interface_configs.split("\n")
59 | output = ch.send_config_set(config_set)
60 | print(output)
61 |
--------------------------------------------------------------------------------
/csv_config_gen/switch-ports.csv:
--------------------------------------------------------------------------------
1 | Switch,Interface,Server,Link,Purpose,VLAN
2 | sbx-n9kv-ao,Ethernet1/13,esxi-01,nic 0,Virtualization Host,trunk
3 | sbx-n9kv-ao,Ethernet1/14,esxi-01,nic 1,Virtualization Host,trunk
4 | sbx-n9kv-ao,Ethernet1/15,esxi-01,nic 2,Virtualization Host,trunk
5 | sbx-n9kv-ao,Ethernet1/16,esxi-01,nic 3,Virtualization Host,trunk
6 | sbx-n9kv-ao,Ethernet1/17,esxi-02,nic 0,Virtualization Host,trunk
7 | sbx-n9kv-ao,Ethernet1/18,esxi-02,nic 1,Virtualization Host,trunk
8 | sbx-n9kv-ao,Ethernet1/19,esxi-02,nic 2,Virtualization Host,trunk
9 | sbx-n9kv-ao,Ethernet1/20,esxi-02,nic 3,Virtualization Host,trunk
10 | sbx-n9kv-ao,Ethernet1/21,esxi-03,nic 0,Virtualization Host,trunk
11 | sbx-n9kv-ao,Ethernet1/22,esxi-03,nic 1,Virtualization Host,trunk
12 | sbx-n9kv-ao,Ethernet1/23,esxi-03,nic 2,Virtualization Host,trunk
13 | sbx-n9kv-ao,Ethernet1/24,esxi-03,nic 3,Virtualization Host,trunk
14 | sbx-n9kv-ao,Ethernet1/25,esxi-04,nic 0,Virtualization Host,trunk
15 | sbx-n9kv-ao,Ethernet1/26,esxi-04,nic 1,Virtualization Host,trunk
16 | sbx-n9kv-ao,Ethernet1/27,esxi-04,nic 2,Virtualization Host,trunk
17 | sbx-n9kv-ao,Ethernet1/28,esxi-04,nic 3,Virtualization Host,trunk
18 | sbx-n9kv-ao,Ethernet1/29,esxi-05,nic 0,Virtualization Host,trunk
19 | sbx-n9kv-ao,Ethernet1/30,esxi-05,nic 1,Virtualization Host,trunk
20 | sbx-n9kv-ao,Ethernet1/31,esxi-05,nic 2,Virtualization Host,trunk
21 | sbx-n9kv-ao,Ethernet1/32,esxi-05,nic 3,Virtualization Host,trunk
22 | sbx-n9kv-ao,Ethernet1/33,esxi-06,nic 0,Virtualization Host,trunk
23 | sbx-n9kv-ao,Ethernet1/34,esxi-06,nic 1,Virtualization Host,trunk
24 | sbx-n9kv-ao,Ethernet1/35,esxi-06,nic 2,Virtualization Host,trunk
25 | sbx-n9kv-ao,Ethernet1/36,esxi-06,nic 3,Virtualization Host,trunk
26 | sbx-n9kv-ao,Ethernet1/37,esxi-07,nic 0,Virtualization Host,trunk
27 | sbx-n9kv-ao,Ethernet1/38,esxi-07,nic 1,Virtualization Host,trunk
28 | sbx-n9kv-ao,Ethernet1/39,esxi-07,nic 2,Virtualization Host,trunk
29 | sbx-n9kv-ao,Ethernet1/40,esxi-07,nic 3,Virtualization Host,trunk
30 | sbx-n9kv-ao,Ethernet1/41,esxi-08,nic 0,Virtualization Host,trunk
31 | sbx-n9kv-ao,Ethernet1/42,esxi-08,nic 1,Virtualization Host,trunk
32 | sbx-n9kv-ao,Ethernet1/43,esxi-08,nic 2,Virtualization Host,trunk
33 | sbx-n9kv-ao,Ethernet1/44,esxi-08,nic 3,Virtualization Host,trunk
34 | sbx-n9kv-ao,Ethernet1/45,db-01,nic 0,Database Server,101
35 | sbx-n9kv-ao,Ethernet1/46,db-01,nic 1,Database Server,101
36 | sbx-n9kv-ao,Ethernet1/47,db-02,nic 0,Database Server,101
37 | sbx-n9kv-ao,Ethernet1/48,db-02,nic 1,Database Server,101
38 | sbx-n9kv-ao,Ethernet1/49,db-03,nic 0,Database Server,101
39 | sbx-n9kv-ao,Ethernet1/50,db-03,nic 1,Database Server,101
40 | sbx-n9kv-ao,Ethernet1/51,dev-db-01,nic 0,Database Server,102
41 | sbx-n9kv-ao,Ethernet1/52,dev-db-01,nic 1,Database Server,102
42 | sbx-n9kv-ao,Ethernet1/53,dev-db-02,nic 0,Database Server,102
43 | sbx-n9kv-ao,Ethernet1/54,dev-db-02,nic 1,Database Server,102
44 | sbx-n9kv-ao,Ethernet1/55,dev-db-03,nic 0,Database Server,102
45 | sbx-n9kv-ao,Ethernet1/56,dev-db-03,nic 1,Database Server,102
46 | sbx-n9kv-ao,Ethernet1/57,admin-01,nic 0,Admin Server,100
47 | sbx-n9kv-ao,Ethernet1/58,admin-01,nic 2,Admin Server,100
48 | sbx-n9kv-ao,Ethernet1/59,server-01,nic 0,App Server,103
49 | sbx-n9kv-ao,Ethernet1/60,server-01,nic 1,App Server,103
50 | sbx-n9kv-ao,Ethernet1/61,server-02,nic 0,App Server,104
51 | sbx-n9kv-ao,Ethernet1/62,server-02,nic 1,App Server,104
52 | sbx-n9kv-ao,Ethernet1/63,server-03,nic 0,App Server,105
53 | sbx-n9kv-ao,Ethernet1/64,server-03,nic 1,App Server,105
--------------------------------------------------------------------------------
/csv_config_gen/switchport-interface-template.j2:
--------------------------------------------------------------------------------
1 | ! Generated Configuration
2 | interface {{ interface }}
3 | description Link to {{ server }} port {{ link }} for {{ purpose }}
4 | switchport
5 | {% if vlan == "trunk" -%}
6 | switchport mode trunk
7 | {% else -%}
8 | switchport mode access
9 | switchport access vlan {{ vlan }}
10 | spanning-tree port type edge
11 | {% endif -%}
12 | no shutdown
13 |
14 |
15 |
--------------------------------------------------------------------------------
/data_manipulation/csv/add_router.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """This script illustrates how to use the Python csv library to add data to a file.
3 |
4 | Copyright (c) 2018 Cisco and/or its affiliates.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | """
24 |
25 | import csv
26 |
27 | # Collect information from the user and save to variables
28 | print("Let's add a new router.")
29 | hostname = input("What is the hostname? ")
30 | ip = input("What is the ip address? ")
31 | location = input("What is the location? ")
32 |
33 | # Create new list representing device
34 | device = [hostname, ip, location]
35 |
36 | # Open the csv file in "append" mode to add new device
37 | with open("csv_example.csv", "a") as f:
38 | # Create a csv.writer object from the file
39 | csv_writer = csv.writer(f)
40 | # Add new row based on new device
41 | csv_writer.writerow(device)
42 |
--------------------------------------------------------------------------------
/data_manipulation/csv/csv_example.csv:
--------------------------------------------------------------------------------
1 | "router1","10.1.0.1","New York"
2 | "router2","10.2.0.1","Denver"
3 | "router3","10.3.0.1","Austin"
4 |
--------------------------------------------------------------------------------
/data_manipulation/csv/csv_example.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """This script illustrates how to manipulate csv data easily in Python with
3 | the csv library.
4 |
5 | Copyright (c) 2018 Cisco and/or its affiliates.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 | """
25 |
26 | # Import the csv library
27 | import csv
28 |
29 | # Open the sample csv file and print it to screen
30 | with open("csv_example.csv") as f:
31 | print(f.read())
32 |
33 | # Open the sample csv file, and create a csv.reader object
34 | with open("csv_example.csv") as f:
35 | csv_python = csv.reader(f)
36 | # Loop over each row in csv and leverage the data in code
37 | for row in csv_python:
38 | print("{device} is in {location} " \
39 | "and has IP {ip}.".format(
40 | device = row[0],
41 | location = row[2],
42 | ip = row[1]
43 | )
44 | )
45 |
--------------------------------------------------------------------------------
/data_manipulation/json/json_example.json:
--------------------------------------------------------------------------------
1 | {
2 | "interface": {
3 | "name": "GigabitEthernet2",
4 | "description": "Wide Area Network",
5 | "enabled": true,
6 | "ipv4": {
7 | "address": [
8 | {
9 | "ip": "172.16.0.2",
10 | "netmask": "255.255.255.0"
11 | }
12 | ]
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/data_manipulation/json/json_example.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """This script illustrates how to manipulate JSON data easily in Python with
3 | the json library.
4 |
5 | Copyright (c) 2018 Cisco and/or its affiliates.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 | """
25 |
26 | # Import the jsontodict library
27 | import json
28 |
29 | # Open the sample json file and read it into variable
30 | with open("json_example.json") as f:
31 | json_example = f.read()
32 |
33 | # Print the raw json data
34 | print(json_example)
35 |
36 | # Parse the json into a Python dictionary
37 | json_dict = json.loads(json_example)
38 |
39 | # Save the interface name into a variable
40 | int_name = json_dict["interface"]["name"]
41 |
42 | # Print the interface name
43 | print(int_name)
44 |
45 | # Change the IP address of the interface
46 | json_dict["interface"]["ipv4"]["address"][0]["ip"] = "192.168.0.2"
47 |
48 | # Revert to the json string version of the dictionary
49 | print(json.dumps(json_dict))
50 |
--------------------------------------------------------------------------------
/data_manipulation/xml/xml_example.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """This script illustrates how to manipulate XML data easily in Python with
3 | the xmltodict library.
4 |
5 | Prep with:
6 | pip install xmltodict
7 |
8 | Copyright (c) 2018 Cisco and/or its affiliates.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 | """
28 |
29 | # Import the xmltodict library
30 | import xmltodict
31 |
32 | # Open the sample xml file and read it into variable
33 | with open("xml_example.xml") as f:
34 | xml_example = f.read()
35 |
36 | # Print the raw XML data
37 | print(xml_example)
38 |
39 | # Parse the XML into a Python dictionary
40 | xml_dict = xmltodict.parse(xml_example)
41 |
42 | # Save the interface name into a variable using XML nodes as keys
43 | int_name = xml_dict["interface"]["name"]
44 |
45 | # Print the interface name
46 | print(int_name)
47 |
48 | # Change the IP address of the interface
49 | xml_dict["interface"]["ipv4"]["address"]["ip"] = "192.168.0.2"
50 |
51 | # Revert to the XML string version of the dictionary
52 | print(xmltodict.unparse(xml_dict))
53 |
--------------------------------------------------------------------------------
/data_manipulation/xml/xml_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | GigabitEthernet2
4 | Wide Area Network
5 | true
6 |
7 |
8 | 172.16.0.2
9 | 255.255.255.0
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/data_manipulation/yaml/yaml_example.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """This script illustrates how to manipulate yaml data easily in Python with
3 | the PyYAML library.
4 |
5 | Copyright (c) 2018 Cisco and/or its affiliates.
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 | """
25 |
26 | # Import the yamltodict library
27 | import yaml
28 |
29 | # Open the sample yaml file and read it into variable
30 | with open("yaml_example.yaml") as f:
31 | yaml_example = f.read()
32 |
33 | # Print the raw yaml data
34 | print(yaml_example)
35 |
36 | # Parse the yaml into a Python dictionary
37 | yaml_dict = yaml.load(yaml_example)
38 |
39 | # Save the interface name into a variable
40 | int_name = yaml_dict["interface"]["name"]
41 |
42 | # Print the interface name
43 | print(int_name)
44 |
45 | # Change the IP address of the interface
46 | yaml_dict["interface"]["ipv4"]["address"][0]["ip"] = "192.168.0.2"
47 |
48 | # Revert to the yaml string version of the dictionary
49 | print(yaml.dump(yaml_dict, default_flow_style=False))
50 |
--------------------------------------------------------------------------------
/data_manipulation/yaml/yaml_example.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | interface:
3 | name: GigabitEthernet2
4 | description: Wide Area Network
5 | enabled: true
6 | ipv4:
7 | address:
8 | - ip: 172.16.0.2
9 | netmask: 255.255.255.0
10 |
--------------------------------------------------------------------------------
/data_manipulation/yang/cisco-xe-ietf-ip-deviation.yang:
--------------------------------------------------------------------------------
1 | module cisco-xe-ietf-ip-deviation {
2 | namespace "http://cisco.com/ns/cisco-xe-ietf-ip-deviation";
3 |
4 | prefix ip-devs;
5 |
6 | import ietf-interfaces {
7 | prefix if;
8 | }
9 |
10 | import ietf-ip {
11 | prefix ip;
12 | }
13 |
14 | organization
15 | "Cisco Systems, Inc.";
16 |
17 | contact
18 | "Cisco Systems, Inc.
19 | Customer Service
20 |
21 | Postal: 170 W Tasman Drive
22 | San Jose, CA 95134
23 |
24 | Tel: +1 1800 553-NETS
25 |
26 | E-mail: cs-yang@cisco.com";
27 |
28 | description
29 | "This module defines deviation statements for ietf-ip module.";
30 |
31 | revision 2016-08-10 {
32 | description
33 | "Updated deviation statements for 16.3.2 release.";
34 | }
35 |
36 | revision 2015-09-11 {
37 | description
38 | "Initial Revision";
39 |
40 | reference
41 | "RFC 6020: YANG - A Data Modeling Language for the
42 | Network Configuration Protocol (NETCONF)";
43 | }
44 |
45 | deviation /if:interfaces/if:interface/ip:ipv4/ip:enabled {
46 | deviate not-supported;
47 | description "Not supported in IOS-XE 3.17 release.";
48 | }
49 |
50 | deviation /if:interfaces/if:interface/ip:ipv4/ip:forwarding {
51 | deviate not-supported;
52 | description "Not supported in IOS-XE 3.17 release.";
53 | }
54 |
55 | deviation /if:interfaces/if:interface/ip:ipv4/ip:mtu {
56 | deviate not-supported;
57 | description "Not supported in IOS-XE 3.17 release.";
58 | }
59 |
60 | /* deviation "/if:interfaces/if:interface/ip:ipv4/ip:address" +
61 | "/ip:subnet/ip:prefix-length" {
62 | deviate not-supported;
63 | description "Not supported in IOS-XE 3.17 release.";
64 | } */
65 |
66 | deviation /if:interfaces/if:interface/ip:ipv4/ip:neighbor {
67 | deviate not-supported;
68 | description "Not supported in IOS-XE 3.17 release.";
69 | }
70 |
71 | deviation /if:interfaces/if:interface/ip:ipv6/ip:enabled {
72 | deviate not-supported;
73 | description "Not supported in IOS-XE 3.17 release.";
74 | }
75 |
76 | deviation /if:interfaces/if:interface/ip:ipv6/ip:forwarding {
77 | deviate not-supported;
78 | description "Not supported in IOS-XE 3.17 release.";
79 | }
80 |
81 | deviation /if:interfaces/if:interface/ip:ipv6/ip:mtu {
82 | deviate not-supported;
83 | description "Not supported in IOS-XE 3.17 release.";
84 | }
85 |
86 | deviation /if:interfaces/if:interface/ip:ipv6/ip:dup-addr-detect-transmits {
87 | deviate not-supported;
88 | description "Not supported in IOS-XE 3.17 release.";
89 | }
90 |
91 | deviation /if:interfaces/if:interface/ip:ipv6/ip:autoconf {
92 | deviate not-supported;
93 | description "Not supported in IOS-XE 3.17 release.";
94 | }
95 |
96 | deviation /if:interfaces/if:interface/ip:ipv6/ip:neighbor {
97 | deviate not-supported;
98 | description "Not supported in IOS-XE 3.17 release.";
99 | }
100 |
101 | deviation /if:interfaces-state/if:interface/ip:ipv4 {
102 | deviate not-supported;
103 | description "Not supported in IOS-XE 16.3.2 release";
104 | }
105 |
106 | deviation /if:interfaces-state/if:interface/ip:ipv6 {
107 | deviate not-supported;
108 | description "Not supported in IOS-XE 16.3.2 release";
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/data_manipulation/yang/ietf-ipv4-unicast-routing.yang:
--------------------------------------------------------------------------------
1 | module ietf-ipv4-unicast-routing {
2 |
3 | yang-version "1.1";
4 |
5 | namespace "urn:ietf:params:xml:ns:yang:ietf-ipv4-unicast-routing";
6 |
7 | prefix "v4ur";
8 |
9 | import ietf-routing {
10 | prefix "rt";
11 | }
12 |
13 | import ietf-inet-types {
14 | prefix "inet";
15 | }
16 | organization
17 | "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
18 |
19 | contact
20 | "WG Web:
21 | WG List:
22 |
23 | WG Chair: Lou Berger
24 |
25 |
26 | WG Chair: Kent Watsen
27 |
28 |
29 | Editor: Ladislav Lhotka
30 |
31 |
32 | Editor: Acee Lindem
33 | ";
34 |
35 | description
36 | "This YANG module augments the 'ietf-routing' module with basic
37 | configuration and state data for IPv4 unicast routing.
38 |
39 | Copyright (c) 2016 IETF Trust and the persons identified as
40 | authors of the code. All rights reserved.
41 |
42 | Redistribution and use in source and binary forms, with or
43 | without modification, is permitted pursuant to, and subject to
44 | the license terms contained in, the Simplified BSD License set
45 | forth in Section 4.c of the IETF Trust's Legal Provisions
46 | Relating to IETF Documents
47 | (http://trustee.ietf.org/license-info).
48 |
49 | The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
50 | NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'MAY', and
51 | 'OPTIONAL' in the module text are to be interpreted as described
52 | in RFC 2119.
53 |
54 | This version of this YANG module is part of RFC 8022;
55 | see the RFC itself for full legal notices.";
56 |
57 | revision 2016-11-04 {
58 | description
59 | "Initial revision.";
60 | reference
61 | "RFC 8022: A YANG Data Model for Routing Management";
62 | }
63 |
64 | /* Identities */
65 |
66 | identity ipv4-unicast {
67 | base rt:ipv4;
68 | description
69 | "This identity represents the IPv4 unicast address family.";
70 | }
71 |
72 | /* State data */
73 |
74 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route" {
75 | when "derived-from-or-self(../../rt:address-family, "
76 | + "'v4ur:ipv4-unicast')" {
77 | description
78 | "This augment is valid only for IPv4 unicast.";
79 | }
80 | description
81 | "This leaf augments an IPv4 unicast route.";
82 | leaf destination-prefix {
83 | type inet:ipv4-prefix;
84 | description
85 | "IPv4 destination prefix.";
86 | }
87 | }
88 |
89 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
90 | + "rt:next-hop/rt:next-hop-options/rt:simple-next-hop" {
91 | when "derived-from-or-self(../../../rt:address-family, "
92 | + "'v4ur:ipv4-unicast')" {
93 | description
94 | "This augment is valid only for IPv4 unicast.";
95 | }
96 | description
97 | "Augment 'simple-next-hop' case in IPv4 unicast routes.";
98 | leaf next-hop-address {
99 | type inet:ipv4-address;
100 | description
101 | "IPv4 address of the next hop.";
102 | }
103 | }
104 |
105 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:routes/rt:route/"
106 | + "rt:next-hop/rt:next-hop-options/rt:next-hop-list/"
107 | + "rt:next-hop-list/rt:next-hop" {
108 | when "derived-from-or-self(../../../../../rt:address-family, "
109 | + "'v4ur:ipv4-unicast')" {
110 | description
111 | "This augment is valid only for IPv4 unicast.";
112 | }
113 | description
114 | "This leaf augments the 'next-hop-list' case of IPv4 unicast
115 | routes.";
116 | leaf address {
117 | type inet:ipv4-address;
118 | description
119 | "IPv4 address of the next-hop.";
120 | }
121 | }
122 |
123 | augment
124 | "/rt:routing-state/rt:ribs/rt:rib/rt:active-route/rt:input" {
125 | when "derived-from-or-self(../rt:address-family, "
126 | + "'v4ur:ipv4-unicast')" {
127 | description
128 | "This augment is valid only for IPv4 unicast RIBs.";
129 | }
130 | description
131 | "This augment adds the input parameter of the 'active-route'
132 | action.";
133 | leaf destination-address {
134 | type inet:ipv4-address;
135 | description
136 | "IPv4 destination address.";
137 | }
138 | }
139 |
140 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:active-route/"
141 | + "rt:output/rt:route" {
142 | when "derived-from-or-self(../../rt:address-family, "
143 | + "'v4ur:ipv4-unicast')" {
144 | description
145 | "This augment is valid only for IPv4 unicast.";
146 | }
147 | description
148 | "This augment adds the destination prefix to the reply of the
149 | 'active-route' action.";
150 | leaf destination-prefix {
151 | type inet:ipv4-prefix;
152 | description
153 | "IPv4 destination prefix.";
154 | }
155 | }
156 |
157 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:active-route/"
158 | + "rt:output/rt:route/rt:next-hop/rt:next-hop-options/"
159 | + "rt:simple-next-hop" {
160 | when "derived-from-or-self(../../../rt:address-family, "
161 | + "'v4ur:ipv4-unicast')" {
162 | description
163 | "This augment is valid only for IPv4 unicast.";
164 | }
165 | description
166 | "Augment 'simple-next-hop' case in the reply to the
167 | 'active-route' action.";
168 | leaf next-hop-address {
169 | type inet:ipv4-address;
170 | description
171 | "IPv4 address of the next hop.";
172 | }
173 | }
174 |
175 | augment "/rt:routing-state/rt:ribs/rt:rib/rt:active-route/"
176 | + "rt:output/rt:route/rt:next-hop/rt:next-hop-options/"
177 | + "rt:next-hop-list/rt:next-hop-list/rt:next-hop" {
178 | when "derived-from-or-self(../../../../../rt:address-family, "
179 | + "'v4ur:ipv4-unicast')" {
180 | description
181 | "This augment is valid only for IPv4 unicast.";
182 | }
183 | description
184 | "Augment 'next-hop-list' case in the reply to the
185 | 'active-route' action.";
186 | leaf next-hop-address {
187 | type inet:ipv4-address;
188 | description
189 | "IPv4 address of the next hop.";
190 | }
191 | }
192 |
193 | /* Configuration data */
194 |
195 | augment "/rt:routing/rt:control-plane-protocols/"
196 | + "rt:control-plane-protocol/rt:static-routes" {
197 | description
198 | "This augment defines the configuration of the 'static'
199 | pseudo-protocol with data specific to IPv4 unicast.";
200 | container ipv4 {
201 | description
202 | "Configuration of a 'static' pseudo-protocol instance
203 | consists of a list of routes.";
204 | list route {
205 | key "destination-prefix";
206 | description
207 | "A list of static routes.";
208 | leaf destination-prefix {
209 | type inet:ipv4-prefix;
210 | mandatory "true";
211 | description
212 | "IPv4 destination prefix.";
213 | }
214 | leaf description {
215 | type string;
216 | description
217 | "Textual description of the route.";
218 | }
219 | container next-hop {
220 | description
221 | "Configuration of next-hop.";
222 | uses rt:next-hop-content {
223 | augment "next-hop-options/simple-next-hop" {
224 | description
225 | "Augment 'simple-next-hop' case in IPv4 static
226 | routes.";
227 | leaf next-hop-address {
228 | type inet:ipv4-address;
229 | description
230 | "IPv4 address of the next hop.";
231 | }
232 | }
233 | augment "next-hop-options/next-hop-list/next-hop-list/"
234 | + "next-hop" {
235 | description
236 | "Augment 'next-hop-list' case in IPv4 static
237 | routes.";
238 | leaf next-hop-address {
239 | type inet:ipv4-address;
240 | description
241 | "IPv4 address of the next hop.";
242 | }
243 | }
244 | }
245 | }
246 | }
247 | }
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/data_manipulation/yang/pyang-examples.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | # These example bash commands show how to use the pyang utility to work
3 | # with yang module files.
4 | #
5 | # Copyright (c) 2018 Cisco and/or its affiliates.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a copy
8 | # of this software and associated documentation files (the "Software"), to deal
9 | # in the Software without restriction, including without limitation the rights
10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | # copies of the Software, and to permit persons to whom the Software is
12 | # furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in all
15 | # copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | # SOFTWARE.
24 |
25 | echo "Print the YANG module in a simple text tree"
26 | pyang -f tree ietf-interfaces.yang
27 |
28 | echo "Print only part of the tree"
29 | pyang -f tree --tree-path=/interfaces/interface \
30 | ietf-interfaces.yang
31 |
32 | echo "Print an example XML skeleton (NETCONF)"
33 | pyang -f sample-xml-skeleton ietf-interfaces.yang
34 |
35 | echo "Create an HTTP/JS view of the YANG Model"
36 | pyang -f jstree -o ietf-interfaces.html \
37 | ietf-interfaces.yang
38 | open ietf-interfaces.html
39 |
40 | echo 'Control the "nested depth" in trees'
41 | pyang -f tree --tree-depth=2 ietf-ip.yang
42 |
43 | echo "Include deviation models in the processing"
44 | pyang -f tree \
45 | --deviation-module=cisco-xe-ietf-ip-deviation.yang \
46 | ietf-ip.yang
47 |
--------------------------------------------------------------------------------
/device_apis/cli/netmiko_example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the netmiko library for CLI interfacing
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from netmiko import ConnectHandler
29 | import re
30 | import sys
31 |
32 | # Add parent directory to path to allow importing common vars
33 | sys.path.append("..") # noqa
34 | from device_info import ios_xe1 as device # noqa
35 |
36 | # Set device_type for netmiko
37 | device["device_type"] = "cisco_ios"
38 |
39 | # Create a CLI command template
40 | show_interface_config_temp = "show running-config interface {}"
41 |
42 | # Open CLI connection to device
43 | with ConnectHandler(ip = device["address"],
44 | port = device["ssh_port"],
45 | username = device["username"],
46 | password = device["password"],
47 | device_type = device["device_type"]) as ch:
48 |
49 | # Create desired CLI command and send to device
50 | command = show_interface_config_temp.format("GigabitEthernet2")
51 | interface = ch.send_command(command)
52 |
53 | # Print the raw command output to the screen
54 | print(interface)
55 |
56 | # Use regular expressions to parse the output for desired data
57 | name = re.search(r'interface (.*)', interface).group(1)
58 | description = re.search(r'description (.*)', interface).group(1)
59 | ip_info = re.search(r'ip address (.*) (.*)', interface)
60 | ip = ip_info.group(1)
61 | netmask = ip_info.group(2)
62 |
63 | # Print the info to the screen
64 | print("The interface {name} has ip address {ip}/{mask}".format(
65 | name = name,
66 | ip = ip,
67 | mask = netmask,
68 | )
69 | )
70 |
--------------------------------------------------------------------------------
/device_apis/cli/netmiko_example1a.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the netmiko library for CLI interfacing
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from netmiko import ConnectHandler
29 | import re
30 | import sys
31 |
32 | # Add parent directory to path to allow importing common vars
33 | sys.path.append("..") # noqa
34 | from device_info import ios_xe1 as device # noqa
35 |
36 | # Set device_type for netmiko
37 | device["device_type"] = "cisco_ios"
38 |
39 | # Create a CLI command template
40 | show_interface_config_temp = "show running-config interface {}"
41 |
42 | # Open CLI connection to device
43 | with ConnectHandler(ip = device["address"],
44 | port = device["ssh_port"],
45 | username = device["username"],
46 | password = device["password"],
47 | device_type = device["device_type"]) as ch:
48 |
49 | # Create desired CLI command and send to device
50 | command = show_interface_config_temp.format("Loopback103")
51 | interface = ch.send_command(command)
52 |
53 | # Print the raw command output to the screen
54 | print(interface)
55 |
56 | # Use regular expressions to parse the output for desired data
57 | name = re.search(r'interface (.*)', interface).group(1)
58 | description = re.search(r'description (.*)', interface).group(1)
59 | ip_info = re.search(r'ip address (.*) (.*)', interface)
60 | ip = ip_info.group(1)
61 | netmask = ip_info.group(2)
62 |
63 | # Print the info to the screen
64 | print("The interface {name} has ip address {ip}/{mask}".format(
65 | name = name,
66 | ip = ip,
67 | mask = netmask,
68 | )
69 | )
70 |
--------------------------------------------------------------------------------
/device_apis/cli/netmiko_example2.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the netmiko library for CLI interfacing
3 |
4 | This script will create new configuration on a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from netmiko import ConnectHandler
29 | import sys
30 |
31 | # Add parent directory to path to allow importing common vars
32 | sys.path.append("..") # noqa
33 | from device_info import ios_xe1 as device # noqa
34 |
35 | # Set device_type for netmiko
36 | device["device_type"] = "cisco_ios"
37 |
38 | # New Loopback Details
39 | loopback = {"int_name": "Loopback103",
40 | "description": "Demo interface by CLI and netmiko",
41 | "ip": "192.168.103.1",
42 | "netmask": "255.255.255.0"}
43 |
44 | # Create a CLI configuration
45 | interface_config = [
46 | "interface {}".format(loopback["int_name"]),
47 | "description {}".format(loopback["description"]),
48 | "ip address {} {}".format(loopback["ip"], loopback["netmask"]),
49 | "no shut"
50 | ]
51 |
52 | # Open CLI connection to device
53 | with ConnectHandler(ip = device["address"],
54 | port = device["ssh_port"],
55 | username = device["username"],
56 | password = device["password"],
57 | device_type = device["device_type"]) as ch:
58 |
59 | # Send configuration to device
60 | output = ch.send_config_set(interface_config)
61 |
62 | # Print the raw command output to the screen
63 | print("The following configuration was sent: ")
64 | print(output)
65 |
--------------------------------------------------------------------------------
/device_apis/cli/netmiko_example3.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the netmiko library for CLI interfacing
3 |
4 | This script will delete configuration on a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from netmiko import ConnectHandler
29 | import sys
30 |
31 | # Add parent directory to path to allow importing common vars
32 | sys.path.append("..") # noqa
33 | from device_info import ios_xe1 as device # noqa
34 |
35 | # Set device_type for netmiko
36 | device["device_type"] = "cisco_ios"
37 |
38 | # New Loopback Details
39 | loopback = {"int_name": "Loopback103"}
40 |
41 | # Create a CLI configuration
42 | interface_config = [
43 | "no interface {}".format(loopback["int_name"])
44 | ]
45 |
46 | # Open CLI connection to device
47 | with ConnectHandler(ip = device["address"],
48 | port = device["ssh_port"],
49 | username = device["username"],
50 | password = device["password"],
51 | device_type = device["device_type"]) as ch:
52 |
53 | # Send configuration to device
54 | output = ch.send_config_set(interface_config)
55 |
56 | # Print the raw command output to the screen
57 | print("The following configuration was sent: ")
58 | print(output)
59 |
--------------------------------------------------------------------------------
/device_apis/device_info.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Device Details for DevNet Sandboxes
3 |
4 | This script is imported into other code.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | __author__ = "Hank Preston"
28 | __author_email__ = "hapresto@cisco.com"
29 | __copyright__ = "Copyright (c) 2016 Cisco Systems, Inc."
30 | __license__ = "MIT"
31 |
32 | # DevNet Always-On NETCONF/YANG & RESTCONF Sandbox Device
33 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/27d9747a-db48-4565-8d44-df318fce37ad?diagramType=Topology
34 | ios_xe1 = {
35 | "address": "ios-xe-mgmt.cisco.com",
36 | "netconf_port": 10000,
37 | "restconf_port": 9443,
38 | "ssh_port": 8181,
39 | "username": "root",
40 | "password": "D_Vay!_10&"
41 | }
42 |
43 | # Vagrant option - Uncomment the below if using Vagrant IOS XE Device
44 | vagrant_iosxe = {
45 | "address": "127.0.0.1",
46 | "netconf_port": 2223,
47 | "restconf_port": 2225,
48 | "ssh_port": 2222,
49 | "snmp_port": 2227,
50 | "username": "vagrant",
51 | "password": "vagrant"
52 | }
53 |
54 |
55 | # DevNet Always-On Sandbox APIC-EM
56 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/2e0f9525-5f46-4f46-973e-0f0c1bf934fa?diagramType=Topology
57 | apicem = {
58 | "host": "sandboxapicem.cisco.com",
59 | "username": "devnetuser",
60 | "password": "Cisco123!",
61 | "port": 443
62 | }
63 |
64 | # DevNet Always-On Sandbox ACI APIC
65 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/5a229a7c-95d5-4cfd-a651-5ee9bc1b30e2?diagramType=Topology
66 | apic = {
67 | "host": "https://sandboxapicdc.cisco.com",
68 | "username": "admin",
69 | "password": "ciscopsdt",
70 | "port": 443
71 | }
72 |
--------------------------------------------------------------------------------
/device_apis/netconf/netconf-ssh-example.md:
--------------------------------------------------------------------------------
1 | # Example NETCONF Flow over SSH
2 |
3 | 1. Open SSH Connection
4 |
5 | ```bash
6 | ssh -oHostKeyAlgorithms=+ssh-dss root@ios-xe-mgmt.cisco.com -p 10000 -s netconf
7 | ```
8 |
9 | 1. Send Password
10 |
11 | ```bash
12 | D_Vay!_10&
13 | ```
14 |
15 | 1. Receive agent ``.
16 |
17 | 1. Send manager ``
18 |
19 | ```xml
20 |
21 |
22 |
23 | urn:ietf:params:netconf:base:1.0
24 |
25 | ]]>]]>
26 | ```
27 |
28 | * _Note: There will be **NO** response from device._
29 |
30 | 1. End connection with ``
31 |
32 | ```xml
33 |
34 |
35 |
36 |
37 | ]]>]]>
38 | ```
39 |
40 | 1. Receive `` from agent. Notice how the `message-id` matches your sent value.
41 |
--------------------------------------------------------------------------------
/device_apis/netconf/netconf_example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the ncclient library for NETCONF
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from ncclient import manager
29 | from xml.dom import minidom
30 | import xmltodict
31 | import sys
32 |
33 | # Add parent directory to path to allow importing common vars
34 | sys.path.append("..") # noqa
35 | # from device_info import ios_xe1 as device # noqa
36 | from device_info import ios_xe1 as device # noqa
37 |
38 |
39 | # Create filter template for an interface
40 | interface_filter = """
41 |
42 |
43 |
44 | {int_name}
45 |
46 |
47 |
48 | """
49 |
50 | # Open NETCONF connection to device
51 | with manager.connect(host = device["address"],
52 | port = device["netconf_port"],
53 | username = device["username"],
54 | password = device["password"],
55 | hostkey_verify = False) as m:
56 |
57 | # Create desired NETCONF filter and
58 | filter = interface_filter.format(int_name = "GigabitEthernet1")
59 | r = m.get_config("running", filter)
60 |
61 | # Pretty print raw xml to screen
62 | xml_doc = minidom.parseString(r.xml)
63 | print(xml_doc.toprettyxml(indent = " "))
64 |
65 | # Process the XML data into Python Dictionary and use
66 | interface = xmltodict.parse(r.xml)
67 |
68 | # Only if RPC returned data
69 | if not interface["rpc-reply"]["data"] is None:
70 | interface = interface["rpc-reply"]["data"]["interfaces"]["interface"]
71 |
72 | print("The interface {name} has ip address {ip}/{mask}".format(
73 | name = interface["name"]["#text"],
74 | ip = interface["ipv4"]["address"]["ip"],
75 | mask = interface["ipv4"]["address"]["netmask"],
76 | )
77 | )
78 | else:
79 | print("No interface {} found".format("GigabitEthernet1"))
80 |
--------------------------------------------------------------------------------
/device_apis/netconf/netconf_example1a.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the ncclient library for NETCONF
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from ncclient import manager
29 | from xml.dom import minidom
30 | import yaml, xmltodict
31 | import sys
32 |
33 | # Add parent directory to path to allow importing common vars
34 | sys.path.append("..") # noqa
35 | from device_info import ios_xe1 as device # noqa
36 |
37 | # Create filter template for an interface
38 | interface_filter = """
39 |
40 |
41 |
42 | {int_name}
43 |
44 |
45 |
46 | """
47 |
48 | # Open NETCONF connection to device
49 | with manager.connect(host = device["address"],
50 | port = device["netconf_port"],
51 | username = device["username"],
52 | password = device["password"],
53 | hostkey_verify = False) as m:
54 |
55 | # Create desired NETCONF filter and
56 | filter = interface_filter.format(int_name = "Loopback102")
57 | r = m.get_config("running", filter)
58 |
59 | # Pretty print raw xml to screen
60 | xml_doc = minidom.parseString(r.xml)
61 | print(xml_doc.toprettyxml(indent = " "))
62 |
63 | # Process the XML data into Python Dictionary and use
64 | interface = xmltodict.parse(r.xml)
65 |
66 | # Only if RPC returned data
67 | if not interface["rpc-reply"]["data"] is None:
68 | interface = interface["rpc-reply"]["data"]["interfaces"]["interface"]
69 |
70 | print("The interface {name} has ip address {ip}/{mask}".format(
71 | name = interface["name"]["#text"],
72 | ip = interface["ipv4"]["address"]["ip"],
73 | mask = interface["ipv4"]["address"]["netmask"],
74 | )
75 | )
76 | else:
77 | print("No interface {} found".format("Loopback102"))
78 |
--------------------------------------------------------------------------------
/device_apis/netconf/netconf_example2.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the ncclient library for NETCONF
3 |
4 | This script will create new configuration on a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from ncclient import manager
29 | from xml.dom import minidom
30 | import xmltodict
31 | import sys
32 |
33 | # Add parent directory to path to allow importing common vars
34 | sys.path.append("..") # noqa
35 | from device_info import ios_xe1 as device # noqa
36 |
37 | # New Loopback Details
38 | loopback = {"int_name": "Loopback102",
39 | "description": "Demo interface by NETCONF",
40 | "ip": "192.168.102.1",
41 | "netmask": "255.255.255.0"}
42 |
43 |
44 | # Create config template for an interface
45 | config_data = """
46 |
47 |
48 |
49 | {int_name}
50 | {description}
51 |
52 | ianaift:softwareLoopback
53 |
54 | true
55 |
56 |
57 | {ip}
58 | {netmask}
59 |
60 |
61 |
62 |
63 |
64 | """
65 |
66 | # Open NETCONF connection to device
67 | with manager.connect(host = device["address"],
68 | port = device["netconf_port"],
69 | username = device["username"],
70 | password = device["password"],
71 | hostkey_verify = False) as m:
72 |
73 | # Create desired NETCONF config payload and
74 | config = config_data.format(**loopback)
75 | r = m.edit_config(target = "running", config = config)
76 |
77 | # Print OK status
78 | print("NETCONF RPC OK: {}".format(r.ok))
79 |
--------------------------------------------------------------------------------
/device_apis/netconf/netconf_example3.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the ncclient library for NETCONF
3 |
4 | This script will delete configuration on a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | from ncclient import manager
29 | from xml.dom import minidom
30 | import xmltodict
31 | import sys
32 |
33 | # Add parent directory to path to allow importing common vars
34 | sys.path.append("..") # noqa
35 | from device_info import ios_xe1 as device # noqa
36 |
37 | # New Loopback Details
38 | loopback = {"int_name": "Loopback102",
39 | "description": "Demo interface by NETCONF",
40 | "ip": "192.168.102.1",
41 | "netmask": "255.255.255.0"}
42 |
43 |
44 | # Create config template for an interface
45 | config_data = """
46 |
47 |
48 |
49 | {int_name}
50 |
51 |
52 |
53 | """
54 |
55 | # Open NETCONF connection to device
56 | with manager.connect(host = device["address"],
57 | port = device["netconf_port"],
58 | username = device["username"],
59 | password = device["password"],
60 | hostkey_verify = False) as m:
61 |
62 | # Create desired NETCONF config payload and
63 | config = config_data.format(**loopback)
64 | r = m.edit_config(target = "running", config = config)
65 |
66 | # Print OK status
67 | print("NETCONF RPC OK: {}".format(r.ok))
68 |
--------------------------------------------------------------------------------
/device_apis/rest/restconf_example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the requests library for RESTCONF.
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | import requests, urllib3
29 | import sys
30 |
31 | # Add parent directory to path to allow importing common vars
32 | sys.path.append("..") # noqa
33 | from device_info import ios_xe1 as device # noqa
34 |
35 | # Disable Self-Signed Cert warning for demo
36 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
37 |
38 | # Setup base variable for request
39 | restconf_headers = {"Accept": "application/yang-data+json"}
40 | restconf_base = "https://{ip}:{port}/restconf/data"
41 | interface_url = restconf_base + "/ietf-interfaces:interfaces/interface={int_name}"
42 |
43 | # Create URL and send RESTCONF request to core1 for GigE2 Config
44 | url = interface_url.format(ip = device["address"],
45 | port = device["restconf_port"],
46 | int_name = "GigabitEthernet1"
47 | )
48 | print("URL: {}\n".format(url))
49 |
50 | r = requests.get(url,
51 | headers = restconf_headers,
52 | auth=(device["username"], device["password"]),
53 | verify=False)
54 |
55 | # Print returned data
56 | print("GET DATA:")
57 | print(r.text)
58 |
59 | if r.status_code == 200:
60 | # Process JSON data into Python Dictionary and use
61 | interface = r.json()["ietf-interfaces:interface"]
62 | print("The interface {name} has ip address {ip}/{mask}".format(
63 | name = interface["name"],
64 | ip = interface["ietf-ip:ipv4"]["address"][0]["ip"],
65 | mask = interface["ietf-ip:ipv4"]["address"][0]["netmask"],
66 | )
67 | )
68 | else:
69 | print("No interface {} found.".format("GigabitEthernet1"))
70 |
--------------------------------------------------------------------------------
/device_apis/rest/restconf_example1a.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the requests library for RESTCONF.
3 |
4 | This script will retrieve information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | import requests, urllib3
29 | import sys
30 | import yaml
31 |
32 | # Add parent directory to path to allow importing common vars
33 | sys.path.append("..") # noqa
34 | from device_info import ios_xe1 as device # noqa
35 |
36 | # Disable Self-Signed Cert warning for demo
37 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
38 |
39 | # Setup base variable for request
40 | restconf_headers = {"Accept": "application/yang-data+json"}
41 | restconf_base = "https://{ip}:{port}/restconf/data"
42 | interface_url = restconf_base + "/ietf-interfaces:interfaces/interface={int_name}"
43 |
44 | # Create URL and send RESTCONF request to core1 for GigE2 Config
45 | url = interface_url.format(ip = device["address"],
46 | port = device["restconf_port"],
47 | int_name = "Loopback101"
48 | )
49 | print("URL: {}\n".format(url))
50 |
51 | r = requests.get(url,
52 | headers = restconf_headers,
53 | auth=(device["username"], device["password"]),
54 | verify=False)
55 |
56 | # Print returned data
57 | print("GET DATA:")
58 | print(r.text)
59 |
60 | if r.status_code == 200:
61 | # Process JSON data into Python Dictionary and use
62 | interface = r.json()["ietf-interfaces:interface"]
63 | print("The interface {name} has ip address {ip}/{mask}".format(
64 | name = interface["name"],
65 | ip = interface["ietf-ip:ipv4"]["address"][0]["ip"],
66 | mask = interface["ietf-ip:ipv4"]["address"][0]["netmask"],
67 | )
68 | )
69 | else:
70 | print("No interface {} found.".format("Loopback101"))
71 |
--------------------------------------------------------------------------------
/device_apis/rest/restconf_example2.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the requests library for RESTCONF.
3 |
4 | This script will create new configuration on a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | import requests, urllib3, sys, yaml
29 |
30 | # Add parent directory to path to allow importing common vars
31 | sys.path.append("..") # noqa
32 | from device_info import ios_xe1 as device # noqa
33 |
34 | # Disable Self-Signed Cert warning for demo
35 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
36 |
37 | # Setup base variable for request
38 | restconf_headers = {"Accept": "application/yang-data+json",
39 | "Content-Type": "application/yang-data+json"}
40 | restconf_base = "https://{ip}:{port}/restconf/data"
41 | interface_url = restconf_base + "/ietf-interfaces:interfaces/interface={int_name}"
42 |
43 | # New Loopback Details
44 | loopback = {"name": "Loopback101",
45 | "description": "Demo interface by RESTCONF",
46 | "ip": "192.168.101.1",
47 | "netmask": "255.255.255.0"}
48 |
49 | # Setup data body to create new loopback interface
50 | data = {
51 | "ietf-interfaces:interface": {
52 | "name": loopback["name"],
53 | "description": loopback["description"],
54 | "type": "iana-if-type:softwareLoopback",
55 | "enabled": True,
56 | "ietf-ip:ipv4": {
57 | "address": [
58 | {
59 | "ip": loopback["ip"],
60 | "netmask": loopback["netmask"]
61 | }
62 | ]
63 | }
64 | }
65 | }
66 |
67 | # Create URL and send RESTCONF request to device
68 | url = interface_url.format(ip = device["address"],
69 | port = device["restconf_port"],
70 | int_name = loopback["name"]
71 | )
72 | print("URL: {}\n".format(url))
73 |
74 | r = requests.put(url,
75 | headers = restconf_headers,
76 | auth=(device["username"], device["password"]),
77 | json = data,
78 | verify=False)
79 |
80 | # Print returned data
81 | print("PUT Request Status Code: {}".format(r.status_code))
82 |
--------------------------------------------------------------------------------
/device_apis/rest/restconf_example3.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the requests library for RESTCONF.
3 |
4 | This script will delete information from a device.
5 |
6 | Copyright (c) 2018 Cisco and/or its affiliates.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in all
16 | copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | """
26 |
27 | # Import libraries
28 | import requests, urllib3
29 | import sys
30 |
31 | # Add parent directory to path to allow importing common vars
32 | sys.path.append("..") # noqa
33 | from device_info import ios_xe1 as device # noqa
34 |
35 | # Disable Self-Signed Cert warning for demo
36 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
37 |
38 | # Setup base variable for request
39 | restconf_headers = {"Accept": "application/yang-data+json"}
40 | restconf_base = "https://{ip}:{port}/restconf/data"
41 | interface_url = restconf_base + "/ietf-interfaces:interfaces/interface={int_name}"
42 |
43 | # Create URL and send RESTCONF request to core1 for GigE2 Config
44 | url = interface_url.format(ip = device["address"],
45 | port = device["restconf_port"],
46 | int_name = "Loopback101"
47 | )
48 | print("URL: {}\n".format(url))
49 |
50 | r = requests.delete(url,
51 | headers = restconf_headers,
52 | auth=(device["username"], device["password"]),
53 | verify=False)
54 |
55 | # Print returned data
56 | print("DELETE Request Status Code: {}".format(r.status_code))
57 |
58 | # # Process JSON data into Python Dictionary and use
59 | # interface = r.json()["ietf-interfaces:interface"]
60 | # print("The interface {name} has ip address {ip}/{mask}".format(
61 | # name = interface["name"],
62 | # ip = interface["ietf-ip:ipv4"]["address"][0]["ip"],
63 | # mask = interface["ietf-ip:ipv4"]["address"][0]["netmask"],
64 | # )
65 | # )
66 |
--------------------------------------------------------------------------------
/device_apis/snmp/pysnmp_example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the PySNMP library for SNMP interfacing
3 |
4 | This script will query for information from a device
5 |
6 | Uses code example from: https://github.com/etingof/pysnmp
7 |
8 | Copyright (c) 2018 Cisco and/or its affiliates.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 | """
28 |
29 | # Import libraries
30 | from pysnmp.hlapi import *
31 | import sys
32 |
33 | # Add parent directory to path to allow importing common vars
34 | sys.path.append("..") # noqa
35 | from device_info import ios_xe1 as device # noqa
36 |
37 | ro_community, rw_community = "public", "private"
38 |
39 | # Setup SNMP connection and query a MIB
40 | iterator = getCmd(SnmpEngine(),
41 | CommunityData(ro_community),
42 | UdpTransportTarget((device["address"], device["snmp_port"])),
43 | ContextData(),
44 | ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)))
45 |
46 | # Process the query
47 | errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
48 |
49 | # Check for errors, and if OK, print returned result
50 | if errorIndication: # SNMP engine errors
51 | print(errorIndication)
52 | else:
53 | if errorStatus: # SNMP agent errors
54 | print('%s at %s' % (errorStatus.prettyPrint(),
55 | varBinds[int(errorIndex)-1] if errorIndex else '?'))
56 | else:
57 | for varBind in varBinds: # SNMP response contents
58 | print(' = '.join([x.prettyPrint() for x in varBind]))
59 |
--------------------------------------------------------------------------------
/network_testing/pyats/default_testbed.yaml:
--------------------------------------------------------------------------------
1 | testbed:
2 |
3 | name: test_default_q2KEVs
4 |
5 |
6 | devices:
7 |
8 | csr1000v:
9 | alias: csr1000v
10 | os: iosxe
11 | type: CSR1000v
12 | tacacs:
13 | username: root
14 | passwords:
15 | tacacs: D_Vay!_10&
16 |
17 | connections:
18 | defaults:
19 | class: unicon.Unicon
20 | console:
21 | ip: ios-xe-mgmt.cisco.com
22 | protocol: ssh
23 | port: 8181
24 | custom:
25 | abstraction:
26 | order: [os, type]
27 |
28 | sbx-n9kv-ao:
29 | alias: nxos
30 | os: nxos
31 | type: Nexus9000v
32 | tacacs:
33 | username: admin
34 | passwords:
35 | tacacs: Admin_1234!
36 |
37 | connections:
38 | defaults:
39 | class: unicon.Unicon
40 | console:
41 | ip: sbx-nxos-mgmt.cisco.com
42 | protocol: ssh
43 | port: 8181
44 | custom:
45 | abstraction:
46 | order: [os, type]
47 |
48 | vagrant-iosxe1:
49 | alias: vagrant-iosxe1
50 | os: iosxe
51 | type: CSR1000v
52 | tacacs:
53 | username: vagrant
54 | passwords:
55 | tacacs: vagrant
56 |
57 | connections:
58 | defaults:
59 | class: unicon.Unicon
60 | console:
61 | ip: 127.0.0.1
62 | protocol: ssh
63 | port: 2222
64 | custom:
65 | abstraction:
66 | order: [os, type]
67 |
68 |
69 | topology:
70 | csr1000v:
71 | interfaces:
72 | GigabitEthernet1:
73 | ipv4: 10.10.20.48
74 | link: flat
75 | type: ethernet
76 |
77 | vagrant-iosxe1:
78 | interfaces:
79 | GigabitEthernet1:
80 | ipv4: 10.0.1.23
81 | link: flat
82 | type: ethernet
83 | GigabitEthernet2:
84 | ipv4: 10.2.1.1
85 | link: flat
86 | type: ethernet
87 |
88 | sbx-n9kv-ao:
89 | interfaces:
90 | Ethernet1/1:
91 | ipv4: 10.10.20.95
92 | link: flat
93 | type: ethernet
94 |
--------------------------------------------------------------------------------
/network_testing/pyats/pyats-example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Sample use of the pyATS library.
3 |
4 | This script will connects to a device and makes several queries.
5 |
6 | The commands are intended to be executed from within an interactive interpreter.
7 |
8 | Copyright (c) 2018 Cisco and/or its affiliates.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 | """
28 | # Import in pyATS libraries and tools
29 | from genie.conf import Genie
30 | from ats.topology import loader
31 | from genie.abstract import Lookup
32 | from genie.libs import ops # noqa
33 |
34 | # Read and process the testbed (inventory) file
35 | genie_testbed = Genie.init("./default_testbed.yaml")
36 |
37 | # Create a pyATS device object from testbed
38 | vagrant_iosxe1 = genie_testbed.devices["vagrant-iosxe1"]
39 |
40 | # Connect to the device
41 | vagrant_iosxe1.connect()
42 |
43 | # Create an abstract device to standardize Python API and code for platform
44 | vagrant_iosxe1_abstract = Lookup.from_device(vagrant_iosxe1)
45 |
46 | # Using the absract device, learn about the Interfaces on the end device
47 | vagrant_iosxe1_interfaces = vagrant_iosxe1_abstract.ops.interface.interface.Interface(vagrant_iosxe1)
48 | vagrant_iosxe1_interfaces.learn()
49 |
50 | # Print out the interface details that were learned
51 | vagrant_iosxe1_interfaces.info
52 |
53 | # Display a single interface from the device
54 | vagrant_iosxe1_interfaces.info["GigabitEthernet1"]
55 |
56 | # Print the mac address for the interface
57 | vagrant_iosxe1_interfaces.info["GigabitEthernet1"]["mac_address"]
58 |
59 | # Notice that there was no parsing of command line output needed to access this data
60 |
61 | # Execute a command on the device and print the output
62 | print(vagrant_iosxe1.execute("show version"))
63 |
64 | # Or store the output into a variable
65 | version = vagrant_iosxe1.execute("show version")
66 |
67 | # Send a configuration command to the
68 | vagrant_iosxe1.configure("ntp server 10.10.10.10")
69 |
70 | # Create a configuration command list and send to the device
71 | config_loopback = [
72 | "interface Loopback201",
73 | "description Configured by pyATS",
74 | "ip address 172.16.201.1 255.255.255.0",
75 | "no shut"
76 | ]
77 | vagrant_iosxe1.configure(config_loopback)
78 |
79 | # Re-learn the interfaces
80 | vagrant_iosxe1_interfaces = vagrant_iosxe1_abstract.ops.interface.interface.Interface(vagrant_iosxe1)
81 | vagrant_iosxe1_interfaces.learn()
82 |
83 | # Get details about new interface
84 | vagrant_iosxe1_interfaces.info["Loopback201"]
85 |
86 | # Disconnect from the devices
87 | vagrant_iosxe1.disconnect()
88 |
--------------------------------------------------------------------------------
/python_code_tips/README.md:
--------------------------------------------------------------------------------
1 | # Python Code Tips
2 | This directory includes a selection of example scripts highlighting different Python coding tips discussed in workshops and presentations such as [Python Skills and Techniques for Network Engineers](https://developer.cisco.com/netdevops/live/#s02t01) from [NetDevOps Live!](https://developer.cisco.com/netdevops/live/)
--------------------------------------------------------------------------------
/python_code_tips/command_line_tool_example/argparse_example.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Simple CLI Tool Example to check routing table using ietf-routing YANG model and NETCONF
3 | """
4 |
5 | from ncclient import manager
6 | from ncclient.transport.errors import SSHError
7 | import xmltodict
8 | from xml.dom import minidom
9 |
10 |
11 | def get_ipv4_default_rib(host, username, password, port=830):
12 | """Use NETCONF to connect to device, retrieve IPv4 default RIP, and return as dictionary
13 | """
14 | filter = """
15 |
16 |
18 |
19 | default
20 |
21 |
22 | ipv4-default
23 |
24 |
25 |
26 |
27 |
28 | """
29 |
30 | # Open NETCONF connection to device
31 | try:
32 | with manager.connect(
33 | host=host,
34 | port=port,
35 | username=username,
36 | password=password,
37 | hostkey_verify=False,
38 | ) as m:
39 |
40 | r = m.get(filter)
41 | except SSHError:
42 | print(
43 | "Unable to connect to device {} with NETCONF on port {}.".format(
44 | host, port
45 | )
46 | )
47 | exit(1)
48 |
49 | # Pretty print raw xml to screen
50 | # xml_doc = minidom.parseString(r.xml)
51 | # print(xml_doc.toprettyxml(indent = " "))
52 |
53 | # Process the XML data into Python Dictionary and use
54 | response_dict = xmltodict.parse(r.xml)
55 |
56 | routes = response_dict["rpc-reply"]["data"]["routing-state"][
57 | "routing-instance"
58 | ]["ribs"]["rib"]["routes"]["route"]
59 |
60 | return routes
61 |
62 |
63 | def print_routes(routes):
64 | """Print out the routing table based on ietf-routing ipv4 ribs
65 | """
66 | if len(routes) == 0:
67 | print("No routes found.")
68 | exit(1)
69 |
70 | try:
71 | print(
72 | "{route:<20} {source:<10} {nexthop:<20}".format(
73 | route="Prefix", source="Source", nexthop="Next Hop"
74 | )
75 | )
76 | for route in routes:
77 | print(
78 | "{route:<20} {source:<10} {nexthop:<20}".format(
79 | route=route["destination-prefix"],
80 | source=route["source-protocol"],
81 | nexthop=route["next-hop"]["next-hop-address"],
82 | )
83 | )
84 | except Exception:
85 | print("Problem in routing table, unable to print.")
86 | exit(1)
87 |
88 |
89 | # Script Entry Point
90 | if __name__ == "__main__":
91 | # Use Arg Parse to retrieve device details
92 | import argparse
93 | import os
94 |
95 | parser = argparse.ArgumentParser()
96 | parser.add_argument(
97 | "--host", help="Host address for network device", required=True
98 | )
99 | parser.add_argument(
100 | "--port", help="Override default NETCONF port of 830", default=830
101 | )
102 | parser.add_argument("--username", help="Device username", required=False)
103 | parser.add_argument("--password", help="Device password", required=False)
104 |
105 | args = parser.parse_args()
106 | username = args.username
107 | password = args.password
108 |
109 | # If Username or Password not provided as arguments, check OS ENV
110 | if username is None:
111 | username = os.getenv("USERNAME")
112 | if password is None:
113 | password = os.getenv("PASSWORD")
114 |
115 | if username is None or password is None:
116 | print(
117 | "You must provide a username and password as a command argument,"
118 | )
119 | print("or as Environment Variables of USERNAME or PASSWORD")
120 | exit(1)
121 |
122 | print("Getting route list from device...")
123 | print("")
124 |
125 | # Get route list
126 | routes = get_ipv4_default_rib(
127 | host=args.host, port=args.port, username=username, password=password
128 | )
129 |
130 | # Print route list
131 | print_routes(routes)
132 |
--------------------------------------------------------------------------------
/python_code_tips/exception_handling/with_try.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | # Diable InsecureRequestWarning
4 | requests.packages.urllib3.disable_warnings(
5 | requests.packages.urllib3.exceptions.InsecureRequestWarning
6 | )
7 |
8 | headers = {"content-type": "application/json", "x-auth-token": ""}
9 |
10 |
11 | def dnac_login(dnac, username, password):
12 | """
13 | Use the REST API to Log into an DNA Center and retrieve ticket
14 | """
15 | url = "https://{}/dna/system/api/v1/auth/token".format(dnac)
16 |
17 | # Make Login request and return the response body
18 | try:
19 | response = requests.request(
20 | "POST",
21 | url,
22 | auth=(username, password),
23 | headers=headers,
24 | verify=False,
25 | )
26 | except requests.exceptions.ConnectionError:
27 | print("Unable to connect to address https://{}".format(dnac))
28 | exit(1)
29 |
30 | if response.status_code != 200:
31 | print(
32 | "Login request failed. Status Code {}".format(
33 | response.status_code
34 | )
35 | )
36 | print("Response body: ")
37 | print(response.text)
38 | exit(1)
39 |
40 | # Return the Token
41 | try:
42 | return response.json()["Token"]
43 | except KeyError:
44 | print("No token found in authentication response.")
45 | print("Response body: ")
46 | print(response.text)
47 | exit(1)
48 |
49 |
50 | # Entry point for program
51 | if __name__ == "__main__":
52 | # Setup Arg Parse for Command Line parameters
53 | import argparse
54 |
55 | parser = argparse.ArgumentParser()
56 |
57 | # Command Line Parameters for Source and Destination IP
58 | parser.add_argument("dnac", help="Cisco DNA Center Address")
59 | parser.add_argument("username", help="Cisco DNA Center Username")
60 | parser.add_argument("password", help="Cisco DNA Center Password")
61 | args = parser.parse_args()
62 |
63 | # Get Source and Destination IPs from Command Line
64 | dnac = args.dnac
65 | username = args.username
66 | password = args.password
67 |
68 | # Log into the dnac Controller to get Ticket
69 | token = dnac_login(dnac, username, password)
70 |
71 | print("Your token is {}".format(token))
72 |
--------------------------------------------------------------------------------
/python_code_tips/exception_handling/without_try.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | # Diable InsecureRequestWarning
4 | requests.packages.urllib3.disable_warnings(
5 | requests.packages.urllib3.exceptions.InsecureRequestWarning
6 | )
7 |
8 | headers = {"content-type": "application/json", "x-auth-token": ""}
9 |
10 |
11 | def dnac_login(dnac, username, password):
12 | """
13 | Use the REST API to Log into an DNA Center and retrieve ticket
14 | """
15 | url = "https://{}/dna/system/api/v1/auth/token".format(dnac)
16 |
17 | # Make Login request and return the response body
18 | response = requests.request(
19 | "POST", url, auth=(username, password), headers=headers, verify=False
20 | )
21 | return response.json()["Token"]
22 |
23 |
24 | # Entry point for program
25 | if __name__ == "__main__":
26 | # Setup Arg Parse for Command Line parameters
27 | import argparse
28 |
29 | parser = argparse.ArgumentParser()
30 |
31 | # Command Line Parameters for Source and Destination IP
32 | parser.add_argument("dnac", help="Cisco DNA Center Address")
33 | parser.add_argument("username", help="Cisco DNA Center Username")
34 | parser.add_argument("password", help="Cisco DNA Center Password")
35 | args = parser.parse_args()
36 |
37 | # Get Source and Destination IPs from Command Line
38 | dnac = args.dnac
39 | username = args.username
40 | password = args.password
41 |
42 | # Log into the dnac Controller to get Ticket
43 | token = dnac_login(dnac, username, password)
44 |
45 | print("Your token is {}".format(token))
46 |
--------------------------------------------------------------------------------
/python_code_tips/functions_example/functions-after.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | import requests
3 | import json
4 | import argparse
5 |
6 | # Diable InsecureRequestWarning
7 | requests.packages.urllib3.disable_warnings(
8 | requests.packages.urllib3.exceptions.InsecureRequestWarning
9 | )
10 |
11 | # DevNet Always-On Sandbox DNA Center
12 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/471eb739-323e-4805-b2a6-d0ec813dc8fc?diagramType=Topology
13 | dnac = {
14 | "host": "sandboxdnac2.cisco.com",
15 | "username": "devnetuser",
16 | "password": "Cisco123!",
17 | "port": 443,
18 | }
19 |
20 | # Headers for DNAC
21 | headers = {"content-type": "application/json", "x-auth-token": ""}
22 |
23 |
24 | def dnac_login(dnac, port, username, password):
25 | """
26 | Use the REST API to Log into an DNA Center and retrieve ticket
27 | """
28 | url = "https://{}:{}/dna/system/api/v1/auth/token".format(dnac, port)
29 |
30 | # Make Login request and return the response body
31 | response = requests.request(
32 | "POST", url, auth=(username, password), headers=headers, verify=False
33 | )
34 | return response.json()["Token"]
35 |
36 |
37 | def host_list(dnac, ticket, ip=None):
38 | """
39 | Use the REST API to retrieve the list of hosts.
40 | Optional parameters to filter by:
41 | IP address
42 | MAC address
43 | Hostname
44 | """
45 | url = "https://{}/api/v1/host?hostIp={}".format(dnac, ip)
46 | headers["x-auth-token"] = ticket
47 | filters = []
48 |
49 | # Make API request and return the response body
50 | response = requests.request("GET", url, headers=headers, verify=False)
51 | return response.json()["response"]
52 |
53 |
54 | def print_host_details(host):
55 | """
56 | Print to screen interesting details about a given host.
57 | Input Paramters are:
58 | host_desc: string to describe this host. Example "Source"
59 | host: dictionary object of a host returned from dnac
60 | Standard Output Details:
61 | Host Name (hostName) - If available
62 | Host IP (hostIp)
63 | Host MAC (hostMac)
64 | Network Type (hostType) - wired/wireless
65 | Host Sub Type (subType)
66 | VLAN (vlanId)
67 | Connected Network Device (connectedNetworkDeviceIpAddress)
68 |
69 | Wired Host Details:
70 | Connected Interface Name (connectedInterfaceName)
71 |
72 | Wireless Host Details:
73 | Connected AP Name (connectedAPName)
74 | """
75 | # If optional host details missing, add as "Unavailable"
76 | if "hostName" not in host.keys():
77 | host["hostName"] = "Unavailable"
78 |
79 | # Print Standard Details
80 | print("Host Name: {}".format(host["hostName"]))
81 | print("Network Type: {}".format(host["hostType"]))
82 | print(
83 | "Connected Network Device: {}".format(
84 | host["connectedNetworkDeviceIpAddress"]
85 | )
86 | ) # noqa: E501
87 |
88 | # Print Wired/Wireless Details
89 | if host["hostType"] == "wired":
90 | print(
91 | "Connected Interface Name: {}".format(
92 | host["connectedInterfaceName"]
93 | )
94 | ) # noqa: E501
95 | if host["hostType"] == "wireless":
96 | print("Connected AP Name: {}".format(host["connectedAPName"]))
97 |
98 | # Print More Standard Details
99 | print("VLAN: {}".format(host["vlanId"]))
100 | print("Host IP: {}".format(host["hostIp"]))
101 | print("Host MAC: {}".format(host["hostMac"]))
102 | print("Host Sub Type: {}".format(host["subType"]))
103 |
104 | # Blank line at the end
105 | print("")
106 |
107 |
108 | # Entry point for program
109 | if __name__ == "__main__":
110 | # Setup Arg Parse for Command Line parameters
111 | import argparse
112 |
113 | parser = argparse.ArgumentParser()
114 |
115 | # Command Line Parameters for Source and Destination IP
116 | parser.add_argument("source_ip", help="Source IP Address")
117 | parser.add_argument("destination_ip", help="Destination IP Address")
118 | args = parser.parse_args()
119 |
120 | # Get Source and Destination IPs from Command Line
121 | source_ip = args.source_ip
122 | destination_ip = args.destination_ip
123 |
124 | # Print Starting message
125 | print("Running Troubleshooting Script for ")
126 | print(" Source IP: {} ".format(source_ip))
127 | print(" Destination IP: {}".format(destination_ip))
128 | print("")
129 |
130 | # Log into the dnac Controller to get Ticket
131 | token = dnac_login(
132 | dnac["host"], dnac["port"], dnac["username"], dnac["password"]
133 | )
134 |
135 | # Retrieve Host Details from dnac
136 | source_host = host_list(dnac["host"], token, ip=source_ip)
137 | destination_host = host_list(dnac["host"], token, ip=destination_ip)
138 |
139 | # Print Out Host details
140 | print("Source Host Details:")
141 | print("-" * 25)
142 | print_host_details(source_host[0])
143 |
144 | print("Destination Host Details:")
145 | print("-" * 25)
146 | print_host_details(destination_host[0])
147 |
--------------------------------------------------------------------------------
/python_code_tips/functions_example/functions-before.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | import requests
4 | import json
5 | import argparse
6 |
7 | # Diable InsecureRequestWarning
8 | requests.packages.urllib3.disable_warnings(
9 | requests.packages.urllib3.exceptions.InsecureRequestWarning
10 | )
11 |
12 | # DevNet Always-On Sandbox DNA Center
13 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/471eb739-323e-4805-b2a6-d0ec813dc8fc?diagramType=Topology
14 | dnac = {
15 | "host": "sandboxdnac2.cisco.com",
16 | "username": "devnetuser",
17 | "password": "Cisco123!",
18 | "port": 443,
19 | }
20 |
21 |
22 | # Setup Arg Parse for Command Line parameters
23 | parser = argparse.ArgumentParser()
24 |
25 | # Command Line Parameters for Source and Destination IP
26 | parser.add_argument("source_ip", help="Source IP Address")
27 | parser.add_argument("destination_ip", help="Destination IP Address")
28 | args = parser.parse_args()
29 |
30 | # Get Source and Destination IPs from Command Line
31 | source_ip = args.source_ip
32 | destination_ip = args.destination_ip
33 |
34 | # Print Starting message
35 | print("Running Troubleshooting Script for ")
36 | print(" Source IP: {} ".format(source_ip))
37 | print(" Destination IP: {}".format(destination_ip))
38 | print("")
39 |
40 | # Headers for DNAC
41 | headers = {"content-type": "application/json", "x-auth-token": ""}
42 |
43 |
44 | # Login to DNAC
45 | url = "https://{}:{}/dna/system/api/v1/auth/token".format(
46 | dnac["host"], dnac["port"]
47 | )
48 |
49 | # Make Login request and return the response body
50 | response = requests.request(
51 | "POST",
52 | url,
53 | auth=(dnac["username"], dnac["password"]),
54 | headers=headers,
55 | verify=False,
56 | )
57 | token = response.json()["Token"]
58 | headers["x-auth-token"] = token
59 |
60 | # URL for Host Calls
61 | url = "https://{}/api/v1/host".format(dnac["host"])
62 |
63 | # Get Host Infomration for Source
64 | source_url = url + "?" + "&hostIp={}".format(source_ip)
65 |
66 | # Make API request and return the response body
67 | response = requests.request("GET", source_url, headers=headers, verify=False)
68 | source_host = response.json()["response"][0]
69 |
70 | # Print out details about source
71 | print("Source Host Details:")
72 | print("-" * 25)
73 | # If optional host details missing, add as "Unavailable"
74 | if "hostName" not in source_host.keys():
75 | source_host["hostName"] = "Unavailable"
76 |
77 | # Print Standard Details
78 | print("Host Name: {}".format(source_host["hostName"]))
79 | print("Network Type: {}".format(source_host["hostType"]))
80 | print(
81 | "Connected Network Device: {}".format(
82 | source_host["connectedNetworkDeviceIpAddress"]
83 | )
84 | ) # noqa: E501
85 |
86 | # Print Wired/Wireless Details
87 | if source_host["hostType"] == "wired":
88 | print(
89 | "Connected Interface Name: {}".format(
90 | source_host["connectedInterfaceName"]
91 | )
92 | ) # noqa: E501
93 | if source_host["hostType"] == "wireless":
94 | print("Connected AP Name: {}".format(source_host["connectedAPName"]))
95 |
96 | # Print More Standard Details
97 | print("VLAN: {}".format(source_host["vlanId"]))
98 | print("Host IP: {}".format(source_host["hostIp"]))
99 | print("Host MAC: {}".format(source_host["hostMac"]))
100 | print("Host Sub Type: {}".format(source_host["subType"]))
101 |
102 | # Blank line at the end
103 | print("")
104 |
105 | # Get Host Infomration for Destination
106 | destination_url = url + "?" + "&hostIp={}".format(destination_ip)
107 |
108 | # Make API request and return the response body
109 | response = requests.request(
110 | "GET", destination_url, headers=headers, verify=False
111 | )
112 | destination_host = response.json()["response"][0]
113 |
114 | # Print out details about source
115 | print("Detination Host Details:")
116 | print("-" * 25)
117 | # If optional host details missing, add as "Unavailable"
118 | if "hostName" not in destination_host.keys():
119 | destination_host["hostName"] = "Unavailable"
120 |
121 | # Print Standard Details
122 | print("Host Name: {}".format(destination_host["hostName"]))
123 | print("Network Type: {}".format(destination_host["hostType"]))
124 | print(
125 | "Connected Network Device: {}".format(
126 | destination_host["connectedNetworkDeviceIpAddress"]
127 | )
128 | ) # noqa: E501
129 |
130 | # Print Wired/Wireless Details
131 | if destination_host["hostType"] == "wired":
132 | print(
133 | "Connected Interface Name: {}".format(
134 | destination_host["connectedInterfaceName"]
135 | )
136 | ) # noqa: E501
137 | if destination_host["hostType"] == "wireless":
138 | print("Connected AP Name: {}".format(destination_host["connectedAPName"]))
139 |
140 | # Print More Standard Details
141 | print("VLAN: {}".format(destination_host["vlanId"]))
142 | print("Host IP: {}".format(destination_host["hostIp"]))
143 | print("Host MAC: {}".format(destination_host["hostMac"]))
144 | print("Host Sub Type: {}".format(destination_host["subType"]))
145 |
146 | # Blank line at the end
147 | print("")
148 |
--------------------------------------------------------------------------------
/python_code_tips/misc/example1.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Example Python script.
3 |
4 | Copyright (c) 2018 Cisco and/or its affiliates."""
5 |
6 | import os
7 |
8 | def say_hello(name):
9 | """Function that will say hello to someone.
10 | """
11 |
12 | # Print out a hello message to the name given
13 | print("Hello there {name}. It's great to see you.".format(name = name))
14 |
15 |
16 |
17 | def script_details():
18 | """Function that reports by printing to screen some details about the execution of the script."""
19 | # Get the current directory and print it out.
20 | cur_dir = os.getcwd()
21 | print("Current directory is {}".format(cur_dir))
22 |
23 | # Get the User ID and Group List for the User
24 | user_id = os.getuid()
25 | group_list = os.getgroups()
26 |
27 | # Print to screen
28 | print("The user id is {}".format(user_id))
29 | print("The user is a member of the following groups:")
30 | print(",".join(str(g) for g in group_list))
31 |
32 |
33 | if __name__ == "__main__":
34 | # If executed as a script, run this block.
35 |
36 | # Check Script details
37 | script_details()
38 |
39 | # List of names, and say hello to them
40 | names = ["Hank","Eric","Stuart","Bryan"]
41 | for name in names:
42 | say_hello(name)
43 |
--------------------------------------------------------------------------------
/python_code_tips/modules_example/dnac_functions.py:
--------------------------------------------------------------------------------
1 | from time import sleep
2 | import json
3 | import requests
4 | import sys
5 |
6 | # Import DNAC Resources
7 | from dnac_resources import dnac, headers
8 |
9 | # Diable InsecureRequestWarning
10 | requests.packages.urllib3.disable_warnings(
11 | requests.packages.urllib3.exceptions.InsecureRequestWarning
12 | )
13 |
14 |
15 | def dnac_login(dnac, port, username, password):
16 | """
17 | Use the REST API to Log into an DNA Center and retrieve ticket
18 | """
19 | url = "https://{}:{}/dna/system/api/v1/auth/token".format(dnac, port)
20 |
21 | # Make Login request and return the response body
22 | response = requests.request(
23 | "POST", url, auth=(username, password), headers=headers, verify=False
24 | )
25 | return response.json()["Token"]
26 |
27 |
28 | def host_list(dnac, ticket, ip=None, mac=None, name=None):
29 | """
30 | Use the REST API to retrieve the list of hosts.
31 | Optional parameters to filter by:
32 | IP address
33 | MAC address
34 | Hostname
35 | """
36 | url = "https://{}/api/v1/host".format(dnac)
37 | headers["x-auth-token"] = ticket
38 | filters = []
39 |
40 | # Add filters if provided
41 | if ip:
42 | filters.append("hostIp={}".format(ip))
43 | if mac:
44 | filters.append("hostMac={}".format(mac))
45 | if name:
46 | filters.append("hostName={}".format(name))
47 | if len(filters) > 0:
48 | url += "?" + "&".join(filters)
49 |
50 | # Make API request and return the response body
51 | response = requests.request("GET", url, headers=headers, verify=False)
52 | return response.json()["response"]
53 |
54 |
55 | def verify_single_host(host, ip):
56 | """
57 | Simple function to verify only a single host returned from query.
58 | If no hosts, or multiple hosts are returned, an error message is printed
59 | and the program exits.
60 | """
61 | if len(host) == 0:
62 | print("Error: No host with IP address {} was found".format(ip))
63 | sys.exit(1)
64 | if len(host) > 1:
65 | print("Error: Multiple hosts with IP address {} were found".format(ip))
66 | print(json.dumps(host, indent=2))
67 | sys.exit(1)
68 |
69 |
70 | def print_host_details(host):
71 | """
72 | Print to screen interesting details about a given host.
73 | Input Paramters are:
74 | host_desc: string to describe this host. Example "Source"
75 | host: dictionary object of a host returned from dnac
76 | Standard Output Details:
77 | Host Name (hostName) - If available
78 | Host IP (hostIp)
79 | Host MAC (hostMac)
80 | Network Type (hostType) - wired/wireless
81 | Host Sub Type (subType)
82 | VLAN (vlanId)
83 | Connected Network Device (connectedNetworkDeviceIpAddress)
84 |
85 | Wired Host Details:
86 | Connected Interface Name (connectedInterfaceName)
87 |
88 | Wireless Host Details:
89 | Connected AP Name (connectedAPName)
90 | """
91 | # If optional host details missing, add as "Unavailable"
92 | if "hostName" not in host.keys():
93 | host["hostName"] = "Unavailable"
94 |
95 | # Print Standard Details
96 | print("Host Name: {}".format(host["hostName"]))
97 | print("Network Type: {}".format(host["hostType"]))
98 | print(
99 | "Connected Network Device: {}".format(
100 | host["connectedNetworkDeviceIpAddress"]
101 | )
102 | ) # noqa: E501
103 |
104 | # Print Wired/Wireless Details
105 | if host["hostType"] == "wired":
106 | print(
107 | "Connected Interface Name: {}".format(
108 | host["connectedInterfaceName"]
109 | )
110 | ) # noqa: E501
111 | if host["hostType"] == "wireless":
112 | print("Connected AP Name: {}".format(host["connectedAPName"]))
113 |
114 | # Print More Standard Details
115 | print("VLAN: {}".format(host["vlanId"]))
116 | print("Host IP: {}".format(host["hostIp"]))
117 | print("Host MAC: {}".format(host["hostMac"]))
118 | print("Host Sub Type: {}".format(host["subType"]))
119 |
120 | # Blank line at the end
121 | print("")
122 |
123 |
124 | def network_device_list(dnac, ticket, id=None):
125 | """
126 | Use the REST API to retrieve the list of network devices.
127 | If a device id is provided, return only that device
128 | """
129 | url = "https://{}/dna/intent/api/v1/network-device".format(dnac)
130 | headers["x-auth-token"] = ticket
131 |
132 | # Change URL to single device given an id
133 | if id:
134 | url += "/{}".format(id)
135 |
136 | # Make API request and return the response body
137 | response = requests.request("GET", url, headers=headers, verify=False)
138 |
139 | # Always return a list object, even if single device for consistency
140 | if id:
141 | return [response.json()["response"]]
142 |
143 | return response.json()["response"]
144 |
145 |
146 | def interface_details(dnac, ticket, id):
147 | """
148 | Use the REST API to retrieve details about an interface based on id.
149 | """
150 | url = "https://{}/dna/intent/api/v1/interface/{}".format(dnac, id)
151 | headers["x-auth-token"] = ticket
152 |
153 | response = requests.request("GET", url, headers=headers, verify=False)
154 | return response.json()["response"]
155 |
156 |
157 | def print_network_device_details(network_device):
158 | """
159 | Print to screen interesting details about a network device.
160 | Input Paramters are:
161 | network_device: dict object of a network device returned from dnac
162 | Standard Output Details:
163 | Device Hostname (hostname)
164 | Management IP (managementIpAddress)
165 | Device Location (locationName)
166 | Device Type (type)
167 | Platform Id (platformId)
168 | Device Role (role)
169 | Serial Number (serialNumber)
170 | Software Version (softwareVersion)
171 | Up Time (upTime)
172 | Reachability Status (reachabilityStatus)
173 | Error Code (errorCode)
174 | Error Description (errorDescription)
175 | """
176 |
177 | # Print Standard Details
178 | print("Device Hostname: {}".format(network_device["hostname"]))
179 | print("Management IP: {}".format(network_device["managementIpAddress"]))
180 | print("Device Location: {}".format(network_device["locationName"]))
181 | print("Device Type: {}".format(network_device["type"]))
182 | print("Platform Id: {}".format(network_device["platformId"]))
183 | print("Device Role: {}".format(network_device["role"]))
184 | print("Serial Number: {}".format(network_device["serialNumber"]))
185 | print("Software Version: {}".format(network_device["softwareVersion"]))
186 | print("Up Time: {}".format(network_device["upTime"]))
187 | print(
188 | "Reachability Status: {}".format(network_device["reachabilityStatus"])
189 | ) # noqa: E501
190 | print("Error Code: {}".format(network_device["errorCode"]))
191 | print("Error Description: {}".format(network_device["errorDescription"]))
192 |
193 | # Blank line at the end
194 | print("")
195 |
196 |
197 | def print_interface_details(interface):
198 | """
199 | Print to screen interesting details about an interface.
200 | Input Paramters are:
201 | interface: dictionary object of an interface returned from dnac
202 | Standard Output Details:
203 | Port Name - (portName)
204 | Interface Type (interfaceType) - Physical/Virtual
205 | Admin Status - (adminStatus)
206 | Operational Status (status)
207 | Media Type - (mediaType)
208 | Speed - (speed)
209 | Duplex Setting (duplex)
210 | Port Mode (portMode) - access/trunk/routed
211 | Interface VLAN - (vlanId)
212 | Voice VLAN - (voiceVlan)
213 | """
214 |
215 | # Print Standard Details
216 | print("Port Name: {}".format(interface["portName"]))
217 | print("Interface Type: {}".format(interface["interfaceType"]))
218 | print("Admin Status: {}".format(interface["adminStatus"]))
219 | print("Operational Status: {}".format(interface["status"]))
220 | print("Media Type: {}".format(interface["mediaType"]))
221 | print("Speed: {}".format(interface["speed"]))
222 | print("Duplex Setting: {}".format(interface["duplex"]))
223 | print("Port Mode: {}".format(interface["portMode"]))
224 | print("Interface VLAN: {}".format(interface["vlanId"]))
225 | print("Voice VLAN: {}".format(interface["voiceVlan"]))
226 |
227 | # Blank line at the end
228 | print("")
229 |
230 |
231 | def run_flow_analysis(dnac, ticket, source_ip, destination_ip):
232 | """
233 | Use the REST API to initiate a Flow Analysis (Path Trace) from a given
234 | source_ip to destination_ip. Function will wait for analysis to complete,
235 | and return the results.
236 | """
237 | base_url = "https://{}/dna/intent/api/v1/flow-analysis".format(dnac)
238 | headers["x-auth-token"] = ticket
239 |
240 | # initiate flow analysis
241 | body = {"destIP": destination_ip, "sourceIP": source_ip}
242 | initiate_response = requests.post(
243 | base_url, headers=headers, verify=False, json=body
244 | )
245 |
246 | # Verify successfully initiated. If not error and exit
247 | if initiate_response.status_code != 202:
248 | print("Error: Flow Analysis Initiation Failed")
249 | print(initiate_response.text)
250 | sys.exit(1)
251 |
252 | # Check status of analysis and wait until completed
253 | flowAnalysisId = initiate_response.json()["response"]["flowAnalysisId"]
254 | detail_url = base_url + "/{}".format(flowAnalysisId)
255 | detail_response = requests.get(detail_url, headers=headers, verify=False)
256 | while (
257 | not detail_response.json()["response"]["request"]["status"]
258 | == "COMPLETED"
259 | ): # noqa: E501
260 | print("Flow analysis not complete yet, waiting 5 seconds")
261 | sleep(5)
262 | detail_response = requests.get(
263 | detail_url, headers=headers, verify=False
264 | )
265 |
266 | # Return the flow analysis details
267 | return detail_response.json()["response"]
268 |
269 |
270 | def print_flow_analysis_details(flow_analysis):
271 | """
272 | Print to screen interesting details about the flow analysis.
273 | Input Parameters are:
274 | flow_analysis: dictionary object of a flow analysis returned from dnac
275 | """
276 | hops = flow_analysis["networkElementsInfo"]
277 |
278 | print("Number of Hops from Source to Destination: {}".format(len(hops)))
279 | print()
280 |
281 | # Print Details per hop
282 | print("Flow Details: ")
283 | # Hop 1 (index 0) and the last hop (index len - 1) represent the endpoints
284 | for i, hop in enumerate(hops):
285 | if i == 0 or i == len(hops) - 1:
286 | continue
287 |
288 | print("*" * 40)
289 | print("Hop {}: Network Device {}".format(i, hop["name"]))
290 | # If the hop is "UNKNOWN" continue along
291 | if hop["name"] == "UNKNOWN":
292 | print()
293 | continue
294 |
295 | print("Device IP: {}".format(hop["ip"]))
296 | print("Device Role: {}".format(hop["role"]))
297 |
298 | # If type is an Access Point, skip interface details
299 | if hop["type"] == "Unified AP":
300 | continue
301 | print()
302 |
303 | # Step 4: Are there any problems along the path?
304 | # Print details about each interface
305 | print("Ingress Interface")
306 | print("-" * 20)
307 | ingress = interface_details(
308 | dnac["host"],
309 | token,
310 | hop["ingressInterface"]["physicalInterface"]["id"],
311 | ) # noqa: E501
312 | print_interface_details(ingress)
313 | print("Egress Interface")
314 | print("-" * 20)
315 | egress = interface_details(
316 | dnac["host"],
317 | token,
318 | hop["egressInterface"]["physicalInterface"]["id"],
319 | ) # noqa: E501
320 | print_interface_details(egress)
321 |
322 | # Print blank line at end
323 | print("")
324 |
--------------------------------------------------------------------------------
/python_code_tips/modules_example/dnac_resources.py:
--------------------------------------------------------------------------------
1 | # DevNet Always-On Sandbox DNA Center
2 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/471eb739-323e-4805-b2a6-d0ec813dc8fc?diagramType=Topology
3 | dnac = {
4 | "host": "sandboxdnac2.cisco.com",
5 | "username": "devnetuser",
6 | "password": "Cisco123!",
7 | "port": 443,
8 | }
9 |
10 |
11 | headers = {"content-type": "application/json", "x-auth-token": ""}
12 |
--------------------------------------------------------------------------------
/python_code_tips/modules_example/modules_after.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | """
4 |
5 | # Import and functions
6 | from dnac_resources import dnac
7 | from dnac_functions import (
8 | dnac_login,
9 | host_list,
10 | verify_single_host,
11 | print_host_details,
12 | network_device_list,
13 | interface_details,
14 | print_network_device_details,
15 | print_interface_details,
16 | )
17 |
18 |
19 | # Entry point for program
20 | if __name__ == "__main__":
21 | # Setup Arg Parse for Command Line parameters
22 | import argparse
23 |
24 | parser = argparse.ArgumentParser()
25 |
26 | # Command Line Parameters for Source and Destination IP
27 | parser.add_argument("source_ip", help="Source IP Address")
28 | parser.add_argument("destination_ip", help="Destination IP Address")
29 | args = parser.parse_args()
30 |
31 | # Get Source and Destination IPs from Command Line
32 | source_ip = args.source_ip
33 | destination_ip = args.destination_ip
34 |
35 | # Print Starting message
36 | print("Running Troubleshooting Script for ")
37 | print(" Source IP: {} ".format(source_ip))
38 | print(" Destination IP: {}".format(destination_ip))
39 | print("")
40 |
41 | # Log into the dnac Controller to get Ticket
42 | token = dnac_login(
43 | dnac["host"], dnac["port"], dnac["username"], dnac["password"]
44 | )
45 |
46 | # Step 1: Identify involved hosts
47 | # Retrieve Host Details from dnac
48 | source_host = host_list(dnac["host"], token, ip=source_ip)
49 | destination_host = host_list(dnac["host"], token, ip=destination_ip)
50 |
51 | # Verify single host found for each IP
52 | verify_single_host(source_host, source_ip)
53 | verify_single_host(destination_host, destination_ip)
54 |
55 | # Print Out Host details
56 | print("Source Host Details:")
57 | print("-" * 25)
58 | print_host_details(source_host[0])
59 |
60 | print("Destination Host Details:")
61 | print("-" * 25)
62 | print_host_details(destination_host[0])
63 |
64 | # Step 2: Where are they in the network?
65 | # Retrieve and Print Source Device Details from dnac
66 | source_host_net_device = network_device_list(
67 | dnac["host"], token, id=source_host[0]["connectedNetworkDeviceId"]
68 | ) # noqa: E501
69 | print("Source Host Network Connection Details:")
70 | print("-" * 45)
71 | print_network_device_details(source_host_net_device[0])
72 | # If Host is wired, collect interface details
73 | if source_host[0]["hostType"] == "wired":
74 | source_host_interface = interface_details(
75 | dnac["host"], token, id=source_host[0]["connectedInterfaceId"]
76 | ) # noqa: E501
77 | print("Attached Interface:")
78 | print("-" * 20)
79 | print_interface_details(source_host_interface)
80 |
81 | destination_host_net_device = network_device_list(
82 | dnac["host"], token, id=destination_host[0]["connectedNetworkDeviceId"]
83 | ) # noqa: E501
84 | print("Destination Host Network Connection Details:")
85 | print("-" * 45)
86 | print_network_device_details(destination_host_net_device[0])
87 | # If Host is wired, collect interface details
88 | if destination_host[0]["hostType"] == "wired":
89 | destination_host_interface = interface_details(
90 | dnac["host"], token, id=destination_host[0]["connectedInterfaceId"]
91 | ) # noqa: E501
92 | print("Attached Interface:")
93 | print("-" * 20)
94 | print_interface_details(destination_host_interface)
95 |
--------------------------------------------------------------------------------
/python_code_tips/modules_example/modules_before.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | """
4 |
5 |
6 | from time import sleep
7 | import json
8 | import requests
9 | import sys
10 |
11 | # Diable InsecureRequestWarning
12 | requests.packages.urllib3.disable_warnings(
13 | requests.packages.urllib3.exceptions.InsecureRequestWarning
14 | )
15 |
16 | # DevNet Always-On Sandbox DNA Center
17 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/471eb739-323e-4805-b2a6-d0ec813dc8fc?diagramType=Topology
18 | dnac = {
19 | "host": "sandboxdnac2.cisco.com",
20 | "username": "devnetuser",
21 | "password": "Cisco123!",
22 | "port": 443,
23 | }
24 |
25 |
26 | headers = {"content-type": "application/json", "x-auth-token": ""}
27 |
28 |
29 | def dnac_login(dnac, port, username, password):
30 | """
31 | Use the REST API to Log into an DNA Center and retrieve ticket
32 | """
33 | url = "https://{}:{}/dna/system/api/v1/auth/token".format(dnac, port)
34 |
35 | # Make Login request and return the response body
36 | response = requests.request(
37 | "POST", url, auth=(username, password), headers=headers, verify=False
38 | )
39 | return response.json()["Token"]
40 |
41 |
42 | def host_list(dnac, ticket, ip=None, mac=None, name=None):
43 | """
44 | Use the REST API to retrieve the list of hosts.
45 | Optional parameters to filter by:
46 | IP address
47 | MAC address
48 | Hostname
49 | """
50 | url = "https://{}/api/v1/host".format(dnac)
51 | headers["x-auth-token"] = ticket
52 | filters = []
53 |
54 | # Add filters if provided
55 | if ip:
56 | filters.append("hostIp={}".format(ip))
57 | if mac:
58 | filters.append("hostMac={}".format(mac))
59 | if name:
60 | filters.append("hostName={}".format(name))
61 | if len(filters) > 0:
62 | url += "?" + "&".join(filters)
63 |
64 | # Make API request and return the response body
65 | response = requests.request("GET", url, headers=headers, verify=False)
66 | return response.json()["response"]
67 |
68 |
69 | def verify_single_host(host, ip):
70 | """
71 | Simple function to verify only a single host returned from query.
72 | If no hosts, or multiple hosts are returned, an error message is printed
73 | and the program exits.
74 | """
75 | if len(host) == 0:
76 | print("Error: No host with IP address {} was found".format(ip))
77 | sys.exit(1)
78 | if len(host) > 1:
79 | print("Error: Multiple hosts with IP address {} were found".format(ip))
80 | print(json.dumps(host, indent=2))
81 | sys.exit(1)
82 |
83 |
84 | def print_host_details(host):
85 | """
86 | Print to screen interesting details about a given host.
87 | Input Paramters are:
88 | host_desc: string to describe this host. Example "Source"
89 | host: dictionary object of a host returned from dnac
90 | Standard Output Details:
91 | Host Name (hostName) - If available
92 | Host IP (hostIp)
93 | Host MAC (hostMac)
94 | Network Type (hostType) - wired/wireless
95 | Host Sub Type (subType)
96 | VLAN (vlanId)
97 | Connected Network Device (connectedNetworkDeviceIpAddress)
98 |
99 | Wired Host Details:
100 | Connected Interface Name (connectedInterfaceName)
101 |
102 | Wireless Host Details:
103 | Connected AP Name (connectedAPName)
104 | """
105 | # If optional host details missing, add as "Unavailable"
106 | if "hostName" not in host.keys():
107 | host["hostName"] = "Unavailable"
108 |
109 | # Print Standard Details
110 | print("Host Name: {}".format(host["hostName"]))
111 | print("Network Type: {}".format(host["hostType"]))
112 | print(
113 | "Connected Network Device: {}".format(
114 | host["connectedNetworkDeviceIpAddress"]
115 | )
116 | ) # noqa: E501
117 |
118 | # Print Wired/Wireless Details
119 | if host["hostType"] == "wired":
120 | print(
121 | "Connected Interface Name: {}".format(
122 | host["connectedInterfaceName"]
123 | )
124 | ) # noqa: E501
125 | if host["hostType"] == "wireless":
126 | print("Connected AP Name: {}".format(host["connectedAPName"]))
127 |
128 | # Print More Standard Details
129 | print("VLAN: {}".format(host["vlanId"]))
130 | print("Host IP: {}".format(host["hostIp"]))
131 | print("Host MAC: {}".format(host["hostMac"]))
132 | print("Host Sub Type: {}".format(host["subType"]))
133 |
134 | # Blank line at the end
135 | print("")
136 |
137 |
138 | def network_device_list(dnac, ticket, id=None):
139 | """
140 | Use the REST API to retrieve the list of network devices.
141 | If a device id is provided, return only that device
142 | """
143 | url = "https://{}/dna/intent/api/v1/network-device".format(dnac)
144 | headers["x-auth-token"] = ticket
145 |
146 | # Change URL to single device given an id
147 | if id:
148 | url += "/{}".format(id)
149 |
150 | # Make API request and return the response body
151 | response = requests.request("GET", url, headers=headers, verify=False)
152 |
153 | # Always return a list object, even if single device for consistency
154 | if id:
155 | return [response.json()["response"]]
156 |
157 | return response.json()["response"]
158 |
159 |
160 | def interface_details(dnac, ticket, id):
161 | """
162 | Use the REST API to retrieve details about an interface based on id.
163 | """
164 | url = "https://{}/dna/intent/api/v1/interface/{}".format(dnac, id)
165 | headers["x-auth-token"] = ticket
166 |
167 | response = requests.request("GET", url, headers=headers, verify=False)
168 | return response.json()["response"]
169 |
170 |
171 | def print_network_device_details(network_device):
172 | """
173 | Print to screen interesting details about a network device.
174 | Input Paramters are:
175 | network_device: dict object of a network device returned from dnac
176 | Standard Output Details:
177 | Device Hostname (hostname)
178 | Management IP (managementIpAddress)
179 | Device Location (locationName)
180 | Device Type (type)
181 | Platform Id (platformId)
182 | Device Role (role)
183 | Serial Number (serialNumber)
184 | Software Version (softwareVersion)
185 | Up Time (upTime)
186 | Reachability Status (reachabilityStatus)
187 | Error Code (errorCode)
188 | Error Description (errorDescription)
189 | """
190 |
191 | # Print Standard Details
192 | print("Device Hostname: {}".format(network_device["hostname"]))
193 | print("Management IP: {}".format(network_device["managementIpAddress"]))
194 | print("Device Location: {}".format(network_device["locationName"]))
195 | print("Device Type: {}".format(network_device["type"]))
196 | print("Platform Id: {}".format(network_device["platformId"]))
197 | print("Device Role: {}".format(network_device["role"]))
198 | print("Serial Number: {}".format(network_device["serialNumber"]))
199 | print("Software Version: {}".format(network_device["softwareVersion"]))
200 | print("Up Time: {}".format(network_device["upTime"]))
201 | print(
202 | "Reachability Status: {}".format(network_device["reachabilityStatus"])
203 | ) # noqa: E501
204 | print("Error Code: {}".format(network_device["errorCode"]))
205 | print("Error Description: {}".format(network_device["errorDescription"]))
206 |
207 | # Blank line at the end
208 | print("")
209 |
210 |
211 | def print_interface_details(interface):
212 | """
213 | Print to screen interesting details about an interface.
214 | Input Paramters are:
215 | interface: dictionary object of an interface returned from dnac
216 | Standard Output Details:
217 | Port Name - (portName)
218 | Interface Type (interfaceType) - Physical/Virtual
219 | Admin Status - (adminStatus)
220 | Operational Status (status)
221 | Media Type - (mediaType)
222 | Speed - (speed)
223 | Duplex Setting (duplex)
224 | Port Mode (portMode) - access/trunk/routed
225 | Interface VLAN - (vlanId)
226 | Voice VLAN - (voiceVlan)
227 | """
228 |
229 | # Print Standard Details
230 | print("Port Name: {}".format(interface["portName"]))
231 | print("Interface Type: {}".format(interface["interfaceType"]))
232 | print("Admin Status: {}".format(interface["adminStatus"]))
233 | print("Operational Status: {}".format(interface["status"]))
234 | print("Media Type: {}".format(interface["mediaType"]))
235 | print("Speed: {}".format(interface["speed"]))
236 | print("Duplex Setting: {}".format(interface["duplex"]))
237 | print("Port Mode: {}".format(interface["portMode"]))
238 | print("Interface VLAN: {}".format(interface["vlanId"]))
239 | print("Voice VLAN: {}".format(interface["voiceVlan"]))
240 |
241 | # Blank line at the end
242 | print("")
243 |
244 |
245 | # Entry point for program
246 | if __name__ == "__main__":
247 | # Setup Arg Parse for Command Line parameters
248 | import argparse
249 |
250 | parser = argparse.ArgumentParser()
251 |
252 | # Command Line Parameters for Source and Destination IP
253 | parser.add_argument("source_ip", help="Source IP Address")
254 | parser.add_argument("destination_ip", help="Destination IP Address")
255 | args = parser.parse_args()
256 |
257 | # Get Source and Destination IPs from Command Line
258 | source_ip = args.source_ip
259 | destination_ip = args.destination_ip
260 |
261 | # Print Starting message
262 | print("Running Troubleshooting Script for ")
263 | print(" Source IP: {} ".format(source_ip))
264 | print(" Destination IP: {}".format(destination_ip))
265 | print("")
266 |
267 | # Log into the dnac Controller to get Ticket
268 | token = dnac_login(
269 | dnac["host"], dnac["port"], dnac["username"], dnac["password"]
270 | )
271 |
272 | # Step 1: Identify involved hosts
273 | # Retrieve Host Details from dnac
274 | source_host = host_list(dnac["host"], token, ip=source_ip)
275 | destination_host = host_list(dnac["host"], token, ip=destination_ip)
276 |
277 | # Verify single host found for each IP
278 | verify_single_host(source_host, source_ip)
279 | verify_single_host(destination_host, destination_ip)
280 |
281 | # Print Out Host details
282 | print("Source Host Details:")
283 | print("-" * 25)
284 | print_host_details(source_host[0])
285 |
286 | print("Destination Host Details:")
287 | print("-" * 25)
288 | print_host_details(destination_host[0])
289 |
290 | # Step 2: Where are they in the network?
291 | # Retrieve and Print Source Device Details from dnac
292 | source_host_net_device = network_device_list(
293 | dnac["host"], token, id=source_host[0]["connectedNetworkDeviceId"]
294 | ) # noqa: E501
295 | print("Source Host Network Connection Details:")
296 | print("-" * 45)
297 | print_network_device_details(source_host_net_device[0])
298 | # If Host is wired, collect interface details
299 | if source_host[0]["hostType"] == "wired":
300 | source_host_interface = interface_details(
301 | dnac["host"], token, id=source_host[0]["connectedInterfaceId"]
302 | ) # noqa: E501
303 | print("Attached Interface:")
304 | print("-" * 20)
305 | print_interface_details(source_host_interface)
306 |
307 | destination_host_net_device = network_device_list(
308 | dnac["host"], token, id=destination_host[0]["connectedNetworkDeviceId"]
309 | ) # noqa: E501
310 | print("Destination Host Network Connection Details:")
311 | print("-" * 45)
312 | print_network_device_details(destination_host_net_device[0])
313 | # If Host is wired, collect interface details
314 | if destination_host[0]["hostType"] == "wired":
315 | destination_host_interface = interface_details(
316 | dnac["host"], token, id=destination_host[0]["connectedInterfaceId"]
317 | ) # noqa: E501
318 | print("Attached Interface:")
319 | print("-" * 20)
320 | print_interface_details(destination_host_interface)
321 |
--------------------------------------------------------------------------------
/python_code_tips/objects_example/dnac/__init__.py:
--------------------------------------------------------------------------------
1 | """Basic package for interacting with Cisco DNA Center"""
2 |
3 | from .DNAC import DNAC
4 |
--------------------------------------------------------------------------------
/python_code_tips/objects_example/host_troubleshooting.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Discover details about Cisco DNA Center connected hosts.
4 | """
5 |
6 | # Import and functions
7 | from dnac import DNAC
8 |
9 |
10 | # Entry point for program
11 | if __name__ == "__main__":
12 | # Setup Arg Parse for Command Line parameters
13 | import argparse
14 |
15 | parser = argparse.ArgumentParser()
16 |
17 | # Command Line Parameters for Source and Destination IP
18 | parser.add_argument("source_ip", help="Source IP Address")
19 | parser.add_argument("destination_ip", help="Destination IP Address")
20 | parser.add_argument(
21 | "--dnac", help="Address for Cisco DNA Center", required=True
22 | )
23 | parser.add_argument(
24 | "--port",
25 | help="Override default port of 443 for Cisco DNA Center",
26 | required=False,
27 | default=443,
28 | )
29 | parser.add_argument(
30 | "--username", help="Username for Cisco DNA Center", required=True
31 | )
32 | parser.add_argument(
33 | "--password", help="Password for Cisco DNA Center", required=True
34 | )
35 | args = parser.parse_args()
36 |
37 | # Get Source and Destination IPs from Command Line
38 | source_ip = args.source_ip
39 | destination_ip = args.destination_ip
40 |
41 | # Print Starting message
42 | print("Running Troubleshooting Script for ")
43 | print(" Source IP: {} ".format(source_ip))
44 | print(" Destination IP: {}".format(destination_ip))
45 | print("")
46 |
47 | # Initialize Cisco DNA Center Object
48 | dnac = DNAC(
49 | address=args.dnac,
50 | port=args.port,
51 | username=args.username,
52 | password=args.password,
53 | )
54 |
55 | # Step 1: Identify involved hosts
56 | # Retrieve Host Details from dnac
57 | source_host = dnac.host_list(ip=source_ip)
58 | destination_host = dnac.host_list(ip=destination_ip)
59 |
60 | # Verify single host found for each IP
61 | dnac.verify_single_host(source_host, source_ip)
62 | dnac.verify_single_host(destination_host, destination_ip)
63 |
64 | # Print Out Host details
65 | print("Source Host Details:")
66 | print("-" * 25)
67 | dnac.print_host_details(source_host[0])
68 |
69 | print("Destination Host Details:")
70 | print("-" * 25)
71 | dnac.print_host_details(destination_host[0])
72 |
73 | # Step 2: Where are they in the network?
74 | # Retrieve and Print Source Device Details from dnac
75 | source_host_net_device = dnac.network_device_list(
76 | id=source_host[0]["connectedNetworkDeviceId"]
77 | ) # noqa: E501
78 | print("Source Host Network Connection Details:")
79 | print("-" * 45)
80 | dnac.print_network_device_details(source_host_net_device[0])
81 | # If Host is wired, collect interface details
82 | if source_host[0]["hostType"] == "wired":
83 | source_host_interface = dnac.interface_details(
84 | id=source_host[0]["connectedInterfaceId"]
85 | ) # noqa: E501
86 | print("Attached Interface:")
87 | print("-" * 20)
88 | dnac.print_interface_details(source_host_interface)
89 |
90 | destination_host_net_device = dnac.network_device_list(
91 | id=destination_host[0]["connectedNetworkDeviceId"]
92 | ) # noqa: E501
93 | print("Destination Host Network Connection Details:")
94 | print("-" * 45)
95 | dnac.print_network_device_details(destination_host_net_device[0])
96 | # If Host is wired, collect interface details
97 | if destination_host[0]["hostType"] == "wired":
98 | destination_host_interface = dnac.interface_details(
99 | id=destination_host[0]["connectedInterfaceId"]
100 | ) # noqa: E501
101 | print("Attached Interface:")
102 | print("-" * 20)
103 | dnac.print_interface_details(destination_host_interface)
104 |
--------------------------------------------------------------------------------
/python_code_tips/packages_example/dnac/__init__.py:
--------------------------------------------------------------------------------
1 | """Basic package for interacting with Cisco DNA Center"""
2 |
3 | from .dnac_resources import dnac
4 | from .dnac_functions import (
5 | dnac_login,
6 | host_list,
7 | verify_single_host,
8 | print_host_details,
9 | network_device_list,
10 | interface_details,
11 | print_network_device_details,
12 | print_interface_details,
13 | )
14 |
--------------------------------------------------------------------------------
/python_code_tips/packages_example/dnac/dnac_resources.py:
--------------------------------------------------------------------------------
1 | # DevNet Always-On Sandbox DNA Center
2 | # https://devnetsandbox.cisco.com/RM/Diagram/Index/471eb739-323e-4805-b2a6-d0ec813dc8fc?diagramType=Topology
3 | dnac = {
4 | "host": "sandboxdnac2.cisco.com",
5 | "username": "devnetuser",
6 | "password": "Cisco123!",
7 | "port": 443,
8 | }
9 |
10 |
11 | headers = {"content-type": "application/json", "x-auth-token": ""}
12 |
--------------------------------------------------------------------------------
/python_code_tips/packages_example/host_troubleshooting.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """
3 | Discover details about Cisco DNA Center connected hosts.
4 | """
5 |
6 | # Import and functions
7 | from dnac import (
8 | dnac,
9 | dnac_login,
10 | host_list,
11 | verify_single_host,
12 | print_host_details,
13 | network_device_list,
14 | interface_details,
15 | print_network_device_details,
16 | print_interface_details,
17 | )
18 |
19 |
20 | # Entry point for program
21 | if __name__ == "__main__":
22 | # Setup Arg Parse for Command Line parameters
23 | import argparse
24 |
25 | parser = argparse.ArgumentParser()
26 |
27 | # Command Line Parameters for Source and Destination IP
28 | parser.add_argument("source_ip", help="Source IP Address")
29 | parser.add_argument("destination_ip", help="Destination IP Address")
30 | args = parser.parse_args()
31 |
32 | # Get Source and Destination IPs from Command Line
33 | source_ip = args.source_ip
34 | destination_ip = args.destination_ip
35 |
36 | # Print Starting message
37 | print("Running Troubleshooting Script for ")
38 | print(" Source IP: {} ".format(source_ip))
39 | print(" Destination IP: {}".format(destination_ip))
40 | print("")
41 |
42 | # Log into the dnac Controller to get Ticket
43 | token = dnac_login(
44 | dnac["host"], dnac["port"], dnac["username"], dnac["password"]
45 | )
46 |
47 | # Step 1: Identify involved hosts
48 | # Retrieve Host Details from dnac
49 | source_host = host_list(dnac["host"], token, ip=source_ip)
50 | destination_host = host_list(dnac["host"], token, ip=destination_ip)
51 |
52 | # Verify single host found for each IP
53 | verify_single_host(source_host, source_ip)
54 | verify_single_host(destination_host, destination_ip)
55 |
56 | # Print Out Host details
57 | print("Source Host Details:")
58 | print("-" * 25)
59 | print_host_details(source_host[0])
60 |
61 | print("Destination Host Details:")
62 | print("-" * 25)
63 | print_host_details(destination_host[0])
64 |
65 | # Step 2: Where are they in the network?
66 | # Retrieve and Print Source Device Details from dnac
67 | source_host_net_device = network_device_list(
68 | dnac["host"], token, id=source_host[0]["connectedNetworkDeviceId"]
69 | ) # noqa: E501
70 | print("Source Host Network Connection Details:")
71 | print("-" * 45)
72 | print_network_device_details(source_host_net_device[0])
73 | # If Host is wired, collect interface details
74 | if source_host[0]["hostType"] == "wired":
75 | source_host_interface = interface_details(
76 | dnac["host"], token, id=source_host[0]["connectedInterfaceId"]
77 | ) # noqa: E501
78 | print("Attached Interface:")
79 | print("-" * 20)
80 | print_interface_details(source_host_interface)
81 |
82 | destination_host_net_device = network_device_list(
83 | dnac["host"], token, id=destination_host[0]["connectedNetworkDeviceId"]
84 | ) # noqa: E501
85 | print("Destination Host Network Connection Details:")
86 | print("-" * 45)
87 | print_network_device_details(destination_host_net_device[0])
88 | # If Host is wired, collect interface details
89 | if destination_host[0]["hostType"] == "wired":
90 | destination_host_interface = interface_details(
91 | dnac["host"], token, id=destination_host[0]["connectedInterfaceId"]
92 | ) # noqa: E501
93 | print("Attached Interface:")
94 | print("-" * 20)
95 | print_interface_details(destination_host_interface)
96 |
--------------------------------------------------------------------------------
/requirements-win.txt:
--------------------------------------------------------------------------------
1 | ipython==6.5.0
2 | napalm==2.3.1
3 | ncclient==0.6.0
4 | netmiko==2.2.2
5 | pyang==1.7.5
6 | pysnmp==4.4.4
7 | pyyaml>=4.2b1
8 | requests>=2.20.0
9 | urllib3==1.23
10 | virlutils==0.8.4
11 | xmltodict==0.11.0
12 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | ansible==2.6.3
2 | black==19.3b0
3 | flake8==3.7.7
4 | genie==19.0.1
5 | ipython==6.5.0
6 | napalm==2.4.0
7 | ncclient==0.6.3
8 | netmiko==2.3.3
9 | pyang==1.7.5
10 | pyats==19.0
11 | PyYAML==5.1
12 | requests==2.21.0
13 | urllib3==1.24.1
14 | virlutils==0.8.4
15 | xmltodict==0.12.0
16 |
--------------------------------------------------------------------------------
/setup/ansible.cfg:
--------------------------------------------------------------------------------
1 | # config file for ansible
2 | # override global certain global settings
3 |
4 | [defaults]
5 | # default to inventory file of ./hosts
6 | inventory = ./default_inventory.yaml
7 | # disable host checking to automatically add hosts to known_hosts
8 | host_key_checking = False
9 | # set the roles path to the local directory
10 | roles_path = ./roles/
11 |
12 | [persistent_connection]
13 | connect_timeout = 300
14 | command_timeout = 300
15 | connect_retry_timeout = 300
16 |
--------------------------------------------------------------------------------
/setup/configs/README.md:
--------------------------------------------------------------------------------
1 | Constructed configuration files stored here.
2 |
--------------------------------------------------------------------------------
/setup/group_vars/access.yaml:
--------------------------------------------------------------------------------
1 | ansible_network_os: nxos
2 | portchannels:
3 | - port_channel_id: 11
4 | vpc: false
5 | members:
6 | - Ethernet1/1
7 | - Ethernet1/2
8 |
--------------------------------------------------------------------------------
/setup/group_vars/all.yaml:
--------------------------------------------------------------------------------
1 | ansible_python_interpreter: /usr/bin/env python
2 | ansible_user: cisco
3 | ansible_ssh_pass: cisco
4 | ansible_become: no
5 | ansible_become_method: enable
6 | ansible_become_pass: cisco
7 | snmp_ro_community: public
8 | snmp_rw_community: private
9 | vlans:
10 | - id: 100
11 | name: Management
12 | gateway: 172.20.100.1
13 | - id: 101
14 | name: Private
15 | gateway: 172.20.101.1
16 | - id: 102
17 | name: Guest
18 | gateway: 172.20.102.1
19 | - id: 103
20 | name: Security
21 | gateway: 172.20.103.1
22 |
--------------------------------------------------------------------------------
/setup/group_vars/core.yaml:
--------------------------------------------------------------------------------
1 | ansible_network_os: ios
2 | ospf:
3 | process_id: 1
4 |
--------------------------------------------------------------------------------
/setup/group_vars/distribution.yaml:
--------------------------------------------------------------------------------
1 | ansible_network_os: nxos
2 | hsrp:
3 | interfaces:
4 | - interface: vlan100
5 | group: 10
6 | vip: 172.16.100.1
7 | - interface: vlan101
8 | group: 10
9 | vip: 172.16.101.1
10 | - interface: vlan102
11 | group: 10
12 | vip: 172.16.102.1
13 | - interface: vlan103
14 | group: 10
15 | vip: 172.16.103.1
16 | ospf:
17 | process_id: 1
18 | networks:
19 | - interface: Ethernet1/5
20 | area: 0
21 | - interface: Ethernet1/6
22 | area: 0
23 | - interface: vlan100
24 | area: 0
25 | - interface: vlan101
26 | area: 0
27 | - interface: vlan102
28 | area: 0
29 | - interface: vlan103
30 | area: 0
31 | - interface: loopback0
32 | area: 0
33 | vpc:
34 | domain: 100
35 | pkl_vrf: management
36 | port_channel:
37 | id: 1
38 | members:
39 | - Ethernet1/3
40 | - Ethernet1/4
41 | portchannels:
42 | - port_channel_id: 11
43 | vpc: true
44 | members:
45 | - Ethernet1/1
46 |
--------------------------------------------------------------------------------
/setup/host_vars/access1.yaml:
--------------------------------------------------------------------------------
1 | provider:
2 | host: "{{ ansible_host }}"
3 | username: cisco
4 | password: cisco
5 | auth_pass: cisco
6 | authorize: no
7 | port: 22
8 | timeout: 15
9 | l3_interfaces:
10 | - interface_type: Loopback
11 | interface_id: 0
12 | description: Default Loopback
13 | ip_address: 192.168.0.2
14 | subnet_mask: 255.255.255.255
15 | prefix: 32
16 | area: 0
17 |
--------------------------------------------------------------------------------
/setup/host_vars/core1.yaml:
--------------------------------------------------------------------------------
1 | provider:
2 | host: "{{ ansible_host }}"
3 | username: cisco
4 | password: cisco
5 | auth_pass: cisco
6 | authorize: no
7 | port: 22
8 | timeout: 20
9 | l3_interfaces:
10 | - interface_type: GigabitEthernet
11 | interface_id: 2
12 | description: L3 Link to dist1
13 | ip_address: 172.16.0.1
14 | subnet_mask: 255.255.255.252
15 | prefix: 30
16 | - interface_type: GigabitEthernet
17 | interface_id: 3
18 | description: L3 Link to dist2
19 | ip_address: 172.16.0.5
20 | subnet_mask: 255.255.255.252
21 | prefix: 30
22 | - interface_type: GigabitEthernet
23 | interface_id: 4
24 | description: L3 Link to core2
25 | ip_address: 172.16.0.17
26 | subnet_mask: 255.255.255.252
27 | prefix: 30
28 | - interface_type: Loopback
29 | interface_id: 0
30 | description: Default Loopback
31 | ip_address: 192.168.1.1
32 | subnet_mask: 255.255.255.255
33 | prefix: 32
34 | ospf_router_id: 192.168.1.1
35 | ospf_networks:
36 | - network: 172.16.0.0
37 | mask: 0.0.0.3
38 | area: 0
39 | - network: 172.16.0.4
40 | mask: 0.0.0.3
41 | area: 0
42 | - network: 172.16.0.16
43 | mask: 0.0.0.3
44 | area: 0
45 | - network: 192.168.1.1
46 | mask: 0.0.0.0
47 | area: 0
48 |
--------------------------------------------------------------------------------
/setup/host_vars/core2.yaml:
--------------------------------------------------------------------------------
1 | provider:
2 | host: "{{ ansible_host }}"
3 | username: cisco
4 | password: cisco
5 | auth_pass: cisco
6 | authorize: no
7 | port: 22
8 | timeout: 20
9 | l3_interfaces:
10 | - interface_type: GigabitEthernet
11 | interface_id: 2
12 | description: L3 Link to dist2
13 | ip_address: 172.16.0.13
14 | subnet_mask: 255.255.255.252
15 | prefix: 30
16 | - interface_type: GigabitEthernet
17 | interface_id: 3
18 | description: L3 Link to dist1
19 | ip_address: 172.16.0.9
20 | subnet_mask: 255.255.255.252
21 | prefix: 30
22 | - interface_type: GigabitEthernet
23 | interface_id: 4
24 | description: L3 Link to core1
25 | ip_address: 172.16.0.18
26 | subnet_mask: 255.255.255.252
27 | prefix: 30
28 | - interface_type: Loopback
29 | interface_id: 0
30 | description: Default Loopback
31 | ip_address: 192.168.1.2
32 | subnet_mask: 255.255.255.255
33 | prefix: 32
34 | ospf_router_id: 192.168.1.2
35 | ospf_networks:
36 | - network: 172.16.0.12
37 | mask: 0.0.0.3
38 | area: 0
39 | - network: 172.16.0.8
40 | mask: 0.0.0.3
41 | area: 0
42 | - network: 172.16.0.16
43 | mask: 0.0.0.3
44 | area: 0
45 | - network: 192.168.1.2
46 | mask: 0.0.0.0
47 | area: 0
48 |
--------------------------------------------------------------------------------
/setup/host_vars/dist1.yaml:
--------------------------------------------------------------------------------
1 | provider:
2 | host: "{{ ansible_host }}"
3 | username: cisco
4 | password: cisco
5 | auth_pass: cisco
6 | authorize: no
7 | port: 22
8 | timeout: 15
9 | ospf_router_id: 192.168.0.1
10 | vpc_pkl_src: 172.16.30.101
11 | vpc_pkl_dest: 172.16.30.102
12 | l3_interfaces:
13 | - interface_type: Loopback
14 | interface_id: 0
15 | description: Default Loopback
16 | ip_address: 192.168.0.1
17 | subnet_mask: 255.255.255.255
18 | prefix: 32
19 | area: 0
20 | - interface_type: Ethernet
21 | interface_id: 1/5
22 | description: L3 Link to core1
23 | ip_address: 172.16.0.2
24 | subnet_mask: 255.255.255.252
25 | prefix: 30
26 | area: 0
27 | - interface_type: Ethernet
28 | interface_id: 1/6
29 | description: L3 Link to core2
30 | ip_address: 172.16.0.10
31 | subnet_mask: 255.255.255.252
32 | prefix: 30
33 | area: 0
34 | - interface_type: vlan
35 | interface_id: 100
36 | description: VLAN Interface - Management
37 | ip_address: 172.16.100.2
38 | subnet_mask: 255.255.255.0
39 | prefix: 24
40 | area: 0
41 | - interface_type: vlan
42 | interface_id: 101
43 | description: VLAN Interface - Private
44 | ip_address: 172.16.101.2
45 | subnet_mask: 255.255.255.0
46 | prefix: 24
47 | area: 0
48 | - interface_type: vlan
49 | interface_id: 102
50 | description: VLAN Interface - Guest
51 | ip_address: 172.16.102.2
52 | subnet_mask: 255.255.255.0
53 | prefix: 24
54 | area: 0
55 | - interface_type: vlan
56 | interface_id: 103
57 | description: VLAN Interface - Security
58 | ip_address: 172.16.103.2
59 | subnet_mask: 255.255.255.0
60 | prefix: 24
61 | area: 0
62 |
--------------------------------------------------------------------------------
/setup/host_vars/dist2.yaml:
--------------------------------------------------------------------------------
1 | provider:
2 | host: "{{ ansible_host }}"
3 | username: cisco
4 | password: cisco
5 | auth_pass: cisco
6 | authorize: no
7 | port: 22
8 | timeout: 15
9 | ospf_router_id: 192.168.0.2
10 | vpc_pkl_src: 172.16.30.102
11 | vpc_pkl_dest: 172.16.30.101
12 | l3_interfaces:
13 | - interface_type: Loopback
14 | interface_id: 0
15 | description: Default Loopback
16 | ip_address: 192.168.0.2
17 | subnet_mask: 255.255.255.255
18 | prefix: 32
19 | area: 0
20 | - interface_type: Ethernet
21 | interface_id: 1/5
22 | description: L3 Link to core2
23 | ip_address: 172.16.0.14
24 | subnet_mask: 255.255.255.252
25 | prefix: 30
26 | area: 0
27 | - interface_type: Ethernet
28 | interface_id: 1/6
29 | description: L3 Link to core1
30 | ip_address: 172.16.0.6
31 | subnet_mask: 255.255.255.252
32 | prefix: 30
33 | area: 0
34 | - interface_type: vlan
35 | interface_id: 100
36 | description: VLAN Interface - Management
37 | ip_address: 172.16.100.3
38 | subnet_mask: 255.255.255.0
39 | prefix: 24
40 | area: 0
41 | - interface_type: vlan
42 | interface_id: 101
43 | description: VLAN Interface - Private
44 | ip_address: 172.16.101.3
45 | subnet_mask: 255.255.255.0
46 | prefix: 24
47 | area: 0
48 | - interface_type: vlan
49 | interface_id: 102
50 | description: VLAN Interface - Guest
51 | ip_address: 172.16.102.3
52 | subnet_mask: 255.255.255.0
53 | prefix: 24
54 | area: 0
55 | - interface_type: vlan
56 | interface_id: 103
57 | description: VLAN Interface - Security
58 | ip_address: 172.16.103.3
59 | subnet_mask: 255.255.255.0
60 | prefix: 24
61 | area: 0
62 |
--------------------------------------------------------------------------------
/setup/network_deploy.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Wait for all devices to be available
3 | hosts: all
4 | connection: local
5 | gather_facts: false
6 |
7 | tasks:
8 | - wait_for:
9 | port: 22
10 | sleep: 10
11 |
12 | - name: Gather Facts about Network
13 | hosts: all
14 | connection: network_cli
15 | gather_facts: false
16 |
17 | roles:
18 | - network_inspect
19 |
20 | - name: Enable Network APIs
21 | hosts: all
22 | connection: network_cli
23 | gather_facts: false
24 |
25 | roles:
26 | - network_enable_api
27 |
28 | - name: Configure Network Core
29 | hosts: core
30 | connection: local
31 | gather_facts: false
32 |
33 | roles:
34 | - network_interface
35 | - network_ospf
36 |
37 | - name: Configure Distribution Switches
38 | hosts: distribution
39 | connection: network_cli
40 | gather_facts: false
41 |
42 | roles:
43 | - network_vlan
44 | - network_vpc
45 | - network_interface
46 | - network_ospf
47 |
48 | - name: Configure Access Switches
49 | hosts: access
50 | connection: network_cli
51 | gather_facts: false
52 |
53 | roles:
54 | - network_vlan
55 | - network_interface
56 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_enable_api
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_enable_api
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/tasks/ios.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Configure NETCONF
3 | tags: [api, netconf]
4 | ios_config:
5 | provider: "{{provider}}"
6 | lines:
7 | - netconf-yang
8 | - netconf-yang cisco-odm polling-enable
9 | - restconf
10 | - ip http server
11 | - ip http secure-server
12 |
13 | - name: Configure SNMP
14 | tags: [api]
15 | ios_config:
16 | provider: "{{provider}}"
17 | lines:
18 | - snmp-server community {{ snmp_ro_community | default('public') }} ro
19 | - snmp-server community {{ snmp_rw_community | default('private') }} rw
20 |
21 | - name: Pause for NETCONF to start
22 | pause:
23 | seconds: 45
24 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_enable_api
3 | - name: IOS Devices
4 | include_tasks: ios.yml
5 | when: ansible_network_os == "ios"
6 | - name: NX-OS Devices
7 | include_tasks: nxos.yml
8 | when: ansible_network_os == "nxos"
9 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/tasks/nxos.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable NX-API
3 | tags: [api, nxapi]
4 | nxos_feature:
5 | provider: "{{provider}}"
6 | feature: nxapi
7 | state: enabled
8 |
9 | - name: Enable SNMP
10 | tags: [api]
11 | nxos_config:
12 | provider: "{{provider}}"
13 | lines:
14 | - snmp-server community {{ snmp_ro_community | default('public') }} ro
15 | - snmp-server community {{ snmp_rw_community | default('private') }} rw
16 |
17 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_enable_api
--------------------------------------------------------------------------------
/setup/roles/network_enable_api/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_enable_api
--------------------------------------------------------------------------------
/setup/roles/network_inspect/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_inspect/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_inspect
--------------------------------------------------------------------------------
/setup/roles/network_inspect/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_inspect
--------------------------------------------------------------------------------
/setup/roles/network_inspect/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_inspect/tasks/ios.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Gather IOS Facts
3 | ios_facts:
4 | provider: "{{ provider }}"
5 | gather_subset: all
6 |
--------------------------------------------------------------------------------
/setup/roles/network_inspect/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_inspect
3 | - name: Inspect IOS
4 | include_tasks: ios.yml
5 | when: ansible_network_os == "ios"
6 | - name: Inspect NX-OS
7 | include_tasks: nxos.yml
8 | when: ansible_network_os == "nxos"
9 |
10 | - name: Device Info
11 | debug:
12 | msg: "Device Type: {{ ansible_network_os }} OS Version: {{ ansible_net_version }}"
13 |
--------------------------------------------------------------------------------
/setup/roles/network_inspect/tasks/nxos.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Gather NX-OS Facts
3 | nxos_facts:
4 | provider: "{{ provider }}"
5 | gather_subset: all
6 |
--------------------------------------------------------------------------------
/setup/roles/network_inspect/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_inspect/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_inspect
--------------------------------------------------------------------------------
/setup/roles/network_inspect/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_inspect
--------------------------------------------------------------------------------
/setup/roles/network_interface/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_interface
--------------------------------------------------------------------------------
/setup/roles/network_interface/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_interface
--------------------------------------------------------------------------------
/setup/roles/network_interface/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_interface/tasks/hsrp_nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable Features
3 | tags: [api, nxapi, hsrp]
4 | with_items:
5 | - hsrp
6 | nxos_feature:
7 | provider: "{{provider}}"
8 | feature: "{{ item }}"
9 | state: enabled
10 |
11 | - name: Configure HSRP
12 | tags: [api, nxapi, hsrp]
13 | with_items: "{{ hsrp.interfaces }}"
14 | nxos_hsrp:
15 | provider: "{{provider}}"
16 | group: "{{ item.group }}"
17 | vip: "{{ item.vip }}"
18 | interface: "{{ item.interface }}"
19 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tasks/l3_netconf.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "Generate NETCONF Interface config"
3 | tags: [api, netconf, layer3]
4 | with_items: "{{l3_interfaces}}"
5 | template:
6 | src: "templates/ietf_interface_template.j2"
7 | dest: "./configs/{{inventory_hostname}}-{{item.interface_type}}{{item.interface_id}}.xml"
8 |
9 | - name: Configure Interfaces with NETCONF
10 | tags: [api, netconf, layer3]
11 | with_items: "{{l3_interfaces}}"
12 | netconf_config:
13 | host: "{{provider.host}}"
14 | hostkey_verify: false
15 | username: "{{provider.username}}"
16 | password: "{{provider.password}}"
17 | port: "{{netconf_port | default(830)}}"
18 | src: "./configs/{{inventory_hostname}}-{{item.interface_type}}{{item.interface_id}}.xml"
19 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tasks/l3_nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable Features
3 | tags: [api, nxapi, layer3]
4 | with_items:
5 | - interface-vlan
6 | nxos_feature:
7 | provider: "{{provider}}"
8 | feature: "{{ item }}"
9 | state: enabled
10 |
11 | - name: Configure Layer 3 Interfaces
12 | tags: [api, nxapi, layer3]
13 | with_items: "{{ l3_interfaces }}"
14 | nxos_interface:
15 | provider: "{{provider}}"
16 | interface: "{{ item.interface_type }}{{ item.interface_id }}"
17 | # mode: layer3
18 | description: "{{ item.description }}"
19 | admin_state: up
20 |
21 | - name: Ethernet and PortChannel Enable Layer 3
22 | tags: [api, nxapi, layer3]
23 | with_items: "{{ l3_interfaces }}"
24 | when: item.interface_type in ["Ethernet", "PortChannel"]
25 | nxos_interface:
26 | provider: "{{provider}}"
27 | interface: "{{ item.interface_type }}{{ item.interface_id }}"
28 | mode: layer3
29 |
30 |
31 | - name: Configure IPv4 Address on Interface
32 | tags: [api, nxapi, layer3]
33 | with_items: "{{ l3_interfaces }}"
34 | nxos_ip_interface:
35 | provider: "{{provider}}"
36 | interface: "{{ item.interface_type }}{{ item.interface_id }}"
37 | version: v4
38 | addr: "{{ item.ip_address }}"
39 | mask: "{{ item.prefix }}"
40 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_interface
3 | - name: IOS Devices L3 Interfaces
4 | include_tasks: l3_netconf.yml
5 | when: ansible_network_os == "ios" and l3_interfaces is defined
6 | - name: NX-OS Devices L3 Interfaces
7 | include_tasks: l3_nxapi.yml
8 | when: ansible_network_os == "nxos" and l3_interfaces is defined
9 | - name: NX-OS Devices HSRP Configuration
10 | include_tasks: hsrp_nxapi.yml
11 | when: ansible_network_os == "nxos" and hsrp is defined
12 | - name: NX-OS Devices PortChannels
13 | include_tasks: portchannel_nxapi.yml
14 | when: ansible_network_os == "nxos" and portchannels is defined
15 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tasks/portchannel_nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable Features
3 | tags: [api, nxapi, vpc, vlan, trunks]
4 | with_items:
5 | # - vpc
6 | - lacp
7 | nxos_feature:
8 | provider: "{{provider}}"
9 | feature: "{{ item }}"
10 | state: enabled
11 |
12 | - name: Create Port Channels
13 | tags: [api, nxapi, vpc, vlan, trunks]
14 | with_items: "{{ portchannels }}"
15 | nxos_portchannel:
16 | provider: "{{provider}}"
17 | group: "{{ item.port_channel_id }}"
18 | members: "{{ item.members }}"
19 | force: true
20 | mode: on
21 | state: present
22 |
23 | - name: Configure Access Switch Port Channels as Trunk
24 | tags: [api, nxapi, vpc, vlan, trunks]
25 | with_items: "{{ portchannels }}"
26 | nxos_switchport:
27 | provider: "{{provider}}"
28 | interface: "po{{ item.port_channel_id }}"
29 | mode: trunk
30 |
31 | - name: Enable Port Channel as VPC
32 | tags: [api, nxapi, vpc, vlan, trunks]
33 | with_items: "{{ portchannels }}"
34 | when: item.vpc == true
35 | nxos_vpc_interface:
36 | provider: "{{provider}}"
37 | portchannel: "{{ item.port_channel_id }}"
38 | vpc: "{{ item.port_channel_id }}"
39 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/templates/ietf_interface_template.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{item.interface_type}}{{item.interface_id}}
5 | {{item.description}}
6 | {% if item.interface_type == "Loopback" %}
7 | ianaift:softwareLoopback
8 | {% else %}
9 | ianaift:ethernetCsmacd
10 | {% endif %}
11 | true
12 |
13 |
14 | {{item.ip_address}}
15 | {{item.subnet_mask}}
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_interface/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_interface
--------------------------------------------------------------------------------
/setup/roles/network_interface/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_interface
--------------------------------------------------------------------------------
/setup/roles/network_ospf/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_ospf
--------------------------------------------------------------------------------
/setup/roles/network_ospf/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_ospf
--------------------------------------------------------------------------------
/setup/roles/network_ospf/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_ospf/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_ospf
3 | - name: IOS Devices
4 | include_tasks: netconf.yml
5 | when: ansible_network_os == "ios" and ospf is defined
6 | - name: NX-OS Devices
7 | include_tasks: nxapi.yml
8 | when: ansible_network_os == "nxos" and ospf is defined
9 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/tasks/netconf.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: "Generate NETCONF OSPF config"
3 | tags: [api, netconf, ospf]
4 | when: ansible_network_os == "ios"
5 | template:
6 | src: "templates/Cisco-IOS-XE_ospf.j2"
7 | dest: "./configs/{{inventory_hostname}}-ospf.xml"
8 |
9 | - name: Configure OSPF with NETCONF
10 | tags: [api, netconf, ospf]
11 | netconf_config:
12 | host: "{{provider.host}}"
13 | hostkey_verify: false
14 | username: "{{provider.username}}"
15 | password: "{{provider.password}}"
16 | port: "{{netconf_port | default(830)}}"
17 | src: "./configs/{{inventory_hostname}}-ospf.xml"
18 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/tasks/nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable Features
3 | tags: [api, nxapi, ospf]
4 | with_items:
5 | - ospf
6 | nxos_feature:
7 | provider: "{{provider}}"
8 | feature: "{{ item }}"
9 | state: enabled
10 |
11 | - name: Configure OSPF
12 | tags: [api, nxapi, ospf]
13 | nxos_ospf:
14 | provider: "{{provider}}"
15 | ospf: "{{ ospf.process_id }}"
16 | state: present
17 |
18 | - name: Configure OSPF Interfaces
19 | tags: [api, nxapi, ospf]
20 | with_items: "{{ ospf.networks }}"
21 | nxos_interface_ospf:
22 | provider: "{{provider}}"
23 | interface: "{{ item.interface }}"
24 | ospf: "{{ ospf.process_id }}"
25 | area: "{{ item.area }}"
26 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/templates/Cisco-IOS-XE_ospf.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ ospf.process_id }}
6 | {{ ospf_router_id }}
7 | {% for network in ospf_networks %}
8 |
9 | {{ network.network }}
10 | {{ network.mask }}
11 | {{ network.area }}
12 |
13 | {% endfor %}
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/templates/ned_ospf.j2:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ ospf.process_id }}
6 | {{ ospf_router_id }}
7 | {% for network in ospf_networks %}
8 |
9 | {{ network.network }}
10 | {{ network.mask }}
11 | {{ network.area }}
12 |
13 | {% endfor %}
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_ospf/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_ospf
--------------------------------------------------------------------------------
/setup/roles/network_ospf/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_ospf
--------------------------------------------------------------------------------
/setup/roles/network_vlan/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_vlan/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_vlan
--------------------------------------------------------------------------------
/setup/roles/network_vlan/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_vlan
--------------------------------------------------------------------------------
/setup/roles/network_vlan/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_vlan/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_vlan
3 | # - name: IOS Devices
4 | # include_tasks: netconf.yml
5 | # when: device_type == "ios" and ospf is defined
6 | - name: NX-OS Devices
7 | include_tasks: nxapi.yml
8 | when: ansible_network_os == "nxos" and vlans is defined
9 |
--------------------------------------------------------------------------------
/setup/roles/network_vlan/tasks/nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Configure VLANs
3 | tags: [api, nxapi, vlan]
4 | with_items: "{{ vlans }}"
5 | nxos_vlan:
6 | provider: "{{provider}}"
7 | vlan_id: "{{ item.id }}"
8 | name: "{{ item.name }}"
9 |
--------------------------------------------------------------------------------
/setup/roles/network_vlan/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_vlan/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_vlan
--------------------------------------------------------------------------------
/setup/roles/network_vlan/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_vlan
--------------------------------------------------------------------------------
/setup/roles/network_vpc/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/setup/roles/network_vpc/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for network_vpc
--------------------------------------------------------------------------------
/setup/roles/network_vpc/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for network_vpc
--------------------------------------------------------------------------------
/setup/roles/network_vpc/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Some suggested licenses:
11 | # - BSD (default)
12 | # - MIT
13 | # - GPLv2
14 | # - GPLv3
15 | # - Apache
16 | # - CC-BY
17 | license: license (GPLv2, CC-BY, etc)
18 |
19 | min_ansible_version: 1.2
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | # Optionally specify the branch Galaxy will use when accessing the GitHub
25 | # repo for this role. During role install, if no tags are available,
26 | # Galaxy will use this branch. During import Galaxy will access files on
27 | # this branch. If Travis integration is configured, only notifications for this
28 | # branch will be accepted. Otherwise, in all cases, the repo's default branch
29 | # (usually master) will be used.
30 | #github_branch:
31 |
32 | #
33 | # platforms is a list of platforms, and each platform has a name and a list of versions.
34 | #
35 | # platforms:
36 | # - name: Fedora
37 | # versions:
38 | # - all
39 | # - 25
40 | # - name: SomePlatform
41 | # versions:
42 | # - all
43 | # - 1.0
44 | # - 7
45 | # - 99.99
46 |
47 | galaxy_tags: []
48 | # List tags for your role here, one per line. A tag is a keyword that describes
49 | # and categorizes the role. Users find roles by searching for tags. Be sure to
50 | # remove the '[]' above, if you add tags to this list.
51 | #
52 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
53 | # Maximum 20 tags per role.
54 |
55 | dependencies: []
56 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
57 | # if you add dependencies to this list.
--------------------------------------------------------------------------------
/setup/roles/network_vpc/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for network_vpc
3 | # - name: IOS Devices
4 | # include_tasks: netconf.yml
5 | # when: device_type == "ios" and ospf is defined
6 | - name: NX-OS Devices
7 | include_tasks: nxapi.yml
8 | when: ansible_network_os == "nxos" and vpc is defined
9 |
--------------------------------------------------------------------------------
/setup/roles/network_vpc/tasks/nxapi.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Enable Features
3 | tags: [api, nxapi, vpc]
4 | with_items:
5 | - vpc
6 | - lacp
7 | nxos_feature:
8 | provider: "{{provider}}"
9 | feature: "{{ item }}"
10 | state: enabled
11 |
12 | - name: Configure VPC
13 | tags: [api, nxapi, vpc]
14 | nxos_vpc:
15 | provider: "{{provider}}"
16 | domain: "{{ vpc.domain }}"
17 | pkl_src: "{{ vpc_pkl_src }}"
18 | pkl_dest: "{{ vpc_pkl_dest }}"
19 | pkl_vrf: "{{ vpc.pkl_vrf }}"
20 | peer_gw: true
21 | auto_recovery: true
22 |
23 | - name: Create Port Channel for VPC
24 | tags: [api, nxapi, vpc]
25 | nxos_portchannel:
26 | provider: "{{provider}}"
27 | group: "{{ vpc.port_channel.id }}"
28 | members: "{{ vpc.port_channel.members }}"
29 | force: true
30 | mode: on
31 | state: present
32 |
33 | - name: Configure VPC Port Channel Trunk
34 | tags: [api, nxapi, vpc]
35 | nxos_switchport:
36 | provider: "{{provider}}"
37 | interface: "po{{ vpc.port_channel.id }}"
38 | mode: trunk
39 |
40 | - name: Enable VPC Peer Link on port_channel
41 | tags: [api, nxapi, vpc]
42 | nxos_vpc_interface:
43 | provider: "{{provider}}"
44 | portchannel: "{{ vpc.port_channel.id }}"
45 | peer_link: true
46 |
--------------------------------------------------------------------------------
/setup/roles/network_vpc/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/setup/roles/network_vpc/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - network_vpc
--------------------------------------------------------------------------------
/setup/roles/network_vpc/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for network_vpc
--------------------------------------------------------------------------------
/topology.virl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | flat
6 |
7 |
8 |
9 | aa:aa:aa:aa:aa:aa
10 |
11 | false
12 |
13 | distribution
14 | power redundancy-mode combined force
15 | license grace-period
16 |
17 | hostname dist1
18 |
19 | feature telnet
20 | feature nxapi
21 | feature bash-shell
22 | feature scp-server
23 |
24 | no password strength-check
25 | username admin password 5 $1$KuOSBsvW$Cy0TSD..gEBGBPjzpDgf51 role network-admin
26 | username cisco password 5 $1$Nk7ZkwH0$fyiRmMMfIheqE3BqvcL0C1 role network-admin
27 | no ip domain-lookup
28 |
29 | vrf context management
30 | ip route 0.0.0.0/0 {{ gateway }}
31 | hardware forwarding unicast trace
32 |
33 | interface mgmt0
34 | description OOB Management
35 | ! Configured on launch
36 | no ip address
37 | mac-address fa16.3e01.0007
38 | no shutdown
39 | vrf member management
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | aa:aa:aa:aa:aa:ac
53 |
54 | false
55 |
56 | access
57 | power redundancy-mode combined force
58 |
59 | license grace-period
60 |
61 | hostname access1
62 |
63 | feature telnet
64 | feature nxapi
65 | feature bash-shell
66 | feature scp-server
67 |
68 | no password strength-check
69 | username admin password 5 $1$KuOSBsvW$Cy0TSD..gEBGBPjzpDgf51 role network-admin
70 | username cisco password 5 $1$Nk7ZkwH0$fyiRmMMfIheqE3BqvcL0C1 role network-admin
71 | no ip domain-lookup
72 |
73 | vrf context management
74 | ip route 0.0.0.0/0 {{ gateway }}
75 | hardware forwarding unicast trace
76 |
77 | interface mgmt0
78 | description OOB Management
79 | ! Configured on launch
80 | no ip address
81 | mac-address fa16.3e03.0007
82 | no shutdown
83 | vrf member management
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | aa:aa:aa:aa:aa:ab
93 |
94 | distribution
95 |
96 | false
97 | power redundancy-mode combined force
98 |
99 | license grace-period
100 |
101 | hostname dist2
102 |
103 | feature telnet
104 | feature nxapi
105 | feature bash-shell
106 | feature scp-server
107 |
108 | no password strength-check
109 | username admin password 5 $1$KuOSBsvW$Cy0TSD..gEBGBPjzpDgf51 role network-admin
110 | username cisco password 5 $1$Nk7ZkwH0$fyiRmMMfIheqE3BqvcL0C1 role network-admin
111 | no ip domain-lookup
112 |
113 | vrf context management
114 | ip route 0.0.0.0/0 {{ gateway }}
115 | hardware forwarding unicast trace
116 |
117 | interface mgmt0
118 | description OOB Management
119 | ! Configured on launch
120 | no ip address
121 | mac-address fa16.3e02.0007
122 | no shutdown
123 | vrf member management
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | core
137 |
138 | false
139 | ! IOS Config generated on 2017-10-04 14:46
140 | hostname core1
141 | boot-start-marker
142 | boot-end-marker
143 | !
144 | vrf definition Mgmt-intf
145 | !
146 | address-family ipv4
147 | exit-address-family
148 | !
149 | address-family ipv6
150 | exit-address-family
151 | !
152 | !
153 | !
154 | license accept end user agreement
155 | license boot level premium
156 | !
157 | !
158 | no aaa new-model
159 | !
160 | !
161 | ipv6 unicast-routing
162 | !
163 | !
164 | service timestamps debug datetime msec
165 | service timestamps log datetime msec
166 | no service password-encryption
167 | no service config
168 | enable password cisco
169 | enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY
170 | ip classless
171 | ip subnet-zero
172 | no ip domain lookup
173 | crypto key generate rsa modulus 1024
174 | ip ssh server algorithm authentication password
175 | username cisco privilege 15 secret cisco
176 | line vty 0 4
177 | transport input ssh telnet
178 | exec-timeout 720 0
179 | password cisco
180 | login local
181 | line con 0
182 | password cisco
183 | !
184 | no cdp run
185 | !
186 | !
187 | interface GigabitEthernet1
188 | description OOB Management
189 | vrf forwarding Mgmt-intf
190 | ! Configured on launch
191 | no ip address
192 | cdp enable
193 | no shutdown
194 |
195 | ip route vrf Mgmt-intf 0.0.0.0 0.0.0.0 {{ gateway }}
196 | !
197 | interface GigabitEthernet2
198 | description to dist1
199 | no shutdown
200 | !
201 | interface GigabitEthernet3
202 | description to dist2
203 | no shutdown
204 | !
205 | interface GigabitEthernet4
206 | description core2
207 | no ip address
208 | no shutdown
209 | !
210 | interface Loopback 0
211 | !
212 | !
213 | !
214 | end
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 | core
224 |
225 | false
226 | ! IOS Config generated on 2017-10-04 14:46
227 | hostname core2
228 | boot-start-marker
229 | boot-end-marker
230 | !
231 | vrf definition Mgmt-intf
232 | !
233 | address-family ipv4
234 | exit-address-family
235 | !
236 | address-family ipv6
237 | exit-address-family
238 | !
239 | !
240 | !
241 | license accept end user agreement
242 | license boot level premium
243 | !
244 | !
245 | no aaa new-model
246 | !
247 | !
248 | ipv6 unicast-routing
249 | !
250 | !
251 | service timestamps debug datetime msec
252 | service timestamps log datetime msec
253 | no service password-encryption
254 | no service config
255 | enable password cisco
256 | enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY
257 | ip classless
258 | ip subnet-zero
259 | no ip domain lookup
260 | crypto key generate rsa modulus 1024
261 | ip ssh server algorithm authentication password
262 | username cisco privilege 15 secret cisco
263 | line vty 0 4
264 | transport input ssh telnet
265 | exec-timeout 720 0
266 | password cisco
267 | login local
268 | line con 0
269 | password cisco
270 | !
271 | no cdp run
272 | !
273 | !
274 | interface GigabitEthernet1
275 | description OOB Management
276 | vrf forwarding Mgmt-intf
277 | ! Configured on launch
278 | no ip address
279 | cdp enable
280 | no shutdown
281 |
282 | ip route vrf Mgmt-intf 0.0.0.0 0.0.0.0 {{ gateway }}
283 | !
284 | interface GigabitEthernet2
285 | description to dist1
286 | no shutdown
287 | !
288 | interface GigabitEthernet3
289 | description to dist2
290 | no shutdown
291 | !
292 | interface GigabitEthernet4
293 | description core2
294 | no ip address
295 | no shutdown
296 | !
297 | interface Loopback 0
298 | !
299 | !
300 | !
301 | end
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
--------------------------------------------------------------------------------
/vagrant_device_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | vagrant-iosxe1
4 |
5 |
6 | 1
7 | MGMT Interface
8 |
9 |
10 | 2
11 | LAN Interface
12 |
13 |
14 |
15 |
16 | 10.2.1.1
17 | 255.255.255.0
18 |
19 |
20 |
21 |
22 | false
23 | false
24 |
25 |
26 | true
27 |
28 |
29 |
30 | 3
31 | WAN Interface
32 |
33 |
34 |
35 |
36 | 10.2.2.1
37 | 255.255.255.0
38 |
39 |
40 |
41 |
42 | false
43 | false
44 |
45 |
46 | true
47 |
48 |
49 |
50 |
51 |
52 | private
53 |
54 |
55 |
56 | public
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/vagrant_device_setup.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """Configure the baseline on Vagrant device
3 |
4 | Copyright (c) 2018 Cisco and/or its affiliates.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | """
24 |
25 | # Import libraries
26 | from ncclient import manager
27 | from xml.dom import minidom
28 | import xmltodict
29 | from device_apis.device_info import vagrant_iosxe as device # noqa
30 |
31 | # Open and read in configuration template
32 | with open("vagrant_device_config.xml") as f:
33 | config_data = f.read()
34 |
35 | # Open NETCONF connection to device
36 | with manager.connect(host = device["address"],
37 | port = device["netconf_port"],
38 | username = device["username"],
39 | password = device["password"],
40 | hostkey_verify = False) as m:
41 |
42 | # Create desired NETCONF config payload and
43 | r = m.edit_config(target = "running", config = config_data)
44 |
45 | # Print OK status
46 | print("NETCONF RPC OK: {}".format(r.ok))
47 |
--------------------------------------------------------------------------------