Is There Some Ansible Equivalent to "Failed_When" for Success

Is there some Ansible equivalent to failed_when for success

I think maybe assert module is what you want.

New in version 1.5

Examples:

- assert: { that: "ansible_os_family != 'RedHat'" }

Ansible: simulating a passed when module

Have a look here:

Is there some Ansible equivalent to "failed_when" for success

- name: ping pong redis
command: redis-cli ping
register: command_result
failed_when:
- "'PONG' not in command_result.stderr"
- "command_result.rc != 0"
  • will not fail if return code is 0 and there is no 'PONG' in stderr.
  • will not fail if there is "PONG" in stderr.

So it passes if any of the list is False

How to print debug message for success and failure in ansible wait_for module to test firewall?

TL;DR;

Here is the debug you are looking for:

- debug:
msg: "{{ 'Failed with message: ' ~ wait_result.msg if wait_result.failed else 'Success connecting to Firewall' }}"

You can always register the result of a task in Ansible.

Then based on this result, you can actually act, or print something.

Here is how I would have approached it: I don't know from the top of my head what a task will give me as a result, but I know for a fact that I can register it and debug it.

So I made this playbook:

- hosts: local
gather_facts: no

tasks:
- name: Check Firewall Connectivity
wait_for:
host: 10.200.12.2
port: 2041
state: started
delay: 0
timeout: 3
ignore_errors: yes
register: wait_result

- debug:
msg: "{{ wait_result }}"

It resulted in this recap:

PLAY [local] *******************************************************************

TASK [Check Firewall Connectivity] *********************************************
fatal: [local]: FAILED! => {"changed": false, "elapsed": 3, "msg": "Timeout when waiting for 127.0.0.1:22"}
...ignoring

TASK [debug] *******************************************************************
ok: [local] => {
"msg": {
"changed": false,
"elapsed": 3,
"failed": true,
"msg": "Timeout when waiting for 127.0.0.1:22"
}
}

PLAY RECAP *********************************************************************
local : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1

So based on this recap, I know that my result have a property failed this is going to be true if the wait_for task fails.

And I even get a msg of failure for it.

So now, with the help of the inline if expression of Jinja, I can create this task:

- debug:
msg: "{{ 'Failed with message: ' ~ wait_result.msg if wait_result.failed else 'Success connecting to Firewall' }}"

This will result in either the recap:

TASK [debug] *******************************************************************
ok: [local] => {
"msg": "Success connecting to Firewall"
}

or the recap:

TASK [debug] *******************************************************************
ok: [local] => {
"msg": "Failed with message: Timeout when waiting for 10.200.12.2:2041"
}

assert module: Is it possible to fail if string is found only once?

TL;DR

- name: "File output | verification"
vars:
watch_regex: '(?:^|\W)(test)(?:$|\W)'
assert:
that:
- testing_parse.stdout | regex_findall(watch_regex) | length > 1
fail_msg: "Exiting now."
success_msg: "Proceeding with task."

Why the in test is not appropriate

in returns a boolean

Let's first see what we get back from the in test in several situations

$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e "my_test='a test'"

localhost | SUCCESS => {
"msg": true
}

$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e "my_test='a test and an other test'"

localhost | SUCCESS => {
"msg": true
}

$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e "my_test='no word we look for'"

localhost | SUCCESS => {
"msg": false
}

As you can see, it will always return a boolean depending on the presence or not of the needle in the haystack.

in does not find words

Note also that in is not very good at finding words (since you mentioned that) as demonstrated below:

# It will match a substring in a middle of an other word
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e my_test="blahtesttoto"

localhost | SUCCESS => {
"msg": true
}

# It will not match a word inside an element of a list...
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e '{"my_test":["this is", "a test"]}'

localhost | SUCCESS => {
"msg": false
}

# ... but only an exact match of an element of a list
$ ansible localhost -m debug -a "msg={{ 'test' in my_test }}" \
-e '{"my_test":["a", "test"]}'

localhost | SUCCESS => {
"msg": true
}

Your expression is wrong anyway

To end with, let's look at your try when you wrote the expression:

'test' in testing_parse.stdout >= '2'

This means:

  1. check if the string testing_parse.stdout is lexically superior or equal to the string '2'.
  2. now check if the string 'test' is found inside the preceding boolean result.

As you can now guess with the explanation, there is absolutely no chance this will ever return true.

