A guide on how to write effective and fault tolerant Ansible code.
Ansible code convention:
- Descriptions are not capitalized
- name: ensuring something- The indentation is 2 (two) spaces, for vim you can use vim-ansible-yaml
- Use dict notation, not in-line, this prevents errors later on, example:
bad: this=command
good:
this: command- When a module does require '=' parameters, use the following:
moduleX:
args:
var: 'something'- When a module does call something using '=' parameters, use the following:
moduleX: >
var='something'- Playbooks should be used for role assignments.
- Use tagging to call a role:
roles:
- { role: myrole, tags: ['myrole', 'optional_alias_myrole'] }- Roles should be used for functional blocks.
- All templates must contain a
{{ ansible_managed }}header. - Ensure
ansible_managedheader is statically set inansible.cfgor it breaks idempotency. - Every role has a self documenting
defaults/main.ymlfile that contains all set-able variables. - All variables in the role scope must be named
role_variablewith the option of spaces being replaced by_hyphens. - The use of dict style variable settings
role.variableis discouraged as it complicates overriding. - Every variable on a new line for readability.
- Role must be a complete basic implementation without requiring further variables.
- Role must be idempotent, meaning: including the role must result in OK, not changed or error when nothing has been changed on the target host.
- Try to stow everything in
main.yml, only use include when it makes sense, which is:- when you need to support multiple platforms, then include each in
main.yml
- when you need to support multiple platforms, then include each in
- Use of comments indicate bad code.
- All templates must contain a
- Completeness (especially idempotency) on the target platform is preferred over portability when starting out a new role.
- Don't use:
backup: yes, rely on git instead!
General rule for when conditions is that variables do not have to be surrounded like {{ var }}. Below are some general use-cases for when conditions:
- When dealing with multiple suitors for a single condition:
- set_fact:
hello: 'world'
- name: do task
command: echo hello world!
when:
- hello | intersect( ['world', 'universe'] )- When dealing with multiple
whenconditions that need to match in anORfashion:
- name: do task
command: echo hello world!
when:
- ((skip_install != True) or (ansible_os_family == 'Debian'))- When dealing with multiple
whenconditions that need to match in anANDfashion:
- name: do task
command: echo hello world!
when:
- (skip_install != True)
- (ansible_os_family == 'Debian')
- (command_result.changed == True)