1

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)]
Etzeitet
  • 1,995
  • 2
  • 18
  • 22
  • I answered this two hours ago: https://stackoverflow.com/a/49817222/2795592 – Konstantin Suvorov Apr 13 '18 at 16:17
  • @KonstantinSuvorov you state not to use vars at all. What is the alternative for setting variables for the whole playbook that may be dynamic and/or rely on other variables already declared? – Etzeitet Apr 15 '18 at 13:47
  • I didn't say that. I said not to use `vars` object to access variables inside Jinja2 expressions. Still you may/should use `vars` keyword to define play/task level variables in playbooks. – Konstantin Suvorov Apr 15 '18 at 18:36
  • @KonstantinSuvorov I may not have been completely clear about my issue. It's not about using `vars` directly, but how other tasks seem to not expand variables. See my update at the end of the post. – Etzeitet Apr 16 '18 at 10:38

1 Answers1

0

Your update to the question is completely different to original post.

And the issue with update part is this: Why a string in always "greater than" a number?

Just do the type casting:

- set_fact:
    is_bigger_dynamic: "{{some_value > max_size_dynamic | int }}"
    is_bigger_static: "{{some_value > max_size_static }}"

In your case some_value and max_size_static are numbers, but max_size_dynamic is a string (you can't make simple integer outside of {{...}} in ansible – only strings/booleans/lists/dictionaries).

Konstantin Suvorov
  • 65,183
  • 9
  • 162
  • 193