Ansible blocks allow you to group multiple tasks together within a playbook. This grouping makes it easier to apply common directives (like when, become, or ignore_errors) to all tasks within the block. Additionally, blocks can be used for error handling, similar to try-except blocks in programming languages like Python or Java.
Basic Structure of an Ansible Block
Here’s a simple structure of how to use a block:
- name: Example of a block in Ansible
hosts: all
become: yes # Apply become to all tasks in the playbook
tasks:
- name: Block of tasks
block:
- name: Task 1
debug:
msg: "This is Task 1"
- name: Task 2
debug:
msg: "This is Task 2"
This creates a block containing two tasks: Task 1 and Task 2. The tasks inside the block are executed sequentially.
Example 1: Grouping Tasks Under One Block
Let’s assume you have multiple tasks to install software packages. Instead of writing them individually, you can group them in a block for better organization.
- name: Install Web Server Packages
hosts: web
become: yes
tasks:
- name: Install web server packages
block:
- name: Install nginx
apt:
name: nginx
state: present
- name: Install apache2
apt:
name: apache2
state: present
In this example:
- nginx and apache2 will be installed on the target
webhosts. - The block groups the two tasks, so you can easily apply additional attributes like
when,become, etc., to both tasks in one place.
Example 2: Conditional Execution Using when
You can apply conditions to entire blocks. For example, if you want to install packages only if the operating system is Debian, you can use the when directive at the block level:
- name: Install Web Server on Debian
hosts: web
become: yes
tasks:
- name: Install web server packages on Debian
block:
- name: Install nginx
apt:
name: nginx
state: present
- name: Install apache2
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"
In this example:
- The block will only run if the host’s OS family is Debian.
- If the host is not Debian (e.g., Ubuntu or RedHat), the block will be skipped.
Example 3: Error Handling with rescue
You can use rescue within a block to handle errors if any task fails. The tasks inside rescue will be executed only if one of the tasks in the block fails. Let’s look at an example:
- name: Handle Errors in a Block
hosts: web
become: yes
tasks:
- name: Block with error handling
block:
- name: Task 1 (Will succeed)
command: /bin/true
- name: Task 2 (Will fail)
command: /bin/false
rescue:
- name: Handle the failure
debug:
msg: "One of the tasks in the block failed."
In this example:
- Task 1 runs successfully (
/bin/true). - Task 2 fails (
/bin/false). - Since Task 2 fails, the rescue section will be executed, and the message “One of the tasks in the block failed.” will be printed.
Example 4: Always Execute a Task with always
The always directive allows you to define tasks that should run no matter what—whether the block succeeds or fails. Here’s an example combining block, rescue, and always:
- name: Block with Rescue and Always
hosts: web
become: yes
tasks:
- name: Task block with rescue and always
block:
- name: Task 1 (Will succeed)
command: /bin/true
- name: Task 2 (Will fail)
command: /bin/false
rescue:
- name: Handle error
debug:
msg: "There was a failure in the block"
always:
- name: Always run task
debug:
msg: "This task always runs, regardless of success or failure"
In this example:
- Task 1 runs successfully.
- Task 2 fails.
- The rescue section is triggered, printing
"There was a failure in the block" - Regardless of success or failure, the always task will execute, printing “This task always runs, regardless of success or failure”.
Example 5: Asynchronous Task with Block and Notification
Blocks can also be used with asynchronous tasks (tasks that run in the background). Here’s an example where we create a backup asynchronously and send an email if it takes too long or fails:
- name: Backup Task with Timeout and Email Notification
hosts: all
become: yes
tasks:
- name: Create Backup of /var Directory
block:
- name: Start backup process (asynchronous)
command: tar czf /tmp/var_backup.tar.gz /var
async: 60 # Run asynchronously with a 60-second timeout
poll: 0 # Don't wait for it to complete
register: backup_result
- name: Wait for the backup to finish
async_status:
jid: "{{ backup_result.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 3 # Retry 3 times
delay: 10 # Wait 10 seconds between retries
rescue:
- name: Send email if backup fails
mail:
host: "smtp.example.com"
to: "[email protected]"
subject: "Backup Failure"
body: "Backup process failed or took too long."
Explanation:
- The block starts a backup process using the tar command. This runs asynchronously and is given 60 seconds to finish (
async: 60). - We then use
async_statusto check if the backup has completed. - If the backup takes longer than expected or fails, the rescue section sends an email to the administrator.
By experimenting with the examples above, you’ll get a solid understanding of how to use blocks in Ansible. You can try applying these techniques in your own playbooks to see how they work in real-world scenarios.