regex_findall to the rescue

A way to look for a specific word is to use a regex. The following will look for the test word i.e. the "test" string preceded and followed by any non-word character (end of line, beginning of line, white space, tab, punctuation....).

(?:^|\W)(test)(?:$|\W)

If you are not familiar with regular expressions, see this answer for a specific explanation and https://www.regextutorial.org/ for a general resource (I'm not affiliated, you can find others using your favorite search engine).

The regex_find_all filter can return all matches of a regex against a string into a list

$ ansible localhost -m debug \
-a "msg={{ my_test | regex_findall('(?:^|\\W)(test)(?:$|\\W)') }}" \
-e "my_test='test'"

localhost | SUCCESS => {
"msg": [
"test"
]
}

$ ansible localhost -m debug \
-a "msg={{ my_test | regex_findall('(?:^|\\W)(test)(?:$|\\W)') }}" \
-e "my_test='test and an other test but not blahtesttoto yet test'"

localhost | SUCCESS => {
"msg": [
"test",
"test",
"test"
]
}

$ ansible localhost -m debug \
-a "msg={{ my_test | regex_findall('(?:^|\\W)(test)(?:$|\\W)') }}" \
-e "my_test='notest'"

localhost | SUCCESS => {
"msg": []
}

Once we have that, we only need to count the number of elements in the returned list whith the length filter.

$ ansible localhost -m debug \
-a "msg={{ my_test | regex_findall('(?:^|\\W)(test)(?:$|\\W)') | length }}" \
-e "my_test='test and an other test but not blahtesttoto yet test'"

localhost | SUCCESS => {
"msg": "3"
}

And finally we can fix your assert task according to your requirement:

- name: "File output | verification"
vars:
watch_regex: '(?:^|\W)(test)(?:$|\W)'
assert:
that:
- testing_parse.stdout | regex_findall(watch_regex) | length > 1
fail_msg: "Exiting now."
success_msg: "Proceeding with task."

How can I configure Ansible playbook to ignore certain error codes?

You can use a better mechanism than ignore_errors in this case, it is failed_when.

With it, you can fine grain the failure of a task to exactly what you want.

In your case it would be something like:

- name: Call MOS Windows Service Endpoint
uri:
url: https://example.org/api
## reduced the uri for brevity
register: trigger_backup_response
failed_when: trigger_backup_response.status not in [202, 400, 422]

This will cause the codes 202, 400 and 422 to have a successful task, all other status code would, then, fail.

Next to this, in order to handle the tasks based on the return of that API call, you can either use a block:

- block:
- debug:
msg: First task upon receiving a return form the API

- debug:
msg: Second task upon receiving a return form the API

- debug:
msg: Third task upon receiving a return form the API

when: trigger_backup_response.status == 202

Or, stop the execution totally, with the help of the meta module.

The task here under will stop the play, on an host basis, if the the return code of the API is either 400 or 422.

- meta: end_host
when: trigger_backup_response.status in [400, 422]

So, having a scenario like:

- name: Call API
uri:
url: https://example.org/api
register: trigger_backup_response
failed_when: trigger_backup_response.status not in [202, 400, 422]

- name: End play for hosts with detached volumes
meta: end_host
when: trigger_backup_response.status in [400, 422]

## From now on, it is safe to assume
## we are only dealing with API answer status being 202
- name: Display volume IDs
debug:
var: backup_properties.volume_ids

Ansible conditional based on stdout of result?

Try checking to see it if equals a blank string or not?

- hosts: myhosts
tasks:
- name: echo hello
command: echo hello
register: result
- command: somecommand {{ result.stdout }}
when: result.stdout != ""
- command: someothercommand
when: result.stdout == ""

Is it possible to have ansible retry only on certain conditions, success/fail on others?

Use an until loop with a generated list of all the 2xx codes as status_code.

The generated list can be done with the range function of Jinja.

This way, you will get an immediate a success for all 2xx code, an immediate failure for all other codes and a retry for the status code 409.

Here is an example:

- uri:
url: https://httpbin.org/status/409
## List containing all the 2xx codes that should be successful
status_code: "{{ range(200, 300) }}"
register: results
retries: 1
delay: 30
until: results.status != 409

Using https://httpbin.org/, you can adapt the status code in the URL to see how the task reacts to different status codes.



Related Topics



Leave a reply



Submit