DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Automating Unix Security Across Hybrid Clouds
  • How to Verify Domain Ownership: A Technical Deep Dive
  • Cloud Automation Excellence: Terraform, Ansible, and Nomad for Enterprise Architecture
  • Designing Embedded Web Device Dashboards

Trending

  • What Nobody Tells You About Multimodal Data Pipelines for AI Training
  • Improving DAG Failure Detection in Airflow Using AI Techniques
  • Self-Hosted Inference Doesn’t Have to Be a Nightmare: How to Use GPUStack
  • Optimizing High-Volume REST APIs Using Redis Caching and Spring Boot (With Load Testing Code)
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. How To Use Ansible Roles

How To Use Ansible Roles

In this article, readers will use a tutorial to learn about the basics of Ansible Roles, experimenting with features, and how to use them in playbooks.

By 
Gunter Rotsaert user avatar
Gunter Rotsaert
DZone Core CORE ·
Mar. 07, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
3.1K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, you will learn the basics of Ansible Roles. With Ansible Roles, you can reuse Ansible content you create and share them with other users. You will learn about Ansible Roles step-by-step by means of examples. Enjoy!

Introduction

In the three previous Ansible posts, you learned how to setup an Ansible test environment, how to create an Ansible inventory, and how to create an Ansible playbook.

To be reminded, here are the three articles: 

  1. How To Setup an Ansible Test Environment
  2. How To Create an Ansible Inventory
  3. How To Create an Ansible Playbook

This article continues this series, but it is not necessary to read the first three posts. In this article, you will learn how to use Ansible Roles. Ansible Roles will allow you to structure your Ansible content in such a way that it can be easily reused. This way, you can share your Ansible content with other users. In addition to this article, it is advised to read the official Ansible documentation roles section.

In case you did not read the previous articles, or just as a reminder, the environment consists out of one “Controller” and two “Target machines.” The “Controller” and “Target machines” run in a VirtualBox VM. Development of the Ansible scripts is done with IntelliJ on the host machine. The files are synchronized from the host machine to the “Controller” by means of a script. In this article, the machines have the following IP addresses:

  • Controller: 192.168.2.11
  • Target 1: 192.168.2.12
  • Target 2: 192.168.2.13

The files being used in this article are available in the corresponding git repository at GitHub.

Prerequisites

The following prerequisites apply to this article:

  • You need an Ansible test environment, see How To Setup an Ansible Test Environment. 
  • You need to have basic Ansible knowledge (read the previous articles in this series if you do not have this knowledge). 
  • If you use your own environment, you should know that Ubuntu 22.04 LTS is used for the “Controller” and “Target machines” and Ansible version 2.13.3. 
  • Basic Linux knowledge.

Starting Point

The starting point will be a playbook, which was created in a previous article. The playbook installs Apache webserver onto both target machines and changes the index page with a welcome message:

YAML
 
- name: Install Apache webserver for target 1
  hosts: target1
  become: yes
 
  tasks:
    - name: Install apache httpd  (state=present is optional)
      ansible.builtin.apt:
        name: apache2
        update_cache: yes
        state: present
 
    - name: Create index page for target 1
      ansible.builtin.copy:
        content: 'Hello world from target 1'
        dest: /var/www/html/index.html
 
- name: Install Apache webserver for target2
  hosts: target2
  become: yes
 
  tasks:
    - name: Install apache httpd  (state=present is optional)
      ansible.builtin.apt:
        name: apache2
        update_cache: yes
        state: present
 
    - name: Create index page for target 2
      ansible.builtin.copy:
        content: 'Hello world from target 2'
        dest: /var/www/html/index.html


As you can see, this playbook contains quite some duplications. This is something that can be solved by using roles.

Role With Fixed Message

In this section, you will restructure the playbook to make use of roles.

Create, in the root of the repository, a roles directory. Inside this roles directory, you create another directory with the name for the role. In this case, you will name it webserverfixed. Inside the webserverfixed directory, you create a tasks directory. The directory structure is the following:

Shell
 
roles
└── webserverfixed
    └── tasks


Inside the tasks directory, you create a main.yml file containing the tasks as used in the playbook. The only difference is that the welcome message contains a fixed message instead of a specific one for each target. You will fix this in the next section:

YAML
 
- name: Install apache httpd  (state=present is optional)
  ansible.builtin.apt:
    name: apache2
    update_cache: yes
    state: present
 
- name: Create index page for target
  ansible.builtin.copy:
    content: 'Hello world from target'
    dest: /var/www/html/index.html


The next step is to create a playbook playbook-roles-fixed-hello-message.yml and use the role:

YAML
 
- name: Install Apache webserver for all targets
  hosts: targets
  become: yes
  roles:
    - webserverfixed


Start your VM environment (if not already done), transfer the repository to the controller by means of the transferdata.sh script, and execute the playbook from the controller. The “BECOME” password is “osboxes.org” and the “Vault” password is “itisniceweather:”

Shell
 
