Simplify tasks by using vendor-independent network resource modules and the ansible.netcommon Ansible Content Collection.
Outcomes
Use the platform-independent ansible.netcommon.cli_command module to run a command on multiple network platforms and display the results.
Use the ansible.utils.cli_parse module to parse command output and display the results.
Create and run playbooks with plays that demonstrate various resource module states.
As the student user on the workstation machine, use the lab command to prepare your system for this exercise.
This command also creates a project directory with the files needed for the exercise.
[student@workstation ~]$ lab start network-independent
Instructions
Open the /home/student/network-independent directory in VS Code and create the send_command.yml playbook to run a command on multiple network platforms and display the results.
Open VS Code and then click → .
Navigate to → and click .
If prompted, select , and then click .
In VS Code, create the send_command.yml playbook file with a play that uses the ansible.netcommon.cli_command module to run a command specified by the show_interfaces variable.
The play must target the managed nodes in the ios, junos, and eos inventory groups.
Add the following lines to the playbook:
---
- name: Run a command across multiple network platforms
hosts: ios,junos,eos
gather_facts: false
tasks:
- name: Run a command
vars:
ansible_connection: ansible.netcommon.network_cli
ansible.netcommon.cli_command:
command: "{{ show_interfaces }}"
register: result
- name: Display the results
ansible.builtin.debug:
var: result['stdout_lines']Create variable files named commands.yml for each of the different network platforms.
The variable files must hold the show_interfaces variable, with the value of that variable set to the command to show a summary of interface statuses for the specific network platform.
In VS Code, create a variable file named group_vars/ios/commands.yml that holds the command to send to the IOS network platform.
The completed file must consist of the following content:
--- show_interfaces: "show ip interface brief"
In VS Code, create a variable file named group_vars/eos/commands.yml that holds the command to send to the EOS network platform.
The completed file must consist of the following content:
--- show_interfaces: "show ip interface brief"
In VS Code, create a variable file named group_vars/junos/commands.yml that holds the command to send to the Junos network platform.
The completed file must consist of the following content:
--- show_interfaces: "show interfaces terse"
The ansible.netcommon.cli_command module also supports sending multiple commands.
You could use a loop and add multiple commands to the variable files to send multiple commands to your managed nodes.
Run the send_command.yml playbook and inspect the playbook output.
Switch to the tab in VS Code, or change to the /home/student/network-independent directory in a GNOME terminal:
[student@workstation ~]$ cd network-independentUse the ansible-navigator run command to run the send_command.yml playbook.
Inspect the playbook output to ensure that the correct command was run on each network platform, and it produced a summary of interface statuses:
[student@workstation network-independent]$ansible-navigator run \send_command.ymlPLAY [Run a command across multiple network platforms] ********************* TASK [Run a command] ******************************************************* ok: [iosxe1.lab.example.com] ok: [iosxe2.lab.example.com] ok: [junos2.lab.example.com] ok: [junos1.lab.example.com] ok: [arista1.lab.example.com] ok: [arista2.lab.example.com] TASK [Display the results] ************************************************* ok: [iosxe1.lab.example.com] => { "result['stdout_lines']": [ "Interface IP-Address OK? Method Status Protocol", "GigabitEthernet1 172.25.250.20 YES NVRAM up up ", "GigabitEthernet2 unassigned YES NVRAM administratively down down" ] } ok: [junos1.lab.example.com] => { "result['stdout_lines']": [ "Interface Admin Link Proto Local Remote", "cbp0 up up", "demux0 up up", "dsc up up", "em1 up up", "em1.0 up up inet 10.0.0.4/8 ", " 128.0.0.1/2 ", " 128.0.0.4/2 ", " inet6 fe80::5254:ff:fe12:bdfe/64", " fec0::a:0:0:4/64", ...output omitted... } ok: [arista1.lab.example.com] => { "result['stdout_lines']": [ "Address", "Interface IP Address Status Protocol MTU Owner ", "----------------- ---------------------- ------------ -------------- ---------- -------", "Management1 172.25.250.24/24 up up 1500" ] } ...output omitted...
Create a playbook named parse_command.yml with a play to run the show ip interface command on IOS managed nodes and then parse and display the output.
Use the ansible.utils.cli_parse module with the ansible.netcommon.native filter to parse the command output.
The YAML template file /templates/interfaces.yml has been provided for you for use with the ansible.netcommon.native plug-in.
The YAML template file uses regular expressions to parse the command output into structured data.
In VS Code, create the parse_command.yml playbook file.
The completed file must consist of the following content:
---
- name: Run a command and parse the output
hosts: ios
gather_facts: false
tasks:
- name: Parse interface data
ansible.utils.cli_parse:
command: "show ip interface"
parser:
name: ansible.netcommon.native
template_path: "./templates/interfaces.yml"
set_fact: ios_interfaces
- name: Display structured data
ansible.builtin.debug:
var: ansible_facts['ios_interfaces']Inspect the contents of the templates/interfaces.yml file:
---
- example: "GigabitEthernet1 is up, line protocol is up"
getval: '(?P<name>\S+)\sis\s(?P<admin_state>\S+)\,\sline\sprotocol\sis\s(?P<oper_state>\S+)'
result:
"{{ name }}":
name: "{{ name }}"
state:
admin: "{{ admin_state }}"
operating: "{{ oper_state }}"Return to the terminal and use the ansible-navigator run command to run the parse_command.yml playbook.
Inspect the playbook output to verify that the values for the name, admin_state, and oper_state variables are present for each interface.
[student@workstation network-independent]$ansible-navigator run \parse_command.ymlPLAY [Run a command and parse the output] ************************************* TASK [Parse interface data] *************************************************** ok: [iosxe1.lab.example.com] ok: [iosxe2.lab.example.com] TASK [Display structured data] ************************************************ ok: [iosxe2.lab.example.com] => { "ansible_facts['ios_interfaces']": { "GigabitEthernet1": {"name": "GigabitEthernet1","state": {"admin": "up","operating": "up"} } } } ok: [iosxe1.lab.example.com] => { "ansible_facts['ios_interfaces']": { "GigabitEthernet1": {"name": "GigabitEthernet1","state": {"admin": "up","operating": "up"} } } } ...output omitted...
Create a playbook named config_states.yml that uses the arista.eos.eos_vlans resource module with the merged state to update the virtual LAN (VLAN) configuration by creating VLANs 100, 200, 300, and 400, and then run the playbook.
In VS Code, create a playbook named config_states.yml with a play that targets the EOS managed nodes and uses the arista.eos.eos_vlans resource module with the state parameter set to merged.
The completed file must consist of the following content:
---
- name: Change configuration and demonstrate a resource module state
hosts: eos
gather_facts: false
tasks:
- name: Change configuration using the merged state
arista.eos.eos_vlans:
state: merged
config:
- name: vlan100
vlan_id: 100
- name: vlan200
vlan_id: 200
- name: vlan300
vlan_id: 300
- name: vlan400
vlan_id: 400
- name: Show configuration after configuration change
arista.eos.eos_command:
commands:
- show run | s vlanReturn to the terminal and use the ansible-navigator run command to run the config_states.yml playbook.
Use the -vvv option to increase the output verbosity, so that the resource module state and the return values of before, after, and commands are displayed in the output.
Inspect the output to see that VLANs 100, 200, 300, and 400 are present in the after key, which means that they have been added to the configuration:
[student@workstation network-independent]$ansible-navigator run \config_states.yml -vvv...output omitted... TASK [Change configuration using the merged state] **************************** ...output omitted... changed: [arista1.lab.example.com] => { "after": [ { "name": "vlan100", "state": "active", "vlan_id": 100 }, { "name": "vlan200", "state": "active", "vlan_id": 200 }, { "name": "vlan300", "state": "active", "vlan_id": 300 }, { "name": "vlan400", "state": "active", "vlan_id": 400 } ], "before": [], "changed": true, "commands": [ "vlan 100", "name vlan100", "vlan 200", "name vlan200", "vlan 300", "name vlan300", "vlan 400", "name vlan400" ], ...output omitted... "state": "merged" } } } ...output omitted... TASK [Show configuration after configuration change] ************************** ok: [arista1.lab.example.com] => { "changed": false, "invocation": { "module_args": { "commands": [ "show run | s vlan" ], "interval": 1, "match": "all", "retries": 10, "wait_for": null } }, "stdout": [ "vlan 100\n name vlan100\nvlan 200\n name vlan200\nvlan 300\n name vlan300\nvlan 400\n name vlan400" ], "stdout_lines": [ [ "vlan 100", " name vlan100", "vlan 200", " name vlan200", "vlan 300", " name vlan300", "vlan 400", " name vlan400" ] ] } ...output omitted...
Run the add_vlan_500.yml playbook to add VLAN 500 to the EOS managed nodes, and then run the config_states.yml playbook again.
Inspect the playbook output to see how the configuration changes when using the merged state.
Inspect the contents of the add_vlan_500.yml file:
---
- name: Add a VLAN
hosts: eos
gather_facts: false
tasks:
- name: Add a VLAN
arista.eos.eos_vlans:
state: merged
config:
- name: vlan500
vlan_id: 500Use the ansible-navigator run command to run the add_vlan_500.yml playbook to add VLAN 500 to the EOS managed nodes:
[student@workstation network-independent]$ ansible-navigator run add_vlan_500.yml
...output omitted...Use the ansible-navigator run command to run the config_states.yml playbook.
Use the -vvv option to increase the verbosity of the resource module output.
Inspect the playbook output to see how the configuration changes when using the merged state:
[student@workstation network-independent]$ansible-navigator run \config_states.yml -vvv...output omitted... ok: [arista1.lab.example.com] => { "changed": false, "invocation": { "module_args": { "commands": [ "show run | s vlan" ], "interval": 1, "match": "all", "retries": 10, "wait_for": null } }, "stdout": [ "vlan 100\n name vlan100\nvlan 200\n name vlan200\nvlan 300\n name vlan300\nvlan 400\n name vlan400\nvlan 500\n name vlan500" ], "stdout_lines": [ [ "vlan 100", " name vlan100", "vlan 200", " name vlan200", "vlan 300", " name vlan300", "vlan 400", " name vlan400","vlan 500"," name vlan500"] ] } ...output omitted...
Notice that the configuration on the EOS managed nodes includes the VLAN you just added; 500.
This is because the merged state does not remove any existing configuration.
Edit the config_states.yml playbook and change the value of the state parameter to overridden.
Inspect the playbook output to see how the configuration changes when using the overridden state.
In VS Code, edit the config_states.yml playbook and change the value of the state parameter to overridden.
The completed file must consist of the following content:
---
- name: Change configuration and demonstrate a resource module state
hosts: eos
gather_facts: false
tasks:
- name: Change configuration using the overridden state
arista.eos.eos_vlans:
state: overridden
config:
- name: vlan100
vlan_id: 100
- name: vlan200
vlan_id: 200
- name: vlan300
vlan_id: 300
- name: vlan400
vlan_id: 400
- name: Show configuration after configuration change
arista.eos.eos_command:
commands:
- show run | s vlanReturn to the terminal and use the ansible-navigator run command to run the config_states.yml playbook.
Use the -vvv option to increase the verbosity of the resource module output:
[student@workstation network-independent]$ansible-navigator run \config_states.yml -vvv...output omitted... ok: [arista1.lab.example.com] => { "changed": false, "invocation": { "module_args": { "commands": [ "show run | s vlan" ], "interval": 1, "match": "all", "retries": 10, "wait_for": null } }, "stdout": [ "vlan 100\n name vlan100\nvlan 200\n name vlan200\nvlan 300\n name vlan300\nvlan 400\n name vlan400" ], "stdout_lines": [ [ "vlan 100", " name vlan100", "vlan 200", " name vlan200", "vlan 300", " name vlan300", "vlan 400", " name vlan400" ] ] } ...output omitted...
Notice that the configuration on the EOS managed nodes no longer includes VLAN 500.
This is because the overridden state enforces all VLAN resources to the data model.
This means that it removes any VLANs that are not defined in the data model being sent.
Edit the config_states.yml playbook and change the value of the state parameter to rendered.
Inspect the playbook output to see the configuration commands generated by the module.
In VS Code, edit the config_states.yml playbook.
Change the value of the state parameter to rendered, and add VLAN 500 to the file.
The completed file must consist of the following content:
---
- name: Render a configuration
hosts: eos
gather_facts: false
tasks:
- name: Render VLAN configuration
arista.eos.eos_vlans:
state: rendered
config:
- name: vlan100
vlan_id: 100
- name: vlan200
vlan_id: 200
- name: vlan300
vlan_id: 300
- name: vlan400
vlan_id: 400
- name: vlan500
vlan_id: 500
- name: Show configuration after configuration change
arista.eos.eos_command:
commands:
- show run | s vlanReturn to the terminal and use the ansible-navigator run command to run the config_states.yml playbook.
Use the -vvv option to increase the verbosity of the resource module output.
Inspect the output to see the rendered configuration commands that would be sent to the device:
[student@workstation network-independent]$ansible-navigator run \config_states.yml -vvv...output omitted... "rendered": [ "vlan 100", "name vlan100", "vlan 200", "name vlan200", "vlan 300", "name vlan300", "vlan 400", "name vlan400", "vlan 500", "name vlan500" ...output omitted...
The rendered state does not communicate with or change managed nodes.
Use the rendered state to get the list of commands that would be sent to managed nodes when using the merged, replaced, or overridden state.
Close the /home/student/network-independent directory in VS Code, and run the cd command in a GNOME terminal to return to the student home directory:
[student@workstation network-independent]$ cd