In this exercise, you will automate the process of configuring dynamic routing with OSPF.
Outcomes
You should be able to:
Compose NOS-specific device configuration templates to provide parameterized configuration statements.
Perform a play that configures OSPF on network devices.
Verify that the outcome is as intended.
Open a terminal window on the workstation VM and change to the ~/proj/ directory.
Compose NOS-specific device configuration templates to provide parameterized configuration statements.
Create a Jinja2 template that constructs statements to configure OSPF on VyOS devices.
Create a file named j2/vyos-ospf.j2 with the following content:
{% for intf in layer3_data[inventory_hostname] %}
{% if intf.name == 'lo' %}
set protocols ospf parameters router-id {{ intf.ipv4 | ipaddr('address') }}
set protocols ospf log-adjacency-changes
set protocols ospf redistribute connected metric-type 2
{% if inventory_hostname == 'spine01' or inventory_hostname == 'spine02' %}
set protocols ospf default-information originate always
set protocols ospf default-information originate metric 10
set protocols ospf default-information originate metric-type 2
{% endif %}
{% else %}
set protocols ospf area 0 network {{ intf.ipv4 | ipaddr('network/prefix') }}
{% endif %}
{% endfor %}
Create a Jinja2 template that constructs statements to configure OSPF on IOS devices.
Create a file named j2/ios-ospf.j2 with the following content: Note the line starting with network may have wrapped; it should end with area 0.
router ospf 1
{% for intf in layer3_data[inventory_hostname] %}
{% if intf.name.startswith('Loopback') %}
router-id {{ intf.ipv4 | ipaddr('address') }}
{% else %}
network {{ intf.ipv4 | ipaddr('network') }} {{ intf.ipv4 | ipaddr('hostmask') }} area 0
{% endif %}
{% endfor %}
There should be a single, very long line between {% else %} and {% endif %} that starts with a space and the word network and ends with area 0.
The line might be wrapped due to length in this student guide.
Perform a play that configures OSPF on network devices.
Compose a playbook that configures OSPF based on data and templates.
Create a file named ospf-consolidation.yml with the following content:
---
- name: play that configures OSPF according to data and templates
hosts: network
vars:
vyos_ospf_template: j2/vyos-ospf.j2
ios_ospf_template: j2/ios-ospf.j2
vars_files:
- vars/consolidation-data.yml
tasks:
- name: configure ospf on vyos
vyos_config:
src: "{{ vyos_ospf_template }}"
save: True
when: ansible_network_os == 'vyos'
- name: configure ospf on ios
ios_config:
src: "{{ ios_ospf_template }}"
save_when: changed
when: ansible_network_os == 'ios'
Check playbook syntax, then perform the play.
If you are having trouble, you may refer to http://materials.example.com/full from your workstation.
[student@workstation proj]$ansible-playbook --syntax-check \>ospf-consolidation.ymlPlaybook: ospf-consolidation.yml[student@workstation proj]$ansible-playbook ospf-consolidation.yml
Execute an ad hoc command that displays IP routes on VyOS device spine01.
[student@workstation proj]$ansible -m vyos_command \>-a "commands='sh ip ro'" spine01spine01 | SUCCESS => { ...output omitted... "stdout_lines": [ [ "Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,", " I - ISIS, B - BGP, > - selected route, * - FIB route", "", "O 0.0.0.0/0 [110/10] via 10.10.5.2, 00:07:07", "S>* 0.0.0.0/0 [1/0] via 172.16.2.2, eth5", "C>* 10.0.0.1/32 is directly connected, lo", "O>* 10.0.0.2/32 [110/20] via 10.10.5.2, eth1, 00:11:03", " * via 10.10.6.2, eth2, 00:11:03", "O>* 10.0.0.11/32 [110/20] via 10.10.5.2, eth1, 00:11:03", "O>* 10.0.0.12/32 [110/20] via 10.10.6.2, eth2, 00:11:13", "O 10.10.5.0/30 [110/10] is directly connected, eth1, 00:12:08", "C>* 10.10.5.0/30 is directly connected, eth1", "O 10.10.6.0/30 [110/10] is directly connected, eth2, 00:12:08", "C>* 10.10.6.0/30 is directly connected, eth2", "O>* 10.10.7.0/30 [110/20] via 10.10.5.2, eth1, 00:11:04", "O>* 10.10.8.0/30 [110/20] via 10.10.6.2, eth2, 00:11:14", "O 10.10.10.0/30 [110/20] via 10.10.5.2, 00:11:04", "S>* 10.10.10.0/30 [1/0] via 10.10.5.2, eth1", "C>* 127.0.0.0/8 is directly connected, lo", "O 172.16.2.0/30 [110/10] is directly connected, eth5, 00:12:07", "C>* 172.16.2.0/30 is directly connected, eth5", "O>* 172.16.10.0/30 [110/11] via 172.16.2.2, eth5, 00:12:03", "O 172.25.250.0/24 [110/20] via 10.10.5.2, 00:11:03", " via 10.10.6.2, 00:11:03", "C>* 172.25.250.0/24 is directly connected, eth0", "O>* 192.168.10.0/30 [110/20] via 10.10.6.2, eth2, 00:11:14" ] ] }
Execute an ad hoc command that displays IP routes on IOS device cs01.
[student@workstation proj]$ansible -m ios_command -a "commands='sh ip ro'" cs01cs01 | SUCCESS => { ...output omitted... "stdout_lines": [ [ "Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP", " D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area ", " N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2", " E1 - OSPF external type 1, E2 - OSPF external type 2", " i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2", " ia - IS-IS inter area, * - candidate default, U - per-user static route", " o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP", " a - application route", " + - replicated route, % - next hop override, p - overrides from PfR", "", "O*E2 0.0.0.0/0 [110/10] via 172.16.2.1, 00:11:46, GigabitEthernet2", " 10.0.0.0/8 is variably subnetted, 8 subnets, 2 masks", "O E2 10.0.0.2/32 [110/20] via 172.16.2.1, 00:11:46, GigabitEthernet2", "O E2 10.0.0.11/32 [110/20] via 172.16.2.1, 00:11:46, GigabitEthernet2", "O E2 10.0.0.12/32 [110/20] via 172.16.2.1, 00:11:46, GigabitEthernet2", "O 10.10.5.0/30 [110/11] via 172.16.2.1, 00:11:36, GigabitEthernet2", "O 10.10.6.0/30 [110/11] via 172.16.2.1, 00:11:56, GigabitEthernet2", "O 10.10.7.0/30 [110/21] via 172.16.2.1, 00:11:36, GigabitEthernet2", "O 10.10.8.0/30 [110/21] via 172.16.2.1, 00:11:46, GigabitEthernet2", "O 10.10.10.0/30 [110/21] via 172.16.2.1, 00:11:36, GigabitEthernet2", " 172.16.0.0/16 is variably subnetted, 5 subnets, 2 masks", "C 172.16.0.1/32 is directly connected, Loopback1", "C 172.16.2.0/30 is directly connected, GigabitEthernet2", "L 172.16.2.2/32 is directly connected, GigabitEthernet2", "C 172.16.10.0/30 is directly connected, GigabitEthernet4", "L 172.16.10.1/32 is directly connected, GigabitEthernet4", " 172.25.0.0/16 is variably subnetted, 2 subnets, 2 masks", "C 172.25.250.0/24 is directly connected, GigabitEthernet1", "L 172.25.250.195/32 is directly connected, GigabitEthernet1", " 192.168.10.0/30 is subnetted, 1 subnets", "O 192.168.10.0 [110/21] via 172.16.2.1, 00:11:46, GigabitEthernet2" "O 192.168.5.0 [110/11] via 172.16.5.1, 00:03:58, GigabitEthernet3", " 192.168.10.0/30 is subnetted, 1 subnets", "O 192.168.10.0 [110/21] via 172.16.5.1, 00:03:58, GigabitEthernet3" ] ] }
This concludes the guided exercise.