Make it Reusable with Ansible Roles

As time goes on, your playbooks will grow to an unwieldy size, and you will need to refactor the code into separate logical groupings. At the same time, you’ll likely create additional Ansible repositories. Ansible roles are the solution.

Ansible roles simplify writing complex playbooks by breaking them into multiple files and providing a framework for developing a fully independent collection of variables, tasks, files, templates, and modules. The result is a reusable code base that can be shared among playbooks and repositories.

The directory structure will look like the one below:

Directory structure

The highlighted lines represent the following:

  1. Name of the role.
  2. Ansible tasks and execution logic.
  3. Handlers for the role.
  4. Files required by the role, scripts, license key files, etc.
  5. Template files for Jinja2 templating.
  6. Non-overwritable variables localized to the role.
  7. Overwritable variables that provide defaults for the role.
  8. Metadata information about the role.

Roles expect files to be in specific directories. Each directory is optional. You can exclude any of the directories that are not in use.

Create an Ansible role#

Scenario#

Create an Ansible Role for Chocolatey.

Tasks#

  1. Install Chocolatey.
  2. Install Chocolatey Core Extensions.

Files#

Use the following files to install chocolatey on your remote Windows host.

Within the configure_iis_web_server.yml playbook, there is a task that installs a DotNet core. The task uses Chocolatey for the install. As a prerequisite, it also installs Chocolatey on the remote host.

Having the install dotnet task install Chocolatey works, but it doesn’t accurately define your configuration, and it isn’t explicit. Instead, it is implicit, which requires mental gymnastics when troubleshooting, and is something to be avoided.

Also, you’ll be installing Chocolatey across your entire environment. For that reason, it makes sense to modularize that configuration. Installing Chocolatey is an excellent opportunity for using a role.

Create the role directory structure#

The Ansible role framework includes many directories to separate the different logic within a playbook.

Let’s start with the minimal directories you need. By default, Ansible looks within the roles/ directory relative to the playbook file for roles to use.

Review commands
We have already executed the commands and created the directories and files to save you from the hassle. You can review the commands to set up the structure below.

Create a directory named chocolatey within the roles directory.

Create chocolatey directory

Add a tasks and files directory within the chocolatey directory.

Create tasks and files directories

Within the tasks directory, create a main.yml playbook.

Create main.yml file

Move ChocolateyInstall.ps1 and chocolatey-core.extension.x.x.x.x.nupkg to the files directory.

Move the downloaded files

The layout should look like the one below:

roles layout

Default Directory
By default Ansible looks within the roles/ directory, relative to the playbook file, or the /etc/ansible/roles directory.

Write the role tasks#

There are two tasks to install Chocolatey:

  • Install Chocolatey.
  • Install chocolatey.core.extension.

Each of these tasks must be automated with Ansible within the /tasks/main.yml playbook.

Create two tasks that register Ansible variables for the Windows $env:TEMP and $env:ProgramData environment variables. These temporary locations will be used for storing the downloads. ProgramData is the default Chocolatey location and will be used to copy the license.

tasks/main.yml register environment variables

The tasks/main.yml does not require a hosts list or a tasks list. The hosts are provided when you call the role from another playbook, and a tasks list isn’t necessary because of the naming of the directory the file is in.

The win_shell module is an Ansible module that executes cmd and PowerShell commands. Using this module, you output the required environment variables and register them as Ansible variables using the register parameter.

A problem with win_shell is it will return a status of changed each time it runs.

Use changed_when to modify that behavior. Setting changed_when to false will ensure the win_shell module always returns OK, which is a more accurate representation of what it is doing. Since it’s just querying environment variables, it doesn’t change anything on the host.

Use the registered variables to set facts for file locations.

tasks/main.yml set facts

Use set_fact to modify the Ansible variables by trimming the trailing \\ from the string and adding \\chocolatey to the choco_location variable.

Copy ChocolateyInstaller.ps1 to the remote Windows host and run the script.

tasks/main.yml install Chocolatey

Copy the chocolatey-core.extension NuGet package and install it with win_chocolatey.

tasks/main.yml install chocolatey.extension

Using win_chocolatey to execute the nugget package provides an idempotent task. By default, win_chocolatey verifies if the package is already installed. If it is, it skips the install.

This is a good example of when it’s best not to use win_shell. Certainly, win_shell is a simple way to get things done. However, avoid relying on it when other modules are available.

Add roles to the site#

Roles cannot be executed without a playbook calling them. By design, the tasks/main.yml does not include a hosts list. This is because the playbook calling the roles provides that information.

Update the site.yml to apply for the chocolatey role against the windows group. Define a new playbook with a hosts list and use the roles parameter to call the Chocolatey role.

This code requires the following environment variables to execute:
AWS_Linux_EC2_Instance_DNS_Name
Not Specified...
AWS_Windows_EC2_Instance_DNS_Name
Not Specified...
Azure_Linux_VM_Instance_DNS_Name
<Linux>
Azure_Windows_VM_Instance_DNS_Name
<Windows>
/
roles
group_vars
windows.yml
linux.yml
configure_nginx_web_server.yml
configure_iis_web_server.yml
site.yml
index.html
Ansible roles

Order is everything in Ansible. The role must be added before the configure_iis_web_server.yml playbook runs. If it doesn’t, the DotNet task will attempt to install Chocolatey.

Update the <Password> with the password created using the ansible-vault command in the group_vars/linux.yml and group_vars/windows.yml files.

Click on the Run button, wait for the environment to set up, and execute the site.yml playbook to configure the web servers using the following command:

Execute the playbook

gather_facts: false
gather_facts: false turns off remote host fact gathering. When this is enabled it queries the remote system for specific details about the host and populates variables that Ansible can use.

In this lesson, we introduced roles, roles directory layout, and you created your first role, called chocolatey.

Build a Site
Decoupling Ansible Roles
Mark as Completed
Report an Issue