UPDATE: The content of the post is now obsolete for more current up to date please refer to Ansible: Automate Cisco LAN Deployment.
Hi everyone, today we’re going to look into Ansible to deploy networks running Cisco IOS. It is one of the configuration management tools like Puppet and Chef. I’ve used Ansible before to update, upgrade, and install packages and application in Linux Desktop environment. I began learning it again with its introduction ios_config network module used to configure Cisco devices running IOS. It supports not just Cisco IOS but also NXOS, manyXR and ASA and other network vendors such as Juniper and Arista.
Note: In this post, it uses the old playbook and variables, and I updated it using roles which are more simple and scalable in creating tasks and variables.
Disclaimer: Beginner here, but crazy about network automation using Ansible. I’m just glad I found out about Ansible, making an automation tool that easy to understand for some general user like me.
The lab performed in GNS3, using Cisco IOU and Ubuntu Server 14.04 running Ansible 2.1.2
Network Design
In the topology above each of the devices has a management port (the blue dotted line) that connects to the management switch where the Ansible host also connect.
Initial configuration
Before we can automate the configuration, we first need to configure the devices for initial connectivity for the Ansible host able to ssh and push the configuration. Below are the basic configs needed.
! Replace the value in italic format. ! enable secret cisco ! ! This is required in order to generate the key and ! this is the domain where the device belongs to. ip domain-name enableconfig.wordpress.com ! crypto key generate rsa modulus 1024 ! ! This username and password will be use to ssh to this device. username rey privilege 15 secret cisco ! ! This enable the device for remote management. The device will use local ! database for authentication by issuing "login local" and it will accept only ! ssh for remote connection by issuing "transport input ssh" line vty 0 4 login local transport input ssh ! ! Configure the mgmt interface. This must be the same ! network with the ansible host. int e1/3 ip address 10.0.0.51 255.255.255.0
Next, refer to the official documentation to install Ansible, (this will be a host controller) on any Linux distribution you prefer. After that, create a directory that includes the ansible.cfg, hostfile, variables, and playbook, rather than modifying the default Ansible configuration which is in etc/ansible/. Below is sample directory for this lab.
First, we need to change the three default configuration of ansible.cfg for this lab.
[defaults] transport=paramiko # < paramiko will be use for ssh connection instead of # the default which is OpenSSH host_key_checking=false #< this will not use ssh key in connecting to the # devices, instead will username and password, set this true for production # environment hostfile=devices #< defined which file ansible look for hosts.
Next, we will specify our host. This is the file that defined in hostfile under ansible.cfg.
[core] core_sw_01 ansible_host=10.0.0.51 ansible_hostname=core_sw_01 core_sw_02 ansible_host=10.0.0.52 ansible_hostname=core_sw_02 [access] acc_sw_01 ansible_host=10.0.0.53 ansible_hostname=acc_sw_01 acc_sw_02 ansible_host=10.0.0.54 ansible_hostname=acc_sw_02 acc_sw_03 ansible_host=10.0.0.55 ansible_hostname=acc_sw_03 acc_sw_04 ansible_host=10.0.0.56 ansible_hostname=acc_sw_04 [switches:children] core access [routers] rtr_01 ansible_host=10.0.0.101 ansible_hostname=rtr_01 rtr_02 ansible_host=10.0.0.102 ansible_hostname=rtr_02
Notice above, the IP address of ansible_host, that’s the IP address of the management interface of each of the device.
Next, we will define our credentials to be used to connect to the devices. This variable is under group_vars/all, meaning that all host were able to use the variable. The username and password were the ones we set during the initial configuration. The host is the IP address or hostname that is configured in the hostfile. The transport is one of the required argument for configuring a network device. Another option is nxapi for Nexus devices.
provider: host: "{{ ansible_host }}" username: rey password: cisco transport: cli
Next, we will create our host and group variables that will be used by the playbook. Below are sample variables, for complete list of variable and playbook, you can download and refer to it at GitHub repository
# this group variables under group_vars/switches.yml to be use by all switches, # that includes core and access switch. --- vlans: - { vlan_id: 15, name: voice15} - { vlan_id: 55, name: data55} # this group variables under group_vars/core.yml will be use by # core_sw_01 and core_sw_02. --- svi_int: - name: vlan15 ip: "{{ vlan15.ip }}" mask: 255.255.255.0 vip: 10.0.15.252 pri: "{{ vlan15.pri }}" # this host variable under host_vars/core_sw_01.yml to be use by core_sw_01. --- vlan15: ip: 10.0.15.252 pri: 110 # this host variable under host_vars/core_sw_02.yml to be use by core_sw_02. --- vlan15: ip: 10.0.15.253 pri: 90
Next, we can now create a playbook and use the variables stated above.
The configuration below is the sample task in the playbook that will create a VLANs in the device and its corresponding VLAN name.
--- - name: core switch configurations hosts: core gather_facts: no connection: local tasks: - name: create vlans ios_config: provider: "{{ provider }}" lines: name {{ item.name }} parents: vlan {{ item.vlan_id }} with_items: "{{ vlans }}"
For better visual representation refer to the figure below.
In the above playbook, the ios_config is the name of Ansible module for configuring Cisco device that is running IOS. Please see the official documentation for the Ansible Cisco module.
Notice the with_items above that is one of the Loops in Ansible called standard loop. It will iterate the content of the variable, in this case, the vlans variable which is in group variable named switches, ( refer to the hostfile) meaning that all the devices under the group switches can use it, that includes the device under core and access group.
Next playbook will configure the device Switch Virtual Interface (SVI) and its IP address and subnet mask.
- name: switch virtual interface ios_config: provider: "{{ provider }}" lines: - ip add {{ item.ip }} {{ item.mask }} - delay 200 parents: interface {{ item.name }} with_items: "{{ svi_int }}"
For better visual representation refer to the figure below.
This time, the task used a group variable and it calls two host variable under core_sw_01 and core_sw_02. It used the same type of loop with_items. I know that there is a lot of ways to construct the variables, and I may be wrong with this one. But in this lab, what I’ve done was, I defined the unique variables on each of the devices, like IP addresses, HSRP priority, STP priority, etc., after that, create group variables then reference those unique variables. An example in the task below, it is an HSRP configuration on core_sw_01 and core_sw_02, it set a virtual IP (common value to two core switch) and priority ( unique value ) that determine which device will be the active or standby router. So the unique value here is the pri under host_vars, then reference it to the group variable named core.yml (includes core_sw_01 and core_sw_02) under group_vars. Notice that also, it used same variable ( svi_int ) and just call whatever attribute is needed in the task.
Right now, I’m reading some of the techniques or best practices, on how to build variables that can scale, optimized and simple to manage.
Below is a video that runs the full playbook ( which is also available on my GitHub ) to configure the devices that are in the topology. It involves a little bit of troubleshooting using the Ansible ios_command module ( basically a show command in Cisco IOS) and a simple, convenient playbook to configure additional configuration without writing a full blown playbook. The video was longer that I expected, but you can skip through just to get the idea, and sorry I don’t have a microphone.
Conclusion
Ansible is a very powerful tool to automate networks and there is a lot of advantages in using it like, increase efficiency and effectiveness and reduce human errors in deploying and maintaining large networks. That is because before you push a configuration to the device, you have a good overview what would be the outcome of the command. Very useful when you have to maintain hundreds of switches, and you have a lot of network projects. Let’s say you are an IT service provider that provide network deployments, what you can do is build the playbook during the planning and designing phase, and on the actual deployment, just need to configure basic connectivity, and automate the rest of the deployment.
Thanks for stopping by.
If you need help regarding the topic, please don’t hesitate to leave a comment or email me.
Reference: https://pynet.twb-tech.com/blog/, http://networkop.github.io/blog/2015/06/24/ansible-intro/, https://github.com/jedelman8/nxos-ansible
Hello,
Thanks for the greate info I only have one question when I execute the playbook show.yml I get the error
The offending line appears to be:\n\n\n – name: show commands\n ^ here\n”}
Where can the issue be?
thanks.
LikeLike
Hi
Sorry for late response, I tested the show.yml playbook in this github repo https://github.com/rynldtbuen/ansible_cisco_ios_01.git and it’s working on me. Could you able to post the whole playbook? Thanks
LikeLike
Hello Reynold,
THanks for you time here is my playbook
—
– hosts: core
gather_facts: true
connection: local
tasks:
– name: show run
ios_command:
commands:
– show run
host: “{{ ansible_host }}”
username: cisco
password: cisco
register: config
– name: save output to /home/juraj/
copy:
content: “{{ config.stdout[0] }}”
dest: “/etc/ansible/backups/show_run_{{ inventory_hostname }}.txt”
LikeLike
Hi Juraj
Sorry for the reply again, I believe it’s was a syntax error, please double check the indentation and spacing of you hosts, tasks, and module. It must be in the same indentation or spacing. I suggest visiting this link https://docs.ansible.com/ansible/playbooks_intro.html and notice the format of the playbook especially the indentation and spacing of the task and module.
LikeLike
hello dear, i am facing issue.
i created host file where I mention the IP address when I am trying to check the reachability between my ansible machine and cisco ios switch its return the below error.
192.168.200.2 | UNREACHABLE! => {
“changed”: false,
“msg”: “Failed to open session”,
“unreachable”: true
}
below is my hosts file:
[ios:vars]
ansible_ssh_user=saad
ansible_ssh_pass=cisco
[ios]
192.168.200.2
Ansible_config:
hosts: /etc/ansible/ansible_projects/hosts
transport= paramiko
host_key_checking=false
I would really appreciate if you help me to figure out this problem.
LikeLike
Hi Saad
Would you able to provide more details of the error by enabling the networking logging, please refer to https://docs.ansible.com/ansible/latest/network_debug_troubleshooting.html on how to enable it. Just for basic troubleshooting, have you tried a normal ping and ssh from ansible host to the cisco switch?
LikeLike