How to Unset/Reset Variables Between Ansible Roles to Prevent Value Leakage


1 views

When running multiple Ansible roles sequentially, variables can persist between role executions unless explicitly cleared. This behavior becomes problematic when:

  • Roles share common variable names (like version)
  • Some roles should use default values
  • Previous role assignments might interfere with subsequent roles

Consider this playbook structure:

roles:
  - { role: mysql, version: "5.7" }
  - { role: rabbitmq } # Should use default version

The version value from mysql (5.7) will persist when rabbitmq runs, potentially causing incorrect installations.

1. Explicit Variable Unsetting

Add this task at the end of each role:

- name: Reset version variable
  set_fact:
    version: ""

2. Role-Specific Variable Scoping

Prefix variables with role names:

roles:
  - { role: mysql, mysql_version: "5.7" }
  - { role: rabbitmq, rabbitmq_version: "" }

3. Using Default Filters

Modify your role templates to explicitly handle undefined cases:

version: "{{ version | default(omit) }}"

Create a custom role for variable management:

- name: Clean variables between roles
  hosts: localhost
  tasks:
    - name: Flush all temporary facts
      set_fact:
        version: null
      delegate_to: localhost
      run_once: true

For production environments, I recommend combining solutions:

  1. Use role-specific variable names (mysql_version, rabbitmq_version)
  2. Implement default filters in templates
  3. Add explicit cleanup tasks for shared variables

This approach provides both immediate resolution and long-term maintainability.


When working with multiple Ansible roles that use the same variable names, you might encounter situations where variable values persist unexpectedly between role executions. This commonly occurs with frequently-used variable names like version, port, or config_path.

# Problem scenario example
roles:
  - { role: mysql, version: "8.0" }
  - { role: rabbitmq }  # Accidentally inherits mysql's version

1. Explicitly Undefining Variables

The most straightforward method is using the set_fact module to nullify the variable:

- name: Reset version variable
  set_fact:
    version: ~
  when: version is defined

2. Role-Specific Variable Scoping

Ansible 2.8+ provides better namespace control with vars:

roles:
  - role: mysql
    vars:
      version: "8.0"
  - role: rabbitmq
    vars:
      version: ""  # Explicit empty value

3. Using Blocks for Isolation

Block-level variable scoping can create clean separation:

- block:
    - include_role:
        name: mysql
    vars:
      version: "5.7"
  rescue:
    - debug:
        msg: "MySQL installation failed"

- block:
    - include_role:
        name: rabbitmq
  vars:
    version: ""  # Reset between blocks

For complex scenarios, consider pre-task cleanup:

- name: Clean environment variables
  hosts: all
  pre_tasks:
    - name: Reset common variables
      set_fact:
        version: ""
        port: ""
        config_path: ""
      run_once: true

Always use role-specific variable prefixes in your roles:

# Instead of:
vars:
  version: "2.3"

# Use:
vars:
  rabbitmq_version: "3.8"
  mysql_version: "8.0"

To troubleshoot variable leakage, add this debug task between roles:

- name: Show current variable state
  debug:
    var: hostvars[inventory_hostname]