I try to pass a condition to failed_when as a variable in a role:
my-role/defaults/main.yml:
# list of commands to execute in form [command, changed_when, failed_when]
my_commands:
- ["myapp init", "cmd_result.rc == 0", "(cmd_result.rc != 0) and ('Non-critical error' not in cmd_result.stdout) and ('Non-critical error' not in cmd_result.stderr)"]
- [...]
This would allow me to loop through the command list with custom changed_when and failed_when conditions:
if I copy the condition line into failed_when statement explicitly, like failed_when: "(cmd_result.rc != 0) and ('Non-critical error' not in cmd_result.stdout) and ('Non-critical error' not in cmd_result.stderr)", task works
I suppose it may be that
the statement is not evaluated properly
cmd_result variable is not injected into the conditional statement
Can anyone explain this, and maybe suggest an elegant and functional way to get this work?
failed_when is evaluated to literal string â(cmd_result.rc != 0) and (âNon-critical errorâ not in cmd_result.stdout) and (âNon-critical errorâ not in cmd_result.stderr)â
What you want is to have same literal string â(cmd_result.rc != 0) and (âNon-critical errorâ not in cmd_result.stdout) and (âNon-critical errorâ not in cmd_result.stderr)â to be used as condition.
In your case there is only one evaluation - my_command[2] is evaluated to string, ansible does just one evaluation.
The solution is
failed_when: "{{ my_command[2] }}"
In this case {{ my _command[2] }} is evaluated to as string (variable evaluation) and when string (condition you wrote) is evaluated as condition.
As mentioned already, the items in my_command are all strings, not variables. If you look at changed_when_result in the output - youâll see a message that itâs derived from a string. If you fix that by adding brackets around the 2nd and 3rd fields for every item in my_commands, youâll run into another issue: the loop is templated before the task executes. Iâd use two different variables - one for the loop, and another that is referenced by changed_when and failed_when using the loop item.
For example, the variables could look like:
my_commands:
- myapp init
cmd_results:
# Or, instead of a dict, you could use a list with the same indices
# as in my_commands, and loop over "{{ range(0, my_commands|length) | list }}".
"myapp init":
changed_when: "{{ cmd_result.rc == 0 }}"
failed_when:
- "{{ cmd_result.rc != 0 }}"
- "{{ 'Non-critical error' not in cmd_result.stdout }}"
- "{{ 'Non-critical error' not in cmd_result.stderr }}"
And could be used in the task like:
changed_when: cmd_results[my_command].changed_when
failed_when: cmd_results[my_command].failed_when is all