Ansible: Loops and Conditionals
Remarks#
Official docs explains playbook conditionals.
Ansible (github)
What kinds of conditionals to use?
Use Conditionals via (syntax is in [brackets]
):
-
when [when:]
Task: - name: run if operating system is debian command: echo "I am a Debian Computer" when: ansible_os_family == "Debian"
-
loops [with_items:]
-
loops [with_dicts:]
-
Custom Facts [ when: my_custom_facts == ‘1234’]
-
Conditional imports
-
Select files and Templates based on variables
[When] Condition: ansible_os_family
Lists
Common use
- when: ansible_os_family == “CentOS”
- when: ansible_os_family == “Redhat”
- when: ansible_os_family == “Darwin”
- when: ansible_os_family == “Debian”
- when: ansible_os_family == “Windows”
All Lists
based on discuss here https://comments.gmane.org/gmane.comp.sysutils.ansible/4685
OS_FAMILY = dict(
RedHat = 'RedHat',
Fedora = 'RedHat',
CentOS = 'RedHat',
Scientific = 'RedHat',
SLC = 'RedHat',
Ascendos = 'RedHat',
CloudLinux = 'RedHat',
PSBM = 'RedHat',
OracleLinux = 'RedHat',
OVS = 'RedHat',
OEL = 'RedHat',
Amazon = 'RedHat',
XenServer = 'RedHat',
Ubuntu = 'Debian',
Debian = 'Debian',
SLES = 'Suse',
SLED = 'Suse',
OpenSuSE = 'Suse',
SuSE = 'Suse',
Gentoo = 'Gentoo',
Archlinux = 'Archlinux',
Mandriva = 'Mandrake',
Mandrake = 'Mandrake',
Solaris = 'Solaris',
Nexenta = 'Solaris',
OmniOS = 'Solaris',
OpenIndiana = 'Solaris',
SmartOS = 'Solaris',
AIX = 'AIX',
Alpine = 'Alpine',
MacOSX = 'Darwin',
FreeBSD = 'FreeBSD',
HPUX = 'HP-UX'
)
When Condition
Basic Usage
Use the when condition to control whether a task or role runs or is skipped. This is normally used to change play behavior based on facts from the destination system. Consider this playbook:
- hosts: all
tasks:
- include: Ubuntu.yml
when: ansible_os_family == "Ubuntu"
- include: RHEL.yml
when: ansible_os_family == "RedHat"
Where Ubuntu.yml
and RHEL.yml
include some distribution-specific logic.
Another common usage is to limit results to those in certain Ansible inventory groups. Consider this inventory file:
[dbs]
mydb01
[webservers]
myweb01
And this playbook:
- hosts: all
tasks:
- name: Restart Apache on webservers
become: yes
service:
name: apache2
state: restarted
when: webservers in group_names
This is using the group_names
magic variable.
Conditional Syntax and Logic
Single condition
Syntax
when: (condition)
Example
when: ansible_os_family == "Debian"
when: ansible_pkg_mgr == "apt"
when: myvariablename is defined
Boolean Filter
Example
when: result|failed
Multiple Conditions
Syntax
When: condition1 and/or condition2
Example (simple)
when: ansible_os_family == "Debian" and ansible_pkg_mgr == "apt"
Example (complex)
Use parentheses for clarity or to control precedence. “AND” has a higher precedence than “OR”.
Clauses can span lines:
when:
ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and
(ansible_distribution_version|version_compare('7', '<') or
ansible_distribution_version|version_compare('8', '>='))
or
ansible_distribution == 'Fedora'
or
ansible_distribution == 'Ubuntu' and
ansible_distribution_version|version_compare('15.04', '>=')
Note the use of parentheses to group the “or” in the first distribution check.
Get ansible_os_family
and ansible_pkg_mgr
with setup
We can get facts (ansible_os_family
, ansible_pkg_mgr
) with Ad-Hoc command of setup module and filter.
-
ansible_os_family:
$ ansible all -m setup -a 'filter=ansible_os_family' ra.local | SUCCESS => { "ansible_facts": { "ansible_os_family": "Debian" }, "changed": false }
-
ansible_pkg_mgr:
$ ansible all -m setup -a 'filter=ansible_pkg_mgr' debian.local | SUCCESS => { "ansible_facts": { "ansible_pkg_mgr": "apt" }, "changed": false }
Simple “When” Example(s)
Given:
---
variable_name: True
Then, these tasks with always run.
- name: This is a conditional task
module: src=/example/ dest=/example
when: variable_name
- name: This is a conditional task
module: src=/example/ dest=/example
when: True
This task will never run.
- name: This is a conditional task
module: src=/example/ dest=/example
when: False
Using until for a retry looping alive check
This is an example of using until/retries/delay to implement an alive check for a webapp that is starting up. It assumes that there will be some period of time (up to 3 minutes) where the webapp is refusing socket connections. After that, it checks the /alive page for the word “OK”. It also delegates the retrieval of the URL to the localhost running ansible. This makes sense as the final task in a deployment playbook.
---
- hosts: my-hosts
tasks:
- action: uri url=https://{{ ansible_all_ipv4_addresses }}:8080/alive return_content=yes
delegate_to: localhost
register: result
until: "'failed' not in result and result.content.find('OK') != -1"
retries: 18
delay: 10
The until retry pattern can be used with any action; Ansible documentation provides an example of waiting until a certain shell command returns a desired result: https://docs.ansible.com/ansible/playbooks_loops.html#do-until-loops.