Read this in other languages: English,
日本語,
Français.
Demonstration use of Ansible Network Resource Modules
This exercise builds upon exercise 4 - Ansible Network Resource Modules. Please complete that exercise before starting this one.
There are two parts to this exercise:
- Cover additional configuration
state
parameters:
replaced
overridden
and contrast them to what we saw with merged
.
- Cover additional read-only
state
parameters
rendered
parsed
and contrast them to the gathered
parameter.
-
Login to an Arista switch. We are assuming the configuration from exercise 4 is already applied
vlan 20 name desktops ! vlan 30 name servers ! vlan 40 name printers ! vlan 50 name DMZ
-
From the control node terminal, you can
ssh rtr2
and typeenable
$ ssh rtr2 Last login: Wed Sep 1 13:44:55 2021 from 44.192.105.112 rtr2>enable
-
Use the command
configure terminal
to manually edit the Arista configuration:rtr2#configure terminal rtr2(config)#
-
Now configure vlan 50 to
state suspend
rtr2(config)#vlan 50 rtr2(config-vlan-50)#state ? active VLAN Active State suspend VLAN Suspended State rtr2(config-vlan-50)#state suspend
-
Save the configuration
rtr2(config-vlan-50)#exit rtr2(config)#end rtr2#copy running-config startup-config Copy completed successfully.
-
Examine the configuration
rtr2#sh run | s vlan vlan 20 name desktops ! vlan 30 name servers ! vlan 40 name printers ! vlan 50 name DMZ state suspend
- The running-configuration no longer matches our playbook! vlan 50 is now in state suspend.
-
Execute the playbook using the
ansible-navigator run
.$ ansible-navigator run resource.yml --mode stdout
-
The output will look similar to the following:
[student@ansible-1 network-workshop]$ ansible-navigator run resource.yml --mode stdout PLAY [configure VLANs] ********************************************************* TASK [use vlans resource module] *********************************************** ok: [rtr4] ok: [rtr2] PLAY RECAP ********************************************************************* rtr2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rtr4 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-
The playbook did NOT modify the configuration. The
state: merged
only enforces that the config provided exists on the network device. Lets contrast this toreplaced
. If you login to the Arista network device thestate suspend
will still be there.
-
Modify the
resource.yml
playbook so thatstate: merged
is nowstate: replaced
-
The playbook should look like the following:
--- - name: configure VLANs hosts: arista gather_facts: false tasks: - name: use vlans resource module arista.eos.vlans: state: replaced config: - name: desktops vlan_id: 20 - name: servers vlan_id: 30 - name: printers vlan_id: 40 - name: DMZ vlan_id: 50
-
Execute the playbook using the
ansible-navigator run
. Since there is just one task we can use the--mode stdout
$ ansible-navigator run resource.yml --mode stdout
-
The output will look similar to the following:
$ ansible-navigator run resource.yml --mode stdout PLAY [configure VLANs] ********************************************************* TASK [use vlans resource module] *********************************************** changed: [rtr4] changed: [rtr2] PLAY RECAP ********************************************************************* rtr2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rtr4 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-
Now examine the config on rtr2, the
state suspend
is now gone. Replaced will enforce (for the specified VLANs) the supplied configurations. This means that sincestate: suspend
was not supplied, and NOT the default for a VLAN, it will remove it from the network device.
-
Create vlan 100 on
rtr2
rtr2(config)#vlan 100 rtr2(config-vlan-100)#name ? WORD The ASCII name for the VLAN rtr2(config-vlan-100)#name artisanal
-
We can assume that someone has created this VLAN outside of automation (e.g. they hand-crafted a VLAN i.e. artisanal VLAN) This is referred to as "out of band" network changes. This is very common in the network industry because a network engineer solved a problem, but then never documented or circled back to remove this configuration. This manual configuration change does not match best practices or their documented policy. This could cause issues where someone tries to use this VLAN in the future, and not aware of this configuration.
rtr2#show vlan
VLAN Name Status Ports
----- -------------------------------- --------- -------------------------------
1 default active
20 desktops active
30 servers active
40 printers active
50 DMZ active
100 artisanal active
- Re-run the playbook again. The VLAN 100 is NOT removed.
-
Modify the playbook again, this time using the
state: overridden
--- - name: configure VLANs hosts: arista gather_facts: false tasks: - name: use vlans resource module arista.eos.vlans: state: overridden config: - name: desktops vlan_id: 20 - name: servers vlan_id: 30 - name: printers vlan_id: 40 - name: DMZ vlan_id: 50
-
Execute the playbook using the
ansible-navigator run
.$ ansible-navigator run resource.yml --mode stdout
-
Login back into the
rtr2
device and examine the VLANsrtr2#show vlan VLAN Name Status Ports ----- -------------------------------- --------- ------------------------------- 1 default active 20 desktops active 30 servers active 40 printers active 50 DMZ active
-
The artisanal VLAN 100 has been removed! Now the same resource modules can be used to not only configure network devices, but enforce which VLANs are configured. This is referred to as policy enforcement, and a huge part of configuration management. Going from
merged
toreplaced
tooverridden
will often match the automation journey for a network team as they gain more and more confidence with automation.
Now lets return to using read-only parameters. These parameters do not modify the configuration on a network device. In exercise 4, we used the state: gathered
to retrieve the VLAN configuration from the Arista network device. This time we will use rendered
to get the Arista commands that generate the configuration:
-
Modify the
resource.yml
playbook tostate: rendered
-
Register the output from the task to a variable named
rendered_config
-
Add a
debug
task to print the output to the terminal window -
The playbook will look like the following:
{% raw %}
- name: use vlans resource module
arista.eos.vlans:
state: rendered
config:
- name: desktops
vlan_id: 20
- name: servers
vlan_id: 30
- name: printers
vlan_id: 40
- name: DMZ
vlan_id: 50
register: rendered_config
- name: use vlans resource module
debug:
msg: "{{ rendered_config }}"
{% endraw %}
-
Execute the playbook using the
ansible-navigator run
.$ ansible-navigator run resource.yml --mode stdout
-
The output will look like the following:
[student@ansible-1 network-workshop]$ ansible-navigator run resource.yml --mode stdout PLAY [configure VLANs] ********************************************************* TASK [use vlans resource module] *********************************************** ok: [rtr2] ok: [rtr4] TASK [use vlans resource module] *********************************************** ok: [rtr4] => { "msg": { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "failed": false, "rendered": [ "vlan 20", "name desktops", "vlan 30", "name servers", "vlan 40", "name printers", "vlan 50", "name DMZ" ] } } ok: [rtr2] => { "msg": { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "failed": false, "rendered": [ "vlan 20", "name desktops", "vlan 30", "name servers", "vlan 40", "name printers", "vlan 50", "name DMZ" ] } } PLAY RECAP ********************************************************************* rtr2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rtr4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-
Specifically the
rendered
key will display the Arista commands that are used to generate the configuration! This allows network automators to know exactly what commands would be run and executed before they actually run automation to apply the commands.
Finally lets cover the parsed parameter. This parameter is used when a existing file contains the network device configuration. Imagine there was already a backup performed.
- First lets backup a configuration. Here is a simple playbook for doing a configuration backup. The playbook is backup.yml.
{% raw %}
---
- name: backup config
hosts: arista
gather_facts: false
tasks:
- name: retrieve backup
arista.eos.config:
backup: true
backup_options:
filename: "{{ inventory_hostname }}.txt"
{% endraw %}
-
Execute the playbook:
$ ansible-navigator run backup.yml --mode stdout
-
Verify the backups were created:
$ ls backup rtr2.txt rtr4.txt
-
Now modify the
resource.yml
playbook to use theparsed
playbook:
{% raw %}
---
- name: use parsed
hosts: arista
gather_facts: false
tasks:
- name: use vlans resource module
arista.eos.vlans:
state: parsed
running_config: "{{ lookup('file', 'backup/{{ inventory_hostname }}.txt') }}"
register: parsed_config
- name: print to terminal screen
debug:
msg: "{{ parsed_config }}"
{% endraw %}
-
There is a couple additional changes:
- instead of
config
we are usingrunning-config
and pointing to the backup file. - We are registering the output from the module to
parsed_config
varaible - We are using the debug module to print the
parsed_config
variable
- instead of
-
Execute the playbook:
$ ansible-navigator run resource.yml --mode stdout
-
The output will look like the following:
[student@ansible-1 network-workshop]$ ansible-navigator run resource.yml --mode stdout PLAY [use parsed] ************************************************************** TASK [use vlans resource module] *********************************************** ok: [rtr4] ok: [rtr2] TASK [print to terminal screen] ************************************************ ok: [rtr2] => { "msg": { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "failed": false, "parsed": [ { "name": "desktops", "state": "active", "vlan_id": 20 }, { "name": "servers", "state": "active", "vlan_id": 30 }, { "name": "printers", "state": "active", "vlan_id": 40 }, { "name": "DMZ", "state": "active", "vlan_id": 50 } ] } } ok: [rtr4] => { "msg": { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "failed": false, "parsed": [ { "name": "desktops", "state": "active", "vlan_id": 20 }, { "name": "servers", "state": "active", "vlan_id": 30 }, { "name": "printers", "state": "active", "vlan_id": 40 }, { "name": "DMZ", "state": "active", "vlan_id": 50 } ] } } PLAY RECAP ********************************************************************* rtr2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rtr4 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
-
In the output above you will see that the flat-file backup was parsed into structured data:
"parsed": [ { "name": "desktops", "state": "active", "vlan_id": 20 }
-
The default output is JSON but can be easily transformed into YAML.
We covered two additional configuration state
parameters:
replaced
- enforced config for specified VLANsoverridden
- enforced config for ALL vlans
Going from merged
to replaced
to overridden
follows the automation adoption journey as network teams gain more confidence with automation.
We covered additional read-only state
parameters
rendered
- shows commands that would generate the desired configurationparsed
- turned a flat-file configuration (such as a backup) into structured data (versus modifying the actual device)
These allow network automators to use resource modules in additional scenarios, such as disconnected environments. Network resource modules provide a consistent experience across different network devices.
The documentation guide provided additional info of using network resource modules.
The finished Ansible Playbook is provided here for an answer key:
You have completed the supplemental lab!
Click here to return to supplemental exercises
Click here to return to the Ansible Network Automation Workshop