The following is an excerpt from Chapter 5 of Ansible for DevOps , a book on Ansible by Jeff Geerling.
Introduced in Ansible 2.0.0 (still in active development, currently in alpha), Blocks allow you to group related tasks together and apply particular task parameters on the block level. They also allow you to handle errors inside the blocks in a way similar to most programming languages' exception handling.
Here's an example playbook that uses blocks with
when
to run group of tasks specific to one platform without
when
parameters on each task:
---
- hosts: web
tasks:
# Install and configure Apache on RedHat/CentOS hosts.
- block:
- yum: name=httpd state=installed
- template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
- service: name=httpd state=started enabled=yes
when: ansible_os_family == 'RedHat'
sudo: yes
# Install and configure Apache on Debian/Ubuntu hosts.
- block:
- apt: name=apache2 state=installed
- template: src=httpd.conf.j2 dest=/etc/apache2/apache2.conf
- service: name=apache2 state=started enabled=yes
when: ansible_os_family == 'Debian'
sudo: yes
If you want to perform a series of tasks with one set of task parameters (e.g.
with_items
,
when
, or
sudo
) applied, blocks are quite handy.
Blocks are also useful if you want to be able to gracefully handle failures in certain tasks. There might be a task that connects your app to a monitoring service that's not essential for a deployment to succeed, so it would be better to gracefully handle a failure than to bail out of the entire deployment!
Here's how to use a block to gracefully handle task failures:
tasks:
- block:
- name: Shell script to connect the app to a monitoring service.
script: monitoring-connect.sh
rescue:
- name: This will only run in case of an error in the block.
debug: msg="There was an error in the block."
always:
- name: This will always run, no matter what.
debug: msg="This always executes."
Tasks inside the
block
will be run first. If there is a failure in any task in
block
, tasks inside
rescue
will be run. The tasks inside
always
will always be run, whether or not there were failures in either
block
or
rescue
.
Blocks can be very helpful for building reliable playbooks, but just like exceptions in programming languages,
block
/
rescue
/
always
failure handling can overcomplicate things. If it's easier to maintain idempotency using
failed_when
per-task to define acceptable failure conditions, or to structure your playbook in a different way, it may not be necessary to use
block
/
rescue
/
always
.
Read more about Blocks on the official Blocks documentation page .
Read Ansible for DevOps, available on LeanPub: