6

Ansible in 1.4 and later provides a way to specify this behavior as follows:

- name: Fail task when the command error output prints FAILED
  command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"

but the common Return Values already include .failed and .changed.

It seems to me these features contradict each other. Is there an official resolution to it? Does Ansible define one of failed_when or changed_when as being evaluated first and affecting the latter? Does it define that both are evaluated without seeing the effect of the other?

E.g. what is the defined behaviour of

  1. command_result.failed within a failed_when expression
  2. command_result.changed within a changed_when expression
  3. command_result.failed within a changed_when expression
  4. command_result.changed within a changed_when expression

To be more clear, e.g. for the third one I'm interested in how well-defined (reliable) the result of the following would be:

- package:
    name: systemd
    state: present
  check_mode: yes
  register: command_result
  failed_when: command_result.changed

Let's say I'm interested in Ansible 2.0 and above.

sourcejedi
  • 50,249

1 Answers1

3

This looks wrong

Your example adds another path to your playbook. If systemd is not installed, the output will be different than if it is installed. And after the first run it will be installed. This goes against the ansible priciple that says:

Idempotency

An operation is idempotent if the result of performing it once is exactly the same as the result of performing it repeatedly without any intervening actions.

If you still do it, make it as explicit as possible

I suggest you run a command which systemctl and register the output. Check the output to install systemd and fail with a fail task.

This is still a very interesting question

I guess there is no real documentation and we have to investigate.

I hope I catched all cases :) but I cannot fill the chart right now.

playbook.yml:

---

- name: test some stuff
  hosts: all
  tasks:
    - include_tasks: tasks.yml
      with_items:
        - { data: ping, changed: true }
        - { data: ping, changed: false }
        - { data: crash, changed: true }
        - { data: crash, changed: false }

tasks.yml

---

- name: Check for command_result is defined and command_result
  ping:
    data: "{{ item.data }}"
  register: command_result
  changed_when: item.changed
  failed_when: command_result is defined and command_result
  ignore_errors: true

- name: Check for command_result is defined and command_result
  file:
    path: ./file
  register: command_result
  changed_when: item.changed
  failed_when: command_result is defined and command_result
  ignore_errors: true

- name: Check for command_result
  ping:
    data: "{{ item.data }}"
  register: command_result
  changed_when: item.changed
  failed_when: command_result
  ignore_errors: true

- name: Check for command_result
  file:
    path: ./file
  register: command_result
  changed_when: item.changed
  failed_when: command_result
  ignore_errors: true

- name: Check for command_result.changed is defined and command_result.changed
  ping:
    data: "{{ item.data }}"
  register: command_result
  changed_when: item.changed
  failed_when: command_result.changed is defined and command_result.changed

- name: Check for command_result.changed is defined and command_result.changed
  ping:
    data: "{{ item.data }}"
  register: command_result
  changed_when: item.changed
  failed_when: command_result.changed is defined and command_result.changed
  ignore_errors: true

- name: Check for command_result.changed
  ping:
    data: "{{ item.data }}"
  register: command_result
  changed_when: item.changed
  failed_when: command_result.changed
  ignore_errors: true

- name: Check for command_result.changed
  file:
    path: ./file
  register: command_result
  changed_when: item.changed
  failed_when: command_result.changed
  ignore_errors: true
ctx
  • 2,495
  • sorry , that's not my question. I have made my question clearer by showing the example I actually had in mind :). – sourcejedi Feb 27 '18 at 17:02
  • hmm how much should I delete... – ctx Feb 27 '18 at 17:12
  • As far as I can tell none of it is relevant any more, sorry. I am sad about this as it's pretty and would have been a nice answer to the right question :). I absolutely take your point that it's confusing for me to ask about .changed while referencing the command example quoted from the docs, given that commands show as changed by default. But I hope the second example I added mostly clears that up. – sourcejedi Feb 27 '18 at 17:54
  • sorry, I had to go home. I try to update the third part and I hope you are not offended by the first two. – ctx Feb 27 '18 at 19:31
  • no offense! but you may have missed the point. https://stackoverflow.com/a/46630866/799204 I am using "check_mode: yes" to avoid ever installing systemd. This was my original goal: test for systemd as a requirement, without installing it and breaking the system :). Although I have chosen a slightly different pattern using assert, it raised this question about how well-defined these Ansible features really are. – sourcejedi Feb 28 '18 at 08:23
  • Note, the current behaviour of a single version of Ansible might be informative, but ultimately if there's no official position then it could change without warning, without being considered a bug etc. That's sort of the answer I imply and expect, and the question is here to ask if people can prove me wrong :). – sourcejedi Feb 28 '18 at 08:29