Master the Power of Ansible Roles: Don't be a Rookie


Ansible Tutorial

Introduction to Ansible Roles

Definition and Overview

Ansible is a popular tool used in IT automation, and within Ansible, a "role" holds a crucial place. An Ansible Role is essentially a way to bundle automation tasks, handlers, default variables, and other assets together. It acts like a blueprint, allowing users to reuse, share, and manage automation structures with ease. By using Ansible Roles, tasks become modular and more straightforward, promoting reusability and simplicity in defining complex configurations and automations.

Importance and Use Cases

The concept of the "Ansible Role" becomes highly valuable when you need to manage complex systems or workflows. Roles are indispensable for organizing and modularizing code into reusable units. They help in breaking down complex tasks into simpler, more manageable pieces, thus making the automation workflows less cluttered and more understandable.

Use cases of Ansible Roles are vast, ranging from configuring system prerequisites and managing users to deploying applications and ensuring that specific services are running on servers. Due to the modular nature of roles, they can be easily shared across different projects, promoting code reuse and consistency.

Architecture and Components

An "Ansible Role" is structured carefully, containing several components or directories, each holding specific types of content. Key components include:

  • Tasks: The main list of tasks that the role will execute.
  • Handlers: Contains handlers, which may be used by this role or even outside this role.
  • Defaults: Default variables for the role.
  • Vars: Other variables for the role.
  • Files and Templates: Contains files or templates which can be deployed by this role.

 

Setting Up Ansible Roles

Prerequisites

Before diving into the setup of Ansible Roles, there are certain prerequisites you need to ensure:

  • Ansible Installation: Ensure that Ansible is installed on the system where you plan to set up roles.
  • Basic Knowledge: Having basic knowledge of YAML syntax, as Ansible Roles will involve working with YAML files.
  • Access Privileges: Necessary access privileges to create and manage files and directories on the system.

Directory Structure

Ansible Roles have a predefined directory structure, which helps in organizing the content and making the role modular and reusable. Here’s how a general directory structure for Ansible Roles looks like:

role_name/
    defaults/
    files/
    handlers/
    meta/
    tasks/
    templates/
    vars/

Each directory has a specific purpose in the role, and understanding these directories is crucial for managing and customizing Ansible Roles effectively.

Initialization

To initialize or create a new Ansible Role, you can use the ansible-galaxy init command, followed by the role name. For example:

ansible-galaxy init my_role

This command will create a new directory with the name my_role, populating it with the necessary directories and files based on the default structure.

 

Creating Ansible Roles

We have covered this in more detail under Ansible roles directory structure

Role Directories and Files

As mentioned, Ansible Roles consist of several directories. Here’s a brief on what to put where:

  • Tasks: List of tasks to execute. These are the main actions of the role.
  • Handlers: Contains handlers that can be triggered by tasks.
  • Defaults: Contains default variables.
  • Vars: Contains other variables.
  • Files and Templates: Files or templates that the role deploys.

Task Definition

Tasks are the fundamental actions that an Ansible Role performs. A task could be anything from installing a package, starting a service, or copying a file. Here is an example of defining tasks in Ansible Roles:

# role_name/tasks/main.yml
---
- name: Install nginx
  apt:
    name: nginx
    state: present

Handlers

Handlers are special types of tasks in Ansible Roles, triggered when notified by another task. For example:

# role_name/handlers/main.yml
---
- name: Restart nginx
  service:
    name: nginx
    state: restarted

Default Variables

Variables allow for flexibility and customization in Ansible Roles. Default variables are defined in the defaults directory and can be overridden. For example:

# role_name/defaults/main.yml
---
nginx_port: 80

 

Using Ansible Roles

Including Roles in Playbooks

Ansible Roles are designed to be reusable components in your automation workflows. To leverage the functionalities defined in roles, you include them in playbooks. Here is how you can incorporate Ansible Roles within a playbook:

---
- hosts: web_servers
  roles:
    - role: nginx_role

In this example, the playbook is assigned to run on web_servers, and it includes an Ansible Role named nginx_role.

Role Dependencies

