Ansible Coding Style

To make collaboration easier, we document some rules we want to follow when creating Ansible Playbooks and Roles.

Playbooks

Playbooks have to written to be called by either an automation controller Job Template or from the command line.

Environment Variables (e.g. for Cloud Credentials) are stored in a sub folder “environments” at the root level of the project.

Project Naming conventions

Projects in this group follow these recommendations:

  • Ansible role: role-xyz

  • Ansible collection: collection-xyz

  • Ansible Playbook: playbook-xyz

Variables

Task names

Tasks names should be short and descriptive. We want to use upper case characters and describe what the task will do, for example:

Good

- name: Install package httpd
- name: Enable HTTP firewall rule
- name: Start and enable service httpd

Bad

- name: check httpd is installed # use upper case instead, don't say "check", say "install httpd" instead
- name: Job Template - Apache # instead use something like "Create Job Template Apache"

Role Defaults

Roles have reasonable defaults set. Variables which have to be set, but defaults are not applicable, are verified by using ‘assert’ checks (for example unique instance names, IP Addresses, passwords, … ).

Variable names

Variables should start with a prefix identifying the application or service they are used for. e.g. variables used by automation controller should be prefixed with controller_, variables for Google Cloud with gcp_. Also we should refrain from using acronyms in variable names unless they are very well known (like HTTP, YML, or IPv4). Since all modern Code Editors provide ways of automatic completion there is no gain in forcing short variable names.

Good

A few good variable names:

controller_gcp_username: # the user name for GCP
controller_http_port: # the web server port
gcp_template: # the name of the instance template
gcp_region: # the region to use
gcp_zone: # and the zone

Bad

Those would be bad choices:

usr: # the user name for GCP
controller_user: # the user name for GCP
tgu: # the user name for GCP
controller_http: # the web server port
tpl: # the name of the instance template
region: # the region to use
gzone: # and the zone

Use Cases

The content provided in this project should be modular when it makes sense. We introduce the concept of “Use Cases” which allows the end user to deploy additional optional features. Use Cases should be used if one or all of the the following criteria are met:

  • enabling the use case causes additional cost, e.g. it requires additional VMs or instances (for example the Satellite Use Case is quite expensive)

  • it causes significant additional deployment time, e.g. the Playbook deploying the Use Case runs for additional several minutes

  • it introduces a conflict, e.g. Use Case A and Use Case B can not be enabled at the same time

When none of the above criteria applies, the necessary tasks should be in a separate task file or role, but within the existing structure.

Collection dependencies

When using Ansible Collections we use version pinning to provide stable, reliable and predictable deployments. Playbooks and rules which require Ansible Collections should use the collections/requirements.yml file to list their dependencies. These files should not list or pin to any particular version of the collections. All version pinning is consolidated in the EE definition. This simplifies dependency management by consolidating version pinning in one file.

To keep track of Ansible Collection dependencies, we use renovate which provides automatic scan for outdated Collections. Currently renovate can only scan Ansible Galaxy though and therefore sometimes creates Merge Requests for Collections not yet available on Automation Hub.

When reviewing the automatically generated Merge Requests, manual checks have to be used to make sure the Collections is in fact available on Automation Hub or the automatic build of the execution environment will fail.