Gone are the days where Network Engineers manually deploy the same bits of config to the network, day after day, week after week. The role of a Network Engineer has evolved and the scope of the job is becoming move involved. Network Engineers need to work faster and be more consistent than ever before. This is where Automation comes in and can make all the difference. I've only just started my journey and it hasn't been easy. This is because most of the Automation tools are written by Software Engineers. People that understand code! To them, the interdependencies of software library versions and the indenting of code are all second nature. As a Network Engineer, it takes some time to get your head around, or at least it did for me.

So I'm going to explain how to set up an environment so that you can play with Ansible with the focus on Network Automation and I will show you what can go wrong (well, what went wrong for me in the beginning). Hopefully by helping you get over the initial hurdle of becoming familiar with Ansible, the actual network stuff will be easy.

 

Step 1 - Using Vagrant

"What the heck is Vagrant and why do I need it?" I hear you ask. Well, I don't like installing and experimenting with software on my laptop. I don't like having to worry about if this version of Python is going to break some application I'm using. I don't like wasting time, trawling through forums trying to figure out what's broken since I installed some update. I like to use virtual machines to separate my environments and if something goes wrong, I roll it back to a snapshot, or just destroy the VM and start again with no impact to my work applications.

If you do not already have VirtualBox installed, go ahead and install that first at VirtualBox.org

Next, install Vargant. Vagrant is a quick way to get a virtual machine setup without having to create the VM and install an Operating System on it.

Create a directory that you want to store your Vagrant VM configuration in and then "cd" into that directory. Then type the following:

vagrant init ubuntu/xenial64

This will install a basic Ubuntu 16.04 VM onto your machine. To start your VM type:

vagrant up

To login to the VM, type:

vagrant ssh

 

Wow, so easy! You now have a Linux box to install Ansible on. Lets get started.

 

Step 2a - How NOT to install Ansible

You should install Ansible as a particular user on the VM but I'm here to learn Network Automation, not System Administration, so I do things the lazy way and "sudo su" and become the root of the VM and install Ansible via "apt":

apt install ansible

Wow, so easy. Ansible is now installed and all the config files are in the right locations. It should now be a case of configuring the Ansible hosts file in "etc/ansible/hosts", write a simple playbook and off we go, Automation here we come.

WRONG!!

After MANY hours for troubleshooting, running wiresharks and not seeing any SSH traffic leave my machine destined for the host I was trying to connect to, it looks like by installing Ansible via APT, Ansible does not know how to use the Python Paramiko SSH library to make an SSH connection to the host you're trying to connect to.

I'm here for Network Automation, not system debugging! So, lets try this again. Thank goodness we can just destroy the VM and in a few seconds build a fresh VM and start again.

vagrant destroy

vagrant up

 

Step 2b - How to install Ansible

 Another way to install Ansible is via the Python package manger called pip. Again, I just "sudo su" into root so that I don't have to worry about user permissions on files and folders. First install PIP and then we can install Ansible.

apt install python-pip

Now install Ansible. I've had a lot of success with 2.8.0 so I'm going to stick with that. 

pip install ansible==2.8.0

After a few seconds, Ansible will be installed and you're almost good to go. The next bit of software you'll need to install is the Python SSH connection library called Paramiko:

pip install paramiko

 

Step 3 - Setting up Ansible

