├── .gitignore ├── .gitmodules ├── Ansible ├── Ansible-Webinar.virl ├── Collections │ └── config-collection │ │ ├── README.md │ │ ├── galaxy.yml │ │ ├── plugins │ │ └── README.md │ │ └── roles │ │ ├── network_device │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── ios-common.j2 │ │ │ └── nxos-common.j2 │ │ └── ospf_router │ │ ├── defaults │ │ └── main.yml │ │ ├── meta │ │ └── main.yml │ │ ├── tasks │ │ └── main.yml │ │ └── templates │ │ ├── ios-ospf.j2 │ │ └── nxos-ospf.j2 ├── Includes │ ├── .gitignore │ ├── README.md │ ├── configs-cleanup.yml │ ├── configs-tasks.yml │ ├── create-configs-initial.yml │ ├── create-configs.yml │ ├── exec │ │ ├── ios-ping.yml │ │ ├── node-ping.yml │ │ └── nxos-ping.yml │ ├── group_vars │ │ └── all.yml │ ├── host_vars │ │ ├── r1.lab.local │ │ │ └── data.yml │ │ ├── r2.lab.local │ │ │ └── data.yml │ │ └── s1.lab.local │ │ │ └── data.yml │ ├── hosts │ ├── import-debug.yml │ ├── import-tasks.yml │ ├── include-tasks-tags.yml │ ├── include-tasks.yml │ ├── ios │ │ └── common.j2 │ ├── nxos │ │ └── common.j2 │ ├── ping-check.yml │ ├── ping-gw.yml │ ├── ping-mesh.yml │ ├── setup-directory.yml │ ├── tasks │ │ ├── ios-config.yml │ │ └── nxos-config.yml │ └── topology.yml ├── Inventory │ ├── backup.cfg │ ├── demo-script.md │ ├── hierarchy.groups.ini │ ├── hierarchy.hosts.ini │ ├── hierarchy.ini │ ├── hierarchy.yaml │ ├── host_vars │ │ └── s1-zh.yaml │ ├── ranges.yaml │ ├── values.ini │ └── values.yaml ├── Logging │ ├── ansible.cfg │ ├── configs-no-facts.yml │ ├── configs-unified.yml │ ├── configs.yml │ ├── deploy.yml │ ├── ghosts │ ├── group_vars │ │ ├── all.yml │ │ ├── ios.yml │ │ └── nxos.yml │ ├── host_vars │ │ ├── r1.lab.local.yml │ │ └── s1.lab.local.yml │ ├── hosts │ ├── hosts-ng │ ├── ios │ │ ├── commands.yml │ │ ├── common.j2 │ │ └── common.js │ ├── nxos │ │ ├── commands.yml │ │ └── common.j2 │ └── show-arp-save.yml ├── Loops │ ├── ansible.cfg │ ├── config-users-loop.yml │ ├── config-users.yml │ ├── hosts.yml │ ├── loop-ping-control.yml │ └── loop-ping.yml ├── NetFilters │ ├── .gitignore │ ├── ansible.cfg │ ├── cli_filters │ │ ├── ios_ospf_interfaces.yml │ │ ├── ios_ospf_neighbor.yml │ │ └── ios_ospf_neighbor_hash.yml │ ├── filter_plugins │ │ └── list.py │ ├── ios-ospf-interfaces.yml │ ├── ios-ospf-neighbor-hash.yml │ ├── ios-ospf-neighbor.yml │ ├── json_filters.yml │ ├── ospf_textfsm.yml │ ├── parsecli_snapshot.yml │ ├── textfsm │ │ └── cisco_ios_show_ip_ospf_neighbor.template │ └── textfsm_snapshot.yml ├── Networking │ ├── .gitignore │ ├── Authentication │ │ └── hosts-pwd.yml │ ├── Command-Playbooks │ │ ├── .gitignore │ │ ├── check-connectivity.yml │ │ ├── check-version-junos.yml │ │ ├── check-version-log.yml │ │ ├── check-version.yml │ │ ├── collect-many-printouts-ios.yml │ │ ├── collect-printout-ios.yml │ │ └── demo-script.md │ ├── Commands │ │ ├── cli-clear-counters.yml │ │ ├── cli-command-simple.yml │ │ ├── demo-script.md │ │ ├── eos-show-arp.yml │ │ ├── ios-command-multiple.yml │ │ ├── ios-command.yml │ │ ├── ios-printouts.j2 │ │ ├── junos-command-xml.yml │ │ ├── junos-command.yml │ │ ├── junos-print-arp.j2 │ │ ├── nxos-command-json.yml │ │ ├── nxos-enable-api.yml │ │ └── nxos-print-arp.j2 │ ├── Configuration │ │ ├── .gitignore │ │ ├── cisco-ios-bgp-as.yml │ │ ├── config-acl-add-before.yml │ │ ├── config-acl-add-exact.yml │ │ ├── config-acl-add.yml │ │ ├── config-acl-remove.yml │ │ ├── config-bgp-ios-check.yml │ │ ├── config-bgp-ios.yml │ │ ├── config-diff.yml │ │ ├── config-enable-http.yml │ │ ├── config-get.yml │ │ ├── config-logging.yml │ │ ├── config-simple.yml │ │ ├── config-snmp-template.yml │ │ ├── demo-script.md │ │ ├── logging.cfg │ │ └── snmp.j2 │ ├── Declarative-Configuration │ │ ├── ios-loopback.yml │ │ ├── net-loopback.yml │ │ ├── nxos-clean-interfaces.yml │ │ ├── nxos-clean-vlan.yml │ │ ├── nxos-feature.yml │ │ ├── nxos-interfaces.yml │ │ ├── nxos-ip-interfaces.yml │ │ ├── nxos-vlan-aggregate-data.yml │ │ ├── nxos-vlan-aggregate-purge.yml │ │ ├── nxos-vlan-aggregate.yml │ │ └── nxos-vlan-set.yml │ ├── Get-Operational-Data │ │ ├── cisco_ios_show_ip_ospf_neighbor.textfsm │ │ ├── device-facts.yml │ │ ├── eos-arp-csv.yml │ │ ├── gather-facts.yml │ │ ├── hosts.yml │ │ ├── ios-config-parse-ttp.yml │ │ ├── ios-ospf-neighbor.yml │ │ ├── ios-ospf-parse-ntc-templates.yml │ │ ├── ios-ospf-parse-pyats.yml │ │ ├── ios-ospf-parse-textfsm.yml │ │ ├── ios_config_interface.ttp │ │ ├── junos-route-csv.yml │ │ ├── napalm-facts.yml │ │ └── templates │ │ │ └── ios_show_ip_ospf_neighbor.textfsm │ ├── Setup │ │ ├── clean-bgp-ios.yml │ │ ├── config-acl-preset.yml │ │ ├── config-ansible-user.yml │ │ ├── config-eem-applet.yml │ │ ├── config-enable-scp.yml │ │ ├── config-enable-snmp.yml │ │ └── config-simple-cleanup.yml │ ├── ansible.cfg │ ├── group_vars │ │ ├── all.yml │ │ ├── ios.yml │ │ └── junos.yml │ ├── host_vars │ │ ├── r1.lab.local.yml │ │ └── s1.lab.local.yml │ ├── hosts │ └── setup.sh ├── Plugins │ ├── .gitignore │ ├── ansible.cfg │ ├── device-type.yml │ ├── filter_plugins │ │ ├── list.py │ │ └── net_helper.py │ ├── group_vars │ │ └── all.yml │ ├── hosts │ ├── test-device-type.yml │ └── test-list-plugin.yml ├── Roles │ ├── .gitignore │ ├── README.md │ ├── config-collection-namespace.yml │ ├── config-collection.yml │ ├── config-complete.yml │ ├── config-import.yml │ ├── config-include.yml │ ├── config-ospf-2.yml │ ├── config-ospf-area.yml │ ├── config-ospf.yml │ ├── config-simple.yml │ ├── group_vars │ │ └── all.yml │ ├── host_vars │ │ ├── r1.lab.local │ │ │ └── data.yml │ │ ├── r2.lab.local │ │ │ └── data.yml │ │ └── s1.lab.local │ │ │ └── data.yml │ ├── requirements-devel.yml │ ├── requirements.yml │ ├── roles │ │ ├── network_device │ │ │ ├── tasks │ │ │ │ └── main.yml │ │ │ └── templates │ │ │ │ ├── ios-common.j2 │ │ │ │ └── nxos-common.j2 │ │ └── ospf_router │ │ │ ├── defaults │ │ │ └── main.yml │ │ │ ├── meta │ │ │ └── main.yml │ │ │ ├── tasks │ │ │ └── main.yml │ │ │ └── templates │ │ │ ├── ios-ospf.j2 │ │ │ └── nxos-ospf.j2 │ ├── setup-directory.yml │ └── topology.yml ├── SNMPFacts │ ├── group_vars │ │ ├── all.yml │ │ ├── ios.yml │ │ └── nxos.yml │ ├── hosts │ └── snmp-facts.yml ├── Simple │ ├── debug.yml │ ├── fail │ ├── ghosts │ ├── hosts │ ├── shosts │ ├── show-arp-conditional.yml │ ├── show-arp-simple-debug.yml │ ├── show-arp-simple-fail.yml │ ├── show-arp-simple-show.yml │ └── show-arp-simple.yml ├── Variables │ ├── ansible.cfg │ ├── debug-dump-all.yml │ ├── debug-dump-single.yml │ ├── debug.yml │ ├── demo-script.md │ ├── fact-caching.yml │ ├── get-files.yml │ ├── group_vars │ │ ├── all.yml │ │ ├── ios.yml │ │ ├── junos.yml │ │ └── nxos.yml │ ├── host_vars │ │ ├── r1.lab.local.yml │ │ ├── r2.lab.local │ │ │ ├── connection.yml │ │ │ └── description.yml │ │ ├── s1.lab.local.yml │ │ └── srx.lab.local.yml │ ├── hosts.ini │ ├── hosts.values.ini │ ├── play-block-facts.yml │ ├── play-block-task-vars.yml │ └── play-task-facts.yml └── Vault │ ├── ansible.cfg │ ├── dump.yml │ ├── group_vars │ └── all │ │ ├── vars.yml │ │ └── x.yml │ ├── host_vars │ └── r1.yml │ ├── hosts.yaml │ ├── pass.py │ └── pass.sh ├── Docker ├── .gitignore ├── Centos │ ├── Dockerfile │ ├── build.sh │ ├── requirements-yum.txt │ ├── requirements.txt │ ├── requirements.yml │ └── run-automation ├── README.md ├── Ubuntu │ ├── Dockerfile │ ├── apt-install.sh │ ├── build.sh │ ├── requirements-apt.txt │ ├── requirements.txt │ ├── requirements.yml │ └── run-automation ├── Vagrantfile └── install-docker.yaml ├── Jinja2 ├── 1-basicFail.j2 ├── 1-basicFail.yml ├── 1-basics.j2 ├── 1-basics.yml ├── 2-conditionals.j2 ├── 2-conditionals.yml ├── 3-complex.j2 ├── 3-complex.yml ├── 4-default.j2 ├── 4-default.yml ├── 5-sequence.j2 ├── 5-sequence.yml ├── 5-sequenceFail.j2 ├── 5-sequenceFail.yml ├── 6-iterable.j2 ├── 6-iterable.yml ├── 6-syslog.j2 ├── 6-syslog.yml ├── 7-sequenceObjects.j2 ├── 7-sequenceObjects.yml ├── 8-iterateDictionary.j2 ├── 8-iterateDictionary.yml ├── 9-loopVariable.j2 ├── 9-loopVariable.yml ├── A-valueLookup.j2 ├── A-valueLookup.yml ├── B-ACL-seq-loopvar.j2 ├── B-ACL-seq-loopvar.yml ├── B-ACL-sequenced.j2 ├── B-ACL-sequenced.yml ├── B-ACL-simple.j2 ├── B-ACL-simple.yml ├── C-macros.j2 ├── C-macros.yml ├── D-import-include.j2 ├── D-import-include.yml ├── P1-strings.j2 ├── P1-strings.yml ├── P2-slicing.j2 ├── P2-slicing.yml ├── README.md ├── includes │ ├── interfaces.j2 │ └── loopback.j2 ├── ipaddr │ ├── 1-ipaddr.j2 │ ├── 1-ipaddr.yml │ ├── 2-iphost.j2 │ ├── 2-iphost.yml │ ├── 3-localACL.j2 │ ├── 3-localACL.yml │ ├── ansible.cfg │ ├── hosts │ ├── render.sh │ └── render.yml ├── render.py ├── setup.sh └── whitespace │ ├── .gitignore │ ├── ansible.cfg │ ├── data.yml │ ├── render.yml │ └── templates │ ├── indent_bol.j2 │ ├── indent_default.j2 │ ├── indent_lstrip.j2 │ ├── inline_if.j2 │ ├── inline_if_extra.j2 │ ├── inline_if_pretty.j2 │ ├── macro.j2 │ ├── macro_strip.j2 │ ├── trim_blocks.j2 │ └── trim_blocks_off.j2 ├── LICENSE.md ├── README.md ├── Scripted Demos ├── 00 - Lean Start into Network Automation.md ├── 00 - Setup.md ├── 10 - Simple-reports.md ├── 11 - Network-graph.md ├── 20 - Compliance-checks.md ├── 30 - Compare-Network-State.md ├── 40 - DMVPN-Deployment.md ├── 41 - OSPF-Deployment.md ├── A1 - Ansible debugging.md ├── AW1 - Ansible Workshop - Introduction.md ├── AW3 - Connecting and Authenticating.md ├── AW6 - Command-Based Playbooks.md ├── AW7 - Managing Configurations.md ├── AW9 - DMVPN-Deployment.md ├── AWS - Setup.md ├── G0 - Push device configs into Git master.md ├── G1 - Push device configurations into Actual branch.md ├── G2 - Merge individual changes as feature branches.md ├── G3 - Change Configs From Git.md ├── Git 101.md └── init-readme.md ├── YAML ├── 0-Value.yml ├── 1-Syntax.yml ├── 2-SimpleList.yml ├── 3-Scalars.yml ├── 4-MultiLine.yml ├── 5-KeyValuePairs.yml ├── 6-ListOfDictionaries.yml ├── 6-ListOfLists.yml ├── 7-ComplexDictionary.yml ├── 8-InlineListDictionary.yml ├── README.md ├── install-perl-cpan.sh ├── setup.sh ├── y2js ├── y2pl └── y2py ├── install ├── Archive │ ├── install.python-2.sh │ └── install.ubuntu-14.04.sh ├── README.md ├── ansible-github.sh ├── ansible.cfg ├── install.sh └── ssh.config ├── tests ├── .gitignore ├── Vagrantfile.bento.18-04 └── test-install.sh ├── tools ├── .bash_profile ├── .bash_prompt ├── config-actions │ ├── enable-lldp.yml │ ├── enable-scp.yml │ ├── no-banner.yml │ └── rollback-to-startup.yml ├── ios-configs │ └── enable_scp.yml ├── prettify-xml ├── ssh-keys │ ├── README.md │ └── get-keys.yml └── xcode └── topologies ├── EOS-Leaf-and-Spine ├── README.md ├── Vagrantfile.linux ├── Vagrantfile.windows ├── hosts.local ├── hosts.vm └── topology.yml ├── README.md ├── VIRL ├── Ansible-Webinar.virl ├── DMVPN.virl ├── Inter-AS.virl ├── README.md └── Vagrantfile ├── YAML-with-Vagrant ├── README.md ├── Vagrantfile └── topology.yml ├── tools └── Vagrant2Inventory.py └── vSRX+VIRL ├── Ansible-Webinar.virl ├── README.md └── Vagrantfile /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Vagrant directories 2 | .vagrant 3 | .DS_Store 4 | /Vagrantfile 5 | /vagrantfile 6 | /topology.yml 7 | # Ignore text files in root directory 8 | *.txt 9 | *.ignore.* 10 | 11 | # Ignore Ansible retry and log files 12 | *.retry 13 | ansible.log 14 | 15 | # Don't publish SFTP configuration 16 | sftp-config.json 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Examples"] 2 | path = Examples 3 | url = https://github.com/ipspace/ansible-examples.git 4 | [submodule "Exercises"] 5 | path = Exercises 6 | url = https://github.com/ipspace/ansible-exercises.git 7 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Collection - ipspace.config 2 | 3 | Documentation for the collection. -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | namespace: ipspace 3 | name: config 4 | version: 1.0.2 5 | 6 | readme: README.md 7 | 8 | authors: 9 | - Ivan Pepelnjak 10 | 11 | description: Simple multi-platform configuration generation 12 | 13 | license: 14 | - GPL-2.0-or-later 15 | 16 | tags: [ netops, config ] 17 | 18 | dependencies: {} 19 | 20 | #repository: http://example.com/repository 21 | #documentation: http://docs.example.com 22 | #homepage: http://example.com 23 | #issues: http://example.com/issue/tracker 24 | 25 | 26 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/plugins/README.md: -------------------------------------------------------------------------------- 1 | # Collections Plugins Directory 2 | 3 | This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that 4 | is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that 5 | would contain module utils and modules respectively. 6 | 7 | Here is an example directory of the majority of plugins currently supported by Ansible: 8 | 9 | ``` 10 | └── plugins 11 | ├── action 12 | ├── become 13 | ├── cache 14 | ├── callback 15 | ├── cliconf 16 | ├── connection 17 | ├── filter 18 | ├── httpapi 19 | ├── inventory 20 | ├── lookup 21 | ├── module_utils 22 | ├── modules 23 | ├── netconf 24 | ├── shell 25 | ├── strategy 26 | ├── terminal 27 | ├── test 28 | └── vars 29 | ``` 30 | 31 | A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible/2.9/plugins/plugins.html). -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/network_device/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: 3 | src: "{{ansible_network_os}}-common.j2" 4 | dest: "{{configs}}/{{inventory_hostname}}/00-common-{{inventory_hostname}}.inc" 5 | name: create common device configuration -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/network_device/templates/ios-common.j2: -------------------------------------------------------------------------------- 1 | hostname {{inventory_hostname}} 2 | ! 3 | logging host {{syslog_host}} 4 | ! 5 | snmp-server community {{snmp_community}} RO 6 | snmp-server location {{location}} 7 | snmp-server contact {{snmp_contact}} 8 | snmp-server chassis-id 9 | snmp-server host {{snmp_host}} {{snmp_community}} 10 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/network_device/templates/nxos-common.j2: -------------------------------------------------------------------------------- 1 | hostname {{inventory_hostname}} 2 | ! 3 | logging server {{syslog_host}} 4 | ! 5 | snmp-server contact {{snmp_contact}} 6 | snmp-server location {{location}} 7 | snmp-server user {{snmp_community}} network-operator 8 | snmp-server host {{snmp_host}} traps version 2 {{snmp_community}} 9 | snmp-server enable traps link 10 | snmp-server community {{snmp_community}} group network-operator 11 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/ospf_router/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ospf_area: 0 3 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/ospf_router/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - network_device 4 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/ospf_router/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: 3 | src: "{{ansible_network_os}}-ospf.j2" 4 | dest: "{{configs}}/{{inventory_hostname}}/10-ospf-{{inventory_hostname}}.inc" 5 | name: create OSPF routing process 6 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/ospf_router/templates/ios-ospf.j2: -------------------------------------------------------------------------------- 1 | ! 2 | router ospf 1 3 | ! 4 | {% if loopback is defined %} 5 | interface loopback0 6 | ip ospf 1 area {{ ospf_area }} 7 | {% endif %} 8 | {% for l in links|default([]) %} 9 | ! 10 | interface {{l.ifname}} 11 | ip ospf 1 area {{ospf_area}} 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /Ansible/Collections/config-collection/roles/ospf_router/templates/nxos-ospf.j2: -------------------------------------------------------------------------------- 1 | ! 2 | feature ospf 3 | router ospf 1 4 | ! 5 | {% if loopback is defined %} 6 | interface loopback0 7 | ip ospf 1 area {{ ospf_area }} 8 | {% endif %} 9 | {% for l in links|default([]) %} 10 | ! 11 | interface {{l.ifname}} 12 | ip ospf 1 area {{ospf_area}} 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /Ansible/Includes/.gitignore: -------------------------------------------------------------------------------- 1 | configs/ 2 | -------------------------------------------------------------------------------- /Ansible/Includes/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Includes Demos 2 | 3 | This directory contains demo playbooks used in *Imports* and *Includes* part of *[Creating Reusable Code](https://my.ipspace.net/bin/list?id=Ansible#INCLUDES)* section of *[Ansible for Networking Engineers](https://www.ipspace.net/Ansible_for_Networking_Engineers)* webinar. 4 | 5 | ## Playbook-level Imports 6 | 7 | ``` 8 | ansible-playbook create-configs-initial.yml 9 | cat create-configs.yml 10 | ansible-playbook create-configs.yml 11 | ansible-playbook create-configs.yml -e config_cleanup=true 12 | vi create-configs.yml 13 | ansible-playbook create-configs.yml 14 | ``` 15 | 16 | ## Task Imports 17 | 18 | ``` 19 | cat import-tasks.yml 20 | ansible-playbook import-tasks.yml 21 | ansible-playbook import-tasks.yml -t debug 22 | ``` 23 | 24 | ## Task Includes 25 | 26 | ``` 27 | ansible-playbook include-tasks.yml 28 | ansible-playbook include-tasks.yml -t debug 29 | ``` 30 | 31 | ``` 32 | ansible-playbook include-tasks-tags.yml -t debug 33 | ``` 34 | 35 | ## Dynamic Included File Names 36 | 37 | ``` 38 | ansible-playbook configs-tasks.yml 39 | ``` 40 | 41 | ## Multi-Platform Playbooks 42 | 43 | ``` 44 | ansible-playbook ping-gw.yml 45 | ``` 46 | 47 | ## Included Loops 48 | 49 | ``` 50 | ansible-playbook ping-mesh.yml 51 | ``` 52 | -------------------------------------------------------------------------------- /Ansible/Includes/configs-cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: setup-directory.yml 3 | name: set up working directories 4 | vars: 5 | cleanup: 1 6 | 7 | - hosts: all 8 | tasks: 9 | - template: src=ios/common.j2 dest=configs/{{inventory_hostname}}.txt 10 | name: create configuration for IOS devices 11 | when: ansible_os == 'ios' 12 | 13 | - hosts: all 14 | tasks: 15 | - template: src=nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 16 | name: create configuration for Nexus devices 17 | when: ansible_os == 'nxos' 18 | -------------------------------------------------------------------------------- /Ansible/Includes/configs-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | 5 | - hosts: all 6 | tasks: 7 | - include_tasks: tasks/{{ansible_network_os}}-config.yml 8 | -------------------------------------------------------------------------------- /Ansible/Includes/create-configs-initial.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | name: Create directory 4 | tasks: 5 | - file: path=configs state=directory 6 | 7 | - hosts: iosv 8 | tasks: 9 | - template: src=ios/common.j2 dest=configs/{{inventory_hostname}}.txt 10 | name: create configuration for IOS devices 11 | 12 | - hosts: nxos 13 | tasks: 14 | - template: src=nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 15 | name: create configuration for Nexus devices 16 | -------------------------------------------------------------------------------- /Ansible/Includes/create-configs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | 5 | - hosts: iosv 6 | tasks: 7 | - template: src=ios/common.j2 dest=configs/{{inventory_hostname}}.txt 8 | name: create configuration for IOS devices 9 | 10 | - hosts: nxos 11 | tasks: 12 | - template: src=nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 13 | name: create configuration for Nexus devices 14 | -------------------------------------------------------------------------------- /Ansible/Includes/exec/ios-ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Ping {{item}} from IOS devices" 3 | ios_ping: 4 | dest: "{{ item }}" 5 | -------------------------------------------------------------------------------- /Ansible/Includes/exec/node-ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Try to reach managed device {{item}}" 3 | command: /bin/ping -q -c 3 -A {{item}} 4 | -------------------------------------------------------------------------------- /Ansible/Includes/exec/nxos-ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Ping {{item}} from NX-OS devices" 3 | nxos_ping: 4 | dest: "{{ item }}" 5 | -------------------------------------------------------------------------------- /Ansible/Includes/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: vagrant 3 | ansible_ssh_pass: vagrant 4 | snmp_community: cisco 5 | snmp_contact: admin@lab.local 6 | snmp_host: 172.16.1.12 7 | syslog_host: 172.16.1.12 8 | gw: 172.16.0.1 9 | connection: network_cli 10 | -------------------------------------------------------------------------------- /Ansible/Includes/host_vars/r1.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-1 -------------------------------------------------------------------------------- /Ansible/Includes/host_vars/r2.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-2 3 | -------------------------------------------------------------------------------- /Ansible/Includes/host_vars/s1.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-2 -------------------------------------------------------------------------------- /Ansible/Includes/hosts: -------------------------------------------------------------------------------- 1 | [iosv] 2 | r1.lab.local ansible_network_os=ios 3 | r2.lab.local ansible_network_os=ios 4 | 5 | [nxos] 6 | s1.lab.local ansible_network_os=nxos 7 | -------------------------------------------------------------------------------- /Ansible/Includes/import-debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: 3 | msg: "Debugging level: {{ level|default('not defined') }}" 4 | - debug: var=ansible_network_os 5 | when: ansible_network_os=='nxos' 6 | -------------------------------------------------------------------------------- /Ansible/Includes/import-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - import_tasks: import-debug.yml 5 | vars: 6 | level: 1 7 | when: ansible_network_os=='ios' 8 | tags: [ debug ] 9 | -------------------------------------------------------------------------------- /Ansible/Includes/include-tasks-tags.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - include_tasks: 5 | file: import-debug.yml 6 | apply: 7 | tags: [ debug ] 8 | vars: 9 | level: 1 10 | when: ansible_network_os=='ios' 11 | tags: [ debug ] 12 | -------------------------------------------------------------------------------- /Ansible/Includes/include-tasks.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - include_tasks: import-debug.yml 5 | vars: 6 | level: 1 7 | when: ansible_network_os=='ios' 8 | tags: [ debug ] 9 | -------------------------------------------------------------------------------- /Ansible/Includes/ios/common.j2: -------------------------------------------------------------------------------- 1 | logging host {{syslog_host}} 2 | ! 3 | snmp-server community {{snmp_community}} RO 4 | snmp-server location {{location}} 5 | snmp-server contact {{snmp_contact}} 6 | snmp-server chassis-id 7 | snmp-server host {{snmp_host}} {{snmp_community}} 8 | -------------------------------------------------------------------------------- /Ansible/Includes/nxos/common.j2: -------------------------------------------------------------------------------- 1 | logging server {{syslog_host}} 2 | ! 3 | snmp-server contact {{snmp_contact}} 4 | snmp-server location {{location}} 5 | snmp-server user {{snmp_community}} network-operator 6 | snmp-server host {{snmp_host}} traps version 2 {{snmp_community}} 7 | snmp-server enable traps link 8 | snmp-server community {{snmp_community}} group network-operator 9 | -------------------------------------------------------------------------------- /Ansible/Includes/ping-check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | tasks: 4 | - include: exec/node-ping.yml 5 | with_items: "{{groups['all']}}" 6 | 7 | - hosts: all 8 | name: ping specified destinations from all hosts 9 | tasks: 10 | - name: Read the list of targets 11 | include_vars: file=ping-targets.yml 12 | - include: exec/{{ansible_os}}-ping.yml 13 | with_items: "{{targets}}" 14 | -------------------------------------------------------------------------------- /Ansible/Includes/ping-gw.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | name: Ping GW from all devices 4 | tasks: 5 | - include_tasks: exec/{{ansible_network_os}}-ping.yml 6 | vars: 7 | item: "{{ gw }}" 8 | -------------------------------------------------------------------------------- /Ansible/Includes/ping-mesh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | name: Ping GW from all devices 4 | tasks: 5 | - set_fact: 6 | ping_list: "{{ hostvars | json_query('*.links[0].ipv4') | ipaddr('address') }}" 7 | - include_tasks: exec/{{ansible_network_os}}-ping.yml 8 | with_items: "{{ ping_list }}" 9 | -------------------------------------------------------------------------------- /Ansible/Includes/setup-directory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | name: Create directory 4 | tasks: 5 | - name: clean up config directory 6 | file: path=configs state=absent 7 | when: config_cleanup is defined 8 | - name: create config directory 9 | file: path=configs state=directory -------------------------------------------------------------------------------- /Ansible/Includes/tasks/ios-config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: src=../ios/common.j2 dest=configs/{{inventory_hostname}}.txt 3 | name: create configuration for IOS devices 4 | -------------------------------------------------------------------------------- /Ansible/Includes/tasks/nxos-config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: src=../nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 3 | name: create configuration for Nexus devices 4 | -------------------------------------------------------------------------------- /Ansible/Includes/topology.yml: -------------------------------------------------------------------------------- 1 | nodes: 2 | - name: r1.lab.local 3 | device: iosv 4 | - name: r2.lab.local 5 | device: iosv 6 | - name: s1.lab.local 7 | device: nxos 8 | 9 | links: 10 | - r1.lab.local: 11 | r2.lab.local: 12 | s1.lab.local: 13 | -------------------------------------------------------------------------------- /Ansible/Inventory/backup.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=hierarchy.ini 3 | gathering=explicit 4 | retry_files_enabled=false 5 | transport=local 6 | force_color=1 7 | host_key_checking=False 8 | -------------------------------------------------------------------------------- /Ansible/Inventory/demo-script.md: -------------------------------------------------------------------------------- 1 | # Ansible Inventory Demo Script 2 | 3 | ## Inventory in INI format 4 | 5 | ``` 6 | less hierarchy.ini 7 | ansible-inventory -i hierarchy.ini --graph 8 | ansible-inventory -i hierarchy.ini --graph zurich 9 | ``` 10 | 11 | ## Inventory in YAML format 12 | 13 | ``` 14 | less hierarchy.yaml 15 | ansible-inventory -i hierarchy.ini --graph 16 | ansible-inventory -i hierarchy.ini --graph zurich 17 | ``` 18 | 19 | ## Ranges of hosts 20 | 21 | ``` 22 | cat ranges.yaml 23 | ansible-inventory -i ranges.yaml --graph 24 | ``` 25 | 26 | ## Host and Group Facts in INI format 27 | 28 | ``` 29 | less values.ini 30 | ansible-inventory -i values.ini --host l2-zh 31 | ansible-inventory -i values.ini --host bl1-zh 32 | ansible-inventory -i values.ini --graph --vars leafs_zurich 33 | ``` 34 | 35 | ## Host and Group Facts in YAML format 36 | 37 | ``` 38 | less values.yaml 39 | ansible-inventory -i values.yaml --host l2-zh 40 | ansible-inventory -i values.yaml --host bl1-zh 41 | ansible-inventory -i values.yaml --graph --vars leafs_zurich 42 | ``` 43 | 44 | ## Host Variable Files 45 | 46 | ``` 47 | cat host_vars/s1-zh.yaml 48 | ansible-inventory -i values.yaml --host s1-zh 49 | ``` 50 | 51 | ## Inventory Sources 52 | 53 | ``` 54 | ansible-inventory -vvv --graph edge_zurich 55 | cp backup.cfg ansible.cfg 56 | cat ansible.cfg 57 | ansible-inventory -vvv --graph edge_zurich 58 | export ANSIBLE_INVENTORY=values.yaml 59 | ansible-inventory -vvv --graph --vars edge_zurich 60 | ansible-inventory -vvv -i hierarchy.yaml --graph --vars edge_zurich 61 | cat hierarchy.hosts.ini 62 | cat hierarchy.groups.ini 63 | ansible-inventory -vvv -i hierarchy.hosts.ini -i hierarchy.groups.ini --graph --vars edge -------------------------------------------------------------------------------- /Ansible/Inventory/hierarchy.groups.ini: -------------------------------------------------------------------------------- 1 | [switches:children] 2 | spines_zurich 3 | leafs_zurich 4 | 5 | [zurich:children] 6 | spines_zurich 7 | leafs_zurich 8 | edge_zurich 9 | 10 | [edge:children] 11 | edge_zurich 12 | -------------------------------------------------------------------------------- /Ansible/Inventory/hierarchy.hosts.ini: -------------------------------------------------------------------------------- 1 | [spines_zurich] 2 | s1-zh 3 | s2-zh 4 | 5 | [leafs_zurich] 6 | l1-zh 7 | l2-zh 8 | bl1-zh 9 | 10 | [edge_zurich] 11 | bl1-zh 12 | fw-zh 13 | -------------------------------------------------------------------------------- /Ansible/Inventory/hierarchy.ini: -------------------------------------------------------------------------------- 1 | ntp-server 2 | dns-server 3 | 4 | [spines_zurich] 5 | s1-zh 6 | s2-zh 7 | 8 | [leafs_zurich] 9 | l1-zh 10 | l2-zh 11 | bl1-zh 12 | 13 | [edge_zurich] 14 | bl1-zh 15 | fw-zh 16 | 17 | [switches:children] 18 | spines_zurich 19 | leafs_zurich 20 | 21 | [zurich:children] 22 | spines_zurich 23 | leafs_zurich 24 | edge_zurich 25 | 26 | [edge:children] 27 | edge_zurich 28 | -------------------------------------------------------------------------------- /Ansible/Inventory/hierarchy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | dns-server: 5 | ntp-server: 6 | 7 | spines_zurich: 8 | hosts: 9 | s1-zh: 10 | s2-zh: 11 | 12 | leafs_zurich: 13 | hosts: 14 | bl1-zh: 15 | l1-zh: 16 | l2-zh: 17 | 18 | edge_zurich: 19 | hosts: 20 | bl1-zh: 21 | fw-zh: 22 | 23 | zurich: 24 | children: 25 | spines_zurich: 26 | leafs_zurich: 27 | edge_zurich: 28 | 29 | edge: 30 | children: 31 | edge_zurich: 32 | 33 | switches: 34 | children: 35 | leafs_zurich: 36 | spines_zurich: 37 | -------------------------------------------------------------------------------- /Ansible/Inventory/host_vars/s1-zh.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.2 3 | -------------------------------------------------------------------------------- /Ansible/Inventory/ranges.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | dns-server-[a:c]: 5 | ntp-server: 6 | 7 | spines_zurich: 8 | hosts: 9 | s[1:4]-zh: 10 | 11 | leafs_zurich: 12 | hosts: 13 | bl1-zh: 14 | l[01:12]-zh: 15 | -------------------------------------------------------------------------------- /Ansible/Inventory/values.ini: -------------------------------------------------------------------------------- 1 | [spines_zurich] 2 | s1-zh ansible_host=10.0.0.1 3 | s2-zh ansible_host=10.0.0.2 4 | 5 | [leafs_zurich] 6 | l1-zh ansible_host=10.0.0.101 7 | l2-zh ansible_host=10.0.0.102 decription="Don't touch" 8 | bl1-zh ansible_host=10.0.0.103 ansible_user=edge 9 | 10 | [edge_zurich] 11 | bl1-zh description="Edge leaf switch" 12 | fw-zh ansible_host=10.0.0.201 13 | 14 | [switches:vars] 15 | ansible_user=admin 16 | 17 | [switches:children] 18 | spines_zurich 19 | leafs_zurich 20 | 21 | [zurich:vars] 22 | snmp_server=nms.zh.example.com 23 | 24 | [zurich:children] 25 | spines_zurich 26 | leafs_zurich 27 | edge_zurich 28 | 29 | [edge:children] 30 | edge_zurich 31 | -------------------------------------------------------------------------------- /Ansible/Inventory/values.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | spines_zurich: 3 | hosts: 4 | s1-zh: 5 | ansible_host: 10.0.0.1 6 | s2-zh: 7 | ansible_host: 10.0.0.2 8 | 9 | leafs_zurich: 10 | hosts: 11 | l1-zh: 12 | ansible_host: 10.0.0.101 13 | l2-zh: 14 | ansible_host: 10.0.0.102 15 | description: Don't touch 16 | bl1-zh: 17 | ansible_host: 10.0.0.103 18 | ansible_user: edge 19 | 20 | edge_zurich: 21 | hosts: 22 | bl1-zh: 23 | fw-zh: 24 | 25 | zurich: 26 | children: 27 | spines_zurich: 28 | leafs_zurich: 29 | edge_zurich: 30 | vars: 31 | snmp_server: nms.zh.example.com 32 | 33 | edge: 34 | children: 35 | edge_zurich: 36 | 37 | switches: 38 | children: 39 | leafs_zurich: 40 | spines_zurich: 41 | vars: 42 | ansible_user: admin -------------------------------------------------------------------------------- /Ansible/Logging/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=./hosts 3 | connection=local 4 | retry_files_enabled=false 5 | gathering=explicit 6 | -------------------------------------------------------------------------------- /Ansible/Logging/configs-no-facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | name: Create directory 5 | connection: local 6 | tasks: 7 | - file: path=configs state=directory 8 | 9 | - hosts: ios 10 | gather_facts: no 11 | connection: local 12 | tasks: 13 | - template: src=ios/common.j2 dest=configs/{{inventory_hostname}}.txt 14 | name: create configuration for IOS devices 15 | 16 | - hosts: nxos 17 | gather_facts: no 18 | connection: local 19 | tasks: 20 | - template: src=nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 21 | name: create configuration for Nexus devices 22 | -------------------------------------------------------------------------------- /Ansible/Logging/configs-unified.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | name: Create directory 5 | connection: local 6 | tasks: 7 | - file: path=configs state=absent 8 | run_once: true 9 | - file: path=configs state=directory 10 | run_once: true 11 | 12 | - name: Build configurations 13 | hosts: all 14 | connection: local 15 | gather_facts: no 16 | tags: build 17 | tasks: 18 | - name: create configuration from platform-specific template 19 | template: src={{ansible_device_os}}/common.j2 dest=configs/{{inventory_hostname}}.txt -------------------------------------------------------------------------------- /Ansible/Logging/configs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | name: Create directory 4 | connection: local 5 | tasks: 6 | - file: path=configs state=directory 7 | 8 | - hosts: ios 9 | connection: local 10 | tasks: 11 | - template: src=ios/common.j2 dest=configs/{{inventory_hostname}}.txt 12 | name: create configuration for IOS devices 13 | 14 | - hosts: nxos 15 | connection: local 16 | tasks: 17 | - template: src=nxos/common.j2 dest=configs/{{inventory_hostname}}.txt 18 | name: create configuration for Nexus devices 19 | -------------------------------------------------------------------------------- /Ansible/Logging/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | name: Create directory 4 | connection: local 5 | gather_facts: no 6 | tags: always 7 | tasks: 8 | - file: path=configs state=directory 9 | run_once: true 10 | 11 | - name: Build configurations 12 | hosts: all 13 | connection: local 14 | gather_facts: no 15 | tags: build 16 | tasks: 17 | - name: create configuration from platform-specific template 18 | template: src={{ansible_device_os}}/common.j2 dest=configs/{{inventory_hostname}}.txt 19 | 20 | - hosts: all 21 | name: Deploy configurations 22 | connection: local 23 | gather_facts: no 24 | tags: deploy 25 | tasks: 26 | - name: copy configuration into the device running config 27 | local_action: > 28 | command /usr/bin/sshpass -p {{ansible_ssh_pass}} 29 | /usr/bin/scp configs/{{inventory_hostname}}.txt {{ansible_user}}@{{inventory_hostname}}:running-config 30 | -------------------------------------------------------------------------------- /Ansible/Logging/ghosts: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local location=Rack-1 3 | 4 | [nxos] 5 | s1.lab.local location=Rack-2 6 | 7 | [all:vars] 8 | ansible_user=cisco 9 | ansible_ssh_pass=cisco 10 | snmp_community=cisco 11 | snmp_contact=admin@lab.local 12 | snmp_host=172.16.1.12 13 | syslog_host=172.16.1.12 -------------------------------------------------------------------------------- /Ansible/Logging/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: cisco 3 | ansible_ssh_pass: cisco 4 | snmp_community: cisco 5 | snmp_contact: admin@lab.local 6 | snmp_host: 172.16.1.12 7 | syslog_host: 172.16.1.12 -------------------------------------------------------------------------------- /Ansible/Logging/group_vars/ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_device_os: ios -------------------------------------------------------------------------------- /Ansible/Logging/group_vars/nxos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_device_os: nxos -------------------------------------------------------------------------------- /Ansible/Logging/host_vars/r1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-1 -------------------------------------------------------------------------------- /Ansible/Logging/host_vars/s1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-2 -------------------------------------------------------------------------------- /Ansible/Logging/hosts: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local 3 | 4 | [nxos] 5 | s1.lab.local -------------------------------------------------------------------------------- /Ansible/Logging/hosts-ng: -------------------------------------------------------------------------------- 1 | r1.lab.local 2 | s1.lab.local -------------------------------------------------------------------------------- /Ansible/Logging/ios/commands.yml: -------------------------------------------------------------------------------- 1 | --- 2 | show_arp: show arp -------------------------------------------------------------------------------- /Ansible/Logging/ios/common.j2: -------------------------------------------------------------------------------- 1 | logging host {{syslog_host}} 2 | ! 3 | snmp-server community {{snmp_community}} RO 4 | snmp-server location {{location}} 5 | snmp-server contact {{snmp_contact}} 6 | snmp-server chassis-id 7 | snmp-server host {{snmp_host}} {{snmp_community}} 8 | -------------------------------------------------------------------------------- /Ansible/Logging/ios/common.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipspace/NetOpsWorkshop/854418ca64c56add35af62814359ebc2b311f8a4/Ansible/Logging/ios/common.js -------------------------------------------------------------------------------- /Ansible/Logging/nxos/commands.yml: -------------------------------------------------------------------------------- 1 | --- 2 | show_arp: show ip arp -------------------------------------------------------------------------------- /Ansible/Logging/nxos/common.j2: -------------------------------------------------------------------------------- 1 | logging server {{syslog_host}} 2 | ! 3 | snmp-server contact {{snmp_contact}} 4 | snmp-server location {{location}} 5 | snmp-server user {{snmp_community}} network-operator 6 | snmp-server host {{snmp_host}} traps version 2 {{snmp_community}} 7 | snmp-server enable traps link 8 | snmp-server community {{snmp_community}} group network-operator 9 | -------------------------------------------------------------------------------- /Ansible/Logging/show-arp-save.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | name: Execute SHOW ARP on all network devices and save results 4 | vars: 5 | output: printouts 6 | vars_files: 7 | - "{{ansible_device_os}}/commands.yml" 8 | 9 | tasks: 10 | - local_action: file path={{output}} state=directory 11 | run_once: true 12 | - raw: "{{show_arp}}" 13 | register: show 14 | - local_action: > 15 | copy content={{show.stdout}} 16 | dest={{output}}/{{inventory_hostname}}.arp.txt -------------------------------------------------------------------------------- /Ansible/Loops/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | library=/usr/local/lib/python2.7/dist-packages/napalm_ansible 3 | inventory=./hosts.yml 4 | gathering=explicit 5 | retry_files_enabled=false 6 | transport=network_cli 7 | force_color=1 8 | host_key_checking=False 9 | 10 | [paramiko_connection] 11 | look_for_keys=False 12 | host_key_auto_add=False 13 | record_host_keys=False 14 | 15 | [netconf_connection] 16 | host_key_checking=False 17 | 18 | -------------------------------------------------------------------------------- /Ansible/Loops/config-users-loop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - name: "Configure users" 5 | ios_config: 6 | lines: 7 | - username {{user.key}} password {{user.value}} 8 | loop: "{{local_users|dict2items}}" 9 | loop_control: 10 | loop_var: user 11 | label: "Configuring {{user.key}}" 12 | -------------------------------------------------------------------------------- /Ansible/Loops/config-users.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - copy: 5 | dest: /tmp/{{inventory_hostname}}.users 6 | content: | 7 | {% for username,password in local_users|dictsort %} 8 | username {{ username }} password {{ password }} 9 | {% endfor %} 10 | - name: "Configure users" 11 | ios_config: 12 | src: /tmp/{{inventory_hostname}}.users 13 | -------------------------------------------------------------------------------- /Ansible/Loops/hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | vars: 4 | ansible_user: cisco 5 | ansible_ssh_pass: cisco 6 | ping_target: 7 | - 172.16.1.1 8 | - 172.16.1.100 9 | - 172.16.1.101 10 | - 172.16.1.105 11 | local_users: 12 | u1: p1 13 | u2: p2 14 | u3: p3 15 | 16 | children: 17 | ios: 18 | hosts: 19 | r1.lab.local: 20 | ansible_host: 172.16.1.100 21 | r2.lab.local: 22 | ansible_host: 172.16.1.102 23 | vars: 24 | ansible_network_os: ios 25 | 26 | nxos: 27 | hosts: 28 | s1.lab.local: 29 | ansible_host: 172.16.1.101 30 | vars: 31 | ansible_network_os: nxos 32 | 33 | junos: 34 | hosts: 35 | srx.lab.local: 36 | ansible_host: 172.16.1.13 37 | vars: 38 | ansible_user: admin 39 | ansible_ssh_pass: admin1 40 | ansible_network_os: junos 41 | -------------------------------------------------------------------------------- /Ansible/Loops/loop-ping-control.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - name: "Ping targets from IOS devices" 5 | ios_command: 6 | commands: "ping vrf Mgmt-intf {{host}}" 7 | register: results 8 | loop: "{{ping_target}}" 9 | loop_control: 10 | loop_var: host 11 | label: "Test #{{count}}: pinging {{host}}" 12 | index_var: count 13 | 14 | - debug: var=results 15 | -------------------------------------------------------------------------------- /Ansible/Loops/loop-ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - name: "Ping targets from IOS devices" 5 | ios_command: 6 | commands: "ping vrf Mgmt-intf {{item}}" 7 | register: results 8 | loop: "{{ping_target}}" 9 | 10 | - debug: var=results 11 | -------------------------------------------------------------------------------- /Ansible/NetFilters/.gitignore: -------------------------------------------------------------------------------- 1 | snap_* 2 | ansible.log 3 | *.pyc 4 | -------------------------------------------------------------------------------- /Ansible/NetFilters/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | library=/usr/local/lib/python2.7/dist-packages/napalm_ansible 3 | inventory=../Networking/hosts 4 | gathering=explicit 5 | retry_files_enabled=false 6 | transport=local 7 | force_color=1 8 | host_key_checking=False 9 | 10 | [paramiko_connection] 11 | look_for_keys=False 12 | host_key_auto_add=False 13 | record_host_keys=False 14 | 15 | [netconf_connection] 16 | host_key_checking=False 17 | 18 | -------------------------------------------------------------------------------- /Ansible/NetFilters/cli_filters/ios_ospf_interfaces.yml: -------------------------------------------------------------------------------- 1 | # CLI filter for "show ip ospf neighbor" Cisco IOS printout 2 | # 3 | --- 4 | vars: 5 | interface: 6 | ifname: "{{ item[0].ifname }}" 7 | admin_state: "{{ item[0].admin_state }}" 8 | op_state: "{{ item[0].op_state }}" 9 | address: "{{ item[1].addr }}" 10 | area: "{{ item[1].area }}" 11 | 12 | keys: 13 | interfaces: 14 | start_block: ".*line protocol is" 15 | end_block: "^$" 16 | type: list 17 | value: "{{ interface }}" 18 | items: 19 | - "^(?P\\S+) is (?P[^,]+), line protocol is (?P\\S+)" 20 | - ".*Internet Address (?P[0-9./]+), Area (?P[0-9.])" 21 | 22 | -------------------------------------------------------------------------------- /Ansible/NetFilters/cli_filters/ios_ospf_neighbor.yml: -------------------------------------------------------------------------------- 1 | # CLI filter for "show ip ospf neighbor" Cisco IOS printout 2 | # 3 | --- 4 | vars: 5 | neighbor: 6 | id: "{{ item.id }}" 7 | state: "{{ item.state }}" 8 | up: "{{ item.state == 'FULL' }}" 9 | address: "{{ item.address}}" 10 | interface: "{{ item.interface }}" 11 | 12 | keys: 13 | neighbors: 14 | type: list 15 | value: "{{ neighbor }}" 16 | items: "^(?P\\d+\\.\\d+\\.\\d+\\.\\d+)[ 0-9]+(?P[A-Z0-9-]+).*?(?P
\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(?P\\S+)" 17 | -------------------------------------------------------------------------------- /Ansible/NetFilters/cli_filters/ios_ospf_neighbor_hash.yml: -------------------------------------------------------------------------------- 1 | # CLI filter for "show ip ospf neighbor" Cisco IOS printout 2 | # 3 | --- 4 | vars: 5 | neighbor: 6 | key: "{{ item.id }}" 7 | values: 8 | state: "{{ item.state }}" 9 | up: "{{ item.state == 'FULL' }}" 10 | address: "{{ item.address}}" 11 | interface: "{{ item.interface }}" 12 | 13 | keys: 14 | neighbors: 15 | type: list 16 | value: "{{ neighbor }}" 17 | items: "^(?P\\d+\\.\\d+\\.\\d+\\.\\d+)[ 0-9]+(?P[A-Z0-9-]+).*?(?P
\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(?P\\S+)" 18 | -------------------------------------------------------------------------------- /Ansible/NetFilters/filter_plugins/list.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple list append filter 3 | # 4 | from __future__ import (absolute_import, division, print_function) 5 | __metaclass__ = type 6 | 7 | from jinja2 import TemplateError 8 | 9 | class FilterModule(object): 10 | 11 | 12 | # 13 | # Append a number of items to the list 14 | # 15 | def list_append(self,l,*argv): 16 | if type(l) is not list: 17 | raise TemplateError("First argument of append filter must be a list") 18 | 19 | for element in argv: 20 | if type(element) is list: 21 | l.extend(element) 22 | else: 23 | l.append(element) 24 | return l 25 | 26 | def dict_to_list(self,o): 27 | if type(o) is not dict: 28 | raise TemplateError("dict_to_list can only be used on dictionaries") 29 | 30 | l = [] 31 | for k,v in o.items(): 32 | v['id'] = k 33 | l.append(v) 34 | 35 | return l 36 | 37 | def filters(self): 38 | return { 39 | 'append': self.list_append, 40 | 'to_list': self.dict_to_list 41 | } -------------------------------------------------------------------------------- /Ansible/NetFilters/ios-ospf-interfaces.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve OSPF interface information 3 | hosts: ios 4 | tasks: 5 | - ios_command: 6 | commands: 7 | - "show ip ospf interface" 8 | register: ospf_printout 9 | 10 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli('cli_filters/ios_ospf_interfaces.yml') }} -------------------------------------------------------------------------------- /Ansible/NetFilters/ios-ospf-neighbor-hash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve OSPF neighbor information 3 | hosts: ios 4 | tasks: 5 | - ios_command: 6 | commands: "show ip ospf neighbor" 7 | register: ospf_printout 8 | 9 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli('cli_filters/ios_ospf_neighbor_hash.yml') }} -------------------------------------------------------------------------------- /Ansible/NetFilters/ios-ospf-neighbor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve OSPF neighbor information 3 | hosts: ios 4 | tasks: 5 | - ios_command: 6 | commands: "show ip ospf neighbor" 7 | register: ospf_printout 8 | 9 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli('cli_filters/ios_ospf_neighbor.yml') }} -------------------------------------------------------------------------------- /Ansible/NetFilters/json_filters.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve BGP neighbor information 3 | hosts: all 4 | roles: 5 | - napalm 6 | tasks: 7 | - napalm_get_facts: 8 | hostname={{ansible_host|default(inventory_hostname)}} 9 | username={{ansible_user}} 10 | password={{ansible_ssh_pass}} 11 | dev_os={{ansible_os}} 12 | filter='bgp_neighbors' 13 | tags: [ always ] 14 | 15 | - include: ../../tools/include/snapshot.yml 16 | when: snapshot is defined 17 | 18 | - name: T1 19 | meta: noop 20 | 21 | - name: Get list of BGP peers from facts dictionary 22 | set_fact: bgp_peer_list={{napalm_bgp_neighbors.global.peers|to_list}} 23 | 24 | - name: Get list of EBGP peers (as dictionary) 25 | set_fact: ebgp_peers={{bgp_peer_list|json_query('[? local_as != remote_as]')}} 26 | 27 | - name: Get list of EBGP peer IDs 28 | set_fact: ebgp_peer_id={{bgp_peer_list|json_query('[? local_as != remote_as].id')}} 29 | 30 | - name: Get list of EBGP peer IDs and prefix count 31 | set_fact: ebgp_peer_pfx={{bgp_peer_list|json_query('[? local_as != remote_as].[id, address_family.ipv4.accepted_prefixes]')}} 32 | 33 | - name: Get list of EBGP peer IDs and prefix count as object 34 | set_fact: 35 | ebgp_peer_dict: | 36 | {{bgp_peer_list|json_query(' 37 | [? local_as != remote_as] 38 | .{neighbor: id, prefixes: address_family.ipv4.accepted_prefixes} 39 | ')}} 40 | 41 | # - debug: 42 | # msg={{ bgp_peer_list|json_query('[? !is_up]') }} -------------------------------------------------------------------------------- /Ansible/NetFilters/ospf_textfsm.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve OSPF neighbor information 3 | hosts: ios 4 | tasks: 5 | - ios_command: 6 | commands: [ show ip ospf neighbor ] 7 | register: ospf_printout 8 | 9 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli_textfsm('textfsm/cisco_ios_show_ip_ospf_neighbor.template') }} -------------------------------------------------------------------------------- /Ansible/NetFilters/parsecli_snapshot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve BGP neighbor information 3 | hosts: all 4 | roles: 5 | - napalm 6 | vars: 7 | - filters: cli_filters/ 8 | tasks: 9 | - ios_command: 10 | commands: 11 | - "{{ show_command | default('show ip ospf neighbor') }}" 12 | register: ospf_printout 13 | 14 | - include: ../../tools/include/snapshot.yml 15 | when: snapshot is defined 16 | 17 | - name: T1 18 | debug: msg={{ospf_printout.stdout}} 19 | 20 | - set_fact: filter={{ filters + cli_filter|default('ios_ospf_neighbor.yml') }} 21 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli(filter) }} -------------------------------------------------------------------------------- /Ansible/NetFilters/textfsm/cisco_ios_show_ip_ospf_neighbor.template: -------------------------------------------------------------------------------- 1 | Value NEIGHBOR_ID (\d+.\d+.\d+.\d+) 2 | Value PRIORITY (\d+) 3 | Value STATE (\S+\/\s+\-|\S+) 4 | Value DEAD_TIME (\d+:\d+:\d+) 5 | Value ADDRESS (\d+.\d+.\d+.\d+) 6 | Value INTERFACE (\S+) 7 | 8 | Start 9 | ^${NEIGHBOR_ID}\s+${PRIORITY}\s+${STATE}\s+${DEAD_TIME}\s+${ADDRESS}\s+${INTERFACE} -> Record 10 | -------------------------------------------------------------------------------- /Ansible/NetFilters/textfsm_snapshot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Retrieve BGP neighbor information 3 | hosts: all 4 | roles: 5 | - napalm 6 | tasks: 7 | - ios_command: 8 | commands: [ show ip ospf neighbor ] 9 | register: ospf_printout 10 | 11 | - include: ../../tools/include/snapshot.yml 12 | when: snapshot is defined 13 | 14 | - name: T1 15 | debug: msg={{ospf_printout.stdout}} 16 | 17 | - debug: msg={{ ospf_printout.stdout[0] | parse_cli_textfsm('textfsm/cisco_ios_show_ip_ospf_neighbor.template') }} -------------------------------------------------------------------------------- /Ansible/Networking/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.txt 3 | -------------------------------------------------------------------------------- /Ansible/Networking/Authentication/hosts-pwd.yml: -------------------------------------------------------------------------------- 1 | all: 2 | hosts: 3 | r1.lab.local: 4 | ansible_host: 172.16.1.100 5 | ansible_connection: network_cli 6 | ansible_network_os: ios 7 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/check-connectivity.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | vars: 4 | ansible_command_timeout: 30 5 | tasks: 6 | - name: "Ping targets from IOS devices" 7 | ios_command: 8 | commands: ping vrf Mgmt-intf {{item}} 9 | loop: "{{ping_target}}" 10 | register: result 11 | failed_when: "not '!!!' in result.stdout[0]" 12 | ignore_errors: yes 13 | 14 | - hosts: nxos 15 | tasks: 16 | - name: "Ping targets from NXOS devices" 17 | nxos_command: 18 | commands: ping {{item}} timeout 1 count 3 vrf management 19 | with_items: "{{ping_target}}" 20 | register: result 21 | failed_when: "not 'icmp_seq' in result.stdout[0]" 22 | ignore_errors: yes 23 | 24 | - hosts: junos 25 | vars: 26 | ansible_command_timeout: 30 27 | tasks: 28 | - name: "Ping targets from Junos devices" 29 | junos_command: 30 | commands: ping count 3 wait 1 {{item}} 31 | display: xml 32 | with_items: "{{ping_target}}" 33 | register: result 34 | failed_when: "result.output[0]['rpc-reply']['ping-results']['ping-failure'] is defined" 35 | ignore_errors: yes 36 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/check-version-junos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: junos 3 | tasks: 4 | - junos_command: 5 | commands: show version 6 | display: xml 7 | register: result 8 | - set_fact: device_version={{ result.output[0]['rpc-reply']['software-information']['package-information'].comment }} 9 | - debug: var=device_version 10 | - fail: msg="Wrong Junos version" 11 | when: "not (version in device_version)" -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/check-version-log.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | tasks: 4 | - file: path=version_report.txt state=absent 5 | - file: path=version_report.txt state=touch 6 | 7 | - hosts: ios 8 | tasks: 9 | - ios_command: 10 | commands: show version 11 | register: result 12 | 13 | - lineinfile: 14 | dest: version_report.txt 15 | regexp: "{{inventory_hostname}}" 16 | line: "{{inventory_hostname}}: IOS version mismatch" 17 | when: "not ('Version '+version in result.stdout[0])" -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/check-version.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - ios_command: 5 | commands: show version 6 | register: result 7 | 8 | - fail: msg="Wrong Cisco IOS version" 9 | when: "not ('Version '+version in result.stdout[0])" 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/collect-many-printouts-ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | tasks: 4 | - file: path=results state=absent 5 | - file: path=results state=directory 6 | 7 | - hosts: ios 8 | vars: 9 | collect: 10 | - show arp 11 | - show version 12 | - show ip interface brief 13 | tasks: 14 | - ios_command: 15 | commands: "{{ collect }}" 16 | register: result 17 | 18 | - copy: 19 | content: | 20 | {{ result.stdout[index] }} 21 | dest: "results/{{inventory_hostname}}_{{item|replace(' ','_')}}.txt" 22 | delegate_to: localhost 23 | loop: "{{ collect }}" 24 | loop_control: 25 | index_var: index 26 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/collect-printout-ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | tasks: 4 | - file: path=results state=absent 5 | - file: path=results state=directory 6 | 7 | - hosts: ios 8 | tasks: 9 | - ios_command: 10 | commands: 11 | - show arp 12 | register: result 13 | 14 | - copy: 15 | content: | 16 | {{ result.stdout[0] }} 17 | dest: "results/{{inventory_hostname}}_show_arp.txt" 18 | delegate_to: localhost 19 | -------------------------------------------------------------------------------- /Ansible/Networking/Command-Playbooks/demo-script.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Command Playbooks** presentation 2 | 3 | ## Initial setup 4 | 5 | * Start the virtual lab; 6 | * Start the Ansible virtual machine 7 | * Log into the Ansible virtual machine 8 | 9 | ``` 10 | . .prompt 11 | rm .ssh/known_hosts 12 | cd /vagrant/Ansible/Networking 13 | . setup.sh 14 | ../../tools/ssh-keys/get-keys.yml 15 | cd Command-Playbooks 16 | ``` 17 | 18 | ## Collect printouts 19 | 20 | ``` 21 | ansible-playbook collect-printout-ios.yml 22 | ``` 23 | 24 | Explore `results` subdirectory 25 | 26 | ``` 27 | ansible-playbook collect-many-printouts-ios.yml 28 | ``` 29 | 30 | Explore `results` subdirectory 31 | 32 | 33 | ## Check device versions 34 | 35 | ``` 36 | more check-version.yml 37 | more ../group_vars/ios.yml 38 | ansible-playbook check-version.yml 39 | ``` 40 | 41 | ``` 42 | more check-version-junos.yml 43 | more ../group_vars/junos.yml 44 | ansible-playbook check-version-junos.yml 45 | ``` 46 | 47 | ``` 48 | more check-version-log.yml 49 | ansible-playbook check-version-log.yml 50 | cat version_report.txt 51 | ``` 52 | 53 | ``` 54 | ansible-playbook check-version-log.yml --extra-vars version=15.6 55 | ``` 56 | 57 | ## Check connectivity 58 | 59 | ``` 60 | more check-connectivity.yml 61 | ansible-playbook check-connectivity.yml -l ios,nxos 62 | ``` 63 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/cli-clear-counters.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | vars: 4 | - ansible_connection: network_cli 5 | tasks: 6 | - cli_command: 7 | command: clear counters 8 | prompt: 9 | - "[confirm]" 10 | answer: 11 | - y 12 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/cli-command-simple.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | - ansible_connection: network_cli 5 | tasks: 6 | - cli_command: 7 | command: show version 8 | register: version 9 | - debug: var=version 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/demo-script.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Executing Commands** presentation 2 | 3 | ## Initial setup 4 | 5 | * Start the virtual lab; 6 | * Start the Ansible virtual machine 7 | * Log into the Ansible virtual machine 8 | 9 | ``` 10 | . .prompt 11 | rm .ssh/known_hosts 12 | cd /vagrant/Ansible/Networking 13 | . setup.sh 14 | ../../tools/ssh-keys/get-keys.yml 15 | cd Commands 16 | ``` 17 | 18 | ## Execute simple commands 19 | 20 | ``` 21 | ansible-playbook -v ios-command.yml -l r1.lab.local 22 | ansible-playbook -v junos-command.yml 23 | ``` 24 | 25 | ## Process command results 26 | 27 | ``` 28 | ansible-playbook ios-command-multiple.yml 29 | more r1.lab.local.txt 30 | ansible-playbook nxos-command-json.yml 31 | cat s1.lab.local.txt 32 | ansible-playbook junos-command-xml.yml 33 | cat srx.lab.local.txt 34 | ``` 35 | 36 | ## Command logging 37 | 38 | Window #1 39 | 40 | ``` 41 | ssh cisco@172.16.1.100 42 | (log in) 43 | conf t 44 | login on-success log 45 | ! 46 | event manager applet CLIlog 47 | event cli pattern ".*" sync no skip no 48 | action 1.0 syslog priority informational msg "$_cli_msg" 49 | action 2.0 set _exit_status "1" 50 | end 51 | term mon 52 | ``` 53 | 54 | Window #2 55 | 56 | ``` 57 | ansible-playbook ios-command-multiple.yml -l r1.lab.local 58 | ``` 59 | 60 | ## Limited command set 61 | 62 | Window #1 63 | 64 | ``` 65 | conf t 66 | username ansible password 0 cisco 67 | username ansible privilege 2 view Ansible 68 | ! 69 | parser view Ansible 70 | secret 5 $1$slTy$cA/Hk/M4F72Msr5BZaHzA/ 71 | commands exec include terminal length 72 | commands exec include terminal width 73 | commands exec include show arp 74 | commands exec include show version 75 | end 76 | ``` 77 | 78 | Window #2 79 | 80 | ``` 81 | ansible-playbook ios-command-multiple.yml -e ansible_user=ansible -l r1.lab.local 82 | ``` 83 | 84 | ## Using cli_command 85 | 86 | ``` 87 | ansible-playbook cli-command-simple.yml 88 | ansible-playbook cli-clear-counters.yml 89 | ``` 90 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/eos-show-arp.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | tasks: 4 | - file: path=arp_table.csv state=absent 5 | - file: path=arp_table.csv state=touch 6 | 7 | - hosts: eos 8 | tasks: 9 | - eos_command: 10 | commands: "show arp | json" 11 | register: result 12 | - debug: var=result 13 | - set_fact: arp_table="{{ result.stdout[0].ipV4Neighbors }}" 14 | - lineinfile: 15 | dest: arp_table.csv 16 | regexp: "^{{inventory_hostname}},{{item['interface']}},{{item['address']}}" 17 | line: "{{inventory_hostname}},{{item['interface']}},{{item['address']}},{{item['hwAddress']}}" 18 | with_items: "{{arp_table}}" -------------------------------------------------------------------------------- /Ansible/Networking/Commands/ios-command-multiple.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - ios_command: 5 | commands: 6 | - show arp 7 | - show ip interface brief 8 | register: results 9 | - template: 10 | src: ios-printouts.j2 11 | dest: "{{inventory_hostname}}.txt" 12 | delegate_to: localhost 13 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/ios-command.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - ios_command: 5 | commands: show version 6 | register: version 7 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/ios-printouts.j2: -------------------------------------------------------------------------------- 1 | Output from SHOW ARP 2 | ==================== 3 | {{ results.stdout[0] }} 4 | 5 | Output from SHOW IP INTERFACES BRIEF 6 | ==================================== 7 | {{ results.stdout[1] }} 8 | 9 | Legend and first ARP entry 10 | ==================================== 11 | {{ results.stdout_lines[0][0] }} 12 | {{ results.stdout_lines[0][1] }} 13 | 14 | Legend and last interface 15 | ==================================== 16 | {{ results.stdout_lines[1][0] }} 17 | {{ results.stdout_lines[1][-1] }} 18 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/junos-command-xml.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: junos 3 | tasks: 4 | - junos_command: 5 | commands: show arp 6 | display: xml 7 | register: results 8 | - template: 9 | src: junos-print-arp.j2 10 | dest: "{{inventory_hostname}}.txt" 11 | delegate_to: localhost 12 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/junos-command.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: junos 3 | tasks: 4 | - junos_command: 5 | commands: "show version" 6 | register: version 7 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/junos-print-arp.j2: -------------------------------------------------------------------------------- 1 | {% set arp = results.output[0]["rpc-reply"]["arp-table-information"] %} 2 | {% for entry in arp["arp-table-entry"] %} 3 | {{ entry["interface-name"] }},{{ entry["ip-address"] }},{{ entry["mac-address"] }} 4 | {% endfor %} -------------------------------------------------------------------------------- /Ansible/Networking/Commands/nxos-command-json.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | tasks: 4 | - nxos_command: 5 | commands: "show ip arp vrf management | json" 6 | register: results 7 | - template: 8 | src: nxos-print-arp.j2 9 | dest: "{{inventory_hostname}}.txt" 10 | delegate_to: localhost 11 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/nxos-enable-api.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | tasks: 4 | - set_fact: ansible_connection="network_cli" 5 | - nxos_nxapi: 6 | state: "{{API|default('present')}}" 7 | connection: network_cli 8 | 9 | -------------------------------------------------------------------------------- /Ansible/Networking/Commands/nxos-print-arp.j2: -------------------------------------------------------------------------------- 1 | {% set arp = results.stdout[0].TABLE_vrf.ROW_vrf.TABLE_adj.ROW_adj %} 2 | {% for entry in arp %} 3 | {{ entry["intf-out"] }},{{ entry["ip-addr-out"] }},{{ entry.mac }} 4 | {% endfor %} -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/.gitignore: -------------------------------------------------------------------------------- 1 | results 2 | backup 3 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/cisco-ios-bgp-as.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | name: "Get BGP AS Number" 4 | tasks: 5 | - ios_command: 6 | commands: 7 | - show ip protocols summary | include bgp 8 | register: protocols 9 | - set_fact: 10 | bgp_as: "{{ protocols.stdout[0]|regex_search('\\d+$') }}" 11 | when: protocols.stdout[0] 12 | - debug: var=bgp_as 13 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-acl-add-before.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure an ACL on Cisco IOS 3 | # 4 | # Final solution: 5 | # * Use 'exact' match to check that the lines are in correct order 6 | # * 'before' parameter removes the ACL if it has to be configured 7 | # 8 | --- 9 | - hosts: ios 10 | tasks: 11 | - name: "Configure ACL on Cisco IOS" 12 | ios_config: 13 | parents: 14 | - "ip access-list extended AllowedTraffic" 15 | lines: 16 | - "permit tcp any eq www any" 17 | - "permit tcp any any eq www" 18 | - "deny tcp any any log" 19 | - "deny ip any any log" 20 | match: exact 21 | before: 22 | - "no ip access-list extended AllowedTraffic" 23 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-acl-add-exact.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure an ACL on Cisco IOS 3 | # 4 | # Second try: let's force the exact match to make sure ACL lines are 5 | # in the correct order 6 | # 7 | --- 8 | - hosts: ios 9 | tasks: 10 | - name: "Configure ACL on Cisco IOS" 11 | ios_config: 12 | parents: 13 | - "ip access-list extended AllowedTraffic" 14 | lines: 15 | - "permit tcp any eq www any" 16 | - "permit tcp any any eq www" 17 | - "deny tcp any any log" 18 | - "deny ip any any log" 19 | match: exact 20 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-acl-add.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure an ACL on Cisco IOS 3 | # 4 | # Simplistic solution, let's list the lines in the ACL and hope for the best 5 | # 6 | --- 7 | - hosts: ios 8 | tasks: 9 | - name: "Configure ACL on Cisco IOS" 10 | ios_config: 11 | parents: 12 | - "ip access-list extended AllowedTraffic" 13 | lines: 14 | - "permit tcp any eq www any" 15 | - "permit tcp any any eq www" 16 | - "deny tcp any any log" 17 | - "deny ip any any log" 18 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-acl-remove.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure an incorrect ACL on Cisco IOS 3 | # 4 | # Use this to playbook to prepare the router configuration for ACL demo 5 | # 6 | --- 7 | - hosts: ios 8 | tasks: 9 | - ios_config: provider="{{cli}}" commands="no ip access-list extended AllowedTraffic" 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-bgp-ios-check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: cisco-ios-bgp-as.yml 3 | 4 | - hosts: ios 5 | vars: 6 | - asnum: 65000 7 | tasks: 8 | - assert: 9 | that: | 10 | bgp_as is not defined or 11 | bgp_as == asnum 12 | msg: Wrong BGP AS number {{ bgp_as|default('') }} configured on the box 13 | 14 | - name: "Configure BGP neighbor on Cisco IOS" 15 | ios_config: 16 | parents: 17 | - "router bgp {{ asnum }}" 18 | lines: 19 | - "neighbor 172.16.1.101 remote-as 65001" 20 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-bgp-ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - name: "Configure BGP neighbor on Cisco IOS" 5 | ios_config: 6 | parents: 7 | - "router bgp 65000" 8 | lines: 9 | - "neighbor 172.16.1.101 remote-as 65001" -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-diff.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Compare startup and running configuration 3 | # 4 | - hosts: ios 5 | tasks: 6 | - ios_config: 7 | diff_against: startup 8 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-enable-http.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Enable HTTP server and save configuration 3 | # 4 | - hosts: ios 5 | tasks: 6 | - ios_config: 7 | lines: 8 | - ip http server 9 | - ip http port 8080 10 | notify: save_config 11 | 12 | handlers: 13 | - name: save_config 14 | ios_config: 15 | save_when: modified 16 | when: not ansible_check_mode 17 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-get.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Get running config 3 | # 4 | - hosts: localhost 5 | tasks: 6 | - file: path=results state=directory 7 | 8 | - hosts: ios 9 | tasks: 10 | - ios_facts: gather_subset=config 11 | - copy: 12 | content: "{{ ansible_net_config }}" 13 | dest: "results/{{ inventory_hostname }}.facts.cfg" 14 | delegate_to: localhost 15 | 16 | - ios_config: backup=yes 17 | register: backup 18 | - debug: msg="Backup config is in {{ backup.backup_path }}" 19 | 20 | - net_get: 21 | src: "system:running-config" 22 | dest: "results/{{ inventory_hostname }}.get.cfg" 23 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-logging.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Enable command logging on Cisco IOS 3 | hosts: ios 4 | tasks: 5 | - ios_config: 6 | src: logging.cfg 7 | register: changes 8 | - debug: var=changes 9 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-simple.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure a few SNMP parameters on Cisco IOS and Nexus OS 3 | # 4 | # Run the playbook with --check first to see what will be changed 5 | # then without --check to do the changes 6 | # 7 | # Repeat the process a few times to see how Ansible figures out 8 | # what needs to be changed 9 | # 10 | --- 11 | - hosts: ios 12 | tasks: 13 | - name: "Configure SNMP on IOS devices" 14 | ios_config: 15 | lines: 16 | - "snmp-server community {{snmp_community}} RO" 17 | - "snmp-server contact {{snmp_contact}}" 18 | - "snmp-server host {{snmp_host}} {{snmp_community}}" 19 | 20 | - hosts: nxos 21 | tasks: 22 | - name: "Configure SNMP on Nexus OS devices" 23 | nxos_config: 24 | lines: 25 | - "snmp-server contact {{snmp_contact}}" 26 | - "snmp-server user {{snmp_community}} network-operator" 27 | - "snmp-server host {{snmp_host}} traps version 2 {{snmp_community}}" 28 | - "snmp-server community {{snmp_community}} group network-operator" 29 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/config-snmp-template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Enable SNMP 3 | hosts: ios 4 | tasks: 5 | - ios_config: 6 | src: snmp.j2 7 | register: changes 8 | - debug: var=changes 9 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/demo-script.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Managing Configurations** presentation 2 | 3 | ## Initial setup 4 | 5 | * Start the virtual lab; 6 | * Start the Ansible virtual machine 7 | * Log into the Ansible virtual machine 8 | 9 | ``` 10 | . .prompt 11 | rm .ssh/known_hosts 12 | cd /vagrant/Ansible/Networking 13 | . setup.sh 14 | ../../tools/ssh-keys/get-keys.yml 15 | cd Setup 16 | ansible-playbook config-eem-applet.yml 17 | ansible-playbook config-simple-cleanup.yml 18 | ansible-playbook config-acl-preset.yml 19 | ansible-playbook clean-bgp-ios.yml -l r2.lab.local -t clean 20 | cd ../Configuration 21 | ``` 22 | 23 | ## Configure SNMP 24 | 25 | ``` 26 | ansible-playbook config-simple.yml --check 27 | ansible-playbook config-simple.yml --check -v 28 | sshpass -p cisco ssh cisco@172.16.1.100 show log 29 | ansible-playbook config-simple.yml -v 30 | sshpass -p cisco ssh cisco@172.16.1.100 show log 31 | ansible-playbook config-simple.yml -v 32 | ``` 33 | 34 | ## Configure BGP Neighbor 35 | 36 | ``` 37 | ansible-playbook -v config-bgp-ios.yml --check -l r1.lab.local 38 | ansible-playbook -v config-bgp-ios.yml -l r1.lab.local 39 | sshpass -p cisco ssh cisco@172.16.1.100 "show running | section router bgp" 40 | ansible-playbook cisco-ios-bgp-as.yml 41 | ansible-playbook config-bgp-ios-check.yml 42 | ``` 43 | 44 | ## Configure ACLs 45 | 46 | ``` 47 | export ANSIBLE_STDOUT_CALLBACK=yaml 48 | ansible-playbook -v config-acl-add.yml -l r1.lab.local 49 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 50 | ansible-playbook -v config-acl-add-exact.yml -l r1.lab.local 51 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 52 | ansible-playbook -v config-acl-add-before.yml -l r1.lab.local 53 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 54 | ``` 55 | 56 | ## Deploying Configuration Files 57 | 58 | ``` 59 | ansible-playbook config-logging.yml 60 | ansible-playbook config-snmp-template.yml 61 | ``` 62 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/logging.cfg: -------------------------------------------------------------------------------- 1 | login on-success log 2 | no banner incoming 3 | no banner exec 4 | no banner login 5 | ! 6 | event manager applet CLIlog 7 | event cli pattern ".*" sync no skip no 8 | action 1.0 syslog priority informational msg "$_cli_msg" 9 | action 2.0 set _exit_status "1" 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Configuration/snmp.j2: -------------------------------------------------------------------------------- 1 | snmp-server community {{snmp_community}} RO 2 | snmp-server contact {{snmp_contact}} 3 | snmp-server host {{snmp_host}} {{snmp_community}} 4 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/ios-loopback.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | name: configure loopbacks 4 | tasks: 5 | - ios_interface: 6 | name: Loopback123 7 | state: up 8 | - ios_l3_interface: 9 | name: Loopback123 10 | ipv4: "{{ ip.Loopback123 }}" 11 | when: ip is defined and ip.Loopback123 is defined 12 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/net-loopback.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios,nxos 3 | name: configure loopbacks 4 | tasks: 5 | - net_interface: 6 | name: Loopback123 7 | state: up 8 | - net_l3_interface: 9 | name: Loopback123 10 | ipv4: "{{ ip.Loopback123 }}" 11 | when: ip is defined and ip.Loopback123 is defined 12 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-clean-interfaces.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: clean interfaces 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_interface: 8 | interface: "Vlan{{item.vlan}}" 9 | state: absent 10 | with_items: "{{ interfaces }}" 11 | when: item.vlan is defined 12 | - nxos_interface: 13 | interface: "{{ item.interface }}" 14 | state: absent 15 | with_items: "{{ interfaces }}" 16 | when: item.interface is defined 17 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-clean-vlan.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: preconfigure VLANs 4 | tags: VLAN 5 | vars: 6 | ansible_connection: network_cli 7 | tasks: 8 | - nxos_vlan: 9 | vlan_range: "101-199" 10 | state: absent 11 | - nxos_vlan: 12 | vlan_id: 201 13 | name: wrong 14 | state: present 15 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-feature.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | tasks: 4 | - nxos_feature: 5 | feature: "{{item}}" 6 | state: enabled 7 | loop: [ ospf,bgp,lldp,bfd ] 8 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-interfaces.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure interfaces 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_interface: 8 | interface: "Vlan{{item.vlan}}" 9 | admin_state: up 10 | with_items: "{{ interfaces }}" 11 | when: item.vlan is defined 12 | - nxos_interface: 13 | interface: "{{ item.interface }}" 14 | admin_state: up 15 | with_items: "{{ interfaces }}" 16 | when: item.interface is defined 17 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-ip-interfaces.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure interfaces IP addresses for VLAN interfaces 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_l3_interface: 8 | name: "Vlan{{item.vlan}}" 9 | ipv4: "{{item.ip}}" 10 | loop: "{{interfaces}}" 11 | when: item.vlan is defined 12 | - nxos_l3_interface: 13 | name: "{{item.interface}}" 14 | ipv4: "{{item.ip}}" 15 | loop: "{{ interfaces }}" 16 | when: item.interface is defined 17 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-vlan-aggregate-data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure VLANs 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - set_fact: 8 | aggregate: > 9 | [ {% for id,name in vlans.iteritems() %} 10 | { "vlan_id": {{id}}, "name": "{{name}}" } 11 | {{ "" if loop.last else "," }} 12 | {% endfor %} ] 13 | - nxos_vlan: 14 | admin_state: up 15 | aggregate: "{{ aggregate }}" 16 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-vlan-aggregate-purge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure VLANs 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_vlan: 8 | admin_state: up 9 | aggregate: 10 | - { vlan_id: 1, name: "default" } 11 | - { vlan_id: 100, name: "mgmt" } 12 | - { vlan_id: 101, name: "web" } 13 | - { vlan_id: 110, name: "db" } 14 | purge: yes 15 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-vlan-aggregate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure VLANs 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_vlan: 8 | admin_state: up 9 | aggregate: 10 | - { vlan_id: 1, name: "default" } 11 | - { vlan_id: 100, name: "mgmt" } 12 | - { vlan_id: 101, name: "web" } 13 | - { vlan_id: 110, name: "db" } 14 | -------------------------------------------------------------------------------- /Ansible/Networking/Declarative-Configuration/nxos-vlan-set.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nxos 3 | name: configure VLANs 4 | vars: 5 | ansible_connection: network_cli 6 | tasks: 7 | - nxos_vlan: 8 | vlan_id: "{{ item.key }}" 9 | admin_state: up 10 | name: "{{ item.value }}" 11 | loop: "{{ vlans|dict2items }}" 12 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/cisco_ios_show_ip_ospf_neighbor.textfsm: -------------------------------------------------------------------------------- 1 | Value NEIGHBOR_ID (\d+.\d+.\d+.\d+) 2 | Value PRIORITY (\d+) 3 | Value STATE (\S+\/\s+\-|\S+) 4 | Value DEAD_TIME (\d+:\d+:\d+) 5 | Value ADDRESS (\d+.\d+.\d+.\d+) 6 | Value INTERFACE (\S+) 7 | 8 | Start 9 | ^${NEIGHBOR_ID}\s+${PRIORITY}\s+${STATE}\s+${DEAD_TIME}\s+${ADDRESS}\s+${INTERFACE} -> Record 10 | # Capture time-stamp if vty line has command time-stamping turned on 11 | ^Load\s+for\s+ 12 | ^Time\s+source\s+is 13 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/device-facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - cisco.ios.ios_facts: 5 | gather_subset: [ interfaces, hardware ] 6 | when: ansible_network_os == 'ios' 7 | 8 | - junipernetworks.junos.junos_facts: 9 | when: ansible_network_os == 'junos' 10 | 11 | - arista.eos.eos_facts: 12 | gather_subset: [ interfaces, hardware ] 13 | when: ansible_network_os == 'eos' 14 | 15 | - debug: var=vars 16 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/eos-arp-csv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: eos 3 | tasks: 4 | - arista.eos.eos_command: 5 | commands: "show arp | json" 6 | register: result 7 | - set_fact: arp_table="{{ result.stdout[0].ipV4Neighbors }}" 8 | - copy: 9 | dest: "{{inventory_hostname}}.arp.csv" 10 | content: | 11 | {% for arp in arp_table %} 12 | {{inventory_hostname}},{{arp.interface}},{{arp.address}},{{arp.hwAddress}} 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/gather-facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: true 4 | module_defaults: 5 | arista.eos.eos_facts: 6 | gather_network_resources: [ interfaces ] 7 | cisco.ios.ios_facts: 8 | gather_subset: [ interfaces,hardware ] 9 | tasks: 10 | - debug: var=ansible_net_version 11 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/hosts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | vars: 4 | ansible_connection: ansible.netcommon.network_cli 5 | ansible_user: lab 6 | ansible_ssh_pass: Complex! 7 | ios: 8 | hosts: 9 | rtr-ios: 10 | ansible_host: 192.168.121.201 11 | vars: 12 | ansible_network_os: ios 13 | eos: 14 | hosts: 15 | sw-eos: 16 | ansible_host: 192.168.121.200 17 | vars: 18 | ansible_network_os: eos 19 | junos: 20 | hosts: 21 | sw-junos: 22 | ansible_host: 172.17.0.2 23 | vars: 24 | ansible_network_os: junos 25 | ansible_connection: ansible.netcommon.netconf 26 | ansible_port: 22 27 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios-config-parse-ttp.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - ansible.netcommon.cli_parse: 6 | command: "show running" 7 | parser: 8 | name: ansible.netcommon.ttp 9 | template_path: ios_config_interface.ttp 10 | register: data 11 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios-ospf-neighbor.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | vars: 5 | home: "{{ lookup('env','HOME') }}" 6 | textfsm_path: "{{ home }}/.ansible/ntc-templates/templates/" 7 | ospf_textfsm: cisco_ios_show_ip_ospf_neighbor.textfsm 8 | tasks: 9 | - cisco.ios.ios_command: 10 | commands: show ip ospf neighbor 11 | register: printout 12 | - set_fact: 13 | ospf_neighbor: 14 | "{{ printout.stdout[0]| 15 | ansible.netcommon.parse_cli_textfsm(textfsm_path+ospf_textfsm)}}" 16 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios-ospf-parse-ntc-templates.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - ansible.netcommon.cli_parse: 6 | command: "show ip ospf neighbor" 7 | parser: 8 | name: ansible.netcommon.ntc_templates 9 | register: data 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios-ospf-parse-pyats.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - ansible.netcommon.cli_parse: 6 | command: "show ip ospf neighbor" 7 | parser: 8 | name: ansible.netcommon.pyats 9 | register: data 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios-ospf-parse-textfsm.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: false 4 | tasks: 5 | - ansible.netcommon.cli_parse: 6 | command: "show ip ospf neighbor" 7 | parser: 8 | name: ansible.netcommon.textfsm 9 | set_fact: ip_ospf_neighbor 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/ios_config_interface.ttp: -------------------------------------------------------------------------------- 1 | interface {{ interface }} 2 | ip address {{ ip }} {{ mask }} 3 | vrf forwarding {{ vrf }} 4 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/junos-route-csv.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: junos 3 | tasks: 4 | - junipernetworks.junos.junos_command: 5 | commands: show route 6 | output: xml 7 | register: result 8 | - copy: 9 | dest: "{{inventory_hostname}}.routes.csv" 10 | content: | 11 | {% set rt = result.output[0]["rpc-reply"]["route-information"]["route-table"][0]["rt"] %} 12 | {% for route in rt %} 13 | {{inventory_hostname}},{{route["rt-destination"]}},{{route["rt-entry"]["nh"]}} 14 | {% endfor %} 15 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/napalm-facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - napalm_get_facts: 5 | hostname: "{{ansible_host|default(inventory_hostname)}}" 6 | username: "{{ansible_user}}" 7 | password: "{{ansible_ssh_pass}}" 8 | dev_os: "{{ansible_network_os}}" 9 | filter: [ arp_table,interfaces ] 10 | -------------------------------------------------------------------------------- /Ansible/Networking/Get-Operational-Data/templates/ios_show_ip_ospf_neighbor.textfsm: -------------------------------------------------------------------------------- 1 | Value NEIGHBOR_ID (\d+.\d+.\d+.\d+) 2 | Value PRIORITY (\d+) 3 | Value STATE (\S+\/\s+\-|\S+) 4 | Value DEAD_TIME (\d+:\d+:\d+) 5 | Value ADDRESS (\d+.\d+.\d+.\d+) 6 | Value INTERFACE (\S+) 7 | 8 | Start 9 | ^${NEIGHBOR_ID}\s+${PRIORITY}\s+${STATE}\s+${DEAD_TIME}\s+${ADDRESS}\s+${INTERFACE} -> Record 10 | # Capture time-stamp if vty line has command time-stamping turned on 11 | ^Load\s+for\s+ 12 | ^Time\s+source\s+is 13 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/clean-bgp-ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | name: "Cleanup BGP configuration from Cisco IOS" 4 | tags: clean 5 | tasks: 6 | - ios_command: 7 | commands: "show ip protocols summary | include bgp" 8 | register: protocols 9 | - set_fact: bgp_as="{% set r = protocols.stdout[0] %}{{ r | regex_replace('^.*bgp\s+(\d+)$','\\1') }}" 10 | - ios_config: 11 | lines: 12 | - "no router bgp {{bgp_as}}" 13 | when: bgp_as 14 | 15 | - hosts: ios 16 | name: "Create BGP process on Cisco IOS" 17 | tags: create 18 | tasks: 19 | - ios_config: 20 | lines: 21 | - "router bgp 123" 22 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-acl-preset.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Configure an incorrect ACL on Cisco IOS 3 | # 4 | # Use this to playbook to prepare the router configuration for ACL demo 5 | # 6 | --- 7 | - hosts: ios 8 | tasks: 9 | - ios_config: 10 | match: exact 11 | before: 12 | - "no ip access-list extended AllowedTraffic" 13 | parents: 14 | - "ip access-list extended AllowedTraffic" 15 | lines: 16 | - "permit tcp any eq www any" 17 | - "deny tcp any any log" 18 | - "deny ip any any log" 19 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-ansible-user.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This playbook configures Ansible user with very limited 3 | # executing capabilities on Cisco IOS, and another user 4 | # that is not privileged (so you can test BECOME functionality) 5 | # 6 | # Use it before running command-ios-limited playbook 7 | # 8 | --- 9 | - hosts: ios 10 | tasks: 11 | - name: "Configure Ansible user" 12 | ios_config: 13 | lines: 14 | - username ansible password 0 ansible 15 | - username ansible privilege 2 view Ansible 16 | - username test password 0 test 17 | 18 | - name: "Configure Ansible view" 19 | ios_config: 20 | parents: 21 | - parser view Ansible 22 | lines: 23 | - secret 5 $1$slTy$cA/Hk/M4F72Msr5BZaHzA/ 24 | - commands exec include terminal length 25 | - commands exec include show arp 26 | - commands exec include show version 27 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-eem-applet.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This playbook configures an EEM applet that logs all commands 3 | # executed on a Cisco IOS device 4 | # 5 | # Use it to monitor commands executed by Ansible on Cisco IOS devices 6 | # 7 | --- 8 | - hosts: ios 9 | tasks: 10 | - name: "Configure log logging" 11 | ios_config: 12 | lines: 13 | - login on-success log 14 | - no banner incoming 15 | - no banner exec 16 | - no banner login 17 | 18 | - name: "Configure EEM applet" 19 | ios_config: 20 | parents: 21 | - event manager applet CLIlog 22 | lines: 23 | - event cli pattern .* sync no skip no 24 | - action 1.0 syslog priority informational msg $_cli_msg 25 | - action 2.0 set _exit_status 1 -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-enable-scp.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This playbook enables SCP on Cisco IOS devices 3 | # 4 | --- 5 | - hosts: ios 6 | tasks: 7 | - name: "Configure SCP on IOS devices" 8 | ios_config: 9 | lines: 10 | - "ip scp server enable" 11 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-enable-snmp.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This playbook removes SNMP configuration from IOS and Nexus-OS devices 3 | # 4 | # Use it before running config-simple playbook, otherwise you won't notice 5 | # any difference 6 | # 7 | --- 8 | - hosts: ios 9 | tasks: 10 | - name: "Configure SNMP on IOS devices" 11 | ios_config: 12 | provider: "{{cli}}" 13 | lines: 14 | - "snmp-server community {{snmp_community}}" 15 | 16 | - hosts: nxos 17 | tasks: 18 | - name: "Configure SNMP on Nexus OS devices" 19 | nxos_config: 20 | provider: "{{cli}}" 21 | lines: 22 | - "snmp-server community {{snmp_community}} group network-operator" 23 | -------------------------------------------------------------------------------- /Ansible/Networking/Setup/config-simple-cleanup.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This playbook removes SNMP configuration from IOS and Nexus-OS devices 3 | # 4 | # Use it before running config-simple playbook, otherwise you won't notice 5 | # any difference 6 | # 7 | --- 8 | - hosts: ios 9 | tasks: 10 | - name: "Unconfigure SNMP on IOS devices" 11 | ios_config: 12 | lines: 13 | - "no snmp-server community {{snmp_community}}" 14 | - "no snmp-server contact {{snmp_contact}}" 15 | - "no snmp-server host {{snmp_host}} {{snmp_community}}" 16 | 17 | - hosts: nxos 18 | vars: 19 | - ansible_connection: network_cli 20 | tasks: 21 | - name: "Unconfigure SNMP on Nexus OS devices" 22 | nxos_config: 23 | lines: 24 | - "no snmp-server contact {{snmp_contact}}" 25 | - "no snmp-server user {{snmp_community}} network-operator" 26 | - "no snmp-server community {{snmp_community}} group network-operator" 27 | - "no snmp-server host {{snmp_host}} version 2c {{snmp_community}}" 28 | -------------------------------------------------------------------------------- /Ansible/Networking/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | library=/usr/local/lib/python2.7/dist-packages/napalm_ansible 3 | inventory=./hosts 4 | gathering=explicit 5 | retry_files_enabled=false 6 | transport=local 7 | force_color=1 8 | host_key_checking=False 9 | 10 | [paramiko_connection] 11 | look_for_keys=False 12 | host_key_auto_add=False 13 | record_host_keys=False 14 | 15 | [netconf_connection] 16 | host_key_checking=False 17 | 18 | -------------------------------------------------------------------------------- /Ansible/Networking/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | snmp_community: cisco 3 | snmp_contact: admin@lab.local 4 | snmp_host: 172.16.1.12 5 | syslog_host: 172.16.1.12 6 | 7 | # Needed for connectivity checks 8 | ping_target: [ '172.16.1.1', '172.16.1.12', '172.16.1.100', '172.16.1.105' ] 9 | 10 | # Needed for interface configuration demos 11 | vlans: 12 | 1: default 13 | 100: mgmt 14 | 101: web 15 | 110: db 16 | -------------------------------------------------------------------------------- /Ansible/Networking/group_vars/ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "15.5(4)M" 3 | ping_target: [ '172.16.1.1', '172.16.1.12', '172.16.1.100', '172.16.1.105' ] 4 | -------------------------------------------------------------------------------- /Ansible/Networking/group_vars/junos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 12.1X47 3 | -------------------------------------------------------------------------------- /Ansible/Networking/host_vars/r1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Needed for BGP configuration demos 3 | bgp: 4 | as: 65000 5 | neighbors: 6 | - { ip: 172.16.1.100, as: 65000 } 7 | - { ip: 172.16.1.102, as: 65002 } 8 | ip: 9 | Loopback123: 172.0.0.1/32 10 | -------------------------------------------------------------------------------- /Ansible/Networking/host_vars/s1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Interface configuration demos 3 | interfaces: 4 | - { vlan: "100", ip: "172.16.1.101/24" } 5 | - { vlan: "101", ip: "192.168.201.3/24" } 6 | - { interface: "loopback0", ip: "192.168.0.1/32" } 7 | 8 | # BGP configuration demos 9 | bgp: 10 | as: 65001 11 | neighbors: 12 | - { ip: 172.16.1.100, as: 65000 } 13 | - { ip: 172.16.1.102, as: 65002 } 14 | -------------------------------------------------------------------------------- /Ansible/Networking/hosts: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local ansible_host=172.16.1.100 3 | r2.lab.local ansible_host=172.16.1.102 4 | 5 | [nxos] 6 | s1.lab.local ansible_host=172.16.1.101 7 | 8 | [junos] 9 | srx.lab.local ansible_host=172.16.1.13 10 | 11 | [all:vars] 12 | ansible_connection=network_cli 13 | ansible_user=cisco 14 | ansible_ssh_pass=cisco 15 | 16 | [ios:vars] 17 | ansible_network_os=ios 18 | 19 | [nxos:vars] 20 | ansible_network_os=nxos 21 | ansible_connection=httpapi 22 | 23 | [junos:vars] 24 | ansible_user=admin 25 | ansible_ssh_pass=admin1 26 | ansible_network_os=junos 27 | ansible_connection=netconf 28 | -------------------------------------------------------------------------------- /Ansible/Networking/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | export ANSIBLE_CONFIG="$PWD/ansible.cfg" 4 | export ANSIBLE_INVENTORY="$PWD/hosts" 5 | # 6 | echo "Set Ansible configuration file to $ANSIBLE_CONFIG" 7 | echo "Ansible inventory used: $ANSIBLE_INVENTORY" 8 | -------------------------------------------------------------------------------- /Ansible/Plugins/.gitignore: -------------------------------------------------------------------------------- 1 | configs/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /Ansible/Plugins/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=./hosts 3 | transport=local 4 | retry_files_enabled=false 5 | gathering=explicit 6 | -------------------------------------------------------------------------------- /Ansible/Plugins/device-type.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set network device type 3 | hosts: all 4 | tasks: 5 | - ios_command: 6 | commands: show version 7 | provider: '{{cli}}' 8 | register: result 9 | - set_fact: 10 | ansible_os: "{{result.stdout[0]|device_type}}" 11 | - debug: msg="Device type for {{inventory_hostname}} set to {{ansible_os}}" 12 | -------------------------------------------------------------------------------- /Ansible/Plugins/filter_plugins/list.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple list append filter 3 | # 4 | from __future__ import (absolute_import, division, print_function) 5 | __metaclass__ = type 6 | 7 | from jinja2 import TemplateError 8 | 9 | class FilterModule(object): 10 | 11 | 12 | # 13 | # Append a number of items to the list 14 | # 15 | def list_append(self,l,*argv): 16 | if type(l) is not list: 17 | raise TemplateError("First argument of append filter must be a list") 18 | 19 | for element in argv: 20 | if type(element) is list: 21 | l.extend(element) 22 | else: 23 | l.append(element) 24 | return l 25 | 26 | def filters(self): 27 | return { 28 | 'append': self.list_append 29 | } -------------------------------------------------------------------------------- /Ansible/Plugins/filter_plugins/net_helper.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple list append filter 3 | # 4 | from __future__ import (absolute_import, division, print_function) 5 | __metaclass__ = type 6 | 7 | from jinja2 import TemplateError 8 | 9 | class FilterModule(object): 10 | 11 | 12 | # 13 | # Figure out network device OS type based on "show version" printout 14 | # 15 | def device_type(self,show_ver,*deftype): 16 | if "Cisco IOS" in show_ver: return "ios" 17 | if "NX-OS" in show_ver: return "nx-os" 18 | if len(deftype) > 0: return deftype[0] 19 | 20 | raise TemplateError("Unknown device type - did you pass me show version?") 21 | 22 | def filters(self): 23 | return { 24 | 'device_type': self.device_type 25 | } -------------------------------------------------------------------------------- /Ansible/Plugins/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | cli: 3 | username: "cisco" 4 | password: "cisco" 5 | host: "{{inventory_hostname}}" 6 | transport: cli 7 | -------------------------------------------------------------------------------- /Ansible/Plugins/hosts: -------------------------------------------------------------------------------- 1 | r1.lab.local ansible_os=ios 2 | s1.lab.local ansible_os=nxos -------------------------------------------------------------------------------- /Ansible/Plugins/test-device-type.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test list plugin 3 | hosts: localhost 4 | connection: local 5 | tasks: 6 | - assert: 7 | that: "'Cisco IOS'|device_type == 'ios'" 8 | msg: Failed to recognize Cisco IOS 9 | - assert: 10 | that: "'NX-OS'|device_type == 'nx-os'" 11 | msg: Failed to recognize Cisco Nexus OS 12 | - assert: 13 | that: "'abcd'|device_type('unknown') == 'unknown'" 14 | msg: failed to process default device type 15 | - set_fact: 16 | x: "{{'aaa'|device_type}}" 17 | ignore_errors: true 18 | register: result 19 | - assert: 20 | that: result|failed 21 | msg: Failed to crash on unknown device type with no default 22 | -------------------------------------------------------------------------------- /Ansible/Plugins/test-list-plugin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Test list plugin 3 | hosts: localhost 4 | connection: local 5 | tasks: 6 | - assert: 7 | that: "[1,2,3]|append(4) is equalto([1,2,3,4])" 8 | msg: Append to list failed 9 | - assert: 10 | that: "[1,2,3]|append(4,5) is equalto([1,2,3,4,5])" 11 | msg: Append multiple elements to list failed 12 | - assert: 13 | that: "[]|append(4) is equalto([4])" 14 | msg: Append to empty list failed 15 | - assert: 16 | that: "[]|append(4,5) is equalto([4,5])" 17 | msg: Append multiple elements to empty list failed 18 | - assert: 19 | that: "[1,2]|append([3,4]) is equalto([1,2,3,4])" 20 | msg: Appending a list to a list should result in a single list 21 | - set_fact: 22 | x: "{{'aaa'|append(4)}}" 23 | ignore_errors: true 24 | register: result 25 | - assert: 26 | that: result|failed 27 | msg: Append to string should fail 28 | -------------------------------------------------------------------------------- /Ansible/Roles/.gitignore: -------------------------------------------------------------------------------- 1 | configs/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /Ansible/Roles/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Roles Demos 2 | 3 | This directory contains demo playbooks used in *Roles* part of *[Creating Reusable Code](https://my.ipspace.net/bin/list?id=Ansible#INCLUDES)* section of *[Ansible for Networking Engineers](https://www.ipspace.net/Ansible_for_Networking_Engineers)* webinar. 4 | 5 | ## Role Includes 6 | 7 | ``` 8 | ansible-playbook config-simple.yml 9 | 10 | ansible-playbook config-ospf.yml 11 | 12 | ansible-playbook config-ospf-2.yml 13 | 14 | cat config-ospf-area.yml 15 | ansible-playbook config-ospf-area.yml 16 | ansible-playbook config-ospf-area.yml -t create 17 | 18 | ansible-playbook config-complete.yml -e config_cleanup=true 19 | tree configs 20 | ``` 21 | 22 | ## Role Imports and Includes 23 | 24 | ``` 25 | cat import-tasks.yml 26 | ansible-playbook config-import.yml 27 | cat config-include.yml 28 | ansible-playbook config-include.yml 29 | ``` 30 | 31 | ## Installing Collections 32 | 33 | ``` 34 | rm -fr ~/.ansible/collections/ansible_collections/ipspace/ 35 | cat requirements.yml 36 | ansible-galaxy install -r requirements.yml 37 | tree ~/.ansible/collections/ansible_collections/ipspace/config 38 | cat requirements-devel.yml 39 | ansible-galaxy install -r requirements-devel.yml 40 | rm -fr ~/.ansible/collections/ansible_collections/ipspace/ 41 | ansible-galaxy install -r requirements-devel.yml 42 | tree ~/.ansible/collections/ansible_collections/ipspace/config 43 | ``` 44 | 45 | ## Using Collections 46 | 47 | ``` 48 | cat config-collection.yml 49 | ansible-playbook config-collection.yml 50 | cat config-collection-namespace.yml 51 | ansible-playbook config-collection-namespace.yml 52 | tree roles 53 | ``` 54 | -------------------------------------------------------------------------------- /Ansible/Roles/config-collection-namespace.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | collections: 4 | - ipspace.config 5 | 6 | tasks: 7 | - import_role: 8 | name: directory 9 | tasks_from: prepare.yml 10 | 11 | - import_role: 12 | name: ospf_router 13 | 14 | - import_role: 15 | name: directory 16 | tasks_from: assemble.yml 17 | -------------------------------------------------------------------------------- /Ansible/Roles/config-collection.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - import_role: 5 | name: ipspace.config.directory 6 | tasks_from: prepare.yml 7 | 8 | - import_role: 9 | name: ipspace.config.ospf_router 10 | 11 | - import_role: 12 | name: ipspace.config.directory 13 | tasks_from: assemble.yml 14 | -------------------------------------------------------------------------------- /Ansible/Roles/config-complete.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | configs: configs/{{inventory_hostname}} 5 | 6 | pre_tasks: 7 | - file: path={{configs}} state=directory 8 | 9 | roles: 10 | - ospf_router 11 | 12 | post_tasks: 13 | - assemble: 14 | src: "{{configs}}" 15 | dest: "configs/{{inventory_hostname}}.cfg" 16 | -------------------------------------------------------------------------------- /Ansible/Roles/config-import.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | configs: configs 5 | tasks: 6 | - debug: msg="AREA {{ ospf_area }}" 7 | - import_role: 8 | name: ospf_router 9 | vars: 10 | ospf_area: 1 11 | - debug: msg="AREA {{ ospf_area }}" 12 | -------------------------------------------------------------------------------- /Ansible/Roles/config-include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars: 4 | configs: configs 5 | tasks: 6 | - debug: msg="AREA {{ ospf_area|default('undefined') }}" 7 | 8 | - include_role: 9 | name: network_device 10 | - include_role: 11 | name: ospf_router 12 | public: yes 13 | vars: 14 | ospf_area: 2 15 | - debug: msg="AREA {{ ospf_area|default('undefined') }}" 16 | -------------------------------------------------------------------------------- /Ansible/Roles/config-ospf-2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | 5 | - hosts: all 6 | vars: 7 | configs: configs 8 | roles: 9 | - ospf_router 10 | -------------------------------------------------------------------------------- /Ansible/Roles/config-ospf-area.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | tags: [ setup ] 5 | 6 | - hosts: all 7 | vars: 8 | configs: configs 9 | roles: 10 | - role: ospf_router 11 | vars: 12 | ospf_area: 1 13 | tags: [ create ] 14 | -------------------------------------------------------------------------------- /Ansible/Roles/config-ospf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | 5 | - hosts: all 6 | vars: 7 | configs: configs 8 | roles: 9 | - network_device 10 | - ospf_router -------------------------------------------------------------------------------- /Ansible/Roles/config-simple.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_playbook: setup-directory.yml 3 | name: set up working directories 4 | 5 | - hosts: all 6 | vars: 7 | configs: configs 8 | roles: 9 | - network_device -------------------------------------------------------------------------------- /Ansible/Roles/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | snmp_community: cisco 3 | snmp_contact: admin@lab.local 4 | snmp_host: 172.16.1.12 5 | syslog_host: 172.16.1.12 6 | -------------------------------------------------------------------------------- /Ansible/Roles/host_vars/r1.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-1 3 | -------------------------------------------------------------------------------- /Ansible/Roles/host_vars/r2.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-2 3 | -------------------------------------------------------------------------------- /Ansible/Roles/host_vars/s1.lab.local/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | location: Rack-2 3 | -------------------------------------------------------------------------------- /Ansible/Roles/requirements-devel.yml: -------------------------------------------------------------------------------- 1 | collections: 2 | - name: https://github.com/ipspace/NetOpsWorkshop.git#Ansible/Collections/config-collection 3 | type: git 4 | version: collection-devel 5 | -------------------------------------------------------------------------------- /Ansible/Roles/requirements.yml: -------------------------------------------------------------------------------- 1 | collections: 2 | - name: https://github.com/ipspace/NetOpsWorkshop.git#Ansible/Collections/config-collection 3 | type: git 4 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/network_device/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: 3 | src: "{{ansible_network_os}}-common.j2" 4 | dest: "{{configs}}/00-common-{{inventory_hostname}}.inc" 5 | name: create common device configuration -------------------------------------------------------------------------------- /Ansible/Roles/roles/network_device/templates/ios-common.j2: -------------------------------------------------------------------------------- 1 | hostname {{inventory_hostname}} 2 | ! 3 | logging host {{syslog_host}} 4 | ! 5 | snmp-server community {{snmp_community}} RO 6 | snmp-server location {{location}} 7 | snmp-server contact {{snmp_contact}} 8 | snmp-server chassis-id 9 | snmp-server host {{snmp_host}} {{snmp_community}} 10 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/network_device/templates/nxos-common.j2: -------------------------------------------------------------------------------- 1 | hostname {{inventory_hostname}} 2 | ! 3 | logging server {{syslog_host}} 4 | ! 5 | snmp-server contact {{snmp_contact}} 6 | snmp-server location {{location}} 7 | snmp-server user {{snmp_community}} network-operator 8 | snmp-server host {{snmp_host}} traps version 2 {{snmp_community}} 9 | snmp-server enable traps link 10 | snmp-server community {{snmp_community}} group network-operator 11 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/ospf_router/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ospf_area: 0 3 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/ospf_router/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: 3 | - network_device 4 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/ospf_router/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - template: 3 | src: "{{ansible_network_os}}-ospf.j2" 4 | dest: "{{configs}}/10-ospf-{{inventory_hostname}}.inc" 5 | name: create OSPF routing process 6 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/ospf_router/templates/ios-ospf.j2: -------------------------------------------------------------------------------- 1 | ! 2 | router ospf 1 3 | ! 4 | {% if loopback is defined %} 5 | interface loopback0 6 | ip ospf 1 area {{ ospf_area }} 7 | {% endif %} 8 | {% for l in links|default([]) %} 9 | ! 10 | interface {{l.ifname}} 11 | ip ospf 1 area {{ospf_area}} 12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /Ansible/Roles/roles/ospf_router/templates/nxos-ospf.j2: -------------------------------------------------------------------------------- 1 | ! 2 | feature ospf 3 | router ospf 1 4 | ! 5 | {% if loopback is defined %} 6 | interface loopback0 7 | ip ospf 1 area {{ ospf_area }} 8 | {% endif %} 9 | {% for l in links|default([]) %} 10 | ! 11 | interface {{l.ifname}} 12 | ip ospf 1 area {{ospf_area}} 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /Ansible/Roles/setup-directory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | name: Create directory 4 | tasks: 5 | - name: clean up config directory 6 | file: path=configs state=absent 7 | when: config_cleanup is defined 8 | - name: create config directory 9 | file: path=configs state=directory -------------------------------------------------------------------------------- /Ansible/Roles/topology.yml: -------------------------------------------------------------------------------- 1 | nodes: 2 | - name: r1.lab.local 3 | device: iosv 4 | - name: r2.lab.local 5 | device: iosv 6 | - name: s1.lab.local 7 | device: nxos 8 | 9 | links: 10 | - r1.lab.local: 11 | r2.lab.local: 12 | - r1.lab.local: 13 | s1.lab.local: 14 | - r2.lab.local: 15 | s1.lab.local: 16 | -------------------------------------------------------------------------------- /Ansible/SNMPFacts/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: cisco 3 | ansible_ssh_pass: cisco 4 | snmp_community: cisco 5 | snmp_contact: admin@lab.local 6 | snmp_host: 172.16.1.12 7 | syslog_host: 172.16.1.12 -------------------------------------------------------------------------------- /Ansible/SNMPFacts/group_vars/ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_device_os: ios -------------------------------------------------------------------------------- /Ansible/SNMPFacts/group_vars/nxos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_device_os: nxos -------------------------------------------------------------------------------- /Ansible/SNMPFacts/hosts: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local 3 | 4 | [nxos] 5 | s1.lab.local -------------------------------------------------------------------------------- /Ansible/SNMPFacts/snmp-facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Gather facts through SNMP 3 | hosts: ios 4 | connection: local 5 | gather_facts: no 6 | tasks: 7 | - snmp_facts: host={{ inventory_hostname }} version=v2c community={{snmp_community}} -------------------------------------------------------------------------------- /Ansible/Simple/debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - debug: var=vars 6 | -------------------------------------------------------------------------------- /Ansible/Simple/ghosts: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local 3 | 4 | [nxos] 5 | s1.lab.local 6 | 7 | [all:vars] 8 | ansible_user=cisco 9 | ansible_ssh_pass=cisco -------------------------------------------------------------------------------- /Ansible/Simple/hosts: -------------------------------------------------------------------------------- 1 | r1.lab.local 2 | s1.lab.local 3 | -------------------------------------------------------------------------------- /Ansible/Simple/shosts: -------------------------------------------------------------------------------- 1 | r1.lab.local 2 | s1.lab.local 3 | 4 | [all:vars] 5 | ansible_user=cisco 6 | ansible_ssh_pass=cisco 7 | -------------------------------------------------------------------------------- /Ansible/Simple/show-arp-conditional.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | tasks: 5 | - raw: "show arp" 6 | register: show_ios 7 | when: "'ios' in group_names" 8 | - raw: "show ip arp" 9 | register: show_nxos 10 | when: "'nxos' in group_names" 11 | - debug: 12 | var: | 13 | show_ios.stdout_lines| 14 | default(show_nxos.stdout_lines) 15 | -------------------------------------------------------------------------------- /Ansible/Simple/show-arp-simple-debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | gather_facts: no 4 | tasks: 5 | - raw: "show arp" 6 | register: show 7 | - debug: var=vars -------------------------------------------------------------------------------- /Ansible/Simple/show-arp-simple-fail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | tasks: 4 | - raw: "show arp" 5 | 6 | - hosts: nxos 7 | tasks: 8 | - raw: "show ip arp" -------------------------------------------------------------------------------- /Ansible/Simple/show-arp-simple-show.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | gather_facts: no 4 | tasks: 5 | - raw: "show arp" 6 | register: show 7 | - debug: var=show.stdout_lines 8 | 9 | - hosts: nxos 10 | gather_facts: no 11 | tasks: 12 | - raw: "show ip arp" 13 | register: show 14 | - debug: var=show.stdout_lines 15 | -------------------------------------------------------------------------------- /Ansible/Simple/show-arp-simple.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: ios 3 | gather_facts: no 4 | tasks: 5 | - raw: "show arp" 6 | 7 | - hosts: nxos 8 | gather_facts: no 9 | tasks: 10 | - raw: "show ip arp" -------------------------------------------------------------------------------- /Ansible/Variables/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=hosts.ini 3 | gathering=explicit 4 | retry_files_enabled=false 5 | force_color=1 6 | host_key_checking=False 7 | 8 | [paramiko_connection] 9 | look_for_keys=False 10 | host_key_auto_add=False 11 | record_host_keys=False 12 | 13 | [netconf_connection] 14 | host_key_checking=False 15 | 16 | -------------------------------------------------------------------------------- /Ansible/Variables/debug-dump-all.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Dump all Ansible variables into .variables.txt 3 | # 4 | --- 5 | - hosts: all 6 | tasks: 7 | - copy: 8 | content: "{{ hostvars[inventory_hostname]|to_yaml }}" 9 | dest: "{{ inventory_hostname }}.variables.txt" 10 | delegate_to: localhost 11 | -------------------------------------------------------------------------------- /Ansible/Variables/debug-dump-single.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Dump all Ansible variables into .variables.txt 3 | # 4 | --- 5 | - hosts: localhost 6 | vars: 7 | dir: /tmp 8 | tasks: 9 | - shell: ls {{ dir }} 10 | register: files 11 | - copy: 12 | content: "{{ files|to_yaml }}" 13 | dest: "{{ inventory_hostname }}.files.txt" 14 | delegate_to: localhost 15 | -------------------------------------------------------------------------------- /Ansible/Variables/debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | vars: 4 | dir: /tmp 5 | tasks: 6 | - shell: ls {{ dir }} 7 | register: files 8 | - debug: var=files 9 | -------------------------------------------------------------------------------- /Ansible/Variables/demo-script.md: -------------------------------------------------------------------------------- 1 | # Ansible Variables Demo Script 2 | 3 | Prepare for the demo 4 | 5 | * Change prompt if needed 6 | * Unset all Ansible environment variables 7 | 8 | ``` 9 | export PS1='\033[33m\W\[\033[00m $ ' 10 | ``` 11 | 12 | ## Inventory and Host/Group Variables 13 | 14 | Variables in inventory file 15 | 16 | ``` 17 | more hosts.values.ini 18 | ansible-inventory -i hosts.values.ini --host r1.lab.local 19 | ansible-inventory -i hosts.values.ini --graph --vars 20 | ``` 21 | 22 | Variables in host_vars and group_vars 23 | 24 | ``` 25 | cat hosts.ini 26 | tree *vars 27 | ansible-inventory --host r1.lab.local 28 | cat host_vars/r2*/* 29 | ansible-inventory --host r2.lab.local 30 | ansible -m debug -a var=hostvars[inventory_hostname] r2.lab.local 31 | ``` 32 | 33 | ## Fact Gathering 34 | 35 | ``` 36 | ansible -m setup localhost|less 37 | ``` 38 | 39 | ## Play-Task-Block Variables 40 | 41 | ``` 42 | cat play-block-task-vars.yml 43 | ansible-playbook play-block-task-vars.yml 44 | cat play-task-facts.yml 45 | ansible-playbook play-task-facts.yml 46 | cat play-block-facts.yml 47 | ansible-playbook play-block-facts.yml 48 | ``` 49 | 50 | ## Fact Caching 51 | 52 | ``` 53 | cat fact-caching.yml 54 | ansible-playbook fact-caching.yml 55 | ``` 56 | 57 | ## Debugging 58 | 59 | Inspecting registered variables 60 | 61 | ``` 62 | cat get-files.yml 63 | ansible-playbook -v get-files.yml 64 | export ANSIBLE_STDOUT_CALLBACK=yaml 65 | ansible-playbook -v get-files.yml 66 | unset ANSIBLE_STDOUT_CALLBACK 67 | cat debug.yml 68 | ansible-playbook debug.yml 69 | export ANSIBLE_STDOUT_CALLBACK=yaml 70 | ansible-playbook debug.yml 71 | ``` 72 | 73 | Dumping variables into files 74 | 75 | ``` 76 | cat debug-dump-single.yml 77 | ansible-playbook debug-dump-single.yml 78 | cat localhost.files.txt 79 | cat debug-dump-all.yml 80 | ansible-playbook debug-dump-all.yml -l r2.lab.local 81 | cat r2.lab.local.variables.txt 82 | ``` 83 | -------------------------------------------------------------------------------- /Ansible/Variables/fact-caching.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Demonstrate fact caching 3 | # 4 | --- 5 | - hosts: localhost 6 | vars: 7 | dir: /tmp 8 | tasks: 9 | - name: First play 10 | debug: var=dir 11 | - set_fact: user=test 12 | - shell: ls {{ dir }} 13 | register: files 14 | 15 | - hosts: localhost 16 | tasks: 17 | - name: Second play, directory 18 | debug: var=dir 19 | - name: Second play, user 20 | debug: var=user 21 | - name: Second play, files 22 | debug: var=files 23 | -------------------------------------------------------------------------------- /Ansible/Variables/get-files.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | vars: 4 | dir: /tmp 5 | tasks: 6 | - shell: ls {{ dir }} 7 | register: files 8 | -------------------------------------------------------------------------------- /Ansible/Variables/group_vars/all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_connection: network_cli 3 | ansible_user: cisco 4 | ansible_ssh_pass: cisco 5 | -------------------------------------------------------------------------------- /Ansible/Variables/group_vars/ios.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: ios 3 | -------------------------------------------------------------------------------- /Ansible/Variables/group_vars/junos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: admin 3 | ansible_ssh_pass: admin1 4 | ansible_network_os: junos 5 | ansible_connection: netconf 6 | -------------------------------------------------------------------------------- /Ansible/Variables/group_vars/nxos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_network_os: nxos 3 | ansible_connection: httpapi 4 | -------------------------------------------------------------------------------- /Ansible/Variables/host_vars/r1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_host: 172.16.1.100 3 | -------------------------------------------------------------------------------- /Ansible/Variables/host_vars/r2.lab.local/connection.yml: -------------------------------------------------------------------------------- 1 | # 2 | # connection.yml 3 | --- 4 | ansible_host: 172.16.1.102 5 | -------------------------------------------------------------------------------- /Ansible/Variables/host_vars/r2.lab.local/description.yml: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # description.yml 4 | --- 5 | description: "Cisco IOS router {{ inventory_hostname }} at {{ ansible_host }}" 6 | -------------------------------------------------------------------------------- /Ansible/Variables/host_vars/s1.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_host: 172.16.1.101 3 | -------------------------------------------------------------------------------- /Ansible/Variables/host_vars/srx.lab.local.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_host: 172.16.1.13 3 | -------------------------------------------------------------------------------- /Ansible/Variables/hosts.ini: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local 3 | r2.lab.local 4 | 5 | [nxos] 6 | s1.lab.local 7 | 8 | [junos] 9 | srx.lab.local 10 | -------------------------------------------------------------------------------- /Ansible/Variables/hosts.values.ini: -------------------------------------------------------------------------------- 1 | [ios] 2 | r1.lab.local ansible_host=172.16.1.100 3 | r2.lab.local ansible_host=172.16.1.102 4 | 5 | [nxos] 6 | s1.lab.local ansible_host=172.16.1.101 7 | 8 | [junos] 9 | srx.lab.local ansible_host=172.16.1.13 10 | 11 | [all:vars] 12 | ansible_connection=network_cli 13 | ansible_user=cisco 14 | ansible_ssh_pass=cisco 15 | 16 | [ios:vars] 17 | ansible_network_os=ios 18 | 19 | [nxos:vars] 20 | ansible_network_os=nxos 21 | ansible_connection=httpapi 22 | 23 | [junos:vars] 24 | ansible_user=admin 25 | ansible_ssh_pass=admin1 26 | ansible_network_os=junos 27 | ansible_connection=netconf 28 | -------------------------------------------------------------------------------- /Ansible/Variables/play-block-facts.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Demonstrate local variables 3 | # 4 | --- 5 | - hosts: localhost 6 | vars: 7 | dir: /bin 8 | tasks: 9 | - name: First in play 10 | debug: var=dir 11 | - block: 12 | - debug: var=dir 13 | name: Within a block 14 | - set_fact: dir=/tmp 15 | - debug: var=dir 16 | name: Within block, after set_fact 17 | vars: 18 | dir: /usr/local/bin 19 | - name: Outside of block 20 | debug: var=dir 21 | -------------------------------------------------------------------------------- /Ansible/Variables/play-block-task-vars.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Demonstrate local variables 3 | # 4 | --- 5 | - hosts: localhost 6 | vars: 7 | dir: /bin 8 | tasks: 9 | - name: First in play 10 | debug: var=dir 11 | - block: 12 | - debug: var=dir 13 | name: Within a block 14 | - debug: var=dir 15 | name: Task variable 16 | vars: 17 | dir: /tmp 18 | - debug: var=dir 19 | name: Back in block 20 | vars: 21 | dir: /usr/local/bin 22 | - name: Outside of block 23 | debug: var=dir 24 | -------------------------------------------------------------------------------- /Ansible/Variables/play-task-facts.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Demonstrate local variables 3 | # 4 | --- 5 | - hosts: localhost 6 | vars: 7 | dir: /bin 8 | tasks: 9 | - name: First in play 10 | debug: var=dir 11 | - set_fact: dir=/tmp 12 | - debug: var=dir 13 | name: After set_fact 14 | - debug: var=dir 15 | name: Task variable 16 | vars: 17 | dir: /usr/local/bin 18 | -------------------------------------------------------------------------------- /Ansible/Vault/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | library=/usr/local/lib/python2.7/dist-packages/napalm_ansible 3 | inventory=./hosts.yaml 4 | gathering=explicit 5 | retry_files_enabled=false 6 | transport=local 7 | force_color=1 8 | host_key_checking=False 9 | 10 | -------------------------------------------------------------------------------- /Ansible/Vault/dump.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Dump Ansible variables 3 | hosts: all 4 | tasks: 5 | - debug: 6 | msg: > 7 | username: {{ansible_user}} 8 | password: {{ansible_ssh_pass}} -------------------------------------------------------------------------------- /Ansible/Vault/group_vars/all/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: "{{vault_ansible_user}}" 3 | ansible_ssh_pass: "{{vault_ansible_pass}}" -------------------------------------------------------------------------------- /Ansible/Vault/group_vars/all/x.yml: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 36356362343537346265303661343331386138336466323965653736336566653030333438613233 3 | 6230326131396631393361663865623263356130333865630a356339383562623564396537356265 4 | 63386538363030363733363266633365333239333637646565303766653533656237333764303630 5 | 6333663563303565350a613736303364643634636161373837643831316137653337383536396438 6 | 36343634353939666135306238653034313735626637656439653739363036643030326264646433 7 | 36396366613131376239666235353133356464376439616362303935653435333461306531386164 8 | 633130633962393931396164343433393064 9 | -------------------------------------------------------------------------------- /Ansible/Vault/host_vars/r1.yml: -------------------------------------------------------------------------------- 1 | ansible_os: ios 2 | ansible_ssh_pass: !vault | 3 | $ANSIBLE_VAULT;1.1;AES256 4 | 62623839303064363133653334313063333865613864303366343064653761643633663239633533 5 | 6134333266616634323262336531336139346132373730370a396161643332346636343764663838 6 | 64366161633133306365323366646161323238333934363461663137383034626434623861663038 7 | 6165333532343930640a643737316165326536663536346665633733346265646639383063323337 8 | 3363 -------------------------------------------------------------------------------- /Ansible/Vault/hosts.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | all: 3 | hosts: 4 | r1: 5 | r2: 6 | -------------------------------------------------------------------------------- /Ansible/Vault/pass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | print "123456"; 3 | -------------------------------------------------------------------------------- /Ansible/Vault/pass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo $VAULT 3 | -------------------------------------------------------------------------------- /Docker/.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | -------------------------------------------------------------------------------- /Docker/Centos/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos8 2 | LABEL author="Ivan Pepelnjak" \ 3 | maintainer="ip@ipspace.net" 4 | RUN echo "===> Install packages ..." 5 | COPY requirements-yum.txt /tmp/requirements-yum.txt 6 | RUN yum -y update && \ 7 | yum install -y epel-release && \ 8 | yum install --enablerepo=epel -y $(strings -1 /tmp/requirements-yum.txt | tr '\n' ' ') 9 | RUN echo "===> Set 'python' to refer to python3 ..." 10 | RUN alternatives --set python /usr/bin/python3 11 | RUN echo "===> Install Ansible (Core & Collections) & dependency Python packages ..." 12 | COPY requirements.txt /tmp/requirements.txt 13 | COPY requirements.yml /tmp/requirements.yml 14 | RUN pip3 install --upgrade -r /tmp/requirements.txt && \ 15 | ansible-galaxy collection install -p /usr/share/ansible/collections -r /tmp/requirements.yml 16 | RUN echo "===> Clean up ..." 17 | RUN yum clean all && \ 18 | rm -rf /var/cache/yum /tmp/* 19 | WORKDIR /ansible 20 | -------------------------------------------------------------------------------- /Docker/Centos/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t ipspace/automation:centos --no-cache . 3 | -------------------------------------------------------------------------------- /Docker/Centos/requirements-yum.txt: -------------------------------------------------------------------------------- 1 | sshpass 2 | python3 3 | python3-setuptools 4 | python3-pip 5 | python3-devel 6 | gcc 7 | openssl-devel 8 | bzip2-devel 9 | libffi-devel 10 | make 11 | git 12 | jq 13 | vim 14 | nano 15 | ipmitool -------------------------------------------------------------------------------- /Docker/Centos/requirements.txt: -------------------------------------------------------------------------------- 1 | ncclient==0.6.9 2 | cryptography==3.3.2 3 | ansible==7.0.0 4 | networklab 5 | paramiko 6 | netmiko 7 | textfsm 8 | pylint>=2.1.1 9 | yapf>=0.2.4 10 | requests>=2.2.0 11 | urllib3>=1.24 12 | lxml>=4.2.5 13 | jmespath 14 | scp 15 | ciscoconfparse 16 | netaddr 17 | genie 18 | pyats 19 | pynetbox 20 | objectpath 21 | napalm 22 | napalm-ansible 23 | yamllint 24 | yq 25 | ntc-templates 26 | ttp 27 | -------------------------------------------------------------------------------- /Docker/Centos/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: cisco.asa 4 | - name: cisco.nxos 5 | - name: cisco.ios 6 | - name: cisco.iosxr 7 | - name: arista.eos 8 | - name: f5networks.f5_modules 9 | - name: netbox.netbox 10 | - name: community.general 11 | - name: junipernetworks.junos 12 | -------------------------------------------------------------------------------- /Docker/Centos/run-automation: -------------------------------------------------------------------------------- 1 | docker run -it --rm \ 2 | --user $(id -u):$(id -g) \ 3 | --volume $(pwd):/ansible \ 4 | --volume="/etc/group:/etc/group:ro" \ 5 | --volume="/etc/passwd:/etc/passwd:ro" \ 6 | --volume="/etc/shadow:/etc/shadow:ro" \ 7 | --volume="/home/$USER:/home/$USER" \ 8 | ipspace/automation:centos $@ 9 | -------------------------------------------------------------------------------- /Docker/README.md: -------------------------------------------------------------------------------- 1 | # Build your own network automation container 2 | 3 | The subdirectories of this directory contain _Dockerfile_ and related lists of packages, Python modules, and Ansible collections that result in a container-packaged network automation development environment including: 4 | 5 | * Git 6 | * Ansible 7 | * NAPALM 8 | * PyATS 9 | * PyNetBox 10 | * jq 11 | * yq 12 | * YAMLlint 13 | 14 | Each subdirectory contains a typical build script (_build.sh_) and a run script (_run.sh_) that you can use to start the container as non-root user. 15 | 16 | Based on your preference for Linux distributions, you can build either a Centos-based or a Ubuntu-based container. Ubuntu-based container uses Ansible release 5.0.1, Centos-based container uses release 4.9.0 because later releases require Python 3.8 (Centos 8 is still on Python 3.6). 17 | 18 | Please feel free to extend the container to fit your needs: 19 | 20 | * To add Centos or Ubuntu packages, modify _requirements-yum.txt_ or _requirements-apt.txt_. 21 | * To add your own Python-based tools to the container, modify _requirements.txt_ 22 | * To add Ansible collections, modify _requirements.yml_ 23 | 24 | If you're using Mac or Windows as your development environment use _Docker Desktop_ to create the containers, but if you're as paranoid about messing up your production laptop as I am, you might prefer using a Linux virtual machine. In that case, use _Vagrantfile_ in this directory to get a fully functional Ubuntu VM with Docker. 25 | 26 | Finally, I'm positive it's perfectly possible to build a much more optimized container. Pull requests along these lines are highly appreciated. 27 | -------------------------------------------------------------------------------- /Docker/Ubuntu/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | LABEL author="Ivan Pepelnjak" \ 3 | maintainer="ip@ipspace.net" 4 | RUN echo "===> Install packages ..." 5 | COPY apt-install.sh /tmp/apt-install.sh 6 | COPY requirements-apt.txt /tmp/requirements-apt.txt 7 | RUN bash /tmp/apt-install.sh 8 | RUN echo "===> Install Ansible (Core & Collections) & dependency Python packages ..." 9 | COPY requirements.txt /tmp/requirements.txt 10 | COPY requirements.yml /tmp/requirements.yml 11 | RUN pip3 install --upgrade -r /tmp/requirements.txt && \ 12 | ansible-galaxy collection install -p /usr/share/ansible/collections -r /tmp/requirements.yml 13 | RUN echo "===> Clean up ..." 14 | RUN apt clean && \ 15 | rm -rf /tmp/* 16 | WORKDIR /ansible 17 | -------------------------------------------------------------------------------- /Docker/Ubuntu/apt-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set noninteractive installation 3 | set -ex 4 | export DEBIAN_FRONTEND=noninteractive 5 | apt-get update -yq 6 | apt-get upgrade -yq 7 | apt-get install -yq tzdata 8 | # set your timezone 9 | dpkg-reconfigure --frontend noninteractive tzdata 10 | apt-get install -yq $(cat /tmp/requirements-apt.txt | tr '\n' ' ') 11 | -------------------------------------------------------------------------------- /Docker/Ubuntu/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t ipspace/automation:ubuntu --no-cache . 3 | -------------------------------------------------------------------------------- /Docker/Ubuntu/requirements-apt.txt: -------------------------------------------------------------------------------- 1 | sshpass 2 | gcc 3 | python3 4 | python3-dev 5 | python3-setuptools 6 | python3-pip 7 | libffi-dev 8 | libxslt1-dev 9 | libssl-dev 10 | make 11 | git 12 | jq 13 | vim 14 | nano 15 | iputils-ping 16 | ipmitool -------------------------------------------------------------------------------- /Docker/Ubuntu/requirements.txt: -------------------------------------------------------------------------------- 1 | ncclient==0.6.9 2 | ansible==7.0.0 3 | networklab 4 | cffi 5 | paramiko 6 | netmiko<4.0.0,>=3.3.0 7 | textfsm 8 | pylint>=2.1.1 9 | yapf>=0.2.4 10 | requests>=2.2.0 11 | urllib3>=1.24 12 | lxml>=4.2.5 13 | jmespath 14 | scp 15 | ciscoconfparse 16 | netaddr 17 | genie 18 | pyats 19 | pynetbox 20 | objectpath 21 | napalm 22 | napalm-ansible 23 | yamllint 24 | yq 25 | ntc-templates 26 | ttp 27 | -------------------------------------------------------------------------------- /Docker/Ubuntu/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: cisco.asa 4 | - name: cisco.nxos 5 | - name: cisco.ios 6 | - name: cisco.iosxr 7 | - name: arista.eos 8 | - name: f5networks.f5_modules 9 | - name: netbox.netbox 10 | - name: community.general 11 | - name: junipernetworks.junos 12 | -------------------------------------------------------------------------------- /Docker/Ubuntu/run-automation: -------------------------------------------------------------------------------- 1 | docker run -it --rm \ 2 | --user $(id -u):$(id -g) \ 3 | --volume $(pwd):/ansible \ 4 | --volume="/etc/group:/etc/group:ro" \ 5 | --volume="/etc/passwd:/etc/passwd:ro" \ 6 | --volume="/etc/shadow:/etc/shadow:ro" \ 7 | --volume="/home/$USER:/home/$USER" \ 8 | ipspace/automation:ubuntu $@ 9 | -------------------------------------------------------------------------------- /Docker/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | 9 | # Specify minimum Vagrant version and Vagrant API version 10 | Vagrant.require_version ">= 1.6.0" 11 | VAGRANTFILE_API_VER = "2" 12 | 13 | # VirtualBox settings 14 | # Increase vmmemory if you want more than 512mb memory in the vm's 15 | vmmemory = 512 16 | # Increase numcpu if you want more cpu's per vm 17 | numcpu = 1 18 | 19 | Vagrant.configure("2") do |config| 20 | config.vm.provider "virtualbox" do |v| 21 | v.memory = vmmemory 22 | v.cpus = numcpu 23 | end 24 | 25 | config.vm.define "docker" do |i| 26 | i.vm.synced_folder "..", "/nws" 27 | i.vm.box = "bento/ubuntu-20.04" 28 | i.vm.hostname = "manager" 29 | i.vm.provision "ansible", playbook: "install-docker.yaml" 30 | i.vm.provider "virtualbox" do |virtualbox| 31 | virtualbox.customize [ 32 | "modifyvm",:id, 33 | "--nicpromisc2", "allow-all", 34 | "--clipboard", "bidirectional"] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /Docker/install-docker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Docker 3 | hosts: all 4 | gather_facts: no 5 | become: yes 6 | tasks: 7 | - name: install python 3 8 | raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal) 9 | 10 | - name: Gather facts after making sure Python is installed 11 | setup: 12 | 13 | - set_fact: target_user={{ ansible_env['SUDO_USER'] }} 14 | 15 | - name: Set hostname 16 | hostname: name={{inventory_hostname}} 17 | 18 | - name: Remove Docker repository 19 | file: path=/etc/apt/sources.list.d/docker.list state=absent 20 | 21 | - name: install missing APT and Python packages 22 | apt: 23 | state: present 24 | update_cache: yes 25 | name: 26 | - apt-transport-https 27 | - ca-certificates 28 | - curl 29 | - gnupg-agent 30 | - software-properties-common 31 | - gnupg-agent 32 | - python3-pip 33 | - bridge-utils 34 | - jq 35 | - tree 36 | - ack 37 | 38 | - name: "Install Docker Repo's Public Key" 39 | apt_key: 40 | url: "https://download.docker.com/linux/ubuntu/gpg" 41 | state: present 42 | 43 | - name: Add Docker Sources 44 | copy: 45 | dest: /etc/apt/sources.list.d/docker.list 46 | content: deb https://download.docker.com/linux/ubuntu {{ansible_distribution_release}} stable 47 | 48 | - name: Install Docker 49 | apt: 50 | state: present 51 | update_cache: yes 52 | name: 53 | - docker-ce 54 | - docker-ce-cli 55 | - containerd.io 56 | 57 | - name: Add Docker Compose 58 | pip: 59 | name: 60 | - docker 61 | - docker-compose 62 | 63 | - name: Create Docker group 64 | group: name=docker state=present 65 | 66 | - name: Add local user to Docker group 67 | user: name={{target_user}} groups=docker 68 | -------------------------------------------------------------------------------- /Jinja2/1-basicFail.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | logging host {{syslog}} 9 | ! 10 | no aaa new-model -------------------------------------------------------------------------------- /Jinja2/1-basicFail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 -------------------------------------------------------------------------------- /Jinja2/1-basics.j2: -------------------------------------------------------------------------------- 1 | {# This is a template comment #} 2 | service timestamps debug datetime msec 3 | service timestamps log datetime msec 4 | no service password-encryption 5 | ! 6 | {# Device name is in the hostname variable #} 7 | hostname {{hostname}} 8 | ! 9 | logging buffered 4096 10 | logging host {{syslog}} 11 | ! 12 | no aaa new-model -------------------------------------------------------------------------------- /Jinja2/1-basics.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | syslog: 172.16.0.1 -------------------------------------------------------------------------------- /Jinja2/2-conditionals.j2: -------------------------------------------------------------------------------- 1 | no service password-encryption 2 | ! 3 | hostname {{hostname}} 4 | ! 5 | no aaa new-model 6 | ! 7 | {% if syslog %} 8 | logging host {{syslog}} 9 | {% else %} 10 | ! no syslog 11 | {% endif %} -------------------------------------------------------------------------------- /Jinja2/2-conditionals.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 -------------------------------------------------------------------------------- /Jinja2/3-complex.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | ! 9 | no aaa new-model 10 | ! 11 | interface loopback 0 12 | ip address {{loopback.ip}} {{loopback.subnet}} -------------------------------------------------------------------------------- /Jinja2/3-complex.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | loopback: { ip: 172.16.0.1, subnet: 255.255.255.255 } 4 | -------------------------------------------------------------------------------- /Jinja2/4-default.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | ! 9 | no aaa new-model 10 | ! 11 | interface loopback 0 12 | ip address {{loopback.ip}} {{loopback.subnet|default("255.255.255.255")}} -------------------------------------------------------------------------------- /Jinja2/4-default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | loopback: { ip: 172.16.0.1 } 4 | -------------------------------------------------------------------------------- /Jinja2/5-sequence.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | {% for hostip in syslog %} 9 | logging host {{hostip}} 10 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/5-sequence.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | syslog: 4 | - 172.16.0.1 5 | - 172.16.0.2 -------------------------------------------------------------------------------- /Jinja2/5-sequenceFail.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | {% for hostip in syslog %} 9 | logging host {{hostip}} 10 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/5-sequenceFail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | syslog: 172.16.0.1 -------------------------------------------------------------------------------- /Jinja2/6-iterable.j2: -------------------------------------------------------------------------------- 1 | value: {{value}} 2 | sequence: {{sequence}} 3 | 4 | Is a string? 5 | {% if value is string%}--> Value is string{% endif %} 6 | {% if sequence is string%}--> Sequence is string{% endif %} 7 | 8 | Is iterable? 9 | {% if value is iterable%}--> Value is iterable{% endif %} 10 | {% if sequence is iterable%}--> Sequence is iterable{% endif %} 11 | 12 | Is sequence? 13 | {% if value is sequence%}--> Value is sequence{% endif %} 14 | {% if sequence is sequence%}--> Sequence is sequence{% endif %} 15 | -------------------------------------------------------------------------------- /Jinja2/6-iterable.yml: -------------------------------------------------------------------------------- 1 | --- 2 | value: R1 3 | sequence: 4 | - 172.16.0.1 5 | - 172.16.0.2 -------------------------------------------------------------------------------- /Jinja2/6-syslog.j2: -------------------------------------------------------------------------------- 1 | service timestamps debug datetime msec 2 | service timestamps log datetime msec 3 | no service password-encryption 4 | ! 5 | hostname {{hostname}} 6 | ! 7 | logging buffered 4096 8 | {% if syslog is string %} 9 | logging host {{syslog}} 10 | {% else %} 11 | {% for hostip in syslog %} 12 | logging host {{hostip}} 13 | {% endfor %} 14 | {% endif %} -------------------------------------------------------------------------------- /Jinja2/6-syslog.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | syslog: 172.16.0.1 -------------------------------------------------------------------------------- /Jinja2/7-sequenceObjects.j2: -------------------------------------------------------------------------------- 1 | ! Local users 2 | {% for user in users %} 3 | user {{user.username}} password {{user.password}} 4 | {% if user.privilege is defined %} 5 | user {{user.username}} privilege {{user.privilege}} 6 | {% endif %} 7 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/7-sequenceObjects.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | users: 4 | - { username: cisco, password: cisco } 5 | - username: admin 6 | password: admin 7 | privilege: 15 -------------------------------------------------------------------------------- /Jinja2/8-iterateDictionary.j2: -------------------------------------------------------------------------------- 1 | ! Local users: 2 | ! {{passwords.keys()}} 3 | ! 4 | ! -- passwords|dictsort 5 | ! Sorted: {{passwords|dictsort}} 6 | ! 7 | ! -- formatted: passwords.keys()|join(",") 8 | ! Nicely formatted: {{passwords.keys()|join(",")}} 9 | ! 10 | ! -- sorted usernames: passwords|sort|join(",") 11 | ! Sorted username: {{passwords|sort|join(",")}} 12 | ! 13 | {% for username,password in passwords.items() %} 14 | user {{username}} password {{password}} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /Jinja2/8-iterateDictionary.yml: -------------------------------------------------------------------------------- 1 | --- 2 | passwords: 3 | cisco: c1sc0 4 | admin: DoNotTouch 5 | guest: guest 6 | default: noPassword -------------------------------------------------------------------------------- /Jinja2/9-loopVariable.j2: -------------------------------------------------------------------------------- 1 | {% for username,password in passwords|dictsort %} 2 | {% if loop.first %} 3 | ! Local user database 4 | {% endif %} 5 | user {{username}} password {{password}} 6 | {% if loop.last %} 7 | ! Total number of users: {{passwords|length}} 8 | {% endif %} 9 | {% endfor %} 10 | -------------------------------------------------------------------------------- /Jinja2/9-loopVariable.yml: -------------------------------------------------------------------------------- 1 | --- 2 | passwords: 3 | cisco: c1sc0 4 | admin: DoNotTouch 5 | guest: guest 6 | default: noPassword -------------------------------------------------------------------------------- /Jinja2/A-valueLookup.j2: -------------------------------------------------------------------------------- 1 | {% for name,vlan in vlans|dictsort %} 2 | vlan {{vlan.id}} 3 | name {{name}} 4 | description {{vlan.description}} 5 | {% endfor %} 6 | ! 7 | {% for name,intf in interfaces|dictsort %} 8 | interface {{name}} 9 | switchport access {{vlans[intf.vlan].id}} 10 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/A-valueLookup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | vlans: 3 | mgmt: { id: 10, description: management } 4 | user: { id: 20, description: Users } 5 | interfaces: 6 | fa0/0: { vlan: mgmt } 7 | fa0/1: { vlan: user } -------------------------------------------------------------------------------- /Jinja2/B-ACL-seq-loopvar.j2: -------------------------------------------------------------------------------- 1 | {% for name,list in acls.items() %} 2 | ip access-list extended {{name}} 3 | {% for line in list %} 4 | {% set count = loop.index * 10 %} 5 | {{ count }} {{ line }} 6 | {% endfor %} 7 | {% endfor %} 8 | -------------------------------------------------------------------------------- /Jinja2/B-ACL-seq-loopvar.yml: -------------------------------------------------------------------------------- 1 | --- 2 | acls: 3 | noweb: 4 | - deny tcp any any eq 80 log 5 | - deny tcp any eq 80 any log 6 | - permit ip any any 7 | noudp: 8 | - deny udp any any log 9 | - permit tcp any any 10 | -------------------------------------------------------------------------------- /Jinja2/B-ACL-sequenced.j2: -------------------------------------------------------------------------------- 1 | {# 2 | The original example no longer works in Jinja2 2.9 and later. 3 | 4 | Jinja2 changed variable scoping rules within for loops - prior to 5 | release 2.9 the variable set within a for loop retained their 6 | value across loop iterations. Starting with release 2.9 the 7 | variables are reinitialized at every iteration of the loop. 8 | 9 | You can, however, use Jinja2 namespaces to have a global variable 10 | you can work with (HT: Asier Gonzales) 11 | #} 12 | {% for name,list in acls.items() %} 13 | ip access-list extended {{name}} 14 | {% set count = namespace(value=0) %} 15 | {% for line in list %} 16 | {% set count.value = count.value + 10 %} 17 | {{ count.value }} {{ line }} 18 | {% endfor %} 19 | {% endfor %} 20 | -------------------------------------------------------------------------------- /Jinja2/B-ACL-sequenced.yml: -------------------------------------------------------------------------------- 1 | --- 2 | acls: 3 | noweb: 4 | - deny tcp any any eq 80 log 5 | - deny tcp any eq 80 any log 6 | - permit ip any any 7 | noudp: 8 | - deny udp any any log 9 | - permit tcp any any 10 | -------------------------------------------------------------------------------- /Jinja2/B-ACL-simple.j2: -------------------------------------------------------------------------------- 1 | {% for name,list in acls.items() %} 2 | ip access-list extended {{name}} 3 | {% for line in list %} 4 | {{ line }} 5 | {% endfor %} 6 | {% endfor %} 7 | -------------------------------------------------------------------------------- /Jinja2/B-ACL-simple.yml: -------------------------------------------------------------------------------- 1 | --- 2 | acls: 3 | noweb: 4 | - deny tcp any any eq 80 log 5 | - deny tcp any eq 80 any log 6 | - permit ip any any 7 | noudp: 8 | - deny udp any any log 9 | - permit tcp any any 10 | -------------------------------------------------------------------------------- /Jinja2/C-macros.j2: -------------------------------------------------------------------------------- 1 | {% macro ifaddr(intf,mask) %} 2 | ip address {{intf.ip}} {{mask|default(intf.mask)|default('255.255.255.0')}} 3 | {% endmacro %} 4 | ! 5 | interface loopback 0 6 | {{ ifaddr(loopback,'255.255.255.255') }} 7 | ! 8 | interface fa0/0 9 | {{ ifaddr(LAN) }} 10 | ! 11 | interface serial0/1 12 | {{ ifaddr(WAN['0']) }} 13 | -------------------------------------------------------------------------------- /Jinja2/C-macros.yml: -------------------------------------------------------------------------------- 1 | --- 2 | loopback: { ip: 172.16.0.1 } 3 | LAN: { ip: 172.16.10.1 } 4 | WAN: 5 | 0: { ip: 172.16.22.2, mask: 255.255.255.240 } 6 | -------------------------------------------------------------------------------- /Jinja2/D-import-include.j2: -------------------------------------------------------------------------------- 1 | {% import 'includes/interfaces.j2' as interfaces %} 2 | {% include 'includes/loopback.j2' %} 3 | ! 4 | interface fa0/0 5 | {{ interfaces.ifaddr(LAN) }} 6 | ! 7 | interface serial0/1 8 | {{ interfaces.ifaddr(WAN.0) }} 9 | -------------------------------------------------------------------------------- /Jinja2/D-import-include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | loopback: { ip: 172.16.0.1 } 3 | LAN: { ip: 172.16.10.1 } 4 | WAN: 5 | 0: { ip: 172.16.22.2, mask: 255.255.255.240 } 6 | -------------------------------------------------------------------------------- /Jinja2/P1-strings.j2: -------------------------------------------------------------------------------- 1 | hostname {{hostname}} 2 | {% if hostname.find('.') > 0 %} 3 | ip domain name {{ hostname.partition('.')[2] }} 4 | {% endif %} 5 | {% set host = hostname.partition('.')[0] %} 6 | {% set idx = host.partition('-')[2] | int %} 7 | {% if idx %} 8 | router bgp {{ 64600 + idx }} 9 | {% endif %} -------------------------------------------------------------------------------- /Jinja2/P1-strings.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: L-1.example.com -------------------------------------------------------------------------------- /Jinja2/P2-slicing.j2: -------------------------------------------------------------------------------- 1 | hostname {{hostname}} 2 | {% set dot = hostname.find('.') %} 3 | {% if dot > 0 %} 4 | ! Dot found in hostname at position {{ dot }} 5 | ip domain name {{ hostname[dot+1:] }} 6 | {% set hostname = hostname[:dot] %} 7 | {% endif %} 8 | {% set dash = hostname.find('-') %} 9 | {% if dash > 0 %} 10 | {% set idx = hostname[dash+1:] | int %} 11 | router bgp {{ 64600 + idx }} 12 | {% endif %} 13 | -------------------------------------------------------------------------------- /Jinja2/P2-slicing.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: L-1.example.com -------------------------------------------------------------------------------- /Jinja2/README.md: -------------------------------------------------------------------------------- 1 | # Test cases for YAML and Jinja2 2 | 3 | This directory contains numerous test cases used to illustrate how to create complex data structures in YAML and how to use them in Jinja2 templates. The _includes_ subdirectory is used to test Jinja2 include functionality, _ipaddr_ directory contains test cases for Ansible **ipaddr** Jinja2 filter, _whitespace_ directory has test cases illustrating whitespace handling when using Jinja2 with Ansible. 4 | 5 | The main directory also includes *render.py* that can be used to render YAML data structure with corresponding Jinja2 template. 6 | 7 | ## Invoking render.py 8 | 9 | The easiest way to invoke **render.py** is simply ./render.py somename. Specify just the file name, not the extension (for example, 1-basics and not 1-basics.yml). Using this syntax the script expects to find: 10 | 11 | * Data structure in _somename_.yml 12 | * Jinja2 template in _somename_.j2 13 | 14 | If you want to use YAML and Jinja2 files with different names or different extensions specify the file names individually. Using this syntax you have to use full file names (including extensions) 15 |
./render.py -yaml yamlfile -jinja jinja2file
16 | Note: you can use -y instead of -yaml and -j instead of -jinja2 17 | 18 | ## Additional parameters 19 | 20 | You can use these command line options to change **render.py** behavior: 21 | 22 | * -n or -notrim: do not trim whitespace (sets **trim_blocks** and **lstrip_blocks**) 23 | * -w or -warning: report usage of undefined variables 24 | * -s or -strict: fail on undefined variables 25 | 26 | -------------------------------------------------------------------------------- /Jinja2/includes/interfaces.j2: -------------------------------------------------------------------------------- 1 | {% macro ifaddr(intf,mask) %} 2 | ip address {{intf.ip}} {{mask|default(intf.mask)|default('255.255.255.0')}} 3 | {% endmacro %} 4 | -------------------------------------------------------------------------------- /Jinja2/includes/loopback.j2: -------------------------------------------------------------------------------- 1 | interface loopback 0 2 | {{ interfaces.ifaddr(loopback,'255.255.255.255') }} 3 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/1-ipaddr.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{intf.name}} 3 | description IP addr = {{intf.ip}} 4 | ip address {{intf.ip | ipaddr('address')}} {{intf.ip | ipaddr('netmask')}} 5 | {% endfor %} 6 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/1-ipaddr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | interfaces: 3 | - name: GigabitEthernet0/0 4 | ip: 172.16.0.1/24 5 | - name: GigabitEthernet0/1 6 | ip: 172.16.1.1/24 7 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/2-iphost.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | ! 3 | ! prefix = {{intf.prefix}} 4 | ! ipaddr(1) = {{intf.prefix | ipaddr(1) }} 5 | ! 6 | interface {{intf.name}} 7 | {% set gw = intf.prefix|ipaddr(1) %} 8 | ip address {{gw | ipaddr('address') }} {{intf.prefix | ipaddr('netmask')}} 9 | {% endfor %} 10 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/2-iphost.yml: -------------------------------------------------------------------------------- 1 | --- 2 | interfaces: 3 | - name: GigabitEthernet0/0 4 | prefix: 172.16.0.0/24 5 | - name: GigabitEthernet0/1 6 | prefix: 172.16.1.18/30 7 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/3-localACL.j2: -------------------------------------------------------------------------------- 1 | ip access-list standard LocalPrefixes 2 | {% for intf in interfaces %} 3 | permit {{ intf.ip|ipaddr(0)|ipaddr('network_wildcard') }} 4 | {% endfor %} 5 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/3-localACL.yml: -------------------------------------------------------------------------------- 1 | --- 2 | interfaces: 3 | - name: GigabitEthernet0/0 4 | ip: 172.16.0.0/24 5 | - name: GigabitEthernet0/1 6 | ip: 172.16.1.18/30 7 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=./hosts 3 | gathering=explicit 4 | transport=local 5 | retry_files_enabled=false 6 | roles_path=. 7 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/hosts: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/render.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "Rendering through Ansible..." 3 | echo "FAILED" >/tmp/results.txt 4 | ansible-playbook render.yml --extra-vars template=$1 >/dev/null 5 | echo "YAML file:" >/tmp/output.txt 6 | echo "=================" >>/tmp/output.txt 7 | cat $1.yml >>/tmp/output.txt 8 | echo "" >>/tmp/output.txt 9 | echo "Jinja2 file:" >>/tmp/output.txt 10 | echo "=================" >>/tmp/output.txt 11 | cat $1.j2 >>/tmp/output.txt 12 | echo "" >>/tmp/output.txt 13 | echo "Results:" >>/tmp/output.txt 14 | echo "=================" >>/tmp/output.txt 15 | cat /tmp/results.txt >>/tmp/output.txt 16 | less /tmp/output.txt 17 | -------------------------------------------------------------------------------- /Jinja2/ipaddr/render.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | connection: local 5 | vars_files: 6 | - "{{template}}.yml" 7 | tasks: 8 | - template: src="{{template}}.j2" dest=/tmp/results.txt 9 | -------------------------------------------------------------------------------- /Jinja2/render.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import getopt 5 | import re 6 | from jinja2 import Environment, FileSystemLoader, Undefined, StrictUndefined, make_logging_undefined 7 | import yaml 8 | from bracket_expansion import * 9 | from pprint import pprint 10 | 11 | import os 12 | os.system('cls' if os.name == 'nt' else 'clear') 13 | 14 | def getOptions(): 15 | try: 16 | options, args = getopt.getopt(sys.argv[1:], "y:j:n:sw", ["yaml=", "jinja=", "notrim", "strict", "warning"]) 17 | except getopt.GetoptError as err: 18 | # print help information and exit: 19 | print (str(err)) # will print something like "option -a not recognized" 20 | sys.exit(2) 21 | 22 | global yamlfile,jinjafile,trim,undefined 23 | trim = True 24 | opts = 0 25 | 26 | for opt,arg in options: 27 | opts = opts + 1 28 | if opt in ("-y","-yaml"): 29 | yamlfile = arg 30 | elif opt in ("-j","-jinja"): 31 | jinjafile = arg 32 | elif opt in ("-n","-notrim"): 33 | trim = False 34 | elif opt in ("-w","-warning"): 35 | undefined = make_logging_undefined (base = Undefined) 36 | elif opt in ("-s","-strict"): 37 | undefined = make_logging_undefined (base = StrictUndefined) 38 | 39 | return opts > 0 40 | 41 | trim = True 42 | undefined = Undefined 43 | yamlfile = None 44 | jinjafile = None 45 | 46 | if not getOptions(): 47 | if (len(sys.argv) > 2): 48 | trim = sys.argv[2] != 'notrim' 49 | 50 | ENV = Environment(loader=FileSystemLoader('.'),trim_blocks=trim,lstrip_blocks=trim,undefined=undefined) 51 | ENV.filters['bracket_expansion'] = bracket_expansion 52 | 53 | filename = re.sub("\.$","",sys.argv[1]) 54 | 55 | if yamlfile is None: 56 | yamlfile = filename+".yml" 57 | 58 | if jinjafile is None: 59 | jinjafile = filename+".j2" 60 | 61 | print ('--- Reading YAML file '+yamlfile+' ---') 62 | with open(yamlfile) as _: yamldict = yaml.load(_,Loader=yaml.BaseLoader) 63 | 64 | print ('--- YAML dictionary in '+yamlfile+' ---') 65 | pprint(yamldict) 66 | print 67 | 68 | print ('--- Rendering template '+jinjafile+' ---') 69 | template = ENV.get_template(jinjafile) 70 | print(template.render(**yamldict)) -------------------------------------------------------------------------------- /Jinja2/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH=.:$PATH 3 | chmod +x render.py 4 | -------------------------------------------------------------------------------- /Jinja2/whitespace/.gitignore: -------------------------------------------------------------------------------- 1 | results/ 2 | -------------------------------------------------------------------------------- /Jinja2/whitespace/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory=./ipaddr/hosts 3 | gathering=explicit 4 | transport=local 5 | retry_files_enabled=false 6 | roles_path=. 7 | -------------------------------------------------------------------------------- /Jinja2/whitespace/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | interfaces: 3 | - name: Ethernet0 4 | desc: LAN interface 5 | ip: 192.168.1.1/24 6 | 7 | - name: Ethernet1 8 | desc: WAN interface 9 | ip: dhcp 10 | 11 | - name: Loopback0 12 | ip: 172.16.0.1 13 | -------------------------------------------------------------------------------- /Jinja2/whitespace/render.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: localhost 3 | gather_facts: no 4 | connection: local 5 | vars_files: 6 | - data.yml 7 | tasks: 8 | - file: path=results state=directory 9 | - template: 10 | src: "{{item}}" 11 | dest: "results/{{item|basename|regex_search('\\A([^.]+)')}}.txt" 12 | with_fileglob: [ "templates/*.j2" ] 13 | -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/indent_bol.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{ intf.name }} 3 | {% if intf.desc is defined %} 4 | description {{ intf.desc }} 5 | {% endif %} 6 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/indent_default.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{ intf.name }} 3 | {% if intf.desc is defined %} 4 | description {{ intf.desc }} 5 | {% endif %} 6 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/indent_lstrip.j2: -------------------------------------------------------------------------------- 1 | #jinja2: lstrip_blocks: True 2 | {% for intf in interfaces %} 3 | interface {{ intf.name }} 4 | {% if intf.desc is defined %} 5 | description {{ intf.desc }} 6 | {% endif %} 7 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/inline_if.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{ intf.name }} 3 | {% if intf.desc is defined %} 4 | description {{ intf.desc }} 5 | {% endif %} 6 | ip address {% if intf.ip == 'dhcp' %}{{intf.ip}}{% else %}{{intf.ip|ipaddr('address')}} {{intf.ip|ipaddr('netmask')}}{% endif %} 7 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/inline_if_extra.j2: -------------------------------------------------------------------------------- 1 | #jinja2: lstrip_blocks: True 2 | {% for intf in interfaces %} 3 | interface {{ intf.name }} 4 | {% if intf.desc is defined %} 5 | description {{ intf.desc }} 6 | {% endif %} 7 | ip address {% if intf.ip == 'dhcp' %}{{intf.ip}}{% else %}{{intf.ip|ipaddr('address')}} {{intf.ip|ipaddr('netmask')}}{% endif %} 8 | 9 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/inline_if_pretty.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{ intf.name }} 3 | {% if intf.desc is defined %} 4 | description {{ intf.desc }} 5 | {% endif %} 6 | ip address {% 7 | if intf.ip == 'dhcp' 8 | %}{{intf.ip}}{% 9 | else 10 | %}{{intf.ip|ipaddr('address')}} {{intf.ip|ipaddr('netmask')}}{% 11 | endif 12 | %} 13 | 14 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/macro.j2: -------------------------------------------------------------------------------- 1 | {% macro address(addr) %} 2 | {% if addr == 'dhcp' %} 3 | {{addr}} 4 | {% else %} 5 | {{addr|ipaddr('address')}} {{addr|ipaddr('netmask')}} 6 | {% endif %} 7 | {% endmacro %} 8 | {% for intf in interfaces %} 9 | interface {{ intf.name }} 10 | {% if intf.desc is defined %} 11 | description {{ intf.desc }} 12 | {% endif %} 13 | ip address {{ address(intf.ip) }} 14 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/macro_strip.j2: -------------------------------------------------------------------------------- 1 | {% macro address(addr) %} 2 | {% if addr == 'dhcp' -%} 3 | {{addr}} 4 | {%- else -%} 5 | {{addr|ipaddr('address')}} {{addr|ipaddr('netmask')}} 6 | {%- endif %} 7 | {% endmacro %} 8 | {% for intf in interfaces %} 9 | interface {{ intf.name }} 10 | {% if intf.desc is defined %} 11 | description {{ intf.desc }} 12 | {% endif %} 13 | ip address {{ address(intf.ip) }} 14 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/trim_blocks.j2: -------------------------------------------------------------------------------- 1 | {% for intf in interfaces %} 2 | interface {{ intf.name }} 3 | {% if intf.desc is defined %} 4 | description {{ intf.desc }} 5 | {% endif %} 6 | {% endfor %} -------------------------------------------------------------------------------- /Jinja2/whitespace/templates/trim_blocks_off.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | {% for intf in interfaces %} 3 | interface {{ intf.name }} 4 | {% if intf.desc is defined %} 5 | description {{ intf.desc }} 6 | {% endif %} 7 | {% endfor %} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network Automation Workshop - Sources 2 | 3 | This repository contains sources for all demos shown during the 4 | [Network Automation workshop](http://www.ipspace.net/NetAutWS) 5 | and [Ansible webinar](http://www.ipspace.net/Ansible): 6 | 7 | ## Subdirectories 8 | * Install: Lab installation guidelines 9 | * YAML: YAML syntax examples (YAML section of the workshop) 10 | * Jinja2: Sample templates (Jinja2 section of the workshop) 11 | * Ansible: Ansible playbooks 12 | * Simple: simple actions using RAW module 13 | * Logging: create SNMP and logging configuration commands for Cisco IOS and Nexus OS 14 | * SNMPFacts: use SNMP facts in Ansible playbooks 15 | * Networking: Ansible Networking modules 16 | * Examples: Further Ansible examples from ansible-examples repository 17 | 18 | ## Installation 19 | 20 | I'm running Ansible in a Ubuntu Vagrant box. Install Vagrant and VirtualBox (or VMware Fusion/Workstation if you're using VIRL) and start vagrant. Further Ubuntu installation scripts are in the _install_ directory. 21 | 22 | The networking examples are focused on Cisco IOS and Nexus OS. You can run them in VIRL or have a Cisco router (or CSR 1000v) connected to a Nexus switch. 23 | 24 | ### Starting the Ubuntu VM 25 | 26 | Various _Vagrantfile_ versions in _install_ directory contain different test environments. Select the one you prefer and copy it into _Vagrantfile_ in top directory. 27 | 28 | To start the Ubuntu VM start the VM with **vagrant up nms**. To start the whole test environment use **vagrant up**. Continue the installation process using the instructions in the [_install_ directory] (install). 29 | 30 | **Note**: if you're using VMware Fusion or Workstation you _MUST_ specify the Vagrant provider in the **vagrant up** command with the 31 | **--provider vmware_fusion** or **--provider vmware_workstation** flags the first time you're starting the VM. 32 | 33 | ## Usage 34 | 35 | Download, explore & enjoy... and when you discover you want to know more, register for the: 36 | 37 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) or 38 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 39 | 40 | -------------------------------------------------------------------------------- /Scripted Demos/00 - Lean Start into Network Automation.md: -------------------------------------------------------------------------------- 1 | # Lean Start into Network Automation 2 | 3 | * [Git 101](Git%20101.md) 4 | 5 | ## Manage Device Configurations with Git 6 | 7 | * [Push configs into master branch](G0%20-%20Push%20device%20configs%20into%20Git%20master.md) 8 | * [Merge individual changes as feature branches](G2%20-%20Merge%20individual%20changes%20as%20feature%20branches.md) 9 | * [Change configs from Git](G3%20-%20Change%20Configs%20From%20Git.md) 10 | 11 | ## Reports 12 | 13 | * [Setup](00%20-%20Setup.md) 14 | * [Simple reports](10%20-%20Simple-reports.md) 15 | * [Network diagram](11%20-%20Network-graph.md) 16 | * [Compare network state](30%20-%20Compare-Network-State.md) 17 | 18 | ## DMVPN Configs 19 | 20 | * [DMVPN deployment](40%20-%20DMVPN-Deployment.md) 21 | 22 | -------------------------------------------------------------------------------- /Scripted Demos/00 - Setup.md: -------------------------------------------------------------------------------- 1 | # Preparing the environment 2 | 3 | * Start VIRL and Inter-AS topology 4 | * Start Vagrant machine (nms) 5 | * Collect SSH keys 6 | ``` 7 | cd /vagrant/Examples/6-router-setup/ 8 | source setup.sh 9 | unset ANSIBLE_STDOUT_CALLBACK 10 | ../../tools/ssh-keys/get-keys.yml 11 | ``` 12 | -------------------------------------------------------------------------------- /Scripted Demos/10 - Simple-reports.md: -------------------------------------------------------------------------------- 1 | # Simple reports 2 | 3 | ## Inventory report 4 | 5 | cd /vagrant/Examples/Summary-Reports 6 | cd inventory 7 | rm -fr ../results/ 8 | ansible-playbook report.yml 9 | 10 | export ANSIBLE_STDOUT_CALLBACK=selective 11 | export ANSIBLE_CALLBACK_PLUGINS=`pwd`/../Plugins/callback/ 12 | export ANSIBLE_SELECTIVE_LINE_LENGTH=80 13 | ansible-playbook report.yml 14 | 15 | * Inspect $OUTPUT/E1.yml 16 | * cat $OUTPUT/inventory.csv 17 | * open $OUTPUT/inventory.html 18 | 19 | ## Uptime report 20 | 21 | cd framework 22 | rm -fr $OUTPUT 23 | ansible-playbook framework.yml -e dst=save 24 | 25 | Inspect ../results/E1.yml 26 | 27 | ansible-playbook framework.yml -e fmt=csv -e output=uptime.csv 28 | ansible-playbook framework.yml \ 29 | -e src=vars \ 30 | -e fmt=html \ 31 | -e output=uptime.html 32 | 33 | ## Create hosts file 34 | 35 | cd hosts-file 36 | ./cleanup.yml 37 | 38 | Run playbook in dump mode 39 | 40 | ./hosts.yml --tags dump 41 | 42 | Create and inspect the hosts file 43 | 44 | ./hosts.yml --tags create 45 | more $OUTPUT/hosts 46 | 47 | Install the hosts file 48 | 49 | ./hosts.yml --tags install 50 | 51 | -------------------------------------------------------------------------------- /Scripted Demos/11 - Network-graph.md: -------------------------------------------------------------------------------- 1 | # Creating a network diagram 2 | 3 | Setup: 4 | 5 | cd /vagrant/Examples/6-router-setup 6 | source setup.sh 7 | 8 | ## Getting and inspecting LLDP neighbor data 9 | 10 | cd ../LLDP-to-Graph 11 | ansible-playbook LLDP-test.yml 12 | ../../tools/config-actions/enable-lldp.yml 13 | ansible-playbook LLDP-test.yml 14 | 15 | ## Create a simple links report 16 | 17 | ansible-playbook LLDP-to-Graph.yml \ 18 | -e template=links.j2 \ 19 | -e output=links.txt 20 | 21 | ## Create a simple graph 22 | 23 | ansible-playbook LLDP-to-Graph.yml \ 24 | -e template=graph-simple.j2 25 | more network.dot 26 | dot network.dot -Tpng >network.png 27 | 28 | Open network.png in host UI 29 | 30 | ## Create a graph with interfaces 31 | 32 | ansible-playbook LLDP-to-Graph.yml 33 | more network.dot 34 | dot network.dot -Tpng >network.png 35 | 36 | Open network.png in host UI 37 | 38 | ## Create a graph with interfaces and short hostnames 39 | 40 | ansible-playbook LLDP-to-Graph.yml -e no_domain=1 41 | more network.dot 42 | dot network.dot -Tpng >network.png 43 | 44 | Open network.png in host UI -------------------------------------------------------------------------------- /Scripted Demos/20 - Compliance-checks.md: -------------------------------------------------------------------------------- 1 | # Compliance checks 2 | 3 | Setup: 4 | 5 | cd /vagrant/Examples/6-router-setup 6 | source setup.sh 7 | 8 | Breaking config: 9 | 10 | cd /vagrant/Examples/Sample-Compliance-Check 11 | ansible-playbook breakConfig.yml 12 | 13 | Run a simple proof-of-concept code 14 | 15 | ansible-playbook check-community.yml -v 16 | 17 | Extend the code with a report 18 | 19 | ansible-playbook check-community-report.yml 20 | cat results/errors.log 21 | 22 | Final playbook (run a battery of tests) 23 | 24 | ansible-playbook check-final.yml 25 | cat results/errors.log 26 | -------------------------------------------------------------------------------- /Scripted Demos/30 - Compare-Network-State.md: -------------------------------------------------------------------------------- 1 | # Compare State Snapshots 2 | 3 | ## Prepare for the demo 4 | 5 | Setup: 6 | 7 | cd /vagrant/Examples/Compare-State-Snapshots/ 8 | unset ANSIBLE_INVENTORY 9 | unset ANSIBLE_CONFIG 10 | /vagrant/tools/ssh-keys/get-keys.yml 11 | /vagrant/tools/config-actions/enable-lldp.yml 12 | /vagrant/tools/config-actions/no-banner.yml 13 | git checkout Compare-State-Initial 14 | 15 | ## Step 1: Time-dependent state 16 | 17 | Collect the state 18 | 19 | ansible-playbook get-state.yml -e output=snapshot 20 | more snapshot/E1.yml 21 | 22 | ## Step 2: Fixed state gathering 23 | 24 | Check out the final branch 25 | 26 | git checkout master 27 | 28 | Collect state 29 | 30 | ansible-playbook get-state.yml -e output=snap_before 31 | colordiff -au snapshot snap_before|less -r 32 | 33 | ## Step 3: Break something 34 | 35 | Log into one of the routers, turn off an interface 36 | 37 | sshpass -p cisco ssh cisco@172.16.1.111 38 | config terminal 39 | interface gig 0/2 40 | shutdown 41 | 42 | Repeat state gathering 43 | 44 | ansible-playbook get-state.yml -e output=snap_after 45 | 46 | Compare the state 47 | 48 | colordiff -au snap_before snap_after|less -r 49 | -------------------------------------------------------------------------------- /Scripted Demos/40 - DMVPN-Deployment.md: -------------------------------------------------------------------------------- 1 | # Build and deploy DMVPN configurations 2 | 3 | Setup: 4 | 5 | * Run DMVPN-topology.virl 6 | * Execute these commands on NMS 7 | 8 | ``` 9 | cd /vagrant/Examples/DMVPN/ 10 | unset ANSIBLE_INVENTORY 11 | unset ANSIBLE_CONFIG 12 | export ANSIBLE_STDOUT_CALLBACK=selective 13 | export ANSIBLE_CALLBACK_PLUGINS=`pwd`/../Plugins/callback/ 14 | export ANSIBLE_SELECTIVE_LINE_LENGTH=80 15 | /vagrant/tools/ssh-keys/get-keys.yml 16 | /vagrant/tools/config-actions/no-banner.yml 17 | ``` 18 | 19 | Build configs: 20 | 21 | ansible-playbook build.yml 22 | more configs/*.conf 23 | 24 | Copy configs 25 | 26 | ansible-playbook deploy_scp.yml --tags copy 27 | 28 | Enable SCP 29 | 30 | ansible-playbook enable_scp.yml 31 | ansible-playbook deploy_scp.yml --tags copy 32 | ansible-playbook deploy_scp.yml --tags deploy 33 | more compiled/results.txt 34 | 35 | Check routing 36 | 37 | ssh cisco@172.16.1.110 38 | show ip bgp sum 39 | show run part router bgp 65000 40 | 41 | Fix configurations 42 | 43 | git checkout DMVPN-Fix 44 | git diff master 45 | ansible-playbook build.yml 46 | ansible-playbook deploy_scp.yml 47 | -------------------------------------------------------------------------------- /Scripted Demos/41 - OSPF-Deployment.md: -------------------------------------------------------------------------------- 1 | # Deploy OSPF in a Fabric 2 | 3 | Setup: 4 | 5 | cd /vagrant/Examples/OSPF-Deployment/ 6 | unset ANSIBLE_INVENTORY 7 | unset ANSIBLE_CONFIG 8 | /vagrant/tools/ssh-keys/get-keys.yml 9 | 10 | Shut down a port 11 | 12 | sshpass -p cisco ssh cisco@172.16.1.111 13 | config terminal 14 | interface gig 0/2 15 | shutdown 16 | 17 | Configure LLDP and validate fabric connectivity 18 | 19 | ansible-playbook validate-fabric.yml 20 | 21 | Re-enable port, repeat the validation 22 | 23 | ansible-playbook validate-fabric.yml --tags validate 24 | 25 | Create the OSPF configuration 26 | 27 | ansible-playbook deploy.yml --tags clean,configs 28 | more configs/E1.ospf.cfg 29 | 30 | Check the configuration changes 31 | 32 | ansible-playbook deploy.yml --tags deploy --check 33 | more configs/changes.txt 34 | 35 | Execute the change, validate OSPF operations 36 | 37 | ansible-playbook deploy.yml --tags deploy,validate 38 | more configs/changes.txt 39 | 40 | Check idempotency 41 | 42 | ansible-playbook deploy.yml --tags deploy --check 43 | 44 | Fix `ios/ospf-config.j2`, rerun 45 | 46 | ansible-playbook deploy.yml --tags configs,deploy --check 47 | -------------------------------------------------------------------------------- /Scripted Demos/A1 - Ansible debugging.md: -------------------------------------------------------------------------------- 1 | # Ansible debugging 2 | 3 | ## Preparing the environment 4 | 5 | * Start VIRL and _Inter-AS Configured_ topology 6 | * Start Vagrant machine (nms) 7 | * Use 6-router setup 8 | 9 | cd /vagrant/Examples/6-router-setup 10 | source setup.sh 11 | 12 | * Collect SSH keys 13 | 14 | cd /vagrant/Examples/LLDP-to-Graph 15 | ../../tools/ssh-keys/get-keys.yml 16 | 17 | ## Using 'debug' module 18 | 19 | * Run the data gathering playbook 20 | 21 | ansible-playbook -l E1 LLDP-test.yml 22 | 23 | * Enable LLDP 24 | 25 | ../../tools/config-actions/enable-lldp.yml 26 | 27 | * Rerun the data gathering playbook 28 | 29 | ansible-playbook -l E1 LLDP-test.yml 30 | 31 | ## Using Ansible debugger 32 | 33 | ansible-playbook -l E1 Debug-LLDP-test.yml 34 | 35 | ## Creating a snapshot 36 | 37 | ansible-playbook Debug-LLDP-to-Graph.yml 38 | more snap_data/hosts 39 | more snap_data/host_vars/E1.yml 40 | 41 | ## Running a playbook from snapshot 42 | 43 | ansible-playbook Debug-LLDP-to-Graph.yml \ 44 | -i snap_data/hosts \ 45 | --start-at-task='Generate Graph' 46 | -------------------------------------------------------------------------------- /Scripted Demos/AW1 - Ansible Workshop - Introduction.md: -------------------------------------------------------------------------------- 1 | # Ansible Workshop (1 day) 2 | 3 | ## Setup 4 | 5 | * Start and simple Ansible topology 6 | * Start nms VM 7 | * Log into nms VM 8 | 9 | ``` 10 | . .prompt 11 | cd /vagrant/ 12 | ``` 13 | 14 | ## Simple examples 15 | 16 | ``` 17 | cd /vagrant/Ansible/Simple 18 | ansible -i hosts -a "show version" all 19 | ansible -i shosts -a "show version" all 20 | ansible -m raw -i shosts -a "show version" all 21 | 22 | ansible -m raw -i shosts -a "show arp" all 23 | ansible -m raw -i ghosts -a "show arp" ios 24 | ansible -m raw -i ghosts -a "show ip arp" nxos 25 | export ANSIBLE_INVENTORY="`pwd`/ghosts" 26 | ``` 27 | 28 | ## Playbooks 29 | 30 | ``` 31 | ansible-playbook -i ghosts show-arp-simple-fail.yml 32 | ansible-playbook -i ghosts show-arp-simple.yml 33 | ansible-playbook -i ghosts show-arp-simple.yml -v 34 | 35 | export ANSIBLE_STDOUT_CALLBACK=yaml 36 | ansible-playbook -i ghosts show-arp-simple.yml -v 37 | 38 | ansible-playbook -i ghosts show-arp-simple-show.yml 39 | ansible-playbook -i ghosts show-arp-simple-debug.yml 40 | ``` 41 | -------------------------------------------------------------------------------- /Scripted Demos/AW3 - Connecting and Authenticating.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Executing Commands** presentation 2 | 3 | ## Initial setup 4 | 5 | ``` 6 | . ~/.prompt 7 | rm ~/.ssh/known_hosts 8 | cd /vagrant/Ansible/Simple 9 | export ANSIBLE_INVENTORY="`pwd`/ghosts" 10 | cd /vagrant/Ansible/Networking 11 | ../../tools/ssh-keys/get-keys.yml 12 | cd Commands 13 | ``` 14 | 15 | ## Execute simple commands 16 | 17 | ``` 18 | ansible-playbook -v ios-command.yml -l r1.lab.local 19 | ``` 20 | 21 | ## Process command results 22 | 23 | ``` 24 | ansible-playbook ios-command-multiple.yml 25 | more r1.lab.local.txt 26 | ansible-playbook nxos-command-json.yml 27 | cat s1.lab.local.txt 28 | ``` 29 | 30 | ## Command logging 31 | 32 | Window #1 33 | 34 | ``` 35 | ssh cisco@172.16.1.100 36 | (log in) 37 | conf t 38 | login on-success log 39 | ! 40 | event manager applet CLIlog 41 | event cli pattern ".*" sync no skip no 42 | action 1.0 syslog priority informational msg "$_cli_msg" 43 | action 2.0 set _exit_status "1" 44 | end 45 | term mon 46 | ``` 47 | 48 | Window #2 49 | 50 | ``` 51 | ansible-playbook ios-command-multiple.yml -l r1.lab.local 52 | ``` 53 | 54 | ## Limited command set 55 | 56 | Window #1 57 | 58 | ``` 59 | conf t 60 | username ansible password 0 cisco 61 | username ansible privilege 2 view Ansible 62 | ! 63 | parser view Ansible 64 | secret 5 $1$slTy$cA/Hk/M4F72Msr5BZaHzA/ 65 | commands exec include terminal length 66 | commands exec include terminal width 67 | commands exec include show arp 68 | commands exec include show version 69 | end 70 | ``` 71 | 72 | Window #2 73 | 74 | ``` 75 | ansible-playbook ios-command-multiple.yml -e ansible_user=ansible -l r1.lab.local 76 | ``` 77 | 78 | ## Using cli_command 79 | 80 | ``` 81 | ansible-playbook cli-command-simple.yml 82 | ansible -m cli_command -a 'command="show version"' -e ansible_connection=network_cli all 83 | ansible-playbook cli-clear-counters.yml 84 | ``` 85 | -------------------------------------------------------------------------------- /Scripted Demos/AW6 - Command-Based Playbooks.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Command Playbooks** presentation 2 | 3 | ## Initial setup 4 | 5 | ``` 6 | cd /vagrant/Ansible/Networking 7 | . setup.sh 8 | cd /vagrant/Ansible/Networking/Command-Playbooks 9 | ``` 10 | 11 | ## Collect printouts 12 | 13 | ``` 14 | ansible-playbook collect-printout-ios.yml 15 | ``` 16 | 17 | Explore `results` subdirectory 18 | 19 | ``` 20 | ansible-playbook collect-many-printouts-ios.yml 21 | ``` 22 | 23 | Explore `results` subdirectory 24 | 25 | 26 | ## Check device versions 27 | 28 | ``` 29 | more check-version.yml 30 | more ../group_vars/ios.yml 31 | ansible-playbook check-version.yml 32 | ``` 33 | 34 | ``` 35 | more check-version-junos.yml 36 | more ../group_vars/junos.yml 37 | ansible-playbook check-version-junos.yml 38 | ``` 39 | 40 | ``` 41 | more check-version-log.yml 42 | ansible-playbook check-version-log.yml 43 | cat version_report.txt 44 | ``` 45 | 46 | ``` 47 | ansible-playbook check-version-log.yml --extra-vars version=15.6 48 | ``` 49 | 50 | ## Check connectivity 51 | 52 | ``` 53 | more check-connectivity.yml 54 | ansible-playbook check-connectivity.yml -l ios,nxos 55 | ``` 56 | -------------------------------------------------------------------------------- /Scripted Demos/AW7 - Managing Configurations.md: -------------------------------------------------------------------------------- 1 | # Demo script for **Ansible Networking Modules - Managing Configurations** presentation 2 | 3 | ## Initial setup 4 | 5 | * Start the virtual lab; 6 | * Start the Ansible virtual machine 7 | * Log into the Ansible virtual machine 8 | 9 | ``` 10 | . .prompt 11 | rm .ssh/known_hosts 12 | cd /vagrant/Ansible/Networking 13 | . setup.sh 14 | ../../tools/ssh-keys/get-keys.yml 15 | cd Setup 16 | ansible-playbook config-eem-applet.yml 17 | ansible-playbook config-simple-cleanup.yml 18 | ansible-playbook config-acl-preset.yml 19 | ansible-playbook clean-bgp-ios.yml -l r2.lab.local -t clean 20 | cd ../Configuration 21 | ``` 22 | 23 | ## Configure SNMP 24 | 25 | ``` 26 | ansible-playbook config-simple.yml --check 27 | ansible-playbook config-simple.yml --check -v 28 | sshpass -p cisco ssh cisco@172.16.1.100 show log 29 | ansible-playbook config-simple.yml -v 30 | sshpass -p cisco ssh cisco@172.16.1.100 show log 31 | ansible-playbook config-simple.yml -v 32 | ``` 33 | 34 | ## Configure BGP Neighbor 35 | 36 | ``` 37 | ansible-playbook -v config-bgp-ios.yml --check -l r1.lab.local 38 | ansible-playbook -v config-bgp-ios.yml -l r1.lab.local 39 | sshpass -p cisco ssh cisco@172.16.1.100 "show running | section router bgp" 40 | ansible-playbook cisco-ios-bgp-as.yml 41 | ansible-playbook config-bgp-ios-check.yml 42 | ``` 43 | 44 | ## Configure ACLs 45 | 46 | ``` 47 | export ANSIBLE_STDOUT_CALLBACK=yaml 48 | ansible-playbook -v config-acl-add.yml -l r1.lab.local 49 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 50 | ansible-playbook -v config-acl-add-exact.yml -l r1.lab.local 51 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 52 | ansible-playbook -v config-acl-add-before.yml -l r1.lab.local 53 | sshpass -p cisco ssh cisco@172.16.1.100 "show run | sect Allow" 54 | ``` 55 | 56 | ## Deploying Configuration Files 57 | 58 | ``` 59 | ansible-playbook config-logging.yml 60 | ansible-playbook config-snmp-template.yml 61 | ``` 62 | -------------------------------------------------------------------------------- /Scripted Demos/AW9 - DMVPN-Deployment.md: -------------------------------------------------------------------------------- 1 | # Build and deploy DMVPN configurations 2 | 3 | Setup: 4 | 5 | * Run DMVPN-topology.virl 6 | * Execute these commands on NMS 7 | 8 | ``` 9 | cd /vagrant/Examples/DMVPN/ 10 | unset ANSIBLE_INVENTORY 11 | unset ANSIBLE_CONFIG 12 | export ANSIBLE_STDOUT_CALLBACK=selective 13 | export ANSIBLE_CALLBACK_PLUGINS=`pwd`/../Plugins/callback/ 14 | export ANSIBLE_SELECTIVE_LINE_LENGTH=80 15 | /vagrant/tools/ssh-keys/get-keys.yml 16 | /vagrant/tools/config-actions/no-banner.yml 17 | ``` 18 | 19 | Build configs: 20 | 21 | ansible-playbook build.yml 22 | more configs/*.conf 23 | 24 | Copy configs 25 | 26 | ansible-playbook deploy_scp.yml --tags copy 27 | ansible-playbook deploy_scp.yml --tags deploy 28 | 29 | Check routing 30 | 31 | ssh cisco@172.16.1.110 32 | show ip bgp sum 33 | show run part router bgp 65000 34 | -------------------------------------------------------------------------------- /Scripted Demos/AWS - Setup.md: -------------------------------------------------------------------------------- 1 | # AWS VPC demo 2 | 3 | aws ec2 describe-security-groups 4 | aws ec2 authorize-security-group-ingress --group-name default --protocol tcp --port 22 --cidr 0.0.0.0/0 -------------------------------------------------------------------------------- /Scripted Demos/G0 - Push device configs into Git master.md: -------------------------------------------------------------------------------- 1 | # Managing network device configurations with Git 2 | 3 | ## Setup 4 | 5 | * Run 3-router VIRL topology 6 | * Log into Ansible VM 7 | * Disable Ctrl-D exit 8 | ``` 9 | export IGNOREEOF=10 10 | ``` 11 | * Setup 3-router environment in `/vagrant/Examples/3-router-setup` 12 | ``` 13 | cd /vagrant/Examples/3-router-setup 14 | source setup.sh 15 | ``` 16 | * Prepare routers for automation 17 | ``` 18 | ../../tools/ssh-keys/get-keys.yml 19 | ../../tools/config-actions/enable-scp.yml 20 | ``` 21 | * Erase and recreate https://gitlab.com/ipspace/ConfigRepo 22 | * Remove /vagrant/Examples/Private/ConfigRepo 23 | * Create a new local clone with `git clone git@gitlab.com:ipspace/ConfigRepo.git` 24 | * Create an initial commit in `master` branch and push it to GitLab 25 | 26 | ## Simple capture-and-commit 27 | 28 | * Grab and commit all configs with 29 | ``` 30 | cd /vagrant/Examples/Config-to-Git 31 | ansible-playbook gc_napalm.yml -e git_branch=master 32 | ``` 33 | * Examine configuration files 34 | ``` 35 | more ../Private/ConfigRepo/*cfg 36 | ``` 37 | * Commit to master branch 38 | ``` 39 | ansible-playbook git_commit.yml -e git_branch=master 40 | ``` 41 | * Remove banners and commit changes 42 | ``` 43 | ../../tools/config-actions/no-banner.yml 44 | ansible-playbook getandcommit.yml -e git_branch=master 45 | ``` 46 | * Inspect https://gitlab.com/ipspace/ConfigRepo/commits/master in browser 47 | * View history in master branch 48 | * Click on commit name to get list of changes 49 | * Click on a file to get more information about that file 50 | -------------------------------------------------------------------------------- /Scripted Demos/G1 - Push device configurations into Actual branch.md: -------------------------------------------------------------------------------- 1 | ## Push device configurations into _Actual_ branch 2 | 3 | * Create actual branch 4 | ``` 5 | pushd ../Private/ConfigRepo 6 | git checkout -b actual 7 | ``` 8 | * Configuration changes are pushed into the `actual` branch 9 | ``` 10 | ansible-playbook getandcommit.yml -e git_branch=actual 11 | ``` 12 | * Change BGP neighbor description on R1 13 | ``` 14 | show run part router bgp 65001 15 | configure terminal 16 | router bgp 65001 17 | neighbor 10.0.0.13 description ISP-A 18 | ``` 19 | * Commit the changes 20 | ``` 21 | ansible-playbook getandcommit.yml -e git_branch=actual 22 | ``` 23 | 24 | ## Merge _actual_ branch into _master_ branch 25 | 26 | * Open GitLab in browser 27 | * Open branches, compare actual and master 28 | * Display local diff 29 | ``` 30 | pushd ../Private/ConfigRepo 31 | git checkout actual 32 | git diff master 33 | ``` 34 | * Create merge request actual-to-master 35 | * Confirm merge request 36 | 37 | -------------------------------------------------------------------------------- /Scripted Demos/G2 - Merge individual changes as feature branches.md: -------------------------------------------------------------------------------- 1 | ## Merge individual changes as feature branches 2 | 3 | * Change interface description on R1 4 | ``` 5 | sshpass -p cisco ssh cisco@172.16.1.101 6 | show run interface gig0/1 7 | configure terminal 8 | interface gig0/1 9 | description Uplink to ISP-A 10 | ``` 11 | * Create loopback interface on R3 12 | ``` 13 | sshpass -p cisco ssh cisco@172.16.1.103 14 | configure terminal 15 | interface loopback 1 16 | description fake loopback 17 | ``` 18 | * Commit the changes 19 | ``` 20 | ansible-playbook getandcommit.yml -e git_branch=actual 21 | ``` 22 | * Display local diff 23 | ``` 24 | pushd ../Private/ConfigRepo 25 | git checkout actual 26 | git diff master 27 | ``` 28 | * Commit my changes to feature branch 29 | ``` 30 | pushd ../Private/ConfigRepo 31 | git checkout master 32 | git checkout -b Desc_ISP_A 33 | git checkout actual R1.cfg 34 | git commit -a -m 'Changed interface description on gig 0/1' 35 | git push --all 36 | ``` 37 | -------------------------------------------------------------------------------- /Scripted Demos/G3 - Change Configs From Git.md: -------------------------------------------------------------------------------- 1 | ## Change configs from Git 2 | 3 | * Grab actual device configuration and push it into Git 4 | ``` 5 | ansible-playbook gc_scp.yml -e git_branch=actual 6 | pushd ../Private/ConfigRepo 7 | git diff master 8 | popd 9 | ansible-playbook git_commit.yml -e git_branch=actual 10 | ``` 11 | * Merge _actual_ into _master_ on GitLab 12 | * Create a feature branch 13 | ``` 14 | pushd ../Private/ConfigRepo 15 | git checkout master 16 | git pull 17 | git checkout -b ISP_B 18 | ``` 19 | * Change R1 in feature branch: under `router bgp` add 20 | ``` 21 | neighbor 10.0.0.17 remote-as 65010 22 | neighbor 10.0.0.17 description ISP-B 23 | ``` 24 | * Display local diff and commit changes 25 | ``` 26 | git diff 27 | git commit -a -m 'Uplink to ISP_B' 28 | git push --all 29 | ``` 30 | * Merge *ISP_B* into _master_ on GitLab using merge request 31 | * Install changes from _master_ to network devices 32 | ``` 33 | export ANSIBLE_STDOUT_CALLBACK=selective 34 | ansible-playbook --check gi_napalm.yml 35 | ansible-playbook gi_napalm.yml 36 | ``` 37 | * Verify successful deployment 38 | ``` 39 | sshpass -p cisco ssh cisco@172.16.1.101 40 | ``` 41 | * Fix BGP configuration 42 | * Download the changes and commit them 43 | ``` 44 | ansible-playbook gc_scp.yml -l R1 -e git_branch=ISP_B 45 | pushd ../Private/ConfigRepo 46 | git diff 47 | git commit -a -m 'Fix ISP-B AS number' 48 | git push --all 49 | ``` 50 | * Merge *ISP_B* to *master* on GitLab 51 | * Validate master == actual 52 | ``` 53 | ansible-playbook gc_scp.yml -e git_branch=actual 54 | ansible-playbook git_commit.yml -e git_branch=actual 55 | pushd ../Private/ConfigRepo 56 | git pull --all 57 | git diff origin/master 58 | ``` 59 | -------------------------------------------------------------------------------- /Scripted Demos/init-readme.md: -------------------------------------------------------------------------------- 1 | # Git 101 2 | 3 | This is the initial readme file for Git 101 repository. 4 | 5 | We'll add a few things to this file as we progress through the demo. 6 | -------------------------------------------------------------------------------- /YAML/0-Value.yml: -------------------------------------------------------------------------------- 1 | # This is a comment 2 | # Three dashes start a new document 3 | --- 4 | SomeValue 5 | 6 | -------------------------------------------------------------------------------- /YAML/1-Syntax.yml: -------------------------------------------------------------------------------- 1 | # This is a comment 2 | # Three dashes start a new document 3 | --- 4 | log_dir: logs 5 | build_dir: build 6 | domain_name: lab.ipspace.net 7 | -------------------------------------------------------------------------------- /YAML/2-SimpleList.yml: -------------------------------------------------------------------------------- 1 | # List of some major network vendors 2 | --- 3 | - Juniper 4 | - Cisco 5 | - Brocade 6 | - F5 # Load balancer is in the network 7 | -------------------------------------------------------------------------------- /YAML/3-Scalars.yml: -------------------------------------------------------------------------------- 1 | # List of some major network vendors 2 | --- 3 | - 12345 4 | - True 5 | - Brocade # soon to be Broadcom 6 | - http://www.cisco.com 7 | - "Quoted string" 8 | -------------------------------------------------------------------------------- /YAML/4-MultiLine.yml: -------------------------------------------------------------------------------- 1 | # Some long strings 2 | --- 3 | - | 4 | multi-line string 5 | indentation indicates it's still the same 6 | scalar value. 7 | !! Newlines are preserved !! 8 | - > 9 | multi-line string rolled 10 | into a single line -------------------------------------------------------------------------------- /YAML/5-KeyValuePairs.yml: -------------------------------------------------------------------------------- 1 | # Router description 2 | --- 3 | hostname: R1 4 | loopback_IP: 192.168.0.1 5 | loopback_subnet: 255.255.255.255 6 | banner: | 7 | The configuration of this router is managed by Ansible. 8 | 9 | Don't change it - your changes will be lost. 10 | -------------------------------------------------------------------------------- /YAML/6-ListOfDictionaries.yml: -------------------------------------------------------------------------------- 1 | # Routers in our network 2 | --- 3 | - description: DMVPN routers 4 | - hostname: R1 5 | loopback: 192.168.0.1 6 | - hostname: R2 7 | loopback: 192.168.0.2 8 | - hostname: R3 9 | loopback: 192.168.0.3 10 | -------------------------------------------------------------------------------- /YAML/6-ListOfLists.yml: -------------------------------------------------------------------------------- 1 | # 2x3 table 2 | --- 3 | - - Cell A1 4 | - Cell A2 5 | - Cell A3 6 | - - Cell B1 7 | - Cell B2 8 | - Cell B3 9 | 10 | -------------------------------------------------------------------------------- /YAML/7-ComplexDictionary.yml: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: R1 3 | addresses: 4 | - 192.168.0.1 5 | - 192.168.0.2 6 | loopback: 7 | ip: 192.168.0.1 8 | mask: 255.255.255.255 -------------------------------------------------------------------------------- /YAML/8-InlineListDictionary.yml: -------------------------------------------------------------------------------- 1 | # Shorter version of 2 | # router description 3 | --- 4 | hostname: R1 5 | addresses: [ 192.168.0.1, 192.168.0.2 ] 6 | loopback: { ip: 192.168.0.1, mask: "/32" } -------------------------------------------------------------------------------- /YAML/README.md: -------------------------------------------------------------------------------- 1 | # YAML examples 2 | 3 | This repository contains sources for YAML demos shown during the 4 | [Network Automation workshop](http://www.ipspace.net/NetAutWS) 5 | and [Ansible online course](http://www.ipspace.net/Ansible): 6 | 7 | ## Usage 8 | * **y2py** is a Python script that reads the YAML file specified on the command line, reports any parsing errors produced by Python YAML parser, and prints Python data structure equivalent to input YAML file 9 | * **y2js** is a YAML-to-JSON converter: it prints JSON data structure equivalent to YAML file specified on the command line 10 | * **y2pl** is the Perl version of **y2py** 11 | 12 | ## Installation 13 | 14 | Python modules needed to run **y2py** are installed with the [install script](../install/install.sh) 15 | 16 | Perl modules needed to run **y2pl** are installed with the **install-perl-cpan.sh** script 17 | 18 | ## Notes 19 | 20 | Perl version of YAML parser does not parse a single-value YAML document. Running **y2pl** on **0-Value.yml** will results in an error. 21 | 22 | ## More information 23 | 24 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) or 25 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 26 | 27 | -------------------------------------------------------------------------------- /YAML/install-perl-cpan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install CPAN modules needed for y2pl 4 | # 5 | sudo cpan install YAML File::Slurp Term::Screen 6 | -------------------------------------------------------------------------------- /YAML/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PATH=.:$PATH 3 | -------------------------------------------------------------------------------- /YAML/y2js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import yaml 4 | import sys 5 | import os 6 | import json 7 | from pprint import pprint 8 | 9 | def ly(filename): 10 | with open(filename) as _: 11 | return yaml.load(_) 12 | 13 | with open(sys.argv[1]) as _: 14 | text = _.read() 15 | body = yaml.load(text,Loader=yaml.BaseLoader) 16 | 17 | if len(sys.argv) > 2 and sys.argv[2] == 'mini': 18 | print (json.dumps(body, separators=(',', ':'))) 19 | else: 20 | os.system('cls' if os.name == 'nt' else 'clear') 21 | 22 | print('### YAML encoding ###') 23 | print(text) 24 | 25 | print('### JSON encoding ###') 26 | print(json.dumps(body, sort_keys=True, indent=2, separators=(', ', ': '))) 27 | -------------------------------------------------------------------------------- /YAML/y2pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use YAML (); 5 | use File::Slurp; 6 | use Data::Dumper; 7 | use Term::Screen; 8 | 9 | sub printout($;$) { 10 | my ($txt,$nl) = @_; 11 | 12 | $nl ||= 1; 13 | chomp $txt; # Remove existing newline and add a new one 14 | $txt .= "\n" x $nl; # to ensure all printouts look the same 15 | $txt =~ s/\n/\r\n/g; # Term::Screen turns STDOUT into raw device 16 | print $txt; 17 | } 18 | 19 | my $scr = new Term::Screen; 20 | $scr->clrscr(); 21 | my $fname = shift @ARGV; 22 | my $yaml = read_file($fname) || die "Cannot read YAML object from file $fname: $!"; 23 | printout $yaml,2; 24 | 25 | my $object = YAML::LoadFile($fname); 26 | 27 | $Data::Dumper::Terse = 1; 28 | my $dashes = "=" x 20; 29 | printout "$dashes PERL object $dashes"; 30 | printout Dumper($object); -------------------------------------------------------------------------------- /YAML/y2py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import yaml 4 | import sys 5 | import os 6 | from pprint import pprint 7 | 8 | def ly(filename): 9 | with open(filename) as _: 10 | return yaml.load(_) 11 | 12 | os.system('cls' if os.name == 'nt' else 'clear') 13 | 14 | with open(sys.argv[1]) as _: 15 | text = _.read() 16 | 17 | print('##################################') 18 | print(text) 19 | 20 | body = yaml.load(text,Loader=yaml.BaseLoader) 21 | print('##################################') 22 | pprint(body) 23 | -------------------------------------------------------------------------------- /install/README.md: -------------------------------------------------------------------------------- 1 | # Installing the Ansible VM 2 | 3 | Prerequisites: 4 | 5 | * hypervisor environment supported by a vagrant provider plugin (VirtualBox, VMware Fusion, VMware Workstation...) 6 | * vagrant 7 | * vagrant provider plugin for the selected hypervisor environment 8 | 9 | ## Select the Vagrant file 10 | 11 | Select the Vagrantfile you like from the topologies directory and copy it as _Vagrantfile_ into the parent directory. 12 | 13 | ## Create the Ubuntu VM (Ansible host) 14 | 15 | From the main repository directory execute *vagrant up* optionally specifying the VM name (for example *vagrant up nms*) if your Vagrantfile has more 16 | than one VM. You might have to specify the virtualization software you're using with the --provider flag. See vagrant documentation for more details. 17 | 18 | ## Installing the prerequisite software 19 | 20 | * Log into the VM with *vagrant ssh* 21 | * Change directory to _/vagrant/install_ 22 | * If you're using Ubuntu 18.04 or later execute *install.sh* (for example, with *bash install.sh*), otherwise execute *install.ubuntu-14.04.sh*. The installation script will: 23 | * Update system software 24 | * Install required Ubuntu packages 25 | * Install Python modules required by YAML, Jinja2 and Ansible demos 26 | * Install Ansible, Junos EZPY and NAPALM 27 | * Optionally install additional software you might need 28 | * Install PERL modules for the YAML demos with *install.perl.sh* 29 | 30 | ## More information 31 | 32 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) or 33 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 34 | 35 | -------------------------------------------------------------------------------- /install/ansible-github.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Install prerequisites 3 | sudo pip install paramiko edcsa 4 | # 5 | # Install Ansible from Github 6 | # 7 | cd ~vagrant 8 | echo "Pull Ansible from Github into Vagrant home directory" 9 | git clone git://github.com/ansible/ansible.git --recursive 10 | # 11 | echo "Install Ansible" 12 | sudo make install 13 | -------------------------------------------------------------------------------- /install/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | library = ~/.ansible/napalm-ansible 3 | -------------------------------------------------------------------------------- /install/ssh.config: -------------------------------------------------------------------------------- 1 | StrictHostKeyChecking=no 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | Vagrantfile 2 | .vagrant/ 3 | -------------------------------------------------------------------------------- /tests/Vagrantfile.bento.18-04: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.require_version ">= 1.6.0" 5 | VAGRANTFILE_API_VER = "2" 6 | 7 | Vagrant.configure("2") do |config| 8 | config.vbguest.auto_update = false 9 | config.vm.box_check_update = false 10 | config.vm.define "test" do |i| 11 | i.vm.box = "bento/ubuntu-18.04" 12 | i.vm.provision "shell", path: "../install/install.sh" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /tests/test-install.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Test all versions of Vagrantfiles 3 | # 4 | vagrant destroy -f 5 | set -e 6 | cp Vagrantfile.bento.18-04 Vagrantfile 7 | vagrant up --provider virtualbox 8 | vagrant destroy -f 9 | 10 | -------------------------------------------------------------------------------- /tools/.bash_profile: -------------------------------------------------------------------------------- 1 | parse_git_branch () 2 | { 3 | git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/' 4 | } 5 | 6 | _git-tree-branch () 7 | { 8 | changed=$(git -c color.status=always status -s) 9 | if [ -n "$changed" ] ; then 10 | printf -v line "%*s" 50 "" 11 | printf "In %s:\n%s\n" "$PWD" ${line// /-} 12 | printf "%s\n\n" "$changed" 13 | fi 14 | } 15 | 16 | git-tree () 17 | { 18 | count=$(find "${1:-.}" -name '.git' -print | wc -l) 19 | if [ $count -ne 0 ] ; then 20 | export -f _git-tree-branch 21 | find "${1:-.}" -name '.git' -execdir bash -c _git-tree-branch "$PWD" \; 22 | else 23 | echo "No Git repositories found within specified directory path" 24 | fi 25 | } 26 | 27 | export PS1='\u \[\033[33m\]\W\[\033[32m\]$(parse_git_branch)\[\033[00m\] $ ' 28 | -------------------------------------------------------------------------------- /tools/.bash_prompt: -------------------------------------------------------------------------------- 1 | declare -x PS1='\[\e[0;32m\]$ \[\e[33m\]' 2 | none='\e[0m' 3 | trap 'echo -ne "$none"' DEBUG 4 | -------------------------------------------------------------------------------- /tools/config-actions/enable-lldp.yml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | # 3 | # Enable LLDP on Cisco IOS 4 | # 5 | --- 6 | - hosts: all 7 | tasks: 8 | - name: Enable LLDP on Cisco IOS devices 9 | ios_config: 10 | lines: 11 | - lldp run 12 | - lldp timer 5 13 | - lldp holdtime 15 14 | authorize: yes 15 | - name: Disable LLDP on GigabitEthernet 0/0 16 | ios_config: 17 | parents: 18 | - interface GigabitEthernet0/0 19 | lines: 20 | - no lldp transmit 21 | - no lldp receive 22 | authorize: yes 23 | tags: [ virl ] 24 | -------------------------------------------------------------------------------- /tools/config-actions/enable-scp.yml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | # 3 | # Enable SCP on Cisco IOS 4 | # 5 | --- 6 | - hosts: all 7 | tasks: 8 | - name: Enable SCP server on Cisco IOS devices 9 | ios_config: 10 | lines: 11 | - ip scp server enable 12 | - alias exec replace configure replace 13 | authorize: yes 14 | - name: Enable configuration archive on Cisco IOS devices 15 | ios_config: 16 | parents: 17 | - archive 18 | lines: 19 | - "path flash:" 20 | authorize: yes 21 | -------------------------------------------------------------------------------- /tools/config-actions/no-banner.yml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | 3 | # 4 | # Disable banners 5 | # 6 | --- 7 | - hosts: all 8 | tasks: 9 | - name: Disable all banners on Cisco IOS devices 10 | ios_config: 11 | lines: 12 | - no banner exec 13 | - no banner incoming 14 | - no banner login 15 | authorize: yes 16 | when: ansible_os == 'ios' 17 | -------------------------------------------------------------------------------- /tools/config-actions/rollback-to-startup.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Replace running config with startup config on Cisco IOS 3 | # 4 | --- 5 | - hosts: all 6 | tasks: 7 | - ios_config: 8 | authorize: yes 9 | lines: 10 | - alias exec replace configure replace 11 | - ios_command: 12 | commands: 13 | - replace nvram:startup-config force 14 | authorize: yes 15 | timeout: 30 16 | -------------------------------------------------------------------------------- /tools/ios-configs/enable_scp.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Enable SCP on Cisco IOS 3 | # 4 | --- 5 | - hosts: all 6 | tasks: 7 | - name: Enable SCP server on Cisco IOS devices 8 | ios_config: 9 | lines: 10 | - ip scp server enable 11 | authorize: yes 12 | -------------------------------------------------------------------------------- /tools/prettify-xml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | use XML::LibXML; 4 | use XML::LibXML::PrettyPrint; 5 | 6 | binmode STDIN; 7 | my $doc = XML::LibXML->load_xml(IO => STDIN); 8 | my $pp = XML::LibXML::PrettyPrint->new(indent_string => " "); 9 | $pp->pretty_print($doc); 10 | print $doc->toString; 11 | -------------------------------------------------------------------------------- /tools/ssh-keys/README.md: -------------------------------------------------------------------------------- 1 | # Collect SSH keys from managed devices 2 | 3 | The playbook collects SSH keys from devices listed in inventory file using either **ansible_host** or **inventory_hostname** to connect to the device. 4 | 5 | The collected keys are stored in an Ansible-managed block in SSH **known_hosts** file (default: per-user file, change the playbook or overwrite the default with --extra-vars) 6 | 7 | Credits: based on [this article](http://everythingshouldbevirtual.com/ansible-ssh-known-host-keys) on Everything Should be Virtual. 8 | 9 | ## Usage 10 | 11 | Download, explore & enjoy... and when you discover you want to know more, register for the: 12 | 13 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) or 14 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 15 | -------------------------------------------------------------------------------- /tools/ssh-keys/get-keys.yml: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ansible-playbook 2 | # 3 | # Get SSH keys from lab devices described in Ansible inventory 4 | # 5 | - name: Get SSH keys 6 | hosts: all 7 | gather_facts: no 8 | vars: 9 | - known_hosts: "~/.ssh/known_hosts" 10 | tasks: 11 | - name: scan and register 12 | command: "ssh-keyscan -p {{ansible_port|default(22)}} {{ansible_host|default(inventory_hostname)}}" 13 | register: "host_keys" 14 | delegate_to: localhost 15 | changed_when: false 16 | 17 | - assert: 18 | that: host_keys.stdout 19 | msg: "We did not get SSH key for {{inventory_hostname}}" 20 | 21 | - name: Create known hosts file 22 | hosts: localhost 23 | vars: 24 | - known_hosts: "~/.ssh/known_hosts" 25 | tasks: 26 | - name: Stat known_hosts file for existance 27 | stat: path="{{ known_hosts }}" 28 | register: fstat 29 | 30 | - name: Create known_hosts file if non-existing 31 | # Creating same using 'touch' has the underisable effect of any non-ansible key additions (using ssh cmd) to file being appended to 32 | # ansible managed code block without a new line, rendering the ansible block non-unique between playbook runs and quite wasted. 33 | copy: content="\n" dest="{{ known_hosts }}" 34 | when: "not fstat.stat.exists" 35 | changed_when: false 36 | 37 | - blockinfile: 38 | dest: "{{known_hosts}}" 39 | marker: "# {mark} This part managed by Ansible" 40 | block: | 41 | {% for h in groups['all'] if hostvars[h].host_keys is defined and hostvars[h].host_keys.stdout is defined %} 42 | {% if hostvars[h].ansible_port is defined %} 43 | {% for key in hostvars[h].host_keys.stdout_lines %} 44 | [{{ key.partition(" ")[0] }}]:{{ hostvars[h].ansible_port }} {{ key.partition(" ")[2] }} 45 | {% endfor %} 46 | {% else %} 47 | {{ hostvars[h].host_keys.stdout }} 48 | {% endif %} 49 | {% endfor %} 50 | -------------------------------------------------------------------------------- /tools/xcode: -------------------------------------------------------------------------------- 1 | output="recode" 2 | resize="" 3 | 4 | while test $# -gt 0; do 5 | case "$1" in 6 | --480) 7 | resize="-vf scale=-1:480" 8 | shift 9 | ;; 10 | --768) 11 | resize="-vf scale=-1:768" 12 | shift 13 | ;; 14 | --output) 15 | shift 16 | if test $# -gt 0; then 17 | export output=$1 18 | else 19 | echo "no output dir specified" 20 | exit 1 21 | fi 22 | shift 23 | ;; 24 | -h|--help|-*) 25 | script=`basename $0` 26 | echo "$script - resize/recode a video" 27 | echo " " 28 | echo "$script [options] files" 29 | echo " " 30 | echo "options:" 31 | echo "--480 resize to 480p" 32 | echo "--output Output directory" 33 | exit 0 34 | ;; 35 | *) 36 | break 37 | ;; 38 | esac 39 | done 40 | 41 | if test $# -eq 0; then 42 | echo "Specify options and a list of files, use -h for help" 43 | exit 44 | fi 45 | 46 | echo "Options" 47 | echo "=======" 48 | echo "Resizing: $resize" 49 | echo "Output directory: $output" 50 | 51 | if ! [ -d "$output" ]; then 52 | mkdir "$output" 53 | fi 54 | for var in "$@" 55 | do 56 | file_dir=`dirname "$var"` 57 | file_name_ext=`basename "$var"` 58 | file_name=${file_name_ext%.*} 59 | file_ext=${file_name_ext#$file_name.} 60 | 61 | echo "Converting" 62 | echo "==========" 63 | echo "input: $var" 64 | echo "output: ${output}/${file_name}.mp4" 65 | echo "" 66 | ffmpeg -i "$var" \ 67 | -loglevel warning \ 68 | -strict -2 $resize \ 69 | -c:v libx264 -preset slower -crf 20 \ 70 | -profile:v baseline -level 3.1 \ 71 | -c:a copy -flags +global_header \ 72 | -r 15 "${output}/${file_name}.mp4" 73 | done 74 | -------------------------------------------------------------------------------- /topologies/EOS-Leaf-and-Spine/README.md: -------------------------------------------------------------------------------- 1 | # vEOS running in Vagrant/VirtualBox 2 | 3 | Use this *Vagrantfile* to build a leaf-and-spine network of vEOS switches. 4 | 5 | ## Getting started 6 | 7 | * Install VirtualBox and Vagrant 8 | * Copy correct *Vagrantfile* and *topology.yml* into an empty directory 9 | * Download vEOS box from Arista and install it as **vEOS** Vagrant box. More details in [Building the Lab Environment tutorial](https://github.com/dravetech/network-tutorials/tree/master/tutorial-0-building-env) by David Barroso 10 | 11 | Notes: 12 | 13 | * vEOS needs serial port emulation that's implemented with virtual pipes resulting in name conflicts on Windows. Make sure you use the correct Vagrantfile. 14 | * Linux version of the Vagrantfile should work on OSX as well. If it doesn't please submit a pull request. 15 | * If needed change the vEOS box name in *topology.yml* to whatever box you created from downloaded vEOS box. 16 | * Remove the 'memory' parameters from *topology.yml* if you have enough physical memory (VirtualBox default = 2048MB). 17 | * Remove **nms** virtual machine from *topology.yml* if you want to run Ansible on your host machine. 18 | * Use the *install.sh* script to install Ansible and NAPALM on **nms**. More details in [this document](https://my.ipspace.net/bin/get?doc=ca659efe-f437-11e6-b42b-005056880254). 19 | * Use the *hosts.vm* inventory if you're running Ansible in **nms** virtual machine or *hosts.local* inventory if you're running Ansible on the host. 20 | 21 | ## More information 22 | 23 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) 24 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 25 | 26 | -------------------------------------------------------------------------------- /topologies/EOS-Leaf-and-Spine/hosts.local: -------------------------------------------------------------------------------- 1 | spine-1 ansible_host=127.0.0.1 ansible_port=20001 api_port=21001 os=eos ansible_user=admin ansible_ssh_pass=admin 2 | spine-2 ansible_host=127.0.0.1 ansible_port=20002 api_port=21002 os=eos ansible_user=admin ansible_ssh_pass=admin 3 | leaf-1 ansible_host=127.0.0.1 ansible_port=20003 api_port=21003 os=eos ansible_user=admin ansible_ssh_pass=admin 4 | leaf-2 ansible_host=127.0.0.1 ansible_port=20004 api_port=21004 os=eos ansible_user=admin ansible_ssh_pass=admin 5 | -------------------------------------------------------------------------------- /topologies/EOS-Leaf-and-Spine/hosts.vm: -------------------------------------------------------------------------------- 1 | spine-1 ansible_host=10.0.2.2 ansible_port=20001 api_port=21001 os=eos ansible_user=admin ansible_ssh_pass=admin 2 | spine-2 ansible_host=10.0.2.2 ansible_port=20002 api_port=21002 os=eos ansible_user=admin ansible_ssh_pass=admin 3 | leaf-1 ansible_host=10.0.2.2 ansible_port=20003 api_port=21003 os=eos ansible_user=admin ansible_ssh_pass=admin 4 | leaf-2 ansible_host=10.0.2.2 ansible_port=20004 api_port=21004 os=eos ansible_user=admin ansible_ssh_pass=admin 5 | -------------------------------------------------------------------------------- /topologies/EOS-Leaf-and-Spine/topology.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: spine-1 3 | box: vEOS 4 | memory: 1800 5 | links: 6 | - name: S1L1 7 | - name: S1L2 8 | forwarded_ports: 9 | - { guest: 22, host: 20001 } 10 | - { guest: 443, host: 21001 } 11 | 12 | - name: spine-2 13 | box: vEOS 14 | memory: 1800 15 | links: 16 | - name: S2L1 17 | - name: S2L2 18 | forwarded_ports: 19 | - { guest: 22, host: 20002 } 20 | - { guest: 443, host: 21002 } 21 | 22 | - name: leaf-1 23 | box: vEOS 24 | memory: 1800 25 | links: 26 | - name: S1L1 27 | - name: S2L1 28 | forwarded_ports: 29 | - { guest: 22, host: 20003 } 30 | - { guest: 443, host: 21003 } 31 | 32 | - name: leaf-2 33 | box: vEOS 34 | memory: 1800 35 | links: 36 | - name: S1L2 37 | - name: S2L2 38 | forwarded_ports: 39 | - { guest: 22, host: 20004 } 40 | - { guest: 443, host: 21004 } 41 | 42 | - name: nms 43 | box: bento/ubuntu-18.04 44 | memory: 1024 45 | 46 | -------------------------------------------------------------------------------- /topologies/README.md: -------------------------------------------------------------------------------- 1 | # Sample lab topologies 2 | 3 | You'll find Vagrantfile-s for several lab topologies in this directory: 4 | 5 | * **VIRL** - Ansible VM to use with VIRL. Includes several Cisco IOS VIRL topologies. See [Using Ansible Playbooks with Cisco VIRL](http://automation.ipspace.net/Example:Using_Ansible_Playbooks_with_Cisco_VIRL) for details. 6 | * **vSRX+VIRL** - Ansible VM + Juniper vSRX to use with VIRL. Includes a Cisco IOS + Nexus OS VIRL topology. 7 | * **EOS-Leaf-and-Spine** - a full-leaf-and-spine topology with Arista vEOS and Ansible VM. The Vagrantfile in this directory uses YAML data file to specify lab topology. 8 | 9 | The *tools* directory contains Vagrant-related tools 10 | 11 | * **Vagrant2Inventory.py** - create Ansible inventory file from Vagrant printout (see [this article](http://automation.ipspace.net/Example:Creating_Ansible_Inventory_from_Vagrant_SSH_Configuration)) for details -------------------------------------------------------------------------------- /topologies/VIRL/README.md: -------------------------------------------------------------------------------- 1 | # Ansible in a VM with VIRL 2 | 3 | Use this *Vagrantfile* when running Ansible in a Vagrant-connected VM with VIRL. The file creates **nms** virtual machine. Use the *install.sh* script to install Ansible and NAPALM on it. More details in [this document](https://my.ipspace.net/bin/get?doc=ca659efe-f437-11e6-b42b-005056880254). 4 | 5 | ## Notes 6 | 7 | * Use `--provider` argument when starting the Vagrant virtual machine for the first time; Vagrant might use the VirtualBox provider otherwise 8 | * The Ansible VM is connected to *vmnet2* network (the VIRL management network) and uses IP address 172.16.1.12 9 | * You **MUST** use VMware desktop virtualization product (Workstation or Fusion) - other hypervisors are not supported by VIRL. 10 | * You might want to use one of the included VIRL topologies as a starting point. 11 | 12 | Read also: 13 | 14 | * [Use Ansible playbooks with Cisco VIRL](http://automation.ipspace.net/Example:Using_Ansible_Playbooks_with_Cisco_VIRL) 15 | 16 | ## More information 17 | 18 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) 19 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 20 | 21 | -------------------------------------------------------------------------------- /topologies/VIRL/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure(2) do |config| 5 | config.vm.box = "bento/ubuntu-18.04" 6 | config.vm.box_check_update = false 7 | 8 | ["vmware_workstation", "vmware_fusion"].each do |vmware_provider| 9 | config.vm.provider(vmware_provider) do |vmware| 10 | vmware.whitelist_verified = true 11 | end 12 | end 13 | 14 | config.vm.define "nms" do |nms| 15 | nms.vm.host_name = "nms" 16 | nms.vm.network "private_network", ip: "172.16.1.12" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /topologies/YAML-with-Vagrant/topology.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: spine-1 3 | box: vEOS 4 | memory: 1800 5 | links: 6 | - name: S1L1 7 | - name: S1L2 8 | forwarded_ports: 9 | - { guest: 22, host: 20001 } 10 | - { guest: 443, host: 21001 } 11 | 12 | - name: spine-2 13 | box: vEOS 14 | memory: 1800 15 | links: 16 | - name: S2L1 17 | - name: S2L2 18 | forwarded_ports: 19 | - { guest: 22, host: 20002 } 20 | - { guest: 443, host: 21002 } 21 | 22 | - name: leaf-1 23 | box: vEOS 24 | memory: 1800 25 | links: 26 | - name: S1L1 27 | - name: S2L1 28 | forwarded_ports: 29 | - { guest: 22, host: 20003 } 30 | - { guest: 443, host: 21003 } 31 | 32 | - name: leaf-2 33 | box: vEOS 34 | memory: 1800 35 | links: 36 | - name: S1L2 37 | - name: S2L2 38 | forwarded_ports: 39 | - { guest: 22, host: 20004 } 40 | - { guest: 443, host: 21004 } 41 | 42 | - name: nms 43 | box: bento/ubuntu-18.04 44 | memory: 1024 45 | 46 | -------------------------------------------------------------------------------- /topologies/vSRX+VIRL/README.md: -------------------------------------------------------------------------------- 1 | # Ansible VM and vSRX with VIRL 2 | 3 | Use this *Vagrantfile* when you want to test a combination of Cisco devices (running in VIRL) and vSRX (running in Vagrant VM with VMware desktop virtualization provider). 4 | 5 | The file creates: 6 | * **nms** virtual machine running Ubuntu 14.04. 7 | * **srx** virtual machine running vSRX box for VMware Vagrant providers. 8 | 9 | Use the *install.sh* script to install Ansible and NAPALM on **nms**. More details in [this document](https://my.ipspace.net/bin/get?doc=ca659efe-f437-11e6-b42b-005056880254). 10 | 11 | ## Notes 12 | 13 | * You **MUST** use VMware desktop virtualization product (Workstation or Fusion) - other hypervisors are not supported by VIRL. 14 | * Use `--provider` argument when starting the Vagrant virtual machines for the first time; Vagrant might use the VirtualBox provider otherwise 15 | * The Ansible and vSRX virtual machines are connected to *vmnet2* network (the VIRL management network) and use IP address 172.16.1.12 and 172.16.1.13. 16 | * You might want to the included VIRL topology (with one Cisco IOS router and one Nexus-OS switch) as a starting point. 17 | 18 | Read also: 19 | 20 | * [Use Ansible playbooks with Cisco VIRL](http://automation.ipspace.net/Example:Using_Ansible_Playbooks_with_Cisco_VIRL) 21 | 22 | ## More information 23 | 24 | * [Ansible for Networking Engineers](http://www.ipspace.net/Ansible_for_Networking_Engineers) online course ([contents](https://my.ipspace.net/bin/list?id=AnsibleOC)) 25 | * [Building Network Automation Solutions](http://www.ipspace.net/Building_Network_Automation_Solutions) online course ([contents](https://my.ipspace.net/bin/list?id=NetAutSol)) 26 | 27 | -------------------------------------------------------------------------------- /topologies/vSRX+VIRL/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | require "vagrant-host-shell" 5 | require "vagrant-junos" 6 | 7 | Vagrant.configure(2) do |config| 8 | config.vm.box = "bento/ubuntu-18.04" 9 | config.vm.box_check_update = false 10 | 11 | ["vmware_workstation", "vmware_fusion"].each do |vmware_provider| 12 | config.vm.provider(vmware_provider) do |vmware| 13 | vmware.whitelist_verified = true 14 | end 15 | end 16 | 17 | config.vm.define "nms" do |nms| 18 | nms.vm.host_name = "nms" 19 | nms.vm.network "private_network", ip: "172.16.1.12" 20 | end 21 | 22 | config.vm.define "srx" do |srx| 23 | srx.vm.box = "juniper/ffp-12.1X47-D20.7" 24 | srx.vm.host_name = "srx" 25 | srx.vm.network "private_network", ip: "172.16.1.13" 26 | 27 | srx.vm.provider "vmware_fusion" do |v| 28 | v.vmx["memsize"] = "2048" 29 | v.vmx["ethernet2.generatedAddress"] = nil 30 | v.vmx["ethernet2.connectionType"] = "custom" 31 | v.vmx["ethernet2.present"] = "TRUE" 32 | v.vmx["ethernet2.vnet"] = "vmnet2" 33 | end 34 | end 35 | end 36 | --------------------------------------------------------------------------------