A lot relate to the proper way to define variables. You can override variables in a 22-item variable precedence list, which has a few surprises – while not explicitly stated, default variables in your role will be overridden by default variables in a role that your role calls. This can cause issues. Note also that “role vars” and “role params” are different but easily confusable.
Ansible’s tips and tricks, particularly related to the use of vaulted variables, are also useful.
Use flat objects
backups: rate: 'weekly' store: 's3'
backups_rate: 'weekly' backups_store: 's3'
Flat objects can be overridden individually more easily. The default behaviour for hashes is that a newly defined hash completely replaces the previous one, instead of merging. The can be configured at the user level, but is a global setting and can break other roles.
At the task level, you can use the combine filter to merge hashes.
Split variables across files
Ordering makes it easier to note structure at a glance. This is likely rare only because the documentation makes it hard to see this is possible:
By default Ansible will look in each directory within a role for a
main.ymlfile for relevant content (also
Fail safely when targeting specific hosts
--- - hosts: all
ansible-playbook playbook.yml --limit <target>
--- - hosts: ''
ansible-playbook playbook.yml --extra-vars target=<target>
If you mistakenly call the first without specifying a limit, you’ll run on all hosts in the inventory. If you mistakenly call the second without specifying extra vars, you won’t run at all.
If running on both Windows and Linux, partition only the different parts
Running on both Windows and Linux is uncommon, but possible. Frequently, you’ll have playbooks or roles that are almost identical except for calls out to
win_copy. Split these into their own files and call them based on either
ansible_facts['distribution'] or by noting the OS in the
hosts file – the latter being required if methods to log on are different (e.g. Windows login requires a Kerberos token and Linux login does not). You can note the OS in the host file by, for example, specifying the host under a
- name: Start deployment debug: msg: "##teamcity[blockOpened name='service-config'] description='Deployment Start'" - block: - block: - name: Install (Windows) include_tasks: windows-install.yml when: "'windows' in group_names" - block: - name: Install (Linux) include_tasks: linux-install.yml when: "'linux' in group_names" become: yes always: - name: Finish deployment debug: msg: "##teamcity[blockClosed name='service-config']"
- name: Call other role include_role: name: deploy-other-thing tasks_from: windows-deploy-other-thing - import_tasks: common.yml - name: Restart service win_service: name: "Service-Win" state: restarted
- name: Call other role include_role: name: deploy-other-thing tasks_from: linux-deploy-other-thing - import_tasks: common.yml - name: Restart service service: name: "Service-Lin" state: restarted
- name: Post a helpful message debug: msg: "Going good!"
Minimises duplication. Better still might be to have a module that can call
win_X if on Windows or
X if on Linux, but I couldn’t find one.