In your "root" users home directory (the directory you're automatically in when you log into the VM) create a file called ".ansible.cfg" and copy and paste the configuration below which stops Ansible from checking SSH keys. This is important especially in a lab environment were you're going to possibly be connecting to different devices with the same IP address at some point in time.

I use the VIM editor, but you can use whichever text editor you're comfortable with:

vim .ansible.cfg

[defaults]
host_key_checking = False

Next, you need to create an Ansible Hosts file which is located in /etc/ansible/hosts. If the file is not there, create it yourself. This file tells Ansible all about the hosts you'll be automating. What kind of hosts they are, what their ip addresses are, credentials etc... it all goes in here.

There is some very good documentation at docs.ansible.com to follow on how to set up your inventory file. Check it out.

For now, I'm just going to configure two Nokia hosts, SR1 and SR2:

[nokia]
SR1 ansible_host=192.168.1.201
SR2 ansible_host=192.168.1.202

That's that. Let's configure a playbook to do something with these hosts!

 

Step 4 - Playbook Basics

Ansible uses the YAML format to write playbooks. Playbooks are a set of instructions to tell Ansible what to do, to which hosts, when, and what to do if something goes wrong. YAML can be a pig to get used to, but once you get the hang of it, writing playbooks becomes easy.

The beauty of playbooks, and with any automation, is that the more you do, the more code you can re-use and the quicker it becomes to automate tasks. It might take you a week to write you first playbook consisting of many tasks. But the next playbook you need to write, you can re-use a vast amount of the first playbook and only adapt the bits you need.

And once you learn how to make use of variables, you playbooks become infinitely more useable and automating tasks becomes lightning fast.

Let's take a look at a sample Playbook. Create a directory and "cd" into it and then create a file with a .yml extension. This will be the file you call when you run the "ansible-playbook" command. 

---
################################################
# Section to define which hosts the playbook   #
# will run on                                  #
################################################
- hosts: SR1
  gather_facts: no
  connection: local

################################################
# The section below defines variables to use   #
# within the playbook                          #
################################################
  vars:
    cli:
      username: admin
      password: admin
    a_side_port1: 1/1/1
    a_side_port2: 1/1/2
    b_side_port1: 1/1/1
    b_side_port2: 1/1/2

################################################
# The section below defines the tasks to run   #
# against the hosts defined in the first       #
# section                                      #
################################################

  tasks:
  - name: configure description on SR1 port {{a_side_port1}}
    sros_config:
      lines:
        - description "SR1:{{a_side_port1}}-to-SR2:{{b_side_port1}}"
      parents:
        - configure
        - port "{{a_side_port1}}"
      provider: "{{ cli }}"

  - name: configure description on SR1 port {{a_side_port2}}
    sros_config:
      lines:
        - description "SR1:{{a_side_port2}}-to-SR2:{{b_side_port2}}"
      parents:
        - configure
        - port "{{a_side_port2}}"
      provider: "{{ cli }}" 

Indentation is critical in YMAL because if you don't have the exact amount of spaces for a line, it moves the meaning of the line to a different level of code which Ansible won't know how to interpret and you will get an error message.

You should write your playbooks in a decent Text Editor such as Atom or Sublime Text so that you can ensure the indentation is correct. You should be able to copy the text above and put it into a text editor to verify the indentation.

 

 undefined

 

I've defined a few variables in the "vars" section and I pass them to various configuration items in the code via the {{ }}. I've highlighted the variables in the code. Using variables makes the code very flexible. Every time I want to run this playbook, all I do is update the hosts and the variables, simple as that.

What does that playbook do? 

Here is the code that I would type out on the router to configure interface descriptions on interfaces 1/1/1 and 1/1/2:

configure
port 1/1/1
description "SR2:1/1/1-to-SR1:1/1/1"
back
port 1/1/2
description "SR2:1/1/2-to-SR1:1/1/2"

 

In the playbook, I have to use the SROS_CONFIG plugin to send my commands to the router. The "parents" are the commands typed before the final level which you want to enter a command. Example, before I type out the interface description, I have to type, "configure" "port 1/1/1" and then type the command that I want to configure "description SR2:1/1/1-to-SR1:1/1/1".

 

 Step 5 - Run the playbook

Now for the fun bit. At your directory prompt type ansible-playbook and the name of the playbook file you created.

ansible-playbook a-side-interfaces.yml

If your indentation is correct, and your /etc/ansible/hosts file has been set up correctly, you should see something like this:

PLAY [SR1] *************************************************************************************************************************************************

TASK [configure description on SR1 port 1/1/1] ***************************************************************************************************************
changed: [SR1]

TASK [configure description on SR1 port 1/1/2] ***************************************************************************************************************
changed: [SR1]

 

What if it goes wrong?

It's not very often that things work right the first time. If you run a Playbook and it fails, the error message will either indicate a syntax error or some other underlying problem with its interaction with the end device.

 

If it's not a syntax problem that's causing problems, the best thing to do is run your Playbook command in Verbose mode, which will give you additional debugging information.

To run your Playbook in verbose mode use the -vvv flag as follows:

 

ansible-playbook -vvv a-side-interfaces.yml

 

 

Conclusion

Seems like a lot of work to configure two interface description. Yes it is. But when you have to update 800 interface descriptions across a network, or configure a new link in the network to have ISIS and MPLS and you do these types of configurations a few times a week, you soon reap the benefits of changing a few variables and hitting "GO".

 

What's next?

As my playbooks advance I'll be updating this blog. I'll show you how to verify the configuration you're deploying at each step of the configuration and how to stop and rollback in case something hasn't gone according to plan, because lets face it, things don't always go to plan.