Introduction

This page has been migrated to Medium

In the previous post we introduced basic aspects of Ansible. Now we’ll talk about some advanced features.

Loops

Another way to describe the tools of the Ansible family can be Infrastructure as code. This is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.

The word code brings an important aspect with it: loops.

In Ansible Playbooks you can use loops to reuse some tasks. An example can be the following:

- name: add several users
  user:
    name: "{{ item }}"
    state: present
    groups: "wheel"
  loop:
     - testuser1
     - testuser2

This task adds several users and in order to do that, iterates over a loop. So you don’t have to write the same task twice.

You can iterate both on simple lists and on lists of maps. This can clarify this:

- name: add several users
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }

Using loops reduces the repetition in your playbooks, keeping them compact and clear.

Roles

Ansible Roles are ways of automatically loading certain vars_files, tasks, and handlers based on a known file structure. Grouping content by roles also allows easy sharing of roles with other users.

Roles are essentially a predefined directory structure that we’re utilizing to put individual pieces of our playbook into, to make it easier to reuse and share among groups.

An example directory structure can be the following:

webservers.yml
fooservers.yml
roles/
    common/
        tasks/
        handlers/
        files/
        templates/
        vars/
        defaults/
        meta/
    webservers/
        tasks/
        defaults/
        meta/

In this structure, we have the playbooks webserver.yaml and fooservers.yml and the roles common and webservers.

When in use, each directory must contain a main.yml file, which contains the relevant content:

  • tasks: contains the main list of tasks to be executed by the role;
  • handlers: contains handlers, which may be used by this role or even anywhere outside this role;
  • defaults: default variables for the role;
  • vars: other variables for the role;
  • files: contains files which can be deployed via this role;
  • templates: contains templates which can be deployed via this role;
  • meta: defines some metadata for this role. See below for more details.

Conventionally, the common role contains a role that has to be run against all of your machines.

We can suppose that inside our roles/common/tasks/httpd.yml we have the following:

- yum:
    name: "httpd"
    state: present

and that inside our roles/webservers/tasks/apache.yml we have the following:

- apt:
    name: "apache2"
    state: present

Inside our playbook we will put:

---
- hosts: webservers
  roles:
    - common
    - webservers

In that way, we included both common and webservers roles so that they can be executed when running the playbook.

With this small example, it’s hard to understand the benefits brought by roles, but as long as your playbook starts growing, you will find this structure a life-saving because you can reuse as much as you can, still keeping everything both clear and compact.

Ansible Galaxy

Ansible Galaxy is Ansible’s official hub for sharing Ansible content. Galaxy provides pre-packaged roles that can be dropped into Ansible PlayBooks and immediately put to work.

You may find roles for provisioning infrastructure, deploying applications, and all of the tasks you do every day.

Using the ansible-galaxy command you can also create the role structure. Once inside the roles directory, you can run

$ ansible-galaxy role init my_role

to create the full structure for the role my_role.

Conclusions

Now that you know those concepts you can be very productive using Ansible. So… good automation!