Following are the differet ways that variables, lists and dictionaries can be set in Ansible. This list is in the order of precedence, where the option higher in the list takes precedence over options lower in the list.
- --extra-vars command line option or Extra Variables in Tower
- set_fact (this article)
- include_vars
- vars_prompt
- vars_files
- vars
- roles vars
- group_vars
- /etc/ansible/hosts or your own inventory file
- lookup vars
- register parameter and debug module
In this example, set_fact is used so that the "foo" variable contains a value of "Hello World" and the debug module is be used to print the variable.
AVOID TROUBLE
The -e or --extra-vars command line option or Extra Variables in Tower will take precedence over set_fact.
---
- hosts: localhost
tasks:
- set_fact:
foo: "Hello World"
- debug:
var: foo
...
Which should produce the following.
ok: [localhost] => {
"foo": "Hello World"
}
In this example, set_fact is used to create a list that contains two values, "Hello" and "World".
---
- hosts: localhost
tasks:
- set_fact:
list: "[ 'Hello', 'World']"
- debug:
msg: "{{ list }}"
...
Which should produce the following.
ok: [localhost] => {
"msg": [
"Hello",
"World"
]
}
In this example, set_fact is used to create a dictionary that contains two key/value pairs.
---
- hosts: localhost
tasks:
- set_fact:
mydict:
- { key: 'fruit', value: 'apple' }
- { key: 'veggy', value: 'pepper' }
- debug:
msg: "{{ mydict }}"
...
Which should produce the following.
ok: [localhost] => {
"mydict": {
"key": "fruit",
"value": "apple",
"key": "veggy",
"value": "pepper"
}
}
create multiple variables using a with_items loop
Here is how you can define multiple variables using a with_items loop. In this example, the "foo" variable will contain a value of "Hello" and the "bar" variable will contain a value of "World".
---
- hosts: locahost
tasks:
- set_fact:
"{{ item.key }}": "{{ item.value }}"
with_items:
- { key: "foo", value: "Hello" }
- { key: "bar", value: "World" }
...
Redefine variable
Let's say you used the vars plugin to give the "foo" key a value of "Hello". set_fact can be used to update the value of the "foo" key. In this example, the "foo" key will be updated to have a value of "World". set_fact will take precedence over vars.
---
- hosts: localhost
vars:
foo: "Hello"
tasks:
- set_fact:
foo: "World"
- debug:
var: foo
...
From an Ansible Fact to a variable
Commonly, set_fact is used to create a variable of an Ansible Fact. For example, let's say the df command on server1 returns the following.
[john.doe@server1 ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 372607 170989 177862 50% /boot
/dev/sda2 129774 6994 122780 6% /
Here is how you would create a variable named foo that contains the available bytes of /dev/sda1 (177862).
---
- hosts: localhost
tasks:
- set_fact:
size: "{{ item.size_available }}"
with_items: "{{ ansible_mounts }}"
- debug:
var: size
...
Which should return the following.
TASK [debug]
ok: [localhost] => {
"size": "177862"
}
AVOID TROUBLE
Notice 177862 is wrapped in double quotes, meaning that the size variable contains a string, not an integer, which can be confirmed using the type_debug filter. This is because Jinja2 templating (the double curly braces) always returns a string. However, you can apply some of type filter, such as the bool or int filter in a when statement because Jinja2 templating cannot be used in a when statement.
---
- hosts: localhost
tasks:
- set_fact:
size: "{{ item.size_available }}"
with_items: "{{ ansible_mounts }}"
- debug:
msg: size is greater than 123456
when: size | int > 123456
...
Setting fact based on a condition (when parameter / if else statement)
The when parameter can be used to set fact based on a condition. In this example, if the managed node hostname begins with a "d" then the environment variable will contain a value of "development.
---
- hosts: localhost
tasks:
- set_fact:
env: development
when: inventory_hostname|lower is regex '^d.*'
- set_fact:
env: production
when: inventory_hostname|lower is regex '^p.*'
...
However, it may be more efflective to use a jinja2 if / else statement so that you have a single task that sets the fact.
---
- hosts: localhost
tasks:
- set_fact:
env: "{% if inventory_hostname|lower is regex '^d.*' %}development{% elif inventory_hostname|lower is regex '^p.*' %}producution{% endif %}"
...
Did you find this article helpful?
If so, consider buying me a coffee over at