Roles can depend on other roles, meaning one role can invoke another. Defining dependencies is crucial for managing complex workflows where tasks are interrelated. Dependencies are typically listed in the meta/main.yml file inside the role directory.

# meta/main.yml
dependencies:
  - role: common

In this snippet, the Ansible Role has a dependency on another role named common, which would be executed first.

Passing Variables to Roles

Variables make Ansible Roles highly customizable. When using a role in a playbook, you can pass variables to it to modify its behavior.

---
- hosts: web_servers
  roles:
    - role: nginx_role
      vars:
        nginx_port: 8080

This playbook executes the nginx_role, passing a variable that sets the Nginx port to 8080.

 

Ansible Galaxy

Ansible Galaxy is a repository for sharing Ansible Roles. It’s a community-driven platform where you can find, reuse, and share roles, enhancing productivity and collaboration in managing automation tasks with Ansible Roles.

 

Installing and using Roles on Ansible Galaxy

1. Searching for Roles

Begin by exploring available roles on the Ansible Galaxy website.

You can search for roles by keywords, tags, or author, and filter the results according to your needs.

2. Installing Roles

Once you find a role that suits your needs, you can install it directly from the command line using the ansible-galaxy command.

ansible-galaxy install username.role_name

Replace username and role_name with the appropriate values. This command downloads and installs the role to your system, making it available for use in your playbooks.

3. Using Installed Roles in Playbooks

After installing the role, you can utilize it in your playbooks. Include the role name in your playbook’s roles section.

---
- hosts: your_host
  roles:
    - username.role_name

Ensure that the hosts section correctly targets the hosts where you want the role to be applied.

4. Customizing Roles with Variables

You might need to customize the role according to your specific needs. Look for variables that the role author has made available for customization.

---
- hosts: your_host
  roles:
    - role: username.role_name
      vars:
        var_name: value

Replace var_name and value with the specific variable names and values you want to customize.

5. Executing the Playbook

Run the playbook using the ansible-playbook command, and the role will be executed on the targeted hosts.

ansible-playbook your_playbook.yml

 

Submitting Roles to Ansible Galaxy

Submitting your Ansible Roles to Ansible Galaxy involves several steps to ensure that your role is well-prepared, documented, and easily accessible to other users. Here’s a detailed breakdown with sample commands to guide you through the process:

1. Prepare Your Role

Ensure your role adheres to Ansible’s best practices. Structure your role correctly with meaningful names, organized tasks, handlers, and variables.

2. Create a GitHub Repository

Ansible Galaxy integrates with GitHub. Create a repository for your role on GitHub.

git init ansible-my-role
cd ansible-my-role
git remote add origin https://github.com/your-username/ansible-my-role.git

3. Create a README.md File

Include a README.md in your repository to provide essential information, usage instructions, and examples for your role.

4. Create a meta/main.yml File

This file should include metadata about your role, such as the description, author information, platforms, and dependencies.

---
galaxy_info:
  author: your_name
  description: Your role description
  license: MIT
  min_ansible_version: 2.4
  platforms:
    - name: Ubuntu
      versions:
        - bionic
  galaxy_tags:
    - web
    - nginx
dependencies: []

5. Push Your Role to GitHub

Commit your role files and push them to your GitHub repository.

git add .
git commit -m "Initial commit"
git push -u origin master

6. Submit Your Role to Ansible Galaxy

  • Go to Ansible Galaxy.
  • Log in and click on “Add Content”.
  • Choose "GitHub" as the source and select your repository.
  • Import your role by selecting the repository you want to import.

7. Version Your Role

It’s good practice to create versions of your role. Use git tags to mark versions, and then push these tags to your GitHub repository.

git tag 1.0.0
git push origin 1.0.0

In Ansible Galaxy, new versions will be detected automatically, and users can choose specific versions of your role to install.

 

Parameterization and Variable Usage in Ansible Roles

1. Role Parameters

Role parameters allow you to pass values into your Ansible Roles, making your roles more dynamic and reusable. You define these variables outside of the role, and they modify how the role behaves.

For example:

---
- hosts: web_servers
  roles:
    - role: my_role
      var1: value1
      var2: value2

