Automation, Software Defined

The Answer is ANSIBLE… Sort of…


For a few months now I’ve been dabbling into automation – more specifically automation of the Infrastructure Fabric [remember I want to dissuade the usage of ‘Networking’].  I began this journey for several reasons:

  • I want to make Fabric tasks simpler
  • I want to expand my skillset
  • I want to understand the DevOps way of doing things
  • There is a paradigm shift in IT
  • To maintain a level of relevancy

So I looked at a few programming languages [Python, PowerShell, Ruby…] and tools [Puppet, Chef, Ansible, SALT…] and found a preference for [now] Ansible & Python.

I choose Ansible for a few reasons:

  1. It’s written in Python, hence preference of Python
  2. It’s agentless – No need to have an agent (daemon) running in the background on the end device to consume resources and increase overhead
  3. It’s a configuration management tool
  4. Library of modules are extensive
  5. Probably a lot easier to learn than the others
  6. Has many integrations points

As I browsed through Ansible’s website – more specifically their integration page,, I decided to draw a diagram of some of those points.

Below is a diagram I put together of the integration points Ansible has with many vendors and/or technologies.  I’ve also added interoperability across solution verticals. This diagram doesn’t represent every integration point with Ansible, just at the time of my research.

NOTE: The diagram is based on the vendors/solutions I interact with… Yes, Cisco does integrate with Ansible if you were going to ask 🙂

Nonetheless – the idea, for me, is to apply what I know from my vast years in IT – to a DevOps model.  In other words evolve into –  FabricOps?  NetOps? InfraOps? [You get the idea, I’m still working on the nomenclature.]

The point is… it’s the application that runs business outcomes and survivability – it makes sense to adapt a DevOps’ish model on how we build the Fabric and apply CI/CD principles.

For practical purposes and not diving too deep into the Ansible: Ansible run Playbooks. In the Playbooks, are plays and each play has a list of tasks assigned to be executed against a set of hosts, which is located in an inventory file. The task(s) are executed sequentially and typically calls a module.

If you want to look at it from a football analogy, this is how I interpret Ansible Playbooks, Plays, and Tasks


In this blog – I’ll build an Ansible controller [where the Playbooks & tasks are ran], build two Ansible managed nodes, show a few adhoc commands, and run some Playbooks.

DISCLAIMER: The material presented in this blog is for educational and training purposes only.  Neither the author(s) nor Ahaliblogger©   assume any liability or responsibility to any person or entity with respect to loss or damages incurred from the information contained in this blog.

The diagram below is showing simply how the Ansible controller and the managed nodes are connected.  Since Ansible is a configuration management tool – it makes sense for these devices to communicate via the MGMT/OOBM network.

Ok let’s go ahead and build out an Ansible Server for our network.  We’ll be using a CentOS VM. If you’ve read any of my blogs – you’ll see that this is my preferred Linux distribution.

Task 1: Download and install CentOS 7

You can find the CentOS image here:  Minimal version is probably recommend. There is really no need for the ‘extra’ stuff.

Add a user, if you like as per the following:

useradd ansible; passwd ansible; su - ansible

NOTE: I’ll be using user root for all configurations

Once CentOS is installed.  It’s best to perform an update and install net-tools

[root@localhost ~]# yum -y update
[root@localhost ~]# yum –y install net-tools
Task 2: Configure miscellaneous items for Ansible Controller

After the updates, you’ll configure the Controller’s:

  • FQDN
  • IP (if you want a static one)
  • DNS (if you like)
  • NTP (if desired)
  • Hostname (you should)
  • Host files (if you don’t feel like configure a DNS server… but you should have one if you read my blog on how to configure a DNS server)
  • Disable firewall and netmanager services
Task 3: Install Ansible prerequisites

The easiest way to install Ansible on CentOS is by using standard package repository and EPEL repository. This will install python on your controller

[root@ansible-ctlr ~]# yum -y install epel-release

NOTE: The epel-release is specific to CentOS.  In case, you were wondering.
NOTE: You may also run ‘yum install -y python2 epel-release’ instead of the above syntax, if you’d like.

Next, check the python version, mine is 2.7.5

[root@ansible-ctlr ~]# python --version
Python 2.7.5
[root@ansible-ctlr ~]#

Install python pip

yum -y install python-pip
Task 4: Install Ansible

Now we can install ansible

[root@ansible-ctlr ~]# yum -y install ansible

After installation is completed – check the Ansible version. Your output show be similar

[root@ansible-ctlr ~]# ansible --version
ansible 2.7.2
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Jul 13 2018, 13:06:57) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
[root@ansible-ctlr ~]#

NOTE: If you want to install the latest version of Ansible, you pip: pip install ansible

From your output, ansible is located in /etc/ansible/

[root@ansible-ctlr ~]# cd /etc/ansible/
[root@ansible-ctlr ansible]# ls
ansible.cfg  hosts  roles
[root@ansible-ctlr ansible]#

It is in this location where you’d typically need to be in order to run your Ansible Playbooks… we’ll leave this alone for now and work on the managed nodes to which we’ll run Ansible Playbooks against.

Task 5: Install managed nodes to run Ansible playbooks against

NOTE: DO NOT update the nodes. Playbooks will be used to install those and other stuff.

Just like in Tasks 1 & 2 – Install CentOS on two managed nodes. Make sure the IPs are on the same subnet as the controller and update the /etc/hosts file on your Ansible controller, too.

After the nodes are set-up, we can leave them for now.

Task 6: SSH to Managed Nodes to store Key fingerprint

On the Ansible controller, SSH into the nodes and connect to store the ECDSA key fingerprint  to the list of known hosts

[root@ansible-ctlr ~]# ssh ansible-host1.ahaliblogger.local
The authenticiyty of host 'ansible-host1.ahaliblogger.local (' can't be established.
ECDSA key fingerprint is SHA256:Lh3LfingerprintMJs6CpqKtgWJWi8UPy6U.
ECDSA key fingerprint is MD5:b3:c3:e3:f2:f1:29:1b:00:00:00:36:36:e9:5d:ef:eb.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ansible-host1.ahaliblogger.local,' (ECDSA) to the list of known hosts.
root@ansible-host1.ahaliblogger.local's password:
Last login: Tue Nov 27 14:47:13 2018
[root@ansible-host1 ~]#
[root@ansible-host1 ~]# exit
Connection to ansible-host1.ahaliblogger.local closed.
[root@ansible-ctlr ~]#
[root@ansible-ctlr ~]# ssh ansible-host2.ahaliblogger.local
The authenticity of host 'ansible-host2.ahaliblogger.local (' can't be established.
ECDSA key fingerprint is SHA256:M+vX9IHEPfingerprintPwuDZgeEOsd3DB9kagDr2A.
ECDSA key fingerprint is MD5:a8:d6:68:6a:00:00:00:53:c6:36:96:21:39:0d:bd:02.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ansible-host2.ahaliblogger.local,' (ECDSA) to the list of known hosts.
root@ansible-host2.ahaliblogger.local's password:
Last login: Tue Nov 27 15:08:20 2018
[root@ansible-host2 ~]# exit
Connection to ansible-host2.ahaliblogger.local closed.
[root@ansible-ctlr ~]#
[root@ansible-ctlr ~]#

NOTE: The view the file where your ‘known’ hosts are in – run the following:

[root@ansible-ctlr etc]# cd ~/.ssh/
[root@ansible-ctlr .ssh]# ls
[root@ansible-ctlr .ssh]# vi known_hosts
Task 7: Run SSH key-gen on Ansible controller and copy the public key to Managed Nodes

This task is based on my previous blog posting: No Password SSH… No Problem!

If completed correctly, you should have three files on your Ansible controller

[root@ansible-ctlr ~]# cd ~/.ssh/
[root@ansible-ctlr .ssh]# ls
id_rsa  known_hosts
[root@ansible-ctlr .ssh]#

The Managed Nodes will now have an authorized key file in their ~/.ssh/ directory

[root@ansible-host1 ~]# cd ~/.ssh
[root@ansible-host1 .ssh]# ls
[root@ansible-host1 .ssh]#

Now your Ansible controller can run task against your managed nodes without being prompted for a password.

Task 8: Create ansible.cfg file, project directory, and inventory file

The ansible.cfg file is used to specify generic settings such as escalate permissions, where to find the ‘inventory’ file, and other items. It’s best to create this file relative to your project directory. To know more about the ansible.cfg – navigate to the one provided when Ansible is first installed: vi /etc/ansible/ansible.cfg

My ansible.cfg looks like this:

[root@ansible-ctlr install]# vi ansible.cfg

inventory = inventory
remote_user = root
host_key_checking = false

become = True
become_method = sudo
become_user = root
become_ask_pass = False
[root@ansible-ctlr install]#
[root@ansible-ctlr install]#

Since I defined an inventory file named ‘inventory’ [no too creative, right]. I’ll have to define that file and add my nodes to it.

From a best practice perspective, it’s best to organize Ansible into projects.  So on the Ansible controller, make a directory for your project and create a file called inventory

[root@ansible-ctlr ~]#
[root@ansible-ctlr ~]# mkdir install
[root@ansible-ctlr ~]cd install
[root@ansible-ctlr install~]# touch inventory

This file will be used by Ansible to determine what nodes to run tasks on.  My inventory file looks like this:

[root@ansible-ctlr install]# vi inventory


[root@ansible-ctlr install]# 

I’ve listed both nodes under the host group ‘[all]’ and only ansible-host2 under the host group ‘[web]’. We’ll see shortly how these are used…

With all that done, let’s run a simple Ansible command to test if we done this correctly. Run the following on the controller:

NOTE: The host group ‘[all]’ is always present and doesn’t have to be defined

With all that done, let’s run a simple Ansible command to test if we done this correctly. Run the following on the controller:

[root@ansible-ctlr install]# ansible all -i inventory --list-hosts

Your output should look similar


If it does – then you created the inventory file correctly and successfully ran your first Ansible command!!!

Task 9: Running adhoc commands

Now that where all set-up, let’s run a few adhoc commands. We’ll run the following adhoc command

[root@ansible-ctlr install]# ansible ansible-host1.ahaliblogger.local -m command -a who

This command list who is connected to the host specified [ansible-host1.ahaliblogger.local]

The output looks like this:

