What causes Ansible to evaluate 'false and true' as 'true'? [duplicate] - ansible

I have the following tasks in a playbook I'm writing (results listed next to the debug statement in <>):
- debug: var=nrpe_installed.stat.exists <true>
- debug: var=force_install <true>
- debug: var=plugins_installed.stat.exists <true>
- name: Run the prep
include: prep.yml
when: (nrpe_installed.stat.exists == false or plugins_installed.stat.exists == true or force_install == true)
tags: ['prep']
- debug: var=nrpe_installed.stat.exists <true>
- debug: var=force_install <true>
- debug: var=force_nrpe_install <false>
- name: Install NRPE
include: install-nrpe.yml
when: (nrpe_installed.stat.exists == false or force_install == true or force_nrpe_install == true)
tags: ['install_nrpe']
vars:
nrpe_url: 'http://url.goes.here'
nrpe_md5: 3921ddc598312983f604541784b35a50
nrpe_version: 2.15
nrpe_artifact: nrpe-{{ nrpe_version }}.tar.gz
nagios_ip: {{ nagios_ip }}
config_dir: /home/ansible/config/
And I'm running it with the following command:
ansible-playbook install.yml -i $invFile --extra-vars="hosts=webservers force_install=True"
The first include runs, but the second skips with this output:
skipping: [server1] => {"changed": false, "skip_reason": "Conditional check failed", "skipped": true}
I'm under the impression that the conditional check should pass for all of them as force_install == true evaluates to true which should make the whole when evaluate to true (since it's a series of 'OR's).
How do I get the when to run when the variables are set appropriately?
Edit:
Changing the second when for the Install NRPE include to the following works, but doesn't explain why the other one, Run the prep runs appropriately:
Working:
when: (not nrpe_installed.stat.exists or force_install or force_nrpe_install)
Also working:
when: (nrpe_installed.stat.exists == false or plugins_installed.stat.exists == true or force_install == true)
Not working:
when: (nrpe_installed.stat.exists == false or force_install == true or force_nrpe_install == true)
The truncated (duplicates removed) output of that particular section of the play is:
TASK [debug] *******************************************************************
ok: [server2] => {
"nrpe_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"plugins_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_install": true
}
TASK [Run the prep] ************************************************************
included: /tasks/nrpe-install/prep.yml for server2, server3, server4, server5, server6, server7
TASK [Prep and configure for installation | Install yum packages] **************
ok: [server6] => (item=[u'gcc', u'glibc', u'glibc-common', u'gd', u'gd-devel', u'make', u'net-snmp', u'openssl-devel', u'unzip', u'tar', u'gzip', u'xinetd']) => {"changed": false, "item": ["gcc", "glibc", "glibc-common", "gd", "gd-devel", "make", "net-snmp", "openssl-devel", "unzip", "tar", "gzip", "xinetd"], "msg": "", "rc": 0, "results": ["gcc-4.1.2-55.el5.x86_64 providing gcc is already installed", "glibc-2.5-123.el5_11.3.i686 providing glibc is already installed", "glibc-common-2.5-123.el5_11.3.x86_64 providing glibc-common is already installed", "gd-2.0.33-9.4.el5_4.2.x86_64 providing gd is already installed", "gd-devel-2.0.33-9.4.el5_4.2.i386 providing gd-devel is already installed", "make-3.81-3.el5.x86_64 providing make is already installed", "net-snmp-5.3.2.2-20.el5.x86_64 providing net-snmp is already installed", "openssl-devel-0.9.8e-40.el5_11.x86_64 providing openssl-devel is already installed", "unzip-5.52-3.el5.x86_64 providing unzip is already installed", "tar-1.15.1-32.el5_8.x86_64 providing tar is already installed", "gzip-1.3.5-13.el5.centos.x86_64 providing gzip is already installed", "xinetd-2.3.14-20.el5_10.x86_64 providing xinetd is already installed"]}
TASK [Prep and configure for installation | Make nagios group] *****************
ok: [server2] => {"changed": false, "gid": 20002, "name": "nagios", "state": "present", "system": false}
TASK [Prep and configure for installation | Make nagios user] ******************
ok: [server6] => {"append": false, "changed": false, "comment": "User for Nagios NRPE", "group": 20002, "home": "/home/nagios", "move_home": false, "name": "nagios", "shell": "/bin/bash", "state": "present", "uid": 20002}
TASK [debug] *******************************************************************
ok: [server2] => {
"nrpe_installed.stat.exists": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_install": true
}
TASK [debug] *******************************************************************
ok: [server2] => {
"force_nrpe_install": false
}
TASK [Install NRPE] ************************************************************
skipping: [server2] => {"changed": false, "skip_reason": "Conditional check failed", "skipped": true}

