Part 4: Creating Ansible Roles

Why stop at playbooks, when you can bundle them?

Sebastiaan avatar
  • Sebastiaan
  • 4 min read

Why Roles over Playbooks?

Single playbooks are great for tasks but when a project starts getting complexer, it way more managable in a role then a single playbook. Ansible role is a predefined set of playbooks that is build for a specific purpose. All the necessary configurations can be set and build into the role.

Creating the role

We create the role in the folder we’ve been using in the previous parts /Users/sebas/Desktop/ansible. With following command we can create a pre-setup role through ansible.

ansible-galaxy init /Users/sebas/Desktop/ansible/<name role> 

Role layout

This is the layout of the pre-setup role we’ve created through the previous command.

machine_info                   # Name of the role (created through the init command)
├── README.md                  # Default setup for a readme of the role
├── defaults                   # Standard config place, which can be used in tasks
│   └── main.yml               
├── files                      # Place here all necessary files needed for your role
├── handlers                   # Default place for adding task handlers
│   └── main.yml
├── meta                       # Informational place when you list your role to the internet
│   └── main.yml
├── tasks                      # Tasks folder where playbooks go
│   ├── 00_gather_facts.yml
│   ├── 01_hostname.yml
│   ├── 02_ram.yml
│   └── main.yml
├── templates                   # A place for all templated files which can be used in tasks often defined in jinja templates.
├── tests                       # Created for testing your role
│   ├── inventory
│   └── test.yml
└── vars                        # The is the folder for role specific variables.
    └── main.yml

Tasks files

Each of these tasks files is a separate playbook but together they create a role which can configure or build a service.

We use a special var called ansible_facts, this is information from ansible.builtin.setup. In the next part (5) we will go further into detail about vars and secrets. To show the output of the special var we use the ansible.builtin.debug module.

00_gather_facts.yml

In this playbook we gather all the information that ansible can learn. This is can be the gather_facts = true toggle in a single playbook.

---
- name: Gather facts
  ansible.builtin.setup:
    gather_subset:
      - 'all'

01_hostname.yml

In this playbook we want to know what distribution the machine is running and which version.

---
- name: Get distribution
  ansible.builtin.debug: 
    var: ansible_facts.distribution

- name: Get distribution_version
  ansible.builtin.debug:
    var: ansible_facts.distribution_version 

- name: Get hostname
  ansible.builtin.debug: 
    var: ansible_facts.nodename

02_ram.yml

We also want to know how much RAM we have and how much is used.

---
- name: Get free ram
  ansible.builtin.debug: 
    var: ansible_facts.memfree_mb

- name: Get total ram
  ansible.builtin.debug: 
    var: ansible_facts.memtotal_mb

main.yml

This is the file where every separate playbook comes together to bind the role together.

---
- name: Get facts
  ansible.builtin.include_tasks: 00_gather_facts.yml

- name: Get hostname
  ansible.builtin.include_tasks: 01_hostname.yml

- name: Get ram
  ansible.builtin.include_tasks: 02_ram.yml

Creating the playbook which runs the role

touch /Users/sebas/Desktop/ansible/role_book.yml

Lets copy the following configurion into the role_book.yml file. Ansible uses the roles part in the configuration to know that it is a role which needs to be run.
Because this role is in the same directory as the role_book playbook is doesn’t matter. When you place your role somewhere else you need to add a path like role: <path>/role_name

---
- name: playbook
  hosts: localhost
  roles: 
    - role: machine_info

We use the same command to run a playbook, but now inside the playbook there is a role defined. The working of the command is the same, Ansible knows when it needs to search for the main.yml file in the role when the roles tag is used.

ansible-playbook role_book.yml

Output

sebas@eyeofmordor ansible % ansible-playbook role_book.yml 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'

PLAY [playbook] ****************************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [machine_info : Get facts] ************************************************
included: /Users/sebas/Desktop/ansible/machine_info/tasks/00_gather_facts.yml for localhost

TASK [machine_info : Gather facts] *********************************************
ok: [localhost]

TASK [machine_info : Get hostname] *********************************************
included: /Users/sebas/Desktop/ansible/machine_info/tasks/01_hostname.yml for localhost

TASK [machine_info : Get distribution] *****************************************
ok: [localhost] => {
    "ansible_facts.distribution": "MacOSX"
}

TASK [machine_info : Get distribution_version] *********************************
ok: [localhost] => {
    "ansible_facts.distribution_version": "15.2"
}

TASK [machine_info : Get hostname] *********************************************
ok: [localhost] => {
    "ansible_facts.nodename": "eyeofmordor"
}

TASK [machine_info : Get ram] **************************************************
included: /Users/sebas/Desktop/ansible/machine_info/tasks/02_ram.yml for localhost

TASK [machine_info : Get free ram] *********************************************
ok: [localhost] => {
    "ansible_facts.memfree_mb": "6562"
}

TASK [machine_info : Get total ram] *********************************************
ok: [localhost] => {
    "ansible_facts.memtotal_mb": "8192"
}

PLAY RECAP *********************************************************************
localhost                  : ok=10   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

How to use variables

Variables are a great way of setting informations which can be reused on different places within our playbook or role. This url does a deepdive in variables https://spacelift.io/blog/ansible-variables and does a great way of explaining how to use it.

Conclusion

When you when want to keep all the necessary files together for projects or configurations. Roles is a great solution for this, there is always a playbook needed to call on the role itself.

Stay tuned for the Part 5: Secrets!

Sebastiaan

Written by : Sebastiaan

Sysadmin/Platform/Devops Engineer

Recommended for You

Part 3: Creating Ansible Playbooks

Part 3: Creating Ansible Playbooks

Standard way of doing things with playbooks.

Part 2: Managing Hosts with Ansible

Part 2: Managing Hosts with Ansible

first steps managing a host with Ansible.