[root@ansible-ctlr install]# ansible ansible-host1.ahaliblogger.local -m command -a who
ansible-host1.ahaliblogger.local | CHANGED | rc=0 >>
root     tty1         2018-12-12 19:23
root     pts/0        2018-12-12 19:24 (
root     pts/1        2018-12-12 20:41 (
[root@ansible-ctlr install]#

So it looks like I have two user connected to this host [ & .118] .118 is the Ansible Controller and .97 is my local machine.

Now I’ll run the same command on all my hosts:

[root@ansible-ctlr install]# ansible all -i inventory -m command -a who
ansible-host1.ahaliblogger.local | CHANGED | rc=0 >>
root     tty1         2018-12-12 19:23
root     pts/0        2018-12-12 19:24 (
root     pts/1        2018-12-12 20:45 (

ansible-host2.ahaliblogger.local | CHANGED | rc=0 >>
root     tty1         2018-12-12 19:24
root     pts/0        2018-12-12 19:24 (
root     pts/1        2018-12-12 20:45 (

[root@ansible-ctlr install]#

As you can see it lists the host and who’s connected to them 🙂 !

Task 10:  Create Ansible Playbooks

Ok, so let’s delve into Playbooks that would:

  • Update our hosts and install net-tools to run ifconfig
  • Disable NetworkManager and Firewall Services
  • Update the host’s hosts file to include the Ansible Controller’s FQDN
  • Install NTP service
  • Install NGINX on ansible-host2 and move a file to the html directory

On my Ansible Controller, and in the project directory of ‘install’, I’ll create a YAML [to be] file called basic-update.yml

[root@ansible-ctlr install]# ls
ansible.cfg  inventory
[root@ansible-ctlr install]# touch basic-update.yml
[root@ansible-ctlr install]# ls
ansible.cfg  basic-update.yml  inventory
[root@ansible-ctlr install]#

Every Ansible Playbook should content the following header:

- name: This will perform a basic yum -y update on target host machines
  hosts: all
  remote_user: root
  become: yes

This breaks down into:

To continue, my Playbook for updating my hosts and installing net-tools is as follows:

NOTE: You must pay careful attention to your syntax and its structure in the file! Very important

[root@ansible-ctlr install]# vi basic-update.yml

- name: This will perform a basic yum -y update on target host machines and then install net-tools
  hosts: all
  remote_user: root
  become: yes
  - name: Run yum update
    yum: name=* state=latest

  - name: run yum install net-tools
    yum: name=net-tools state=latest
[root@ansible-ctlr install]#

Very simple, huh? Yep.  This playbook can now be ran on my two hosts, or four, or four thousand hosts.  Just imagine having to manually cut-n-paste all your commands on all your hosts. How long will that take???

The next Playbook for turning off and disabling Firewalld & NetworkManager services, as well as adding the Ansible controller to the nodes /etc/hosts file is as follows:


- name: This will turning off and disable Firewalld & NetworkManager services, and aslo add ansible-ctlr to the node’s /etc/hosts file 
  hosts: all
  remote_user: root
  become: yes

  - name: Stop NetworkManager and disable
    service: name=NetworkManager state=stopped

  - name: Stop firewalld and disable
    service: name=firewalld state=stopped

  - name: Update /etc/hosts file to include Ansible Controller
       path: /etc/hosts
       regexp: '^192.\.168\.64\.118'
       line: '  ansible-ctlr.ahaliblogger.local '
       owner: root
       group: root
       mode: 0644

The Playbook for installing NTP

- name: This will  install and start NTP services
  hosts: all
  gather_facts: true
  remote_user: root
  become: yes

  - name: Install NTP
    yum: name=ntp state=latest

  - name: Start DHCP service and start on boot
      name: ntpd
      state: started
      enabled: yes

And the Playbook for installing NGINX on ansible-host2 and passing a file to its /usr/share/html directory

- name: This will install NGINX on ansible-host2 and copy a file to its html directory
  hosts: web
  remote_user: root
  become: yes
   - name: run yum install epel-release
     yum: name=epel-release state=latest

   - name: install the latest version of nginx
     yum: name=nginx state=latest

   - name: Start nginx service and start on boot
     systemd: name=nginx state=started

  - name:
        src: /root/install/ansible-file-to-nginx.txt
        dest: /usr/share/nginx/html
        owner: root
        group: root
        mode: 0644

NOTE: Notice that ‘hosts’ is now pointing to ‘[web]’ host group in the inventory file.

So now we have 4 Ansible Playbooks to carry out our list of objectives.

Task 11: Running the Playbooks

Ok – The playbooks are complete, Let’s run these books!

First is the Playbook to update our target hosts. The Ansible syntax, specific for updating our target hosts is:

ansible-playbook -i inventory basic-update.yml

This break down into:

When we run this Playbook we’ll see the following:

From the output on the Ansible Server we can ascertain that:

  • We’re able to reach the nodes [ ansible-host1 &2] successfully [shown in green]
  • Changes were performed successfully [shown in yellow] on the nodes per the ansible playbook’s Tasks [ yum update and yum install net—tools]
  • No failures…if there were – it would have shown in red.

Now my nodes have been updated and I’m able to use ‘ifconfig’ to see my interfaces and ip addresses.

Playbook for Disabling NetworkManager and Firewall Services:

[root@ansible-ctlr install]# ansible-playbook -i inventory stop-services.yml

Running the playbook would yield a similar result:

Playbook for updating the host’s hosts file to include the Ansible Controller’s FQDN:

[root@ansible-ctlr install]# ansible-playbook -i inventory update-hostsfile.yml

Playbook to install NTP services

[root@ansible-ctlr install]# ansible-playbook -i inventory install-ntp.yml

And the Playbook to install NGINX on Ansible-host2 and move a file to the html directory:

[root@ansible-ctlr install]# ansible-playbook -i inventory install-nginx.yml

All of the playbooks were ran successfully with zero failures!  Just imagine using these same playbooks, tweaking the content a bit to match your desired results you seeking on your networking. Whether it be infrastructure changes, bring nodes online, or parsing nodes for information…

Also imagine running a single Ansible playbook across a thousand [1000] nodes and having all those changes happen simultaneous without ever logging into every – single – one – of – them! A task that would take days to complete can happen in minutes or a few hours!

Check out the video below to see these playbooks in action.


Hope you enjoyed this blog!  Time to Automate!



About Alim H. Ali

Leave a Reply

Your email address will not be published. Required fields are marked *