Make it Reusable with Ansible Roles
Make the code base 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:
|-- roles/| |-- chocolatey/| | |-- tasks/| | | |-- main.yml| | |-- handlers/| | | |-- main.yml| | |-- files/| | |-- templates/| | |-- vars/| | | |-- main.yml| | |-- defaults/| | | |-- main.yml| | |-- meta
The highlighted lines represent the following:
- Name of the role.
- Ansible tasks and execution logic.
- Handlers for the role.
- Files required by the role, scripts, license key files, etc.
- Template files for Jinja2 templating.
- Non-overwritable variables localized to the role.
- Overwritable variables that provide defaults for the role.
- 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
- Install
Chocolatey
.- 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.
mkdir -p roles/chocolatey
Add a tasks
and files
directory within the chocolatey
directory.
mkdir roles/chocolatey/tasksmkdir roles/chocolatey/files
Within the tasks
directory, create a main.yml
playbook.
touch roles/chocolatey/tasks/main.yml
Move ChocolateyInstall.ps1
and chocolatey-core.extension.x.x.x.x.nupkg
to the files
directory.
mv ~/Downloads/ChocolateyInstall.ps1 roles/chocolatey/filesmv ~/Downloads/chocolatey-core.extension.x.x.x.x.nupkg roles/chocolatey/files
The layout should look like the one below:
|-- roles/| |-- chocolatey/| | |-- files/| | | |-- ChocolateyInstall.ps1| | | |-- chocolatey-core.extension.x.x.x.x.nupkg| | |-- tasks/| | | |-- main.yml
Default Directory
By default Ansible looks within theroles/
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.
---- name: register windows temp env varwin_shell: $env:TEMPregister: temp_outchanged_when: false- name: register windows programdata env varwin_shell: $env:ProgramDataregister: programData_outchanged_when: false
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.
- set_fact:choco_location: "{{ programData_out.stdout | trim + '\\chocolatey' }}"- set_fact:temp_location: "{{ temp_out.stdout | trim }}"
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.
- name: copy ChocolateyInstall.ps1win_copy:src: ChocolateyInstall.ps1dest: "{{ temp_location + '\\ChocolateyInstall.ps1' }}"- name: install chocolateywin_chocolatey:name: chocolateystate: presentsource: "{{ temp_location + '\\ChocolateyInstall.ps1' }}"
Copy the chocolatey-core.extension
NuGet package and install it with win_chocolatey
.
- name: copy chocolatey.extensionwin_copy:src: chocolatey-core.extension.1.3.5.1.nupkgdest: "{{ temp_location + '\\chocolatey-core.extension.1.3.5.1.nupkg' }}"tags: chocolateyExtension- name: install chocolatey.extensionwin_chocolatey:name: chocolatey-core.extensionstate: presentsource: "{{ temp_location + '\\chocolatey-core.extension.1.3.5.1.nupkg' }}"tags: chocolateyExtension
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.
--- - name: register windows temp env var win_shell: $env:TEMP register: temp_out changed_when: false - name: register windows programdata env var win_shell: $env:ProgramData register: programData_out changed_when: false - set_fact: choco_location: "{{ programData_out.stdout | trim + '\\chocolatey' }}" - set_fact: temp_location: "{{ temp_out.stdout | trim }}" - name: copy ChocolateyInstall.ps1 win_copy: src: ChocolateyInstall.ps1 dest: "{{ temp_location + '\\ChocolateyInstall.ps1' }}" - name: install chocolatey win_chocolatey: name: chocolatey state: present source: "{{ temp_location + '\\ChocolateyInstall.ps1' }}" - name: copy chocolatey.extension win_copy: src: chocolatey-core.extension.1.3.5.1.nupkg dest: "{{ temp_location + '\\chocolatey-core.extension.1.3.5.1.nupkg' }}" tags: chocolateyExtension - name: install chocolatey.extension win_chocolatey: name: chocolatey-core.extension state: present source: "{{ temp_location + '\\chocolatey-core.extension.1.3.5.1.nupkg' }}" tags: chocolateyExtension
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:
ansible-playbook site.yml -i hosts --ask-vault-pass#skip Chocolatey tasksansible-playbook site.yml -i hosts --skip-tags chocolateyExtension --ask-vault-pass
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
.
Get hands-on with 1300+ tech skills courses.