Variable Precedence in Ansible

Ansible is a powerful tool for managing infrastructure and automating tasks. It allows you to define variables that can be used throughout your playbooks and roles, making it easy to reuse configuration and logic across multiple tasks and systems. However, when using variables in Ansible, it is important to understand the order in which they are defined, as this determines which value will be used when a variable is defined multiple times. This is known as "variable precedence".

The variable precedence order in Ansible is as follows:

  1. command line values (for example, -u my_user, these are not variables)
  2. role defaults (defined in role/defaults/main.yml)
  3. inventory file or script group vars
  4. inventory group_vars/all
  5. playbook group_vars/all
  6. inventory group_vars/*
  7. playbook group_vars/*
  8. inventory file or script host vars
  9. inventory host_vars/*
  10. playbook host_vars/*
  11. host facts / cached set_facts
  12. play vars
  13. play vars_prompt
  14. play vars_files
  15. role vars (defined in role/vars/main.yml)
  16. block vars (only for tasks in block)
  17. task vars (only for the task)
  18. include_vars
  19. set_facts / registered vars
  20. role (and include_role) params
  21. include params
  22. extra vars (for example, -e "user=my_user")(always win precedence)

Variables with higher precedence will override variables with lower precedence. For example, if a variable is defined in both the inventory file and the playbook file, the value defined in the inventory file will take precedence.

Examples

Example 1: Using Extra Vars

Suppose you have a playbook that defines a variable called my_var. You can override this variable using the -e or --extra-vars option when running the playbook, like this:

ansible-playbook my_playbook.yml -e "my_var=foo"

In this case, the value of my_var will be set to foo, regardless of any other variable definitions in the playbook or role files.

Example 2: Using Role Defaults

Suppose you have a role that defines a variable called my_var in the defaults/main.yml file:

# roles/my_role/defaults/main.yml
my_var: default_value

If you use this role in a playbook and don't define my_var anywhere else in the playbook, the value of my_var will be set to default_value.

Example 3: Using Inventory Variables

Suppose you have an inventory file that defines a variable called my_var for a specific host:

# inventory/my_inventory.yml
my_host:
  my_var: host_value

If you run a playbook that uses my_host as the target, the value of my_var will be set to host_value for that host.

Example 4: Using Block Variables

Suppose you have a playbook that defines a variable called my_var within a block:

- name: My Playbook
  hosts: all
  tasks:
    - block:
        - name: Task 1
          set_fact:
            my_var: block_value
        - name: Task 2
          debug:
            var: my_var
      become: yes

In this case, the value of my_var will be set to block_value within the block, and will be available only to Task 2.

Example 5: Using Registered Variables

Suppose you have a playbook that uses the yum module to install a package, and registers the output using the register keyword:

- name: Install Package
  hosts: all
  tasks:
    - name: Install Package
      yum:
        name: my_package
        state: present
      register: install_result

    - name: Display Output
      debug:
        var: install_result

In this case, the output of the yum module is registered as install_result, and can be used in subsequent tasks in the playbook. The value of install_result will be available only to subsequent tasks in the playbook.

These examples illustrate how variable precedence works in Ansible, and how different types of variables are defined and used. By understanding the order in which variables are defined and the context in which they are used, you can ensure that your playbooks and roles are using the correct values for each variable, and avoid unexpected behaviour.