$ ansible-playbook playbook-roles-fixed-hello-message.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for all targets] **************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************
ok: [target2]
ok: [target1]
 
TASK [webserverfixed : Install apache httpd  (state=present is optional)] ************************************************************
ok: [target2]
ok: [target1]
 
TASK [webserverfixed : Create index page for target] *********************************************************************************
changed: [target2]
changed: [target1]
 
PLAY RECAP ***************************************************************************************************************************
target1                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
target2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  


As you can see in the above output, the index pages are changed. Verify on your host machine whether the welcome messages are correct:

Shell
 
$ curl http://192.168.2.12
Hello world from target
$ curl http://192.168.2.13
Hello world from target


Both target machines return the same welcome message, as expected.

Role With Variable Message

The above playbook works well, but this wasn’t exactly what was defined in the original playbook. The original playbook contained a welcome message specific for each target. So, let’s add this functionality. First of all, copy the webserverfixed directory and paste it as webservervariable. This gives you the following directory structure:

Shell
 
roles
├── webserverfixed
│   └── tasks
│       └── main.yml
└── webservervariable
      └── tasks
          └── main.yml


You will need a variable to create a specific message for each target. Create a directory defaults inside directory webservervariable and add a main.yml file with the following contents:

YAML
 
hello_message: target


Change in tasks/main.yml the welcome message so it uses the variable. Change the following part:

YAML
 
- name: Create index page for target
  ansible.builtin.copy:
    content: 'Hello world from target'
    dest: /var/www/html/index.html


into:

YAML
 
- name: Create index page for target
  ansible.builtin.copy:
    content: 'Hello world from {{ hello_message }}'
    dest: /var/www/html/index.html


Create playbook playbook-roles-variable-hello-message-default.yml with the same contents as the playbook of the previous section. The only thing that changes is the role name. Change it into webservervariable:

YAML
 
- name: Install Apache webserver for all targets
  hosts: targets
  become: yes
  roles:
    - webservervariable


Next, run the playbook. 

Notice: in the output that nothing has changed for the index page:

Shell
 
$ ansible-playbook playbook-roles-variable-hello-message-default.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for all targets] **************************************************************************************************************
 
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [target2]
ok: [target1]
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] *********************************************************************************
ok: [target2]
ok: [target1]
 
TASK [webservervariable : Create index page for target] ******************************************************************************************************
ok: [target2]
ok: [target1]
 
PLAY RECAP ***************************************************************************************************************************************************
target1                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
target2                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 


When you check the contents by means of curl, you will see no difference with the previous section. This is as expected, you only changed the role so it uses a variable, but the variable defaults to the value target.

Create a playbook playbook-roles-variable-hello-message.yml and set the hello_message variable to respectively target1 and target2 dependent on the host:

YAML
 
- name: Install Apache webserver for target1
  hosts: target1
  become: yes
  roles:
    - role: webservervariable
      vars:
        hello_message: 'target1'
 
- name: Install Apache webserver for target2
  hosts: target2
  become: yes
  roles:
    - role: webservervariable
      vars:
        hello_message: 'target2'


Run the playbook. As can be seen from the output, the index pages for target1 and target2 are changed:

Shell
 
$ ansible-playbook playbook-roles-variable-hello-message.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target1]
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] **************************************************************************
ok: [target1]
 
TASK [webservervariable : Create index page for target] ***********************************************************************************************
changed: [target1]
 
PLAY [Install Apache webserver for target2] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target2]
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] **************************************************************************
ok: [target2]
 
TASK [webservervariable : Create index page for target] ***********************************************************************************************
changed: [target2]
 
PLAY RECAP ********************************************************************************************************************************************
target1                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
target2                    : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


Verify the index page by means of curl and you can see that the correct responses are returned:

Shell
 
$ curl http://192.168.2.12
Hello world from target1
$ curl http://192.168.2.13
Hello world from target2


Using Roles

The Ansible documentation states that you can use roles in three different ways:

  1. At the play level with the roles option.
  2. At the tasks level with include_role.
  3. At the tasks level with import_role.

Let’s experiment with this in the next sections:

Using Roles at the Play Level

This is what you have used up to now. To see what happens when other tasks are added to the playbook, you add one extra print task.

Create playbook playbook-roles-at-play-level.yml with the role webservervariable and the one extra task:

YAML
 
- name: Install Apache webserver for target1
  hosts: target1
  become: yes
  roles:
    - role: webservervariable
      vars:
        hello_message: 'target1'
 
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs after the webservervariable role"


Run the playbook and, as you can see in the output, the tasks of the webservervariable role are executed first and, after that, the tasks of the playbook are executed:

Shell
 
$ ansible-playbook playbook-roles-at-play-level.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target1]
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] **************************************************************************
ok: [target1]
 
TASK [webservervariable : Create index page for target] ***********************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs after the webservervariable role"
}
 
PLAY RECAP ********************************************************************************************************************************************
target1                    : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


Including Roles: Dynamic Reuse

With dynamic reuse, you can include a role in between other tasks. The order of the tasks are preserved.

Create a playbook playbook-roles-dynamic-reuse.yml. Add a task before the webservervariable role and add a task after the webservervariable role. The webservervariable role is included in the task by means of include_role. Also note that the variables for the role need to be added at the task level:

YAML
 
- name: Install Apache webserver for target1
  hosts: target1
  become: yes
 
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs before the webservervariable role"
 
    - name: Install Apache webserver for target1
      include_role:
        name: webservervariable
      vars:
          hello_message: 'target1'
 
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs after the webservervariable role"


Run the playbook and, as you can see in the output, the order of the tasks are preserved:

Shell
 
$ ansible-playbook playbook-roles-dynamic-reuse.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs before the webservervariable role"
}
 
TASK [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] **************************************************************************
ok: [target1]
 
TASK [webservervariable : Create index page for target] ***********************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs after the webservervariable role"
}
 
PLAY RECAP ********************************************************************************************************************************************
target1                    : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 


Importing Roles: Static Reuse

With static reuse, you can include a role in between other tasks. The order of the tasks are preserved.

Create a playbook playbook-roles-static-reuse.yml. The contents are a copy of the dynamic reuse playbook where you alter include_role into import_role:

YAML
 
- name: Install Apache webserver for target1
  hosts: target1
  become: yes
 
  tasks:
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs before the webservervariable role"
 
    - name: Install Apache webserver for target1
      import_role:
        name: webservervariable
      vars:
          hello_message: 'target1'
 
    - name: Print a message
      ansible.builtin.debug:
        msg: "this task runs after the webservervariable role"


Run the playbook and, as you can see in the output, the order of the tasks are preserved:

Shell
 
$ ansible-playbook playbook-roles-static-reuse.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs before the webservervariable role"
}
 
TASK [webservervariable : Install apache httpd  (state=present is optional)] **************************************************************************
ok: [target1]
 
TASK [webservervariable : Create index page for target] ***********************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs after the webservervariable role"
}
 
PLAY RECAP ********************************************************************************************************************************************
target1                    : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 


Difference Between Dynamic and Static Reuse

So, you are probably wondering what the difference is between dynamic reuse and static reuse as the output is exactly the same.

One major difference is that dynamic reuse reports errors in the tasks during the execution of the role. As with static reuse, errors in the tasks will be reported at the start of the playbook.

Create a playbook playbook-roles-dynamic-reuse-with-error.yml with similar contents as playbook-roles-dynamic-reuse.yml. However, you use the role webserver, which does not exist instead of role webservervariable.

Run the playbook and, as you can see in the output, the first task is executed and the playbook fails when trying to execute the tasks from the non-existing role:

Shell
 
$ ansible-playbook playbook-roles-dynamic-reuse-with-error.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
 
PLAY [Install Apache webserver for target1] ***********************************************************************************************************
 
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [target1]
 
TASK [Print a message] ********************************************************************************************************************************
ok: [target1] => {
    "msg": "this task runs before the webservervariable role"
}
 
TASK [Install Apache webserver for target1] ***********************************************************************************************************
ERROR! the role 'webserver' was not found in /home/osboxes/MyAnsiblePlanet/roles:/home/osboxes/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/osboxes/MyAnsiblePlanet
 
The error appears to be in '/home/osboxes/MyAnsiblePlanet/playbook-roles-dynamic-reuse-with-error.yml': line 12, column 15, but may
be elsewhere in the file depending on the exact syntax problem.
 
The offending line appears to be:
 
      include_role:
        name: webserver
              ^ here
 
PLAY RECAP ********************************************************************************************************************************************
target1                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


Create a playbook playbook-roles-static-reuse-with-error.yml with similar contents as playbook-roles-static-reuse.yml. However, you use the role webserver, which does not exist instead of role webservervariable.

Run the playbook and, as you can see in the output, the playbook fails immediately:

Shell
 
$ ansible-playbook playbook-roles-static-reuse-with-error.yml -i inventory/inventory.ini --ask-vault-pass --ask-become-pass
BECOME password: 
Vault password: 
ERROR! the role 'webserver' was not found in /home/osboxes/MyAnsiblePlanet/roles:/home/osboxes/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles:/home/osboxes/MyAnsiblePlanet
 
The error appears to be in '/home/osboxes/MyAnsiblePlanet/playbook-roles-static-reuse-with-error.yml': line 12, column 15, but may
be elsewhere in the file depending on the exact syntax problem.
 
The offending line appears to be:
 
      import_role:
        name: webserver
              ^ here


Conclusion

In this article, you learned the basics of Ansible Roles, you experimented with some features and, hopefully, you will be able to use them in your playbooks. Ansible Roles is a nice way of reusing and sharing tasks. 

Ansible (software) Web server

Published at DZone with permission of Gunter Rotsaert. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Automating Unix Security Across Hybrid Clouds
  • How to Verify Domain Ownership: A Technical Deep Dive
  • Cloud Automation Excellence: Terraform, Ansible, and Nomad for Enterprise Architecture
  • Designing Embedded Web Device Dashboards

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook