Search code examples
ansiblejinja2

failed_when is causing a debug task to fail despite the conditional resulting in False?


I want to check that two variables are defined and not empty. I have a task debug with that checks that and if either of the two variables are undefined or empty, it should fail the task. The problem is that, when both are defined, the script returns (correctly) that they are both defined, but the failed_when condition still fails the task.

Here are my tasks:

- set_fact:
    my_variable:
      version: "2"
      previous_version: "1"

- name: Ensure versions are present
  ansible.builtin.debug:
    msg: |
      {% set missing_versions = [] %}
      {% set version_names = ['version','previous_version'] %}
      {% for version_name in version_names %}
        {% if my_variable[version_name] is not defined or my_variable[version_name] == '' %}
          {% set missing_versions = missing_versions + version_name %}
        {% endif %}
      {% endfor %}
      {% if missing_versions | length > 0 %}
        The following value(s) are missing: {{ missing_versions | join(', ') }}
      {% else %}
        The {{ version_names | join(', ') }} values are present.
      {% endif %}
  failed_when: missing_versions | length > 0

Expected result:

When my_variable.version and my_variable.previous_version are both defined:

The version, previous_version values are present.

Else:

The following value(s) are missing:

  • version
  • previous_version

As you can see in the set_fact task, both of those values are defined, and when the debug task runs it outputs "The version, previous_version values are present.", yet the task still fails. If I change the conditional to failed_when: no, it succeeds. I even added text in the task to check the exact same conditional:

- name: Ensure versions are present
  ansible.builtin.debug:
    msg: |
      {% set missing_versions = [] %}
      {% set version_names = ['version','previous_version'] %}
      {% for version_name in version_names %}
        {% if my_variable[version_name] is not defined or my_variable[version_name] == '' %}
          {% set missing_versions = missing_versions + version_name %}
        {% endif %}
      {% endfor %}
      {% if missing_versions | length > 0 %}
        The following value(s) are missing: {{ missing_versions | join(', ') }}
      {% else %}
        The {{ version_names | join(', ') }} values are present.
      {% endif %}
      Missing versions length > 0: {{ missing_versions | length > 0 }}
  failed_when: missing_versions | length > 0

Result:

The version, previous_version values are present. \nMissing versions length > 0: False

So I know the conditional is correct, yet failed_when is still failing the task even when the result is False.

What am I missing? Also, I welcome any suggestions on improving my code to check that those two attributes aren't undefined/empty.


Solution

  • If you want to make a playbook fail for some reason(s) then, don't use a debug task, rather use an assert one:

     - assert:
         that:
           - my_variable.version | default('') | length > 0
           - my_variable.previous_version | default('') | length > 0
    

    Using a default, here, will ensure that the assertion will fail because of the condition defined and not with a failure of the assertion task itself.

    The outcome of such a task would either be:

    ok: [localhost] => changed=false 
      msg: All assertions passed
    

    or

    fatal: [localhost]: FAILED! => changed=false 
      assertion: my_variable.version | default('') | length > 0
      evaluated_to: false
      msg: Assertion failed
    

    And you can further customise those as you're pleased with the success_msg and failed_msg parameters.