Is there a possibility to unset a fact (variable) in Ansible?
Unset in such a way that the check is defined
fails.
For execution decisions I regularly check conditions with is defined
. However, it may be necessary to unset these before execution, e.g. if a role is used multiple times via include_role
or tasks are used multiple times via include_tasks
.
Is there a special syntax for this, e.g. to use the set_fact
module?
If I understood it correctly, meta: clear_facts
takes care of clearing all facts and cannot be restricted to individual ones.
Best Answer
Q: "Is there a possibility to unset a fact (variable) in Ansible?"
A: No. It is not possible to unset variables in Ansible. Instead, it's possible to define variables in various scopes. Such variables won't be defined above the particular scope. See Playbook Keywords. You can define variables in this hierarchy of scopes
- Play
- Role
- Block
- Task
There are various scenarios on how to solve the use cases: "It may be necessary to unset variables before execution, e.g. if a role is used multiple times via include_role or tasks are used multiple times via include_tasks."
For example, create a role
shell> tree roles/roles/└── test_role└── tasks└── main.yml
with the single task
shell> cat roles/test_role/tasks/main.yml - debug:var: test_var
Use case 1. A role is used multiple times via include_role
For example, the playbook
- hosts: localhosttasks:- include_role:name: test_rolevars:test_var: first run- include_role:name: test_role- include_role:name: test_rolevars:test_var: third run
gives (abridged)
test_var: first runtest_var: VARIABLE IS NOT DEFINED!test_var: third run
Use case 2. Tasks are used multiple times via include_tasks
In the same way, the playbook below gives the same result
- hosts: localhosttasks:- include_tasks: roles/test_role/tasks/main.ymlvars:test_var: first run- include_tasks: roles/test_role/tasks/main.yml- include_tasks: roles/test_role/tasks/main.ymlvars:test_var: third run
Use case 3. Use roles
The playbook below gives also the same result
- hosts: localhostroles:- role: test_roletest_var: first run- role: test_role- role: test_roletest_var: third run
Notes
See Variable Scopes
It's good to understand what will happen when you declare an empty variable. For example, the playbook
- hosts: localhostvars:test_var: default_valuetasks:- debug:var: test_var- set_fact:test_var:- debug:msg: "test_var is defined: {{ test_var is defined }}"- debug:var: test_var
shows (abridged) that an empty variable is defined
and null
. You will receive the same results when you set the variable explicitly to null by test_var: !!null
TASK [debug] **********************************************************************************************ok: [localhost] => test_var: default_valueTASK [set_fact] *******************************************************************************************ok: [localhost]TASK [debug] **********************************************************************************************ok: [localhost] => msg: 'test_var is defined: True'TASK [debug] **********************************************************************************************ok: [localhost] => test_var: null
- It's also good to understand that default doesn't set the value when the variable is defined. For example,
- debug:var: test_var- debug:var: test_var|default('default when undef')
shows that the filter default doesn't by default cares the value is null and doesn't set the value because the variable is defined
TASK [debug] **********************************************************************************************ok: [localhost] => test_var: nullTASK [debug] **********************************************************************************************ok: [localhost] => test_var|default('default when undef'): ''
- If you want to set the default value also when the variable is null set the second parameter of the filter
True
. For example,
- debug:var: test_var- debug:var: test_var|default('default when undef or null', true)
gives
TASK [debug] **********************************************************************************************ok: [localhost] => test_var: nullTASK [debug] **********************************************************************************************ok: [localhost] => test_var|default('default when undef or null', true): default when undef or null
Regarding your requirement
Unset in such a way that the check is defined fails.
I understand that you like to check for a condition like
when: VARIABLE is defined
so you could use an approach like
when: VARIABLE | default(None) != None
and set the value of VARIABLE
at any time with
VARIABLE: !!null
Further Documentation
- Ansible Issue #24136
- Set Ansible variable to undefined through extra-vars or inventory variable
- Ansible: How to check if a variable is not null?
Further Reading
- Ansible Issue #75435 "Add an
undef
global Jinja function"