Skip to main content

Using Blocks

1. Defining Blocks

Blocks in Ansible are used to group tasks together and apply common attributes or conditions to all tasks within the block.

Attribute Description Example
block Defines the beginning of a block of tasks block:
rescue Defines a set of tasks to run if any task in the block fails rescue:
always Defines a set of tasks to run regardless of success or failure in the block always:

Example: Basic Block Definition

- name: Run tasks in a block
  block:
    - name: Task 1
      command: echo "Task 1"
    - name: Task 2
      command: echo "Task 2"
  rescue:
    - name: Handle failure
      command: echo "Rescue task"
  always:
    - name: Always run
      command: echo "Always task"

2. Grouping Tasks

Blocks in Ansible allow you to group tasks together and apply common attributes or conditions to all tasks within the block. This is useful for organizing playbooks and applying settings like when, loop, or rescue to a set of tasks.

Attribute Description Usage Example
block Defines a group of tasks to be executed together.
- name: Run tasks in a block
  block:
    - name: Task 1
      debug:
        msg: "Task 1"
    - name: Task 2
      debug:
        msg: "Task 2"
rescue Defines a set of tasks to run if any task in the block fails.
- name: Run tasks with rescue
  block:
    - name: Task that might fail
      command: /bin/false
  rescue:
    - name: Handle failure
      debug:
        msg: "Rescue task executed"
always Defines a set of tasks to run regardless of whether the block succeeded or failed.
- name: Run tasks with always
  block:
    - name: Task in block
      debug:
        msg: "Task in block"
  always:
    - name: Always run task
      debug:
        msg: "Always executed"

Example: Using Blocks with Loop and Rescue

- name: Loop through files and handle errors
  block:
    - name: Create directory if it doesn't exist
      file:
        path: /tmp/testdir
        state: directory

    - name: Create files in loop
      file:
        path: "/tmp/testdir/{{ item }}"
        state: touch
      loop:
        - file1.txt
        - file2.txt
        - file3.txt

  rescue:
    - name: Log error if any task failed
      debug:
        msg: "An error occurred while creating files"

  always:
    - name: Clean up directory
      file:
        path: /tmp/testdir
        state: absent

3. Implementing Error Handling

Action Description Example
ignore_errors Continue execution even if a task fails
- name: Run command that might fail
  command: /bin/false
  ignore_errors: yes
failed_when Custom condition to mark a task as failed
- name: Check for specific output
  command: echo "error"
  failed_when: "'error' in output"
rescue Tasks to run if a block fails
- name: Block with rescue
  block:
    - command: /bin/false
  rescue:
    - debug: msg="Rescue block executed"
always Tasks to run regardless of success or failure
- name: Block with always
  block:
    - command: /bin/false
  always:
    - debug: msg="Always runs"

Example: Using rescue and always blocks

- name: Deploy application with error handling
  hosts: web_servers
  tasks:
    - name: Start deployment
      command: /usr/bin/deploy.sh
      register: deploy_result

    - name: Validate deployment
      command: /usr/bin/validate.sh
      when: deploy_result.rc == 0
      failed_when: "'FAILED' in output"

    - name: Rollback if needed
      command: /usr/bin/rollback.sh
      rescue:
        - debug: msg="Rollback initiated"

    - name: Cleanup resources
      command: /usr/bin/cleanup.sh
      always:
        - debug: msg="Cleanup completed"
Note: The rescue and always blocks are part of the block structure and execute conditionally based on task success or failure.

Error Handling Best Practices

  • Use ignore_errors sparingly and document why
  • Implement custom failure conditions with failed_when
  • Use rescue for rollback or recovery operations
  • Utilize always for cleanup or final status reporting

4. Setting Block Variables

Variable Value Description
block_var value Defines a variable within the block scope
block_var_with_default default_value Variable with a default value if not set

Example: Setting Block Variables

- name: Set block variables
  hosts: all
  vars:
    block_var: "example_value"
    block_var_with_default: "default"
  tasks:
    - name: Use block variables
      debug:
        msg: "{{ block_var }} and {{ block_var_with_default }}"

5. Applying Block Conditions

Condition Type Description Usage Example
when Applies a condition to a block of tasks
- name: Run task only if variable is set
  debug:
    msg: "Variable is set"
  when: some_var is defined
loop Iterates over a list or set of items within a block
- name: Process each item in list
  debug:
    msg: "Processing {{ item }}"
  loop: "{{ my_list }}"
rescue Executes a block only if the main block fails
- name: Main task block
  command: /bin/false
  ignore_errors: yes

- name: Rescue block if main fails
  debug:
    msg: "Main task failed"
  rescue:
    - debug:
        msg: "Executing rescue block"
always Executes a block regardless of success or failure
- name: Main task
  debug:
    msg: "Running main task"

- name: Always execute this block
  debug:
    msg: "Cleanup or final steps"
  always:
    - debug:
        msg: "Always runs"

Example: Using when with block conditions

- name: Conditional block execution
  hosts: all
  tasks:
    - name: Set variable based on OS
      set_fact:
        os_type: "{{ ansible_facts['os_family'] }}"
      when: ansible_facts is defined

    - name: Execute tasks only on Linux
      debug:
        msg: "Running on Linux"
      when: os_type == 'Linux'