You need to convert the variable to a boolean:
force_install|bool == true
I don't claim I understand the logic behind it. In python any non-empty string should be truthy. But when directly used in a condition it evaluates to false.
The bool filter then again interprets the strings 'yes', 'on', '1', 'true' (case-insensitive) and 1 as true (see source). Any other string is false.
You might want to also set a default value in case force_install is not defined, since it would result in an undefined variable error:
force_install|default(false)|bool == true

Yeah... certainly requires testing. I recommend
| bool is good unless you expect undefined vars
var is defined and (var | bool) if you expect undefined vars
default(False) is OK as long and you are happy that these are true if the input is not parsed from YAML. I.e. variables defined through --extra_vars CLI parameter are strings.
"false"
"null"
"defined string"
Hope this helps:
#!/usr/bin/env ansible-playbook
---
- name: Test truthiness
hosts: localhost
gather_facts: False
vars:
truthy_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "false"
- null
- False
- 0
# ERROR (invalid sytax error stops the loop of the first of these)
- "null"
- "defined string"
# ERROR
# truthy_var_undefined
# FALSE
truthy_var_defined:
tasks:
- name: Test truthy
debug:
msg: "is truthy"
ignore_errors: True # beware, the loo
when: item
loop: "{{ truthy_vars }}"
loop_control:
label: Test {{ item }}
- name: truthy_var_undefined
debug:
when: truthy_var_undefined
ignore_errors: true
- name: truthy_var_defined
debug:
when: truthy_var_defined
- name: Test | default(False)
hosts: localhost
gather_facts: False
vars:
default_pipe_vars:
# TRUE
- True
- 1
- "true"
# beware these:
- "false"
- "null"
- "defined string"
# FALSE
- null
- False
- 0
# FALSE
# default_pipe_undefined
# FALSE
default_pipe_defined:
tasks:
- name: Test | default(False)
debug:
msg: "is not | default(False)"
when: item | default(False)
loop: "{{ default_pipe_vars }}"
loop_control:
label: Test {{ item }}
- name: default_pipe_undefined | default(False)
debug:
when: default_pipe_undefined | default(False)
- name: default_pipe_defined | default(False)
debug:
when: default_pipe_defined | default(False)
- name: Test | bool
hosts: localhost
gather_facts: False
vars:
bool_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "defined string"
- "null"
- "false"
- null
- False
- 0
# ERROR
# bool_undefined
# FALSE
bool_defined:
tasks:
- name: Test bool parsing
debug:
msg: "parsed as true booleans"
when: item | bool
loop: "{{ bool_vars }}"
loop_control:
label: Test {{ item }}
- name: bool_undefined | bool
debug:
when: bool_undefined | bool
ignore_errors: true
- name: bool_defined var | bool
debug:
when: bool_defined | bool
- name: Test is defined and | bool
hosts: localhost
gather_facts: False
vars:
defined_bool_vars:
# TRUE
- True
- 1
- "true"
# FALSE
- "defined string"
- "null"
- "false"
- null
- False
- 0
# FALSE
# defined_bool_undefined
# FALSE
defined_bool_defined:
tasks:
- name: Test bool parsing
debug:
msg: "parsed as true booleans"
when:
- item is defined
- item | bool
loop: "{{ defined_bool_vars }}"
loop_control:
label: Test {{ item }}
- name: defined_bool_undefined | bool
debug:
when:
- defined_bool_undefined is defined
- defined_bool_undefined | bool
ignore_errors: true
- name: defined_bool_defined var | bool
debug:
when:
- defined_bool_defined is defined
- defined_bool_defined | bool
https://gist.github.com/kcd83/4ea23d201c271b58f1c4ef7844408657

