← All articles
AutomationFeb 12, 202312 min read

Ansible Automation — 5

Ansible roles are a way to organize and reuse Ansible playbooks. They allow you to encapsulate and package up playbooks, tasks, files, and variables into a reusable and shareable format.

Ansible Automation — 5

Roles are defined as a specific directory structure that follows a certain convention, making it easy for others to understand and use the role. The directory structure of a role typically includes the following elements:

  • tasks directory: This directory contains the main playbook tasks that are executed when the role is run.
  • templates directory: This directory contains Jinja2 templates that are used by the role.
  • files directory: This directory contains any files that are needed by the role, such as configuration files or scripts.
  • handlers directory: This directory contains tasks that are triggered by a change in state, such as a service restart.
  • vars directory: This directory contains any variables that are used by the role.
  • defaults directory: This directory contains default variables that can be overridden by variables defined in other locations.

To use a role in an Ansible playbook, you simply need to specify the role name in the playbook. For example:

- name: Execute my role
hosts: localhost
roles:
- my_role

By using roles in Ansible, you can greatly improve the organization and reusability of your playbooks. Roles can be shared and reused between playbooks, and can also be shared with others in the Ansible community.

The ability to organise and reuse playbooks, tasks, files, and variables is made possible by Ansible’s essential feature of roles. You can make your Ansible playbooks more effective, maintainable, and simple for others to understand and utilise by utilising roles.

Example:

how you might structure a playbook that uses three roles, dev, test, and production:

playbook.yml
roles/
dev/
defaults/
main.yml
tasks/
main.yml
test/
defaults/
main.yml
tasks/
main.yml
production/
defaults/
main.yml
tasks/
main.yml

And here’s an example of what the playbook.yml file might look like:

- hosts: demo
gather_facts: yes
roles:
- { role: dev, when: ansible_os_family == "RedHat" }
- { role: test, when: ansible_os_family == "Debian" }
- production

In this example, the playbook is targeted to the demo host, and it is using different roles, dev, test, and production. The when clause in the dev role tells Ansible to only execute this role when the ansible_os_family variable is equal to "RedHat". Similarly, the test role is executed only when the ansible_os_family variable is equal to "Debian".

Each role has a default variable file in the defaults directory, and a task file in the tasks directory. The tasks in these files are executed in the order they are defined, and they perform the actions that are specific to each role.

In conclusion, the structure of a playbook that uses roles provides a clear and organized way to manage your playbooks, by separating the tasks and other resources into distinct roles that can be reused across multiple playbooks. By using roles, you can simplify the management and maintenance of your playbooks, and make it easier for others to understand and use your playbooks.

Example on Condition:

Ansible playbook that is targeting the test host, and is using four different roles, dev, test, uat, and production.

Let’s consider an example to understand this better.

Suppose you have an infrastructure with several different environments, such as development, testing, user acceptance testing (UAT), and production. In each environment, you have a different set of tasks that need to be performed, such as installing packages, configuring services, and deploying applications.

With Ansible roles, you can define these tasks in separate, reusable components that can be easily managed and shared across your organization. In this example, each role is defined in its own directory, and contains all the tasks, files, templates, and other resources needed to perform a specific function in each environment.

Here’s how the playbook would look like:

- hosts: test
roles:
- { role: dev, when: env == "development" }
- { role: test, when: env == "testing" }
- { role: uat, when: env == "uat" }
- { role: production, when: env == "production" }

The playbook is targeting the test host, and it is using four different roles, dev, test, uat, and production. The when statement in each role definition allows for conditional execution of the role. The role dev will only be executed if the value of the env variable is equal to "development", the role test will only be executed if the value of the env variable is equal to "testing", the role uat will only be executed if the value of the env variable is equal to "uat", and the role production will only be executed if the value of the env variable is equal to "production".

Finally, the usage of roles in Ansible playbooks enables you to divide the playbook code into more manageable, reusable components that can be distributed around your business. When a variable’s value is known, the when statement enables roles to be executed conditionally, allowing them to be targeted towards various settings in various ways.

Pre_tasks and post_tasks:

Pre_tasks and post_tasks are important concepts in Ansible that allow you to execute certain tasks before or after the main tasks in a playbook. In this blog, we will take a closer look at these concepts, and explore how you can use them to accomplish various tasks in your playbooks.

What are Pre_tasks in Ansible?

Pre_tasks are tasks that are executed before the main tasks in a playbook. They are defined using the pre_tasks keyword in a playbook, and they are executed before any other tasks in the playbook. Pre_tasks are useful when you need to perform certain setup or validation tasks before executing the main tasks.

For example, consider a scenario where you need to create a directory before copying files to it. You can define a pre_tasks to create the directory, and then define the main tasks to copy the files. This ensures that the directory is created before the files are copied, reducing the chance of encountering an error.

Here’s an example of how you might define a pre_tasks in a playbook:

- hosts: demo
gather_facts: yes
pre_tasks:
- name: Create the directory
file:
path: /tmp/mydir
state: directory
tasks:
- name: Copy the files
copy:
src: /path/to/src
dest: /tmp/mydir

In this example, the pre_tasks creates the directory /tmp/mydir before the main tasks are executed.

What are Post_tasks in Ansible?

Post_tasks are tasks that are executed after the main tasks in a playbook. They are defined using the post_tasks keyword in a playbook, and they are executed after all the other tasks in the playbook. Post_tasks are useful when you need to perform certain cleanup or validation tasks after executing the main tasks.

For example, consider a scenario where you need to delete a temporary file after executing some tasks. You can define a post_tasks to delete the file, and then define the main tasks to perform the actions. This ensures that the file is deleted after the main tasks are executed, reducing the chance of encountering an error.

Here’s an example of how you might define a post_tasks in a playbook:

- hosts: demo
gather_facts: yes
tasks:
- name: Perform the main tasks
<insert main tasks here>
post_tasks:
- name: Delete the temporary file
file:
path: /tmp/tempfile
state: absent

In this example, the post_tasks deletes the file /tmp/tempfile after the main tasks are executed.

Finally, Pre_tasks and post_tasks are important features in Ansible that allow you to execute certain tasks before or after the main tasks in a playbook. They are useful for performing setup and cleanup tasks, and for performing other actions that need to be executed before or after the main tasks. By using pre_tasks and post_tasks in your playbooks, you can simplify the management and maintenance of your playbooks, and make it easier for others to understand and use your playbooks.

Vault in ansible:

You may store private data, including API keys, certificates, and passwords, using Ansible’s Vault functionality. This sensitive data is protected with encryption by Vault, which encrypts it using AES-256. This implies that even if a hacker manages to access the vault files, they won’t be able to access the private information stored within.

There are several applications for vault in Ansible. It may be used to store API keys, database login information, or even complete configuration files that contain sensitive information. Additionally, you may use it to store encrypted files or strings in variables that you can utilise in your playbooks.

You must first use the ansible-vault create command to generate an encrypted file before you can utilise vault in Ansible. The data in the vault file will then be encrypted, and you will be required to provide a password. The ansible-vault edit command may be used to edit the vault file after it has been generated. You must input the password in order to decrypt the data and make changes to the file while editing it.

The — ask-vault-pass parameter must be used when executing an Ansible playbook that uses vault data in order to ask the user for the vault password. The — vault-password-file switch can also be used to specify a file containing the password, however doing so is not advised since it offers less security.

Using vault in an Ansible playbook would look something like this:

name: Secure task example
hosts: all
gather_facts: no
tasks:
- name: Retrieve password
vars_files:
secrets.yml

The file holding the sensitive data is referenced in vars files. With the help of the ansible-vault command, the file is encrypted. When the playbook is executed, a popup asking for the vault password will appear.

Finally, Ansible Vault is a useful tool that may assist you in safely storing sensitive information in your Ansible playbooks. Even in the case of a data breach, you can guarantee that critical information is safeguarded and secure by utilising vault. To get the most out of vault’s security features, it’s critical to utilise it properly.

Ansible Vault, which is a feature in Ansible that allows users to encrypt sensitive data, such as passwords and keys, within their playbook or inventory files.

Here are a few commonly used Ansible Vault commands and what they do:

  1. ansible-vault create <file>: This command is used to create a new encrypted file. When the file is created, you will be prompted to enter a password, which will be used to encrypt the file.
  2. ansible-vault encrypt <file>: This command is used to encrypt an existing file. If the file is already encrypted, this command will update the encryption password.
  3. ansible-vault decrypt <file>: This command is used to decrypt an encrypted file. When the file is decrypted, it will be stored in its original, unencrypted format.
  4. ansible-vault edit <file>: This command is used to edit an encrypted file. When the file is opened, it will be decrypted, allowing the user to edit its contents. Once the changes have been made, the file will be re-encrypted.
  5. ansible-vault view <file>: This command is used to view the contents of an encrypted file without making any changes. The file will be decrypted and displayed in the terminal.
  6. ansible-vault encrypt_string <string>: This command is used to encrypt a string of text. When the string is encrypted, it can be stored in a playbook or inventory file without being exposed as plain text.
  7. ansible-vault rekey <file>: This command is used to change the password used to encrypt a file. This is useful if you need to update the encryption password for security reasons.

Organizations may safeguard sensitive data within their playbooks and inventory files with Ansible Vault, ensuring that private information is shielded from unwanted access.

Examples:

$ ansible-vault encrypt test.yml
$ ansible-playbook test.yml — ask-vault-pass
$ ansible-vault edit test.yml
$ ansible-vault decrypt test.yml

  1. ansible-vault encrypt test.yml: This command is used to encrypt a file named tags.yml using Ansible Vault. This ensures that the sensitive data stored within the file is protected and encrypted.
  2. ansible-playbook test.yml --ask-vault-pass: This command is used to run an Ansible playbook named tags.yml, and the --ask-vault-pass flag is used to prompt the user for the vault password. The playbook will only run if the correct vault password is provided.
  3. ansible-vault edit test.yml: This command is used to edit a file that has been encrypted with Ansible Vault. When the file is opened, it will be decrypted, allowing the user to edit its contents. Once the changes have been made, the file will be re-encrypted.
  4. ansible-vault decrypt test.yml: This command is used to decrypt a file encrypted with Ansible Vault. This is useful if you need to view the contents of an encrypted file without making any changes. After the file has been decrypted, it will be stored in its original, unencrypted format.

Passwordless Authentication:

Enabling passwordless authentication using SSH is a two-step process: generating an SSH key pair and then copying the public key to the remote server.

Here are the steps to generate an SSH key pair and configure passwordless authentication:

  1. Generate the SSH Key Pair: Run the following command on your local machine to generate an SSH key pair:
ssh-keygen -t rsa

This command will generate a private key (id_rsa) and a public key (id_rsa.pub) in the ~/.ssh directory.

2. Copy the Public Key to the Remote Server: Run the following command to copy the public key to the remote server:

ssh-copy-id user@remote_server_ip

Replace “user” with the username you use to log into the remote server, and “remote_server_ip” with the IP address of the remote server.

3. Verify the Configuration: To verify the configuration, try to log in to the remote server without a password:

ssh user@remote_server_ip

If you are able to log in without being prompted for a password, then passwordless authentication is enabled and configured correctly.

Note: You can also copy the contents of the public key to the ~/.ssh/authorized_keys file on the remote server manually, but using ssh-copy-id is the recommended method.

Script to determine how long it took:

Here’s an example of a bash script that can be used to measure the time taken to run a role in Ansible:

#!/bin/bash

# start the timer
start=$(date +%s)

# run the ansible role
ansible-playbook -i inventory.ini playbook.yml --limit=server --tags=my_role

# stop the timer
end=$(date +%s)

# calculate the elapsed time in minutes
elapsed_time=$((end-start))
elapsed_time_in_minutes=$(echo "$elapsed_time/60" | bc -l)

# print the elapsed time in minutes
echo "Elapsed time: $elapsed_time_in_minutes minutes"

In this script, the date command is used to get the current time in seconds, and then the ansible-playbook command is run with the specified role using the --tags option. After the role is run, the date command is used again to get the current time, and the difference between the two times is calculated. The difference is then divided by 60 to convert it to minutes, and the result is stored in the elapsed_time_in_minutes variable. Finally, the elapsed time in minutes is printed to the console.

MK
Mohankrishna PodileDevOps Engineer & Cloud Architect · Irving, Texas

Comments

Questions, corrections, war stories — all welcome. Sign in with GitHub to join the discussion.