Boolean values act strangely.

So, here's an example playbook:

    - hosts: whatever
      vars:
        foo: yes
      tasks:
        - debug: msg={{ doit }}

This prints "True". Changing 'foo' to 'no', or '0', or 'false' causes
the above to print "False". This is as expected.

If I call the playbook and pass an extra var to it like so:

    -e "foo=yes"

Then the above now prints "no" instead.

It seems that things passed in as extra vars do not get interpreted as
a booleans and replaced with True/False before being passed on to the
rest of the playbook.

This causes strange issues when trying to use extra vars in templates,
and also when using them in the new 1.2 "when" syntax.

Not sure what's going on --- was this always the case?

Excerpts from C. Morgan Hamill's message of 2013-04-15 11:38:27 -0400:

Then the above now prints "no" instead.

s/"no"/"yes"

You seem to be missing something in your copy/paste as the variable is named foo in one place and doit in the other.

Is there a conditional somewhere?

Note YAML interprets “foo: yes” as a Boolean, you would have to quote strings to keep them strings.

Excerpts from Michael DeHaan's message of 2013-04-15 16:13:33 -0400:

You seem to be missing something in your copy/paste as the variable is
named foo in one place and doit in the other.S

Ahh, sorry about that; the variable was supposed to be the same in both
places.

Note YAML interprets "foo: yes" as a Boolean, you would have to quote
strings to keep them strings.

I'm aware of the yaml behavior, but the issue I'm having is instead
this:

If you specify a value in a playbook or vars file or whatnot, things
like "yes" and "no" become real booleans, as expected.

If you specify a value via -e, and use something like "yes" or "no" as
it's value, the value stays a string.

So:

    - hosts: 127.0.0.1
      vars:
        foo: yes
      tasks:
        - debug: msg="{{ foo }}"

prints 'True', while:

    - hosts: 127.0.0.1
      tasks:
        - debug: msg="{{ foo }}"

called with a -e "foo=yes" prints 'yes'.

The inconsistency there is what I'm wondering about.

You will probably have to use a Jinja2 filter to cast the type.

If I am understanding this correctly,

  1. Data from files is YAML data first, with the associated “magic” casting to boolean types.

  2. YAML string values have their {{Jinja2}} fragments interpolated

  3. The result is converted to internal ansible (python) data structures

But with the -e “foo=yes” we skip straight to internal ansible data and there is no “magic” boolean casting,
which makes sense because “foo=yes” is not YAML. Is this correct?

If --extra-vars took YAML syntax like ‘foo: yes’ or ‘foo: “{{ yes }}”’, we might expect something different.

Kal

It has nothing to do with foo=yes not being YAML.

It does have to do with the value of foo being a string when fed into the variable system and “–extra-vars” not knowing to booleanify things.

We could certaintly apply this but I’d be afraid of breaking existing content.

You can definitely check for “foo == ‘yes’” in the conditional here if you don’t want to cast it.

Obviously not had enough coffee to express myself clearly.

What I meant was 'foo=yes' on the command line does not _look_ like YAML,
so we should not _expect_ it to behave like YAML.

I'm assuming 'foo: yes' in an ansible YAML file gets the boolean cast via
some python library for importing YAML and not via ansible's variable
system?

It’s just fed to the variable system to be avialable in templating/other usage, well-post YAML parsing…

Excerpts from Michael DeHaan's message of 2013-04-15 18:59:07 -0400:

We could certaintly apply this but I'd be afraid of breaking existing
content.

Yeah, it's not a big deal; just wondering. The behavior is a bit
surprising, but so it goes.

Hi guys,

Not sure if this has been resolved, but I’m getting really strange behavior with my playbooks in version 1.4. This has nothing to do with --extra-vars, but a boolean variable defined in the “vars” section. Or am I defining it somewhat incorrectly?

Here is an example:

  • hosts: 127.0.0.1
    vars:
    myvar: “{{ ‘foo’ == ‘bar’ }}”

tasks:

  • name: print var value
    command: /bin/echo {{ myvar }}

  • name: this should run
    command: /bin/echo whatever
    when: not myvar

  • name: this should not run
    command: /bin/echo whatever
    when: myvar

This prints “False” for the first task and skips both the other tasks. However, if I change the “when” statements to myvar|bool, it works as expected.
So it seems myvar contains the string representation of the boolean expression returned from the statement.
Is there a way to have the variable of type boolean, or do I always have to explicitly pipe it to the Jinja bool filter?

So I’d request everyone please don’t reply to ancient threads, things change and initial questions are seldom related to the old if you think they might be.

Saving a conditional in a variable should probably not involve a template statement, the need to do this in conditionals has been gone for some time.

We can dig and try to reproduce this later.