Related

Get exactly data from "stdout" or "stdout_lines" with exact words of output

I have a task
- name: DELEGATED ADMIN ACCOUNTS - check, get and send to the file domain.list
shell: /opt/zimbra/bin/zmprov -l gaaa -v zimbraIsDelegatedAdminAccount
and after this task I got output
changed: [Shrrah] => {
"changed": true,
"cmd": [
"sh",
"/home/information_domain.sh"
],
"delta": "0:00:02.495922",
"end": "2022-03-29 10:25:16.936051",
"invocation": {
"module_args": {
"_raw_params": "sh /home/information_domain.sh",
"_uses_shell": false,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": false
}
},
"msg": "",
"rc": 0,
"start": "2022-03-29 10:25:14.440129",
"stderr": "",
"stderr_lines": [],
"stdout": "# name admin#shrrah.esquimail.com\nzimbraIsDelegatedAdminAccount: FALSE\n\n# name prueba5#prueba5.com\n\n# name prueba7#prueba7.com\nzimbraIsDelegatedAdminAccount: TRUE\n\n# name prueba9#prueba9.com",
"stdout_lines": [
"# name admin#shrrah.esquimail.com",
"zimbraIsDelegatedAdminAccount: FALSE",
"",
"# name prueba5#prueba5.com",
"",
"# name prueba7#prueba7.com",
"zimbraIsDelegatedAdminAccount: TRUE",
"",
"# name prueba9#prueba9.com"
]
}
I need to get data with n# name prueba7#prueba7.com\nzimbraIsDelegatedAdminAccount: TRUE from "stdout" or from "stdout_lines" in format:
prueba7#prueba7.com zimbraIsDelegatedAdminAccount: TRUE
or
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: TRUE
and send it to the file.txt. Number of lines can be different (one o more users with domain).
I have no idea how I can do this, is this possible? If you know could you please help with advice? Thank you!
You may have a look into debug – Print statements during execution, Using Variables and Return Values.
---
- hosts: localhost
become: true
gather_facts: false
vars:
RESULT:
STDOUT_LINES:
- "# name admin#shrrah.esquimail.com"
- "zimbraIsDelegatedAdminAccount: FALSE"
- ""
- "# name prueba5#prueba5.com"
- ""
- "# name prueba7#prueba7.com"
- "zimbraIsDelegatedAdminAccount: TRUE"
- ""
- "# name prueba9#prueba9.com"
tasks:
- name: Show STDOUT_LINES
debug:
msg: "{{ RESULT.STDOUT_LINES }}"
resulting into an output only of
TASK [Show STDOUT_LINES] *****************
ok: [localhost] =>
msg:
- '# name admin#shrrah.esquimail.com'
- 'zimbraIsDelegatedAdminAccount: FALSE'
- ''
- '# name prueba5#prueba5.com'
- ''
- '# name prueba7#prueba7.com'
- 'zimbraIsDelegatedAdminAccount: TRUE'
- ''
- '# name prueba9#prueba9.com'
and if Ansible Callback plugin is configured to YAML instead of JSON.
To get lines containing certain strings only you may Loop over the list based on a Condition
- name: Show lines with TRUE only
debug:
msg: "{{ item }}"
when: "'TRUE' in item"
loop: "{{ RESULT.STDOUT_LINES }}"
resulting into an output of
TASK [Show lines with TRUE only] *******************************
ok: [localhost] => (item=zimbraIsDelegatedAdminAccount: TRUE) =>
msg: 'zimbraIsDelegatedAdminAccount: TRUE'
Further Documenation
Index of all Callback Plugins
If you like to have the line before included, you could use an approach like
- name: Show lines with TRUE and line before
debug:
msg: "{{ RESULT.STDOUT_LINES[ansible_loop.index0 - 1] }}\n{{ item }}"
when: "'TRUE' in item"
loop: "{{ RESULT.STDOUT_LINES }}"
loop_control:
extended: true
label: "{{ ansible_loop.index0 }}"
resulting into an output of
TASK [Show lines with TRUE and line before] *************************************************************************************************************************************
ok: [localhost] => (item=6) =>
msg: |-
# name prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: TRUE
Further Documentation
Extended loop variables
Since you are using the shell module, you could use also an approach like
- name: DELEGATED ADMIN ACCOUNTS - check, get and send to the file domain.list
shell:
cmd: /opt/zimbra/bin/zmprov -l gaaa -v zimbraIsDelegatedAdminAccount | grep -B 1 TRUE
and gather only result lines which are true an the line before.
Further Q&A
grep a file, but show several surrounding lines?
Regarding
... send it to the file.txt
you may have a look into
Ansible - Save registered variable to file
Ansible: Save registered variables to file
...
Create a dictionary
- set_fact:
info: "{{ info|d({})|combine({_key: _val}) }}"
loop: "{{ stdout.split('#')[1:] }}"
vars:
_list: "{{ item.split('\n')|map('trim') }}"
_key: "{{ _list.0.split(' ')|last }}"
_val: "{{ _list[1:]|select()|map('from_yaml')|combine }}"
gives
info:
admin#shrrah.esquimail.com:
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com: {}
prueba7#prueba7.com:
zimbraIsDelegatedAdminAccount: true
prueba9#prueba9.com: {}
Then, the template is trivial. Either print all items
- copy:
content: |-
{% for k,v in info.items() %}
{{ k }}
{{ v|to_nice_yaml }}
{% endfor %}
dest: file.txt
gives
shell> cat file.txt
admin#shrrah.esquimail.com
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com
{}
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
prueba9#prueba9.com
{}
, or explicitly select item(s)
- copy:
content: |-
prueba7#prueba7.com
{{ info['prueba7#prueba7.com']|to_nice_yaml }}
dest: file.txt
gives
shell> cat file.txt
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
Note
Additional attributes will be parsed too, e.g.
stdout_lines: [
"# name admin#shrrah.esquimail.com",
"zimbraIsDelegatedAdminAccount: FALSE",
"",
"# name prueba5#prueba5.com",
"",
"# name prueba7#prueba7.com",
"zimbraIsDelegatedAdminAccount: TRUE",
"zimbraIsDelegatedRootAccount: TRUE",
"",
"# name prueba9#prueba9.com"
]
will give
info:
admin#shrrah.esquimail.com:
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com: {}
prueba7#prueba7.com:
zimbraIsDelegatedAdminAccount: true
zimbraIsDelegatedRootAccount: true
prueba9#prueba9.com: {}
and consequently
shell> cat file.txt
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
zimbraIsDelegatedRootAccount: true

Complex with_subelements construct

I have the list:
final_list:
- result:
name: "val1"
status: true
- result:
name: "val2"
status: true
- skipped:
path: "path1"
- result:
results:
- result:
name: "val4"
status: true
- result:
name: "val5"
status: true
- skipped:
path: "path2"
I would like check if any status in my list is false.
I started with:
- set_fact:
any_false: true
when: (item.0.result is defined and item.0.result.status == false) or (item.1.result is defined and item.1.result.status == false)
with_subelements:
- "{{ final_list }}"
- result.results"
- skip_missing: True
but this task ommit elements from finally_list without results in result.
I would expect iterate by all elements which contain status variable.
I tried also:
with_subelements:
- "{{ final_list }}"
- result.results | default([])
but get error:
msg: msg: the key result should point to a dictionary, got 'None'
I suggest to do this a bit differently: get all individual result elements in a single flattened list, extract the status and check that all elements are true (or not).
The following playbook should be self explanatory (run with -v to see intermediate debug)
---
- hosts: localhost
gather_facts: false
vars:
final_list:
- result:
name: "val1"
status: true
- result:
results:
- result:
name: "valA"
status: false
- result:
name: "valB"
status: true
- skipped:
path: "path2"
- result:
name: "val2"
status: true
- skipped:
path: "path1"
- result:
results:
- result:
name: "val4"
status: true
- result:
name: "val5"
status: true
- skipped:
path: "path2"
# List of all top level elements without nested elements
single_results: "{{ final_list | rejectattr('result.results', 'defined') }}"
# Flattened list of all nested result elements.
# Will work with several nested elements (as you can see from my example data)
nested_results: "{{ final_list | selectattr('result.results', 'defined') | map(attribute='result.results') | flatten }}"
# Single list containing top level + nested result elements
all_results: "{{ single_results + nested_results }}"
# List of all existing status values in the list of result elements
all_status: "{{ all_results | selectattr('result.status', 'defined') | map(attribute='result.status') }}"
tasks:
- name: Show entire list
debug:
var: all_results
verbosity: 1
- name: Show list of status
debug:
var: all_status
verbosity: 1
- name: Make sure all exsiting status are true
assert:
that:
- all_status is all
fail_msg: "At least one status is false"
success_msg: "All status are true"
which gives:
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [Show entire list] ****************************************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Show list of status] *************************************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
"assertion": "all_status is all",
"changed": false,
"evaluated_to": false,
"msg": "At least one status is false"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=2 rescued=0 ignored=0
And if you modify the data to all true (only pasting the last task...)
TASK [Make sure all exsiting status are true] ******************************************************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All status are true"
}
Q: "Check if any status is false."
A: Simple brute force
- set_fact:
status: "{{ status|d([]) + [item.split(':')|last|trim|bool] }}"
loop: "{{ (final_list|to_nice_yaml).splitlines() }}"
when: item is match('^.*\\s+status:\\s+.*$')
gives the list of the statuses
status:
- true
- true
- true
- true
See Testing if a list value is True, e.g.
- debug:
msg: No status is False.
when: status is all

