Use custom Ansible role templates with Molecule

Overview

Creating your own role template is a simple 3-step process:

  1. Copy molecule templates
  2. Customize them
  3. Call molecule with your templates

Copy molecule templates

The easiest way to get started is to simply copy the existing molecule template folders. They’re based on a templating system called Cookiecutter. Clone the molecule repository (or alternatively search for the templates in your local python packages path: find ${search_base} -type d -name '*cookiecutter*')

# create our template folder
CUSTOM_TEMPLATE_DIR="corp-molecule-templates"
mkdir -p "$HOME/projects/${CUSTOM_TEMPLATE_DIR}"

# copy templates
git clone https://github.com/ansible/molecule.git
cp -r ./molecule/molecule/cookiecutter "$HOME/projects/${CUSTOM_TEMPLATE_DIR}"

Customization

Then modify them as you see fit - here are a number of suggestions:

  • add company and department/team information
  • add copyright or set software license
  • add CI relevant files
  • add .gitignore file
  • offer sensible defaults for the platforms and galaxy tags in the metadata

Cookiecutter uses the file cookiecutter.json to set default values and prompts.

# cd "$HOME/projects/${CUSTOM_TEMPLATE_DIR}" && find . -name "*.json"
./cookiecutter/role/cookiecutter.json
./cookiecutter/scenario/driver/openstack/cookiecutter.json
./cookiecutter/scenario/driver/docker/cookiecutter.json
./cookiecutter/scenario/driver/azure/cookiecutter.json
./cookiecutter/scenario/driver/vagrant/cookiecutter.json
./cookiecutter/scenario/driver/delegated/cookiecutter.json
./cookiecutter/scenario/driver/gce/cookiecutter.json
./cookiecutter/scenario/driver/lxc/cookiecutter.json
./cookiecutter/scenario/driver/lxd/cookiecutter.json
./cookiecutter/scenario/driver/ec2/cookiecutter.json
./cookiecutter/scenario/verifier/goss/cookiecutter.json
./cookiecutter/scenario/verifier/inspec/cookiecutter.json
./cookiecutter/scenario/verifier/testinfra/cookiecutter.json
./cookiecutter/molecule/cookiecutter.json

Cookiecutter templates are Jinja capable which means you can modify input values (reference)…

{
  "project_name": "My New Project",
  "project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '-') }}",
  "project_slug2": "{{ cookiecutter.project_name.lower().replace(' ', '_') }}",
  "pkg_name": "{{ cookiecutter.project_slug|replace('-', '') }}"
}

… or even define collections of nested objects in your cookiecutter.json and iterate over them (reference):

{
    "project_slug": "new_project",
    "file_types": {
        "png": {
            "name": "Portable Network Graphic",
            "library": "libpng",
            "apps": [
                "GIMP"
            ]
        },
        "bmp": {
            "name": "Bitmap",
            "library": "libbmp",
            "apps": [
                "Paint",
                "GIMP"
            ]
        }
    }
}

The above file_type dictionary variable creates cookiecutter.file_types, which can be used like this:

{% for extension, details in cookiecutter.file_types|dictsort %}
<dl>
  <dt>Format name:</dt>
  <dd>{{ details.name }}</dd>

  <dt>Extension:</dt>
  <dd>{{ extension }}</dd>

  <dt>Applications:</dt>
  <dd>
      <ul>
      {% for app in details.apps -%}
          <li>{{ app }}</li>
      {% endfor -%}
      </ul>
  </dd>
</dl>
{% endfor %}

Invoke your template with Molecule

$ molecule init template --help
Usage: molecule init template [OPTIONS]

  Initialize a new role from a Cookiecutter URL.

Options:
  --url TEXT            URL to the Cookiecutter templates repository.
                        [required]
  --no-input / --input  Do not prompt for parameters and only use
                        cookiecutter.json for content. (false)
  -r, --role-name TEXT  Name of the role to create.
  --help                Show this message and exit.

A real-world invocation looks like this:

# interactive - will ask for confirmation of values defined in cookiecutter.json
molecule init template --url "$HOME/projects/${CUSTOM_TEMPLATE_DIR}/cookiecutter/role" --role-name "ansible-role-apache-permissions"

# unattended - uses the values from cookiecutter.json
molecule init template --url "$HOME/projects/${CUSTOM_TEMPLATE_DIR}/cookiecutter/role" --role-name "ansible-role-apache-permissions" --no-input

From now on, remember to use your template when working on a new role or scenario to save time and standardize your roles.