I am fairly new to Ansible and today while writing a new playbook I came across some behaviour I can't explain. I have been through the documentation and done my best Google-Fu, but I can't seem to find the answer.
The behaviour relates to variables defined in a playbook's "var" section and their lack of expansion into proper values when using other variables or arithmetic.
Take an example playbook with "static" values in vars:
--- # Test playbook vars
- hosts: 'all'
connection: ssh
gather_facts: false
vars:
- max_size_bytes: 10240
tasks:
- name: debug!
debug:
msg: |
"max_size_bytes: {{max_size_bytes}}"
"vars: {{vars['max_size_bytes']}}"
This outputs:
# ansible-playbook -i host1, test_vars.yml
PLAY [all] *************************************************************************************************************************
TASK [debug!] **********************************************************************************************************************
ok: [host1] => {}
MSG:
"max_size_bytes: 10240"
"vars: 10240"
Which is exactly what I would expect.
However, let's say I want to calculate that 10240
number dynamically:
--- # Test playbook vars
- hosts: 'all'
connection: ssh
gather_facts: false
vars:
- max_size_bytes: "{{10 * 1024}}"
tasks:
- name: debug!
debug:
msg: |
"max_size_bytes: {{max_size_bytes}}"
"vars: {{vars['max_size_bytes']}}"
And the new result is:
# ansible-playbook -i host1, test_vars.yml
PLAY [all] *************************************************************************************************************************
TASK [debug!] **********************************************************************************************************************
ok: [host1] => {}
MSG:
"max_size_bytes: 10240"
"vars: {{10 * 1024}}"
I get a similar output if I try to use another variable within the assignment. I came across this issue when I wanted to allow a playbook user to quick change some settings, without requiring them to calculate anything. For example:
vars:
- max_size_in_megabytes: 100 #change me if required
- max_size_bytes: "{{max_size_in_megabytes * 1024 * 1024}}"
But this didn't work as I expected, as above.
In some places the variable is expanded correctly and gives the result I would expect (i.e. the calculated value). At other times, it seems the variable is not expanded and is treated as a string as per the output for vars['max_size_bytes']
.
- What is the reason for this behaviour? Variable expansion and calculated values seem to work elsewhere in a playbook - why not for pre-defined variables?
- If this behaviour is considered normal, what is the proper way of creating global/reusable variables that may need to be calculated on the fly?
UPDATE
I realise there may be some confusion as to what my issue actually is. That's my fault.
To try and explain better, take a look at another example:
--- # Test playbook vars
- hosts: 'localhost'
connection: local
gather_facts: false
vars:
- multiplier: 10 #change me as required
- some_value: 300
- max_size_dynamic: "{{10 * 20}}"
- max_size_static: 200
tasks:
- set_fact:
is_bigger_dynamic: "{{some_value > max_size_dynamic}}"
is_bigger_static: "{{some_value > max_size_static}}"
- name: debug!
debug:
msg: |
multiplier: {{multiplier}}
some_value {{some_value}}
Is {{some_value}} bigger than {{max_size_static}}?
is_bigger_static: {{is_bigger_static}} <-- hooray
Is {{some_value}} bigger than {{max_size_dynamic}}?
is_bigger_dynamic: {{is_bigger_dynamic}} <-- woops!
When running this playbook, you can see that the value of the conditional clauses in the set_fact
task differs based on how a variable is created in vars
.
Output:
PLAY [localhost] **********************************************************************************************************************
TASK [set_fact] ***********************************************************************************************************************
ok: [localhost]
TASK [debug!] *************************************************************************************************************************
ok: [localhost] => {}
MSG:
multiplier: 10
some_value 300
Is 300 bigger than 200?
is_bigger_static: True <-- hooray
Is 300 bigger than 200?
is_bigger_dynamic: False <-- woops!
The conditionals are checking the same expression: 300 > 200
, but if the value 200 is derived from another expression in vars
the condition is wrong.
I suspect in the case of {{some_value > max_size_dynamic}}
the variable isn't being expanded (much like using vars['name\]
as mentioned in the comments). So it looks like the conditional ends up being {{some_value > "{{10 * 20}}"}}
.
Is this expected behaviour with set_fact
? Is there anything I can do to allow expressions in vars
which can be further used in set_fact
tasks?
This is running the latest version of Ansible on MacOS High Sierra:
# ansible --version
ansible 2.5.0
config file = /Users/xxx/.ansible.cfg
configured module search path = [u'/Users/xxx/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/Cellar/ansible/2.5.0/libexec/lib/python2.7/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 2.7.14 (default, Apr 9 2018, 16:44:39) [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)]