How to inherit undefined variables with Jinja2?

0

In my Ansible roles, some roles derive specific configuration settings from global variables Global variables might be undefined. The following code illustrates the schema:

- hosts: localhost
  vars:
    bar: '{{ foo }}'
  tasks:
    # Assume foo comes from an Ansible environment
    - debug: var=foo
    # Assume bar comes from a role default
    - debug: var=bar
    # Catched by the "is defined" condition
    - debug: msg="foo is defined"
      when: 'foo is defined'
    # Cannot catch undefined exception?!
    - debug: msg="bar is defined"
      when: 'bar is defined'

Everything works as expected, but the last statement: Ansible raises an exception because foo is undefined (yes, it is undefined).

PLAY [localhost] *********************************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************************
ok: [localhost]

TASK [debug] *************************************************************************************************************************************************************
ok: [localhost] => {
    "foo": "VARIABLE IS NOT DEFINED!"
}

TASK [debug] *************************************************************************************************************************************************************
ok: [localhost] => {
    "bar": "VARIABLE IS NOT DEFINED!"
}

TASK [debug] *************************************************************************************************************************************************************
skipping: [localhost]

TASK [debug] *************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'bar is defined' failed. The error was: error while evaluating conditional (bar is defined): {{ foo }}: 'foo' is undefined\n\nThe error appears to be in '.../test-undef.yml': line 9, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n      when: 'foo is defined'\n    - debug: msg=\"bar is defined\"\n      ^ here\n"}

So why does bar not “evaluate” to undefined like foo? And how can I trap this “multi-level” undefinedness?

ansible jinja2
2021-11-23 09:46:53
3
0

Try this:

- hosts: localhost
  vars:
    bar: '{{ foo }}'
  tasks:
    # Assume foo comes from an Ansible environment
    - debug: var=vars.foo
    # Assume bar comes from a role default
    - debug: var=vars.bar
    # Catched by the "is defined" condition
    - debug: msg="foo is defined"
      when: vars.foo is defined
    # Cannot catch undefined exception?!
    - debug: msg="bar is defined"
      when: vars.bar is defined
2021-11-23 09:57:21

@Frenchy: Yes, indeed... And if you run my script then you will see that it runs fine...
Swifty

yes...i agree with you,
Frenchy

Thanks, @Swifty. However, Ansible shows vars.bar as defined with your code: text TASK [debug] ************************************************************************************************************************************************************* ok: [localhost] => { "msg": "bar is defined" } Probably because it holds the template string?
Stephan

yes its right, so foo is defined implies bar defined
Frenchy

But foo is not defined …
Stephan

foo not defined implies bar not defined..you just have to check if foo is defined to check if bar is defined
Frenchy

@Stephan Please understand the difference between '{{ foo }}' and "{{ foo }}"... "{{ foo }}" means a variable... '{{ foo }}' means literally that string...
Swifty
0

The problem is that bar is technically defined, and your definition of bar uses a possibly undefined variable. When you attempt to do anything with bar it has to be evaluated as an independent Jinja expression, which happens before the is defined check.

One way to address this is to make it so bar can be evaluated without resulting in an undefined value, e.g.

- hosts: localhost
  vars:
    bar: "{{ foo | default(false) }}"
  tasks:
    - debug:
        msg: bar is truthy
      when: bar is truthy

You can also check foo before bar since evaluation is short-circuitable, but baking knowledge of the variable relationship into your tasks can be unwieldy.

- hosts: localhost
  vars:
    bar: "{{ foo }}"
  tasks:
    - debug:
        msg: bar is truthy
      when: 
        - foo is defined
        - bar is defined
2021-11-23 17:15:56

Please note that @Stephan defined the bar variable as a string! bar: '{{ foo }}' literally means a sting!!!
Swifty
-1

try adding

when: ( vars[bar] is defined )
2021-11-23 15:28:45

vars is an undocumented internal implementation that may be removed in the future and should not be used.
flowerysong

In other languages

This page is in other languages

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................