complex when conditions

Hi,

I am migrating ansible from 0.9 to 1.5 and complex when condition don’t work anymore:

vars:
not_main: “‘$c_main’ == ‘no’”
is_main: “‘$c_main’ == ‘yes’”
not_lxc: “‘$lxc’ != ‘yes’”

tasks:

This does not work properly, it is always being applied

  • name: test0.conf
    action: template src=/tmp/test.conf.j2 dest=/tmp/test0.conf owner=ops group=ops mode=0444
    when: not_main and not_lxc

This works but prints warnings about using ${foo} or $foo. This is what I used in the past with ansible 0.9 (with only_if).

  • name: test1.conf
    action: template src=/opt/opsfs/tmp/test.conf.j2 dest=/tmp/test1.conf owner=ops group=ops mode=0444
    when: $not_main and $not_lxc

This works but is longer to type and not as readable as the first example

  • name: test2.conf
    action: template src=/opt/opsfs/tmp/test.conf.j2 dest=/tmp/test2.conf owner=ops group=ops mode=0444
    when: c_main == ‘no’ and lxc != ‘yes’

What is the correct way to use complex when conditions?

The following tricks are available:

In my scripts I also use “or” expression… How would I do that? And what about the poor souls that want to use complex boolean expression?..

Complex conditionals and or statements are fine.

when: x > 2 or y >3

and complex conditionals are fine as well:

when: (x > 2 or y > 3) and (zebras == 4)

etc

Will it be easier for ansible to recognize pre-defined condition if I put it in brackets?

vars:
amazon: “yes”
lxc: “no”
is_amazon: (amazon == “yes”)
is_lxc: (lxc == “yes”)

tasks:

  • shell: echo hi 1

when: is_amazon or is_lxc

It would be sad if there is no way to use short syntax like this…

You’ll have to be sad then, at least for now.

Too much fuzzy logic is involved for the system to know what is a condition and what is a string, so only bare words
are evaluated as conditionals.

The ansible documentation has this example:

vars:
epic: true
Then a conditional execution might look like:
tasks:

  • shell: echo “This certainly is epic!”
    when: epic

Would it be possible for ansible to interpret conditionals in vars: section and assign proper true/false values to the variables? So that in example below is_amazon is assigned true?
amazon: “yes”
is_amazon: (amazon == “yes”)

Yes, it can go one level deep.

You can’t build conditional expressions out of conditional expressions, but variables will expand.

I’d suggest writing a test playbook and trying it out!

I tested various combinations, and in no case the is_var_evaluatedX got assigned value True…

vars:
amazon: “no”
is_var_evaluated1: (amazon == ‘no’)
is_var_evaluated2: amazon == ‘no’
is_var_evaluated3: $amazon == ‘no’
is_var_evaluated4: “‘$amazon’ == ‘no’”

I would like to file feature request on adding conditional expression evaluation in vars section… Is there ansible’s BTS?

“Is there ansible’s BTS?”

github.com/ansible/ansible.

However, it’s already true that conditionals in the vars section work.

You still have some legacy variables in the bottom half, which is why 3 and 4 don’t work.

amazon: “no”
is_var_evaluated1: (amazon == ‘no’)
is_var_evaluated2: amazon == ‘no’

The first two should be true, and I’ve confirmed that they work on my end at least.

Note that if you forget to quote the no, it will be stored as a False, and this is even cleaner.

when: amazon

The following playbook does not work properly - the action is always executed, why is that?

The following playbook does not work properly - the action is always
executed, why is that?

---
- hosts: *
   vars:
     x: 5
     y: 7
          is_false1: x>y
     is_false2: x>y

Here you set is_false1 and is_false2 to strings "x>y", not to a result of evaluating it (and it would be the same if you put {{ }} around it)

   tasks:

   - name: either is true
     shell: echo either is true
     when: is_false1 or is_false2

And here you check if either is_false1 or is_false2 is true-like - which they both are, as they are non-empty strings. What would work is putting them in {{ }} like this:

   when: '{{ is_false1 }} or {{ is_false2 }}'

which looks bad, and tells you about {{ }} not being needed (which is not true in this case...).

You can’t load a “saved” conditional that way (at least currently) as the conditional loader doesn’t do recursive lookups.

– Michael

What is the recommended way to use “saved” conditionals?

Something like this:

ansible_hosts has this:
machine1 amazon=yes

vars:
is_amazon: (amazon == “yes”)
tasks:

shell: echo we are on amazon
when: is_amazon

Can ansible treat expressions in brackets in vars: section as “saved” conditional? E.g. evaluate it and store in the value boolean True or False? This way the conditional loader does not need to do any lookups, just evaluate the expression as is.

Another question I have - whether the values of variables should be quoted? Double or single quote? From my experience, the quotes in ansible are treated as part of the value.

" when: is_amazon"

This is fine.

“whether the values of variables should be quoted?”

Only if they are strings.

“which looks bad, and tells you about {{ }} not being needed (which is not true in this case…).”

The real fix would be to evaluate things as far recursively as we can, IMHO.

So as long as we have a ticket for that (let’s be sure we have one) {{ foo }} will become uneeded and we don’t need to change the warning.