In this playbook, var1 and var2 are passed as parameters to my_role.

 

2. Variable Scopes and Precedence

Variables in Ansible can be defined in multiple places, and they follow a specific order of precedence. For instance, variables defined within a playbook have higher precedence over those defined in roles.

Example:

  • Role Default:
# roles/my_role/defaults/main.yml
---
var_name: default_value

Playbook:

# playbook.yml
---
- hosts: web_servers
  roles:
    - role: my_role
      var_name: playbook_value

In this example, var_name would take the value playbook_value because it is defined in the playbook and has higher precedence over the role’s default value.

 

3. Dynamic Inclusions

Dynamic inclusions allow you to conditionally include tasks or roles based on the value of variables or facts.

# playbook.yml
---
- hosts: web_servers
  roles:
    - role: "{{ ansible_os_family | lower }}"

In this playbook, the role included will depend on the operating system of the target hosts because of the use of the ansible_os_family fact.

 

Sharing and Reusing Ansible Roles

Ansible Roles can be shared across multiple projects, promoting code reuse. Place the role in a directory accessible by different projects or use a tool like Ansible Galaxy.

Version control systems like Git can be used to manage your Ansible Roles, making collaboration easier. You can track changes, create branches, and accept merge requests to improve the roles.

Example:

Initialize a Git Repository:

git init my_role

Commit Your Role:

git add .
git commit -m "First commit"

Push to a Remote Repository:

git remote add origin <repository-url>
git push -u origin master

 

Advanced Topics in Ansible Roles

1. Conditional Inclusions in Ansible Roles

Conditional inclusions allow you to conditionally include tasks or roles in your playbook based on certain conditions such as variables or facts.

# playbook.yml
---
- hosts: servers
  roles:
    - role: database
      when: ansible_facts['os_family'] == "Debian"

In this example, the database Ansible Role is only applied to hosts where the operating system family is Debian.

 

2. Loops and Iterations in Ansible Roles

Loops in Ansible Roles allow you to execute tasks multiple times, iterating over a list of items. This feature is incredibly powerful for managing repetitive tasks in a concise manner.

Example:

# roles/web/tasks/main.yml
---
- name: Ensure multiple packages are installed
  ansible.builtin.package:
    name: "{{ item }}"
    state: present
  loop: "{{ packages }}"

In this snippet from an Ansible Role, a loop is used to install multiple packages. The variable packages contains a list of packages to be installed.

 

3. Error Handling in Ansible Roles

Error handling is crucial for managing the execution flow of your playbooks. You can manage errors effectively within Ansible Roles by using certain parameters such as ignore_errors or failed_when.

# roles/web/tasks/main.yml
---
- name: Try to start the service
  ansible.builtin.service:
    name: my_service
    state: started
  ignore_errors: yes

In this Ansible Role task, the ignore_errors parameter is set to yes. This means that even if starting the service fails, the playbook execution will continue.

 

Example 1: Ansible roles example to update /etc/motd

Step 1: Create ansible role - motd

[ansible@controller ~]$ mkdir roles
[ansible@controller ~]$ cd roles

Next use ansible-galaxy init command to create ansible role. We will create motd role:

[ansible@controller roles]$ ansible-galaxy init motd
- motd was created successfully

Create ansible role command was successful. You can use tree command to list the ansible role directory structure for motd:

[ansible@controller roles]$ tree motd
motd
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

8 directories, 8 files

As you see all the directories which we discussed in our last article for ansible role are created

Step 2: Create ansible tasks

Now we know we want to update /etc/motd file using ansible playbook roles so we must create tasks so we will use the main.yml file present inside tasks folder

[ansible@controller motd]$ cat tasks/main.yml
---
# tasks file for motd
- name: copy motd file
  template:
     src: templates/motd.j2
     dest: /etc/motd
     owner: root
     group: root
     mode: 0444

We have defined the template path and destination detail to update /etc/motd

Step 3: Create ansible template

Next we will create the template content which will be used to update /etc/motd in our ansible roles examples. I will create a new template file under templates directory using some variables:

[ansible@controller motd]$ cat templates/motd.j2
Welcome to {{ ansible_hostname }}

This file was created on {{ ansible_date_time.date }}
Go away if you have no business being here

Contact {{ system_manager }} if anything is wrong

Step 4: Create ansible variables

We will use defaults folder to define custom variables which is used in our template file templates/motd.j2.

[ansible@controller motd]$ cat defaults/main.yml
---
# defaults file for motd
system_manager: admin@golinuxcloud.com

Step 5 : Remove unwanted directories (Optional)

This step is completely optional. In this ansible roles example we will not use other directories so we are deleting them. After deleting the additional directories you can use tree command to list the directory structure of motd roles

[ansible@controller motd]$ rm -rf handlers tests vars
[ansible@controller motd]$ tree
.
├── defaults
│   └── main.yml
├── files
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
└── templates
    └── motd.j2

5 directories, 5 files

Step 6: Create ansible role playbook

Now after you create ansible role structure, we need a playbook file which will deploy the role to our managed hosts. I will create my playbook file motd-role.yml under base project directory.

[ansible@controller base]$ cat motd-role.yml
---
- name: use motd role playbook
  hosts: server1.example.com
  user: ansible
  become: true

  roles:
    - role: motd
      system_manager: admin@golinuxcloud.com

As you see I have only provided the roles information and no other tasks are specified in the playbook file.

Step 7: Deploy ansible playbook roles

After we create ansible role from scratch and playbook file, we will next deploy our ansible playbook roles to execute the motd role on our managed host.

[ansible@controller base]$ ansible-playbook motd-role.yml

PLAY [use motd role playbook] ***********************************************************************************

TASK [Gathering Facts] ******************************************************************************************
ok: [server1.example.com]

TASK [motd : copy motd file] ************************************************************************************
changed: [server1.example.com]

PLAY RECAP ******************************************************************************************************
server1.example.com        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In the ansible roles example our ansible deployment was successful.

Step 8: Verification

After ansible playbook deployment, verify the task status on your managed host which for us is server1.example.com

[root@server1 ~]# cat /etc/motd
Welcome to server1

This file was created on 2020-02-01
Go away if you have no business being here

Contact admin@golinuxcloud.com if anything is wrong

So the content from our motd file is updated properly on server1 at /etc.motd.

 

Example 2: Configure Virtual Hosting with Ansible Role

This is our second ansible roles example. This play will be operated on server2.example.com and we are going to use "vhost" role for the operation.

Step 1: Create Ansible Role - vhost

We will use our existing ~/base/roles/<rolename> project to create ansible roles directory structure using "vhost" role

[ansible@controller base]$ cd roles/

To create ansible role vhost use ansible-galaxy init <rolename> command as shown below:

[ansible@controller roles]$ ansible-galaxy init vhost
- vhost was created successfully

You can use tree command to check the structure of the vhost directory:

[ansible@controller roles]$ tree
.
└── vhost
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

9 directories, 8 files

Step 2: Create ansible tasks

  • In the main.yml inside tasks folder we define the tasks to be performed
  • Install httpd using yum module
  • Start and enable the httpd service using the service module
  • Next source the vhost.conf.j2 file to destination using template module available under templates directory
[ansible@controller base]$ cat roles/vhost/tasks/main.yml
---
# tasks file for vhost
- name: install http
  yum:
    name: httpd
    state: latest
- name: start and enable httpd
  service:
    name: httpd
    state: started
    enabled: true
- name: install vhost config file
  template:
    src: vhost.conf.j2
    dest: /etc/httpd/conf.d/vhost.conf
    owner: root
    group: root
    mode: 0644

Step 3: Create ansible handlers

In roles we separate tasks with ansible handlers. So in this ansible roles example in handlers/main.yml we instruct ansible to restart httpd once the tasks are done

[ansible@controller base]$ cat roles/vhost/handlers/main.yml
---
# handlers file for vhost

- name: restart_httpd
  service:
     name: httpd
     state: restarted

Step 4: Create ansible template

Below is our virtual host configuration using variables under templates folder. The variables will be auto filled on destination names.

[ansible@controller base]$ cat roles/vhost/templates/vhost.conf.j2
# {{ ansible_managed }}

<VirtualHost *:80>
        ServerAdmin webmaster@{{ ansible_fqdn }}
        ServerName {{ ansible_fqdn }}
        ErrorLog logs/{{ ansible_hostname }}-error.log
        CustomLog logs/{{ansible_hostname }}-common.log common
        DocumentRoot /var/www/vhosts/{{ ansible_hostname }}/

        <Directory /var/www/vhosts/{{ ansible_hostname }}>        
                Options +Indexes +FollowSymlinks +Includes
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>        

Step 5: Remove unwanted directories (Optional)

Now similar to our ansible roles example for motd, we will remove our unwanted directories.

[ansible@controller vhost]$ rm -rf defaults files tests vars

Next you can use tree command to list the remaining directories of vhost role.

[ansible@controller vhost]$ tree
.
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
└── templates

4 directories, 4 files

Step 6: Create post execution tasks

Also we have added post_tasks to copy index.html from localhost to destination on managed host (server2.example.com) under /var/www/html/<hostname>/
So we will create an index.html on the localhost which we want to be copied to the destination with our playbook:

[ansible@controller base]$ mkdir -p files/html

[ansible@controller base]$ echo "Welcome to this host" >> files/html/index.html

[ansible@controller base]$ cat files/html/index.html
Welcome to this host

Step 7: Create ansible role playbook

Now after you create ansible role structure, we need a playbook file which will deploy the role to our managed hosts. I will create apache-vhost.yml playbook file under the base project directory.

[ansible@controller base]$ cat apache-vhost.yml
---
- name: create apache vhost
  hosts: server2.example.com ## Execute on this host only
  become: true ## Perform tasks as root user

  roles:
     - vhost

  post_tasks:
     - name: install contents from local file
       copy:
         src: files/html/
         dest: "/var/www/vhosts/{{ ansible_hostname }}"
       changed_when: true  ## This is to forcefully mark a change
       notify: restart_httpd  ## Execute the handler with the name restart_httpd

Step 8: Deploy ansible playbook roles

After we create ansible role from scratch and playbook file, we will next deploy our ansible playbook roles to execute the vhost role on our managed host.

[ansible@controller base]$ ansible-playbook apache-vhost.yml

PLAY [create apache vhost] **************************************************************************************

TASK [Gathering Facts] ******************************************************************************************
ok: [server2.example.com]

TASK [vhost : install http] *************************************************************************************
ok: [server2.example.com]

TASK [vhost : start and enable httpd] ***************************************************************************
ok: [server2.example.com]

TASK [vhost : install vhost config file] ************************************************************************
changed: [server2.example.com]

TASK [install contents from local file] *************************************************************************
changed: [server2.example.com]

RUNNING HANDLER [vhost : restart_httpd] *************************************************************************
changed: [server2.example.com]

PLAY RECAP ******************************************************************************************************
server2.example.com        : ok=6    changed=4    unreachable=0    failed=0    skipped=0    rescued=0 ignored=0

So looks like our ansible playbook roles has successfully executed. We can verify the same by running ansible ad-hoc commands

NOTE:
You may face issues where the handlers are not executed as part of ansible roles. Ansible will notify handler only when task is in changed state – this is on purpose to prevent unnecessary handlers execution (e.g. service restarts) on subsequent playbook runs. To fix this you can either use notify as I have used in this example or use -include: <path/of/handler/main.yml> to manually execute the file.

Step 9: Verification

To check if httpd service is active on our managed host server2.example.com

[ansible@controller base]$ ansible server2.example.com -a 'systemctl is-active httpd'
server2.example.com | CHANGED | rc=0 >>
active

As we see the service active, we can also check the output of vhost.conf which we had populated. Execute the below command using the controller node

[ansible@controller base]$ ansible server2.example.com -a 'cat /etc/httpd/conf.d/vhost.conf'
server2.example.com | CHANGED | rc=0 >>
# Ansible managed

<VirtualHost *:80>
        ServerAdmin webmaster@server2.example.com
        ServerName server2.example.com
        ErrorLog logs/server2-error.log
        CustomLog logs/server2-common.log common
        DocumentRoot /var/www/vhosts/server2/

        <Directory /var/www/vhosts/server2>        
                Options +Indexes +FollowSymlinks +Includes
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>        

 

Frequently Asked Questions (FAQs)

What are Ansible Roles and why are they important?

Ansible Roles are reusable and portable units of automation, used to organize tasks, handlers, default variables, and metadata. They are significant for simplifying complex playbooks and facilitating code reuse, allowing users to share pre-configured setups and automations, thereby enhancing productivity and consistency in automation strategies.

How do I create and structure an Ansible Role?

To create an Ansible Role, use the ansible-galaxy init command followed by the name of the role. Structuring involves organizing configurations and tasks into directories such as tasks, handlers, templates, and vars. Each directory contains a main.yml file where specific components of the role are defined, ensuring modularity and organization in role definitions.

How can I use variables within Ansible Roles?

Variables in Ansible Roles offer dynamic capabilities and are usually defined within the defaults or vars directory of the role. You can also pass variables to roles directly within playbooks, offering flexibility in customizing role behaviors based on variable values.

How do Ansible Roles interact with Ansible Galaxy?

Ansible Roles can be shared and reused through Ansible Galaxy, a community hub for sharing automation content. You can upload your roles to Ansible Galaxy or install and utilize roles shared by others, promoting collaboration, and code reuse in the Ansible community.

How are conditional statements applied in Ansible Roles?

Conditional statements in Ansible Roles, like when, allow for the execution of tasks based on the evaluation of specified conditions. They enable dynamic inclusion of tasks, roles, or handlers, based on variables, facts, or any conditional logic, making the roles more versatile and adaptable to different scenarios.

How can loops be implemented in Ansible Roles?

Loops can be applied in tasks within Ansible Roles using loop-related directives like loop or with_items. They allow for the iterative execution of tasks over lists or sequences, facilitating repetitive task management with more concise and manageable code.

What strategies are available for error handling in Ansible Roles?

Error handling in Ansible Roles involves using parameters like ignore_errors or implementing blocks with rescue and always sections. Such strategies ensure controlled execution flow, allowing for the management of task failures or errors gracefully, enhancing role reliability and robustness.

How do I manage role dependencies in Ansible?

Role dependencies can be managed by defining them in the meta/main.yml file of a role or directly within a playbook. Defining dependencies ensures that requisite roles are executed in the correct order, maintaining coherence in role interactions and executions.

 

Summary

Creating, managing, and optimizing Ansible Roles are pivotal in leveraging the full potential of Ansible’s automation capabilities. Here’s a concise overview of the important aspects discussed:

  • Introduction to Ansible Roles: Understanding the fundamental concepts, such as the definition, architecture, and importance of roles, sets a strong foundation for working with Ansible Roles.
  • Setting Up and Creating Ansible Roles: Knowing how to initialize and structure the roles, including the organization of directories and files, is crucial for building functional roles.
  • Utilizing Ansible Roles: Incorporating roles within playbooks, managing role dependencies, and passing variables enhance the reusability and functionality of roles.
  • Ansible Galaxy: Learning the intricacies of Ansible Galaxy for installing, using, and submitting roles is essential for community collaboration and role sharing.
  • Parameterization and Variable Usage: Mastery of parameters and variables, including their scopes and precedence, makes roles dynamic and adaptable.
  • Sharing and Reusing Ansible Roles: Implementing best practices for sharing and reusing roles across projects through version control and collaboration tools improves code consistency and teamwork.
  • Advanced Topics: Delving into advanced concepts like conditional inclusions, loops, and error handling allows for the creation of more robust and error-resistant roles.

For an in-depth understanding and exploration of Ansible Roles, refer to the official documentation:

 

What's Next

Next in our Ansible Tutorial we will learn about Ansible Vaults

 

Deepak Prasad

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

6 thoughts on “Master the Power of Ansible Roles: Don't be a Rookie”

  1. In your playbook there is no handler restart task was executed , I think you missed the notify after the copy, Please check once

    Reply
    • Thank you for highlighting this, I may have overlooked the output. I have updated the article with additional NOTE

      Reply

Leave a Comment