Within Ansible there are two techniques for reusing a set of configuration management tasks, includes and roles. Although both techniques function in similar ways, roles appear to be the official way forward. Ansible Galaxy was built as a repository for roles, and as we’ll see in this post, ansible-galaxy
exists to aid in installing and creating them.
Creating a New Role
Let’s start off by creating a role for Packer.
Packer is a useful tool for producing different machine image types with the same set of configuration management tasks. For example, Packer can be used to take a set of Ansible instructions, funnel them through itself, and produce both an AMI and Docker image.
Enough about Packer though, let’s get back to creating an Ansible role for installing Packer.
The first step in creating a role is creating its directory structure. In order to create the base directory structure, we’re going to use a tool bundled with Ansible (since 1.4.2) called ansible-galaxy
:
$ ansible-galaxy init azavea.packer azavea.packer was created successfully
That command will create an azavea.packer
directory with the following structure:
├── README.md ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates └── vars └── main.yml
Explaining the Role Directory Structure
A role’s directory structure consists of defaults
, vars
, files
, handlers
, meta
, tasks
, and templates
. Let’s take a closer look at each:
defaults
Within defaults
, there is a main.yml
file with the default variables used by a role. For the Packer role, there is only a packer_version
default variable. As of this post, the most recent version of Packer is 0.7.1
, so we’ll set it to that:
--- packer_version: "0.7.1"
vars
vars
and defaults
house variables, but variables in vars
have a higher priority, which means that they are more difficult to override. Variables in defaults
have the lowest priority of any variables available, which means they’re easy to override. Placing packer_version
in defaults
instead of vars
is desirable because now it is easier to override when you want to install an older or newer version of Packer:
--- - hosts: all sudo: yes roles: - { role: "azavea.packer", packer_version: "0.7.0" }
All of that said, we’re set with packer_version
in defaults
, so the vars
directory is not needed either.
files
files
is where you put files that need to be added to the machine being provisioned, without modification. Most of the time, files in files
are referenced by copy
tasks.
The Packer role has no need for files
, so we’ll delete that directory.
handlers
handlers
usually contain targets for notify
directives, and are almost always associated with services. For example, if you were creating a role for NTP, you might have an entry in handlers/main.yml
for restarting NTP after a task finishes altering the NTP configuration file.
Packer isn’t a service, so there is no need for the handlers
directory.
meta
meta/main.yml
houses one of the biggest differences between includes from roles: metadata. The metadata of an Ansible role consists of attributes such as author
, supported platforms
, and dependencies
. Most of this file is commented out by default, so I usually go through and fill in or uncomment relevant attributes, then delete anything else.
For the Packer role, I trimmed things down to:
--- galaxy_info: author: Hector Castro description: An Ansible role for installing Packer. company: Azavea Inc. license: Apache min_ansible_version: 1.2 platforms: - name: Ubuntu versions: - trusty categories: - cloud - system dependencies: - { role: "azavea.unzip" }
Ignore the dependencies
bit for right now. We’ll come back to it later.
tasks
tasks
houses a series of Ansible plays to install, configure, and run software. For Packer, we need to download a specific version, and since it’s packaged as a compiled binary in a ZIP archive, extract it. Accomplishing that with Ansible’s built-in get_url
and unarchive
modules looks like this:
--- - name: Download Packer get_url: > url=https://dl.bintray.com/mitchellh/packer/packer_{{ packer_version }}_linux_amd64.zip dest=/usr/local/src/packer_{{ packer_version }}_linux_amd64.zip - name: Extract and install Packer unarchive: src=/usr/local/src/packer_{{ packer_version }}_linux_amd64.zip dest=/usr/local/bin copy=no
templates
templates
is similar to files
except that templates
support modification as they’re added to the machine being provisioned. Modifications are achieved through the Jinja2 templating language. Most software configuration files become templates
.
Packer takes most of its configuration parameters via command-line arguments, so the templates
directory is not needed.
Conclusion
Congratulations! You now have all of the components necessary for an Ansible role.
In part two of this series, we’ll take a look at creating a small playbook to apply the role against a local virtual machine. We’ll also take a closer look at the dependencies
listed in the role metadata.