Note: The when condition can be used at any level in Ansible, including inside blocks to control task execution based on variable or fact values.

6. Using Block Tags

Tag Description Usage
block Defines a block that can be overridden by roles or other playbooks block: followed by a list of tasks
rescue Defines a set of tasks to run if the main block fails rescue: followed by a list of tasks
always Defines a set of tasks to run regardless of success or failure always: followed by a list of tasks

Example: Using block tags in a playbook

- name: Example using block tags
  hosts: all
  tasks:
    - name: Main block
      block:
        - shell: echo "Running main task"
        - debug: msg="Main task completed"
      rescue:
        - debug: msg="Rescue block executed due to failure"
      always:
        - debug: msg="Always block executed"
Note: The rescue and always blocks are optional and can be omitted if not needed.

7. Setting Block Delegation

Block delegation in Ansible allows you to control how blocks are executed, particularly useful for conditional execution and error handling. You can configure delegation using the delegate_to and delegate_facts keywords.

Parameter Description Values
delegate_to Specifies the host to run the block on hostname, localhost, or inventory_hostname
delegate_facts Controls whether facts are delegated to the target host true, false

Example: Delegating a block to localhost

- name: Run a block on localhost
  hosts: all
  tasks:
    - name: Execute commands on localhost
      delegate_to: localhost
      delegate_facts: true
      command: whoami
Note: When using delegate_to, ensure that the target host is reachable and has appropriate permissions to execute the tasks.

8. Executing Rescue Tasks

Property Description Example
rescue Defines a block of tasks to run if any task in the always or main block fails.
- name: Run tasks with rescue
  hosts: all
  tasks:
    - name: Main task
      command: /bin/false
    - name: Rescue task
      rescue:
        - debug:
            msg: "Rescue task executed"
always Defines a block of tasks to run regardless of success or failure in the main or rescue blocks.
- name: Always run tasks
  hosts: all
  tasks:
    - name: Main task
      command: /bin/false
    - name: Always task
      always:
        - debug:
            msg: "Always executed"

Example: Rescue task execution flow

- name: Example with rescue and always
  hosts: localhost
  tasks:
    - name: Fail task to trigger rescue
      command: /bin/false
    - name: Rescue block
      rescue:
        - debug:
            msg: "This runs only if main fails"
    - name: Always block
      always:
        - debug:
            msg: "This runs regardless"

9. Ensuring Cleanup

Example: Using block with cleanup

- name: Ensure cleanup after task
  hosts: all
  tasks:
    - name: Create temporary file
      copy:
        content: "temp data"
        dest: "/tmp/tempfile.txt"

    - name: Use block with cleanup
      block:
        - name: Do some work
          command: echo "working"
        - name: Fail task
          command: false
      rescue:
        - name: Cleanup temp file
          file:
            path: "/tmp/tempfile.txt"
            state: absent
Property Description Values
block Group of tasks to execute together list of task objects
rescue Tasks to run if any task in block fails list of task objects
always Tasks to run regardless of block success/failure list of task objects
Note: The rescue block runs only if a task in the block fails. The always block runs regardless of success or failure.

Block Execution Flow

  • Execute tasks in block
  • If any task fails, execute tasks in rescue
  • Execute tasks in always (regardless of outcome)

10. Nesting Blocks

Blocks can be nested inside other blocks to organize complex logic and reuse templates. This is particularly useful for managing conditional workflows or repeating structures.

Block Type Description Usage Example
block Defines a reusable block of tasks that can be included in other blocks or playbooks.
block:
  - name: Task inside block
    debug:
      msg: "This task is in a block"
rescue Defines a set of tasks to run if any task in the main block fails.
rescue:
  - name: Handle failure
    debug:
      msg: "A task failed in the main block"
always Defines a set of tasks to run regardless of whether the main block or rescue block succeeded.
always:
  - name: Cleanup tasks
    debug:
      msg: "Cleanup after block execution"

Example: Nested Block Usage

- name: Example of nested blocks
  block:
    - name: Main task inside block
      debug:
        msg: "Running main tasks"

    - name: Another task in the same block
      debug:
        msg: "Another task in the main block"

    rescue:
      - name: Handle failure in nested block
        debug:
          msg: "Rescuing from error in nested block"

    always:
      - name: Always run in nested block
        debug:
          msg: "Always running after nested block"
Note: Nested blocks can be deeply nested, but it's recommended to keep nesting levels shallow for better readability and maintainability.

11. Using any_errors_fatal

The any_errors_fatal directive in Ansible controls how the playbook behaves when a task fails. When set to true, it causes the playbook to stop executing immediately upon encountering any failure, regardless of whether the task is part of a loop or conditional block.

Directive Values Description
any_errors_fatal true | false If set to true, stops playbook execution on any task failure.

Example: Using any_errors_fatal at playbook level

---
- name: Example Playbook with any_errors_fatal
  hosts: all
  any_errors_fatal: true
  tasks:
    - name: Task that might fail
      command: /bin/false
    - name: This task will not run if previous fails
      debug:
        msg: "This is skipped"
Note: Setting any_errors_fatal to true affects the entire playbook and overrides any ignore_errors settings on individual tasks.

Was this article helpful?