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
stateparameters:
replacedoverridden
and contrast them to what we saw with merged.
- Cover additional read-only
stateparameters
renderedparsed
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 rtr2and typeenable$ ssh rtr2 Last login: Wed Sep 1 13:44:55 2021 from 44.192.105.112 rtr2>enable -
Use the command
configure terminalto manually edit the Arista configuration:rtr2#configure terminal rtr2(config)# -
Now configure vlan 50 to
state suspendrtr2(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: mergedonly enforces that the config provided exists on the network device. Lets contrast this toreplaced. If you login to the Arista network device thestate suspendwill still be there.
-
Modify the
resource.ymlplaybook so thatstate: mergedis 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 suspendis now gone. Replaced will enforce (for the specified VLANs) the supplied configurations. This means that sincestate: suspendwas not supplied, and NOT the default for a VLAN, it will remove it from the network device.
-
Create vlan 100 on
rtr2rtr2(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
rtr2device 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
mergedtoreplacedtooverriddenwill 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.ymlplaybook tostate: rendered -
Register the output from the task to a variable named
rendered_config -
Add a
debugtask 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
renderedkey 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.ymlplaybook to use theparsedplaybook:
{% 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
configwe are usingrunning-configand pointing to the backup file. - We are registering the output from the module to
parsed_configvaraible - We are using the debug module to print the
parsed_configvariable
- 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