You manage a lot of network devices, but you are alone or you don’t have time. Ansible can help you to manage your change on your whole network very quickly based on your own template. In this article we will use Cisco Nexus 9K.
You have a new DNS server, syslog server etc and you need to modify hundred switches. No worries, with ansible it can be very simple.
First you should create at least two files. The first one will be your inventory and contains your switches. The second will be your playbook.
The first thing is to create a service account for ansible in your switches. This account could be centralize or local. In the following I’ll provide my password in cleartext. Of course, it’s not recommended and you should prefer ssh-key.
On my virtual nexus 9k, I only configured my account and my management IP address.
My topology contains :
- Nexus-1 : IP 10.0.100.99, name: AGG1
- Nexus-2 : IP 10.0.100.100, name: ACC1
- Nexus-3 : IP 10.0.100.101, name: ACC2
switch(config-if)# sh run !Command: show running-config !Running configuration last done at: Sat Mar 21 18:28:03 2020 !Time: Sat Mar 21 18:29:45 2020 version 9.3(2) Bios:version [..] username ansible password 5 $5$.FhD0kmO$4PJV/HKJN5ul9aK7160ii.1WQ3s9pjh2QCRL7x7l EU/ role network-admin username ansible passphrase lifetime 99999 warntime 14 gracetime 3 ip domain-lookup [..] interface mgmt0 vrf member management ip address 10.0.100.100/24 line console line vty
The inventory file will be the following. We can use two formats: YAML or INI. This one will use the INI format. This file contains a group named N9K with three switches.
[N9K] AGR1 ansible_host=10.0.100.99 ansible_port=22 ACC1 ansible_host=10.0.100.100 ansible_port=22 ACC2 ansible_host=10.0.100.101 ansible_port=22 [N9K:vars] ansible_user=ansible ansible_password=@ns1b!E. ansible_connection=network_cli ansible_network_os=nxos ansible_python_interpreter="/usr/bin/env python"
The following file uses the YAML format. This first playbook is very simple and contains one task to configure the switch hostname.
--- - name: Setup Nexus Devices hosts: all connection: local gather_facts: False tasks: - name: configure hostname nxos_config: lines: hostname {{ inventory_hostname }} save_when: modified
Now I’ll verify my playbook, before apply the changes. This command uses the option -i to specify which file should be use as inventory and –check to simulate the changes.
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml --check PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ [WARNING]: Skipping command `copy running-config startup-config` due to check_mode. Configuration not copied to non-volatile storage terpreter_discovery.html for more information. changed: [ACC1] changed: [AGR1] changed: [ACC2] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Now I’ll do the same without the option –check and my Nexus device should be configured. You can see the message copy running is not there.
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ changed: [ACC1] changed: [AGR1] changed: [ACC2] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Fantastic, my nexus have been configured !! With the command show accounting log, you can verify the command injected by ansible. In my playbook, I added the line save_when: modified to save the configuration after the changes.
AGR1# show accounting log | last 10 Sat Mar 21 18:45:42 2020:type=stop:id=10.0.100.150@pts/2:user=ansible:cmd=shell terminated because the ssh session closed Sat Mar 21 18:49:11 2020:type=start:id=10.0.100.150@pts/2:user=ansible:cmd= Sat Mar 21 18:49:12 2020:type=update:id=10.0.100.150@pts/2:user=ansible:cmd=terminal length 0 (SUCCESS) Sat Mar 21 18:49:12 2020:type=update:id=10.0.100.150@pts/2:user=ansible:cmd=terminal width 511 (SUCCESS) Sat Mar 21 18:49:20 2020:type=update:id=10.0.100.150@pts/2:user=ansible:cmd=configure terminal ; hostname AGR1 (SUCCESS) Sat Mar 21 18:49:26 2020:type=update:id=10.0.100.150@pts/2:user=ansible:cmd=Performing configuration copy. Sat Mar 21 18:49:36 2020:type=start:id=vsh.bin.13650:user=admin:cmd= Sat Mar 21 18:49:52 2020:type=update:id=10.0.100.150@pts/2:user=ansible:cmd=copy running-config startup-config (SUCCESS) Sat Mar 21 18:49:53 2020:type=stop:id=10.0.100.150@pts/2:user=ansible:cmd=shell terminated because the ssh session closed Sat Mar 21 18:52:35 2020:type=update:id=console0:user=admin:cmd=terminal width 511 (SUCCESS)
Now you can imagine the next step. You can add your syslog server for example.
- name: configure syslog server nxos_config: lines: - logging server 10.0.100.42 4 use-vrf management facility local7 - logging timestamp milliseconds save_when: modified
Before the change:
AGR1(config)# logging timestamp milliseconds ^C AGR1(config)# sh logging Logging console: enabled (Severity: critical) Logging monitor: enabled (Severity: notifications) Logging linecard: enabled (Severity: notifications) Logging timestamp: Seconds Logging source-interface : disabled Logging rate-limit: enabled Logging server: disabled Logging origin_id : disabled Logging RFC : disabled Logging logflash: enabled (Severity: notifications) Logging logfile: enabled Name - messages: Severity - notifications Size - 4194304 [..]
After the change:
AGR1(config)# 2020 Mar 21 18:58:48 AGR1 %$ VDC-1 %$ %SYSLOG-2-SYSTEM_MSG: Attempt to configure logging server with: hostname/IP 10.0.100.42,severity 4,port 514,facility local7 - syslogd AGR1(config)# sh logging Logging console: enabled (Severity: critical) Logging monitor: enabled (Severity: notifications) Logging linecard: enabled (Severity: notifications) Logging timestamp: Milliseconds Logging source-interface : disabled Logging rate-limit: enabled Logging server: enabled {10.0.100.42} This server is temporarily unreachable server severity: warnings server facility: local7 server VRF: management server port: 514 Logging origin_id : disabled Logging RFC : disabled Logging logflash: enabled (Severity: notifications) Logging logfile: enabled Name - messages: Severity - notifications Size - 4194304 [..]
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ ok: [ACC1] ok: [AGR1] ok: [ACC2] TASK [configure syslog server] ******************************************************************************************************************* changed: [ACC1] changed: [ACC2] changed: [AGR1] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I can be useful to manage your access-list. Imagine you install a new server for the monitoring and you need to update one entry. This time we will use another module named nxos_acl.
- name: configure SNMP-ACCESS-LIST nxos_acl: name: ACL_SNMP-ReadOnly seq: "10" action: permit proto: udp src: 10.0.100.42/32 dest: any state: present
Now we have the ACL configured on all switches. When the module exists, prefer to use the specific module.
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ ok: [ACC1] ok: [AGR1] ok: [ACC2] TASK [configure syslog server] ******************************************************************************************************************* changed: [ACC1] changed: [ACC2] changed: [AGR1] TASK [configure SNMP-ACCESS-LIST] **************************************************************************************************************** changed: [ACC1] changed: [ACC2] changed: [AGR1] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
AGR1(config)# sh ip access-lists ACL_SNMP-ReadOnly IP access list ACL_SNMP-ReadOnly 10 permit udp 10.0.100.42/32 any -- ACC1(config)# sh ip access-lists ACL_SNMP-ReadOnly IP access list ACL_SNMP-ReadOnly 10 permit udp 10.0.100.42/32 any -- ACC2# sh ip access-lists ACL_SNMP-ReadOnly IP access list ACL_SNMP-ReadOnly 10 permit udp 10.0.100.42/32 any
This module is idempotent. Now we will update the ACL with a second entry. The documentation is here.
- name: configure SNMP-ACCESS-LIST nxos_acl: name: ACL_SNMP-ReadOnly seq: "10" action: permit proto: udp src: 10.0.100.42/32 dest: any state: present - name: configure SNMP-ACCESS-LIST nxos_acl: name: ACL_SNMP-ReadOnly seq: "20" action: permit proto: udp src: 10.0.100.43/32 dest: any state: present
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ changed: [ACC1] changed: [AGR1] changed: [ACC2] TASK [configure syslog server] ******************************************************************************************************************* changed: [ACC1] changed: [ACC2] changed: [AGR1] TASK [configure SNMP-ACCESS-LIST] **************************************************************************************************************** ok: [ACC1] ok: [AGR1] ok: [ACC2] TASK [configure SNMP-ACCESS-LIST] **************************************************************************************************************** changed: [ACC1] changed: [AGR1] changed: [ACC2] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
AGR1(config)# sh ip access-lists ACL_SNMP-ReadOnly IP access list ACL_SNMP-ReadOnly 10 permit udp 10.0.100.42/32 any 20 permit udp 10.0.100.43/32 any
and they update the last entry with a new IP address.
- name: configure SNMP-ACCESS-LIST nxos_acl: name: ACL_SNMP-ReadOnly seq: "10" action: permit proto: udp src: 10.0.100.42/32 dest: any state: present - name: configure SNMP-ACCESS-LIST nxos_acl: name: ACL_SNMP-ReadOnly seq: "20" action: permit proto: udp src: 10.0.100.44/32 dest: any state: present
root@09cf326cc275:/ansible/NXOS# ansible-playbook -i inventory-home playbook-home.yaml PLAY [Setup Nexus Devices] *********************************************************************************************************************** TASK [configure hostname] ************************************************************************************************************************ changed: [ACC1] changed: [ACC2] changed: [AGR1] TASK [configure syslog server] ******************************************************************************************************************* changed: [ACC1] changed: [AGR1] changed: [ACC2] TASK [configure SNMP-ACCESS-LIST] **************************************************************************************************************** ok: [ACC1] ok: [AGR1] ok: [ACC2] TASK [configure SNMP-ACCESS-LIST] **************************************************************************************************************** changed: [ACC1] changed: [AGR1] changed: [ACC2] PLAY RECAP *************************************************************************************************************************************** ACC1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ACC2 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 AGR1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
AGR1(config)# sh ip access-lists ACL_SNMP-ReadOnly IP access list ACL_SNMP-ReadOnly 10 permit udp 10.0.100.42/32 any 20 permit udp 10.0.100.44/32 any
You can image a lot of scenario now, and apply your change very quickly.