Ansible remove quote from ansbile fact value

I have below task to setup IPv6 not disable settings. when I used ansible_default_ipv4.interface values its including to quote value. how to remove the quote from ansible fact value for below task?
- name: Ensure IPv6 not disabled with sysctl
sysctl:
name: "{{ item }}"
value: '0'
state: present
sysctl_file: /etc/sysctl.conf
reload: yes
with_items:
- "net.ipv6.conf.{{ ansible_default_ipv4.interface }}.disable_ipv6"
ignore_errors: yes
This gives below message
cannot stat /proc/sys/net/ipv6/conf/\"ens192\"/disable_ipv6: No such file or directory\
Here is the fact value:
"ansible_default_ipv4": {
"alias": "ens192",
"interface": "ens192",
"mtu": 1500,
"type": "ether"
},
Thanks
SR
Works for me in Ansible 2.9.6. For example
- sysctl:
name: "{{ item }}"
value: "1"
register: result
with_items:
- "net.ipv4.conf.{{ ansible_default_ipv4.interface }}.forwarding"
- debug:
var: result
gives
TASK [sysctl] ****
ok: [localhost] => (item=net.ipv4.conf.eth0.forwarding)
TASK [debug] ****
ok: [localhost] =>
result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
changed: false
failed: false
invocation:
module_args:
ignoreerrors: false
name: net.ipv4.conf.eth0.forwarding
reload: true
state: present
sysctl_file: /etc/sysctl.conf
sysctl_set: false
value: '1'
item: net.ipv4.conf.eth0.forwarding

Conditional set_fact doesn't evaluate

I'm looking to set a variable based on the outcome of the following evaluation: ({{ found_files.files|length > 0 }}), however, it doesn't appear to be evaluated fully. What could be the issue?
Desired outcome:found_files2: /dev/null
Outcome:
TASK [debug] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"found_files2": "{'files': [], 'changed': False, 'msg': '', 'matched': 0, 'examined': 0, 'failed': False} if (False) else '/dev/null'"
}
Playbook:
---
- hosts: localhost
gather_facts: no
vars:
backup_dir: /home/user1/projects/ansible/modules/backups/router2
tasks:
- name: get files in backups/<router name>/
delegate_to: localhost
find:
paths: "{{ backup_dir }}"
register: found_files
- set_fact:
found_files2: "{{ found_files }} if ({{ found_files.files|length > 0 }}) else '/dev/null'"
- debug: var=found_files2
The correct syntax is below
- set_fact:
found_files2: "{{ found_files if (found_files.files|length > 0) else '/dev/null' }}"
The filter ternary gives the same result
- set_fact:
found_files2: "{{ (found_files.files|length > 0)|ternary(found_files, '/dev/null') }}"

How to fix "false" being evaluated to True in Ansible (Jinja2 templates) [duplicate]

This question already has answers here:
Conditionals: check type of element
(1 answer)
Ansible "when variable == true" not behaving as expected
(2 answers)
Closed 4 years ago.
How to make sure Jinja2 templates used within Ansible plays / roles are prone to "false" being evaluated to True?
Background:
Boolean handling in Ansible is tricky and may lead to an unexpected results when used along with Jinja2 templating.
Turns out that Ansible handles differently "false" value:
When used in when clause it evaluates to False
When used in Jinja2 template it evaluates to True
Take a look at this simple example:
---
- name: Sample play
hosts: localhost
gather_facts: false
vars:
enabled: 'false'
tasks:
- name: Print enabled / disabled with Jinja2 inline condition
debug:
msg: "{{ 'enabled' if enabled else 'disabled' }}"
- name: Print enabled
debug:
msg: Enabled
when: enabled
First task prints enabled even though variable is 'false', the second task skips:
PLAY [Sample play] *********************************************************************************************************************************************************************
TASK [Print enabled / disabled with Jinja2 inline condition] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "enabled"
}
TASK [Print enabled] *******************************************************************************************************************************************************************
skipping: [localhost]
There are two approaches you can use to make sure "false" is evaluated to False in Jinja2 templates:
1. Use bool filter
Simply add bool filter to every Jinja2 condition when a variable of boolean type is being used:
---
- hosts: localhost
gather_facts: false
tasks:
- debug:
msg: "{{ 'enabled' if item | bool else 'disabled' }}"
with_items:
- "true"
- "false"
- true
- false
This results with:
TASK [debug] ***************************************************************************************************************************************************************************
ok: [localhost] => (item=true) => {
"msg": "enabled"
}
ok: [localhost] => (item=false) => {
"msg": "disabled"
}
ok: [localhost] => (item=True) => {
"msg": "enabled"
}
ok: [localhost] => (item=False) => {
"msg": "disabled"
}
Or in a template file:
{% if enabled | bool %}
# ...
{% endif %}
2. Use assertion
You can also enforce that variable value is a boolean and not a string with an assertion:
- assert:
that:
- enabled == enabled | bool
# or you may use `type_debug` filter
- enable | type_debug == 'bool'
Simply add this at the beginning of your Ansible role / playbook. It will fail if the variable is not a true or false.
For this play:
---
- hosts: localhost
gather_facts: false
tasks:
- assert:
that:
- item == item | bool
with_items:
- "true"
- "false"
- true
- false
Only true and false pass, "true" and "false" is rejected:
TASK [assert] **************************************************************************************************************************************************************************
failed: [localhost] (item=true) => {
"assertion": "item == item | bool",
"changed": false,
"evaluated_to": false,
"item": "true"
}
failed: [localhost] (item=false) => {
"assertion": "item == item | bool",
"changed": false,
"evaluated_to": false,
"item": "false"
}
ok: [localhost] => (item=True) => {
"changed": false,
"item": true,
"msg": "All assertions passed"
}
ok: [localhost] => (item=False) => {
"changed": false,
"item": false,
"msg": "All assertions passed"
}

Resources