How to extract items with Ansible from stdout using json_query - ansible

I am executing shell script with Ansible which returns json output.
- name: Get mlist
become: no
shell: "PYTHONPATH=/home/centos/scripts/users/ python /home/centos/scripts/users/team_members.py {{ parameter }}"
register: account_list
the output looks like
ok: [localhost] => {
"msg": {
"changed": true,
"cmd": "PYTHONPATH=/home/centos/scripts/users/ python /home/centos/scripts/users/team_members.py parameter",
"delta": "0:00:00.530377",
"end": "2019-10-09 08:28:20.222480",
"failed": false,
"rc": 0,
"start": "2019-10-09 08:28:19.692103",
"stderr": "2019-10-09 08:28:19,915 INFO",
"stderr_lines": [
"2019-10-09 08:28:19,915 INFO"
],
"stdout": "[{'id': 'XXX=', 'name': 'XXX', 'login': 'xxx'}, {'id': 'YYY', 'name': 'YYY', 'login': 'yyy'}, {'id': 'ZZZ', 'name': 'zzz', 'login': 'zzz'}]",
"stdout_lines": [
"[{'id': 'XXX=', 'name': 'XXX', 'login': 'xxx'}, {'id': 'YYY', 'name': 'YYY', 'login': 'yyy'}, {'id': 'ZZZ', 'name': 'ZZZ', 'login': 'zzz'}]"
]
}
}
What I would like to do is to extract all login items. So far I've tried various ways
- debug:
msg: "{{ account_list.stdout | to_json | json_query('[*].login') }}"
But this is not working. While putting the .stdout to JSONPath Online Evaluator the .[*].login does what I want I just can't do that with Ansible json_query. Anybody who know how to do that ?
Thank you very much in advance.

I found the solution. I`ve had to update python script to actually output json as previously it didn't output correct json (see use of ' instead of ") and then
- debug:
msg: "{{ item }}"
with_items: "{{ account_list.stdout | from_json | json_query('[*].login') }}"
worked correctly

Related

ansible: "variable is not defined" even with ignore_erros: True & failed_when: 0 > 1 | How to define variable when task is failed/ignored/skipped?

Trying to get a variable defined when the task is partially failed/ignored. When a VM is not found in Vsphere it throws an error: "msg": "Unable to gather information for non-existing VM vm2"
I tried with and without ignore_errors: True and failed_when: 0 > 1 but no change.
I need the variable vm_fact to be defined even when a non-existing VM is in the decom_list. The plan is to change the list after i have identified which VM's are non-existing.
Please note: this task does work when all vm's are present in the system. When one is missing the task fails. I need the task not to fail so that i can clean the decom_list and then run it again.
- name: check/power(on/off) hosts on vsphere
hosts: localhost
ignore_errors: True
vars:
decom_list:
- vm1
- vm2
- vm3
tasks:
- name: check hosts on vsphere
vmware_guest_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
name: "{{ item }}"
schema: vsphere
datacenter: DC1
loop: "{{ decom_list }}"
register: vm_fact
ignore_errors: True
failed_when: 0 > 1
Whatever i try does not work because my vm_fact is not defined.
- debug:
var: "{{ vm_fact }}"
error:
TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
"<class 'dict'>": "VARIABLE IS NOT DEFINED!"
}
Just to confirm i did try all i know.
When i try it with a loop:
- debug:
var: "{{ item['item'] }}"
loop: "{{ vm_fact['results'] }}"
when: '"Unable to gather information for non-existing VM" in item.msg'
I get error:
ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm2', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm2', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm2', 'ansible_loop_var': 'item'}) => {
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": {
"datacenter": "DC1",
"folder": null,
"hostname": "hostname.domain",
"moid": null,
"name": "vm2",
"name_match": "first",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"properties": null,
"proxy_host": null,
"proxy_port": null,
"schema": "vsphere",
"tag_details": false,
"tags": false,
"use_instance_uuid": false,
"username": "username",
"uuid": null,
"validate_certs": true
}
},
"item": "vm2",
"msg": "Unable to gather information for non-existing VM vm2"
},
"vm2": "VARIABLE IS NOT DEFINED!"
}
ok: [localhost] => (item={'failed': False, 'msg': 'Unable to gather information for non-existing VM vm3', 'invocation': {'module_args': {'hostname': 'hostname.domain', 'username': 'username', 'password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'name': 'vm3', 'schema': 'vsphere', 'datacenter': 'DC1', 'port': 443, 'validate_certs': True, 'name_match': 'first', 'use_instance_uuid': False, 'tags': False, 'tag_details': False, 'proxy_host': None, 'proxy_port': None, 'uuid': None, 'moid': None, 'folder': None, 'properties': None}}, 'changed': False, 'failed_when_result': False, 'item': 'vm3', 'ansible_loop_var': 'item'}) => {
"ansible_loop_var": "item",
"item": {
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"failed_when_result": false,
"invocation": {
"module_args": {
"datacenter": "DC1",
"folder": null,
"hostname": "hostname.domain",
"moid": null,
"name": "vm3",
"name_match": "first",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"properties": null,
"proxy_host": null,
"proxy_port": null,
"schema": "vsphere",
"tag_details": false,
"tags": false,
"use_instance_uuid": false,
"username": "username",
"uuid": null,
"validate_certs": true
}
},
"item": "vm3",
"msg": "Unable to gather information for non-existing VM vm3"
},
"vm3": "VARIABLE IS NOT DEFINED!"
}
fatal: [localhost]: FAILED! => {"msg": "The conditional check '\"Unable to gather information for non-existing VM\" in item.msg' failed. The error was: error while evaluating conditional (\"Unable to gather information for non-existing VM\" in item.msg): 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 33, column 24, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n # - debug: var=vm_fact\n ^ here\n\nThere appears to be both 'k=v' shorthand syntax and YAML in this task. Only one syntax may be used.\n"}
Tried:
- debug:
msg: "{{ vm_fact['results']|json_query('msg') }}"
- debug:
msg: "{{ vm_fact['results']|to_json|from_json|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|dict2items|map(attribute='msg') }}"
- debug:
msg: "{{ vm_fact['results']|flatten|map(attribute='msg') }}"
error:
TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
"msg": ""
}
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 42, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'location': line 45, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ vm_fact['results']|dict2items|map(attribute='msg') }}): dict2items requires a dictionary, got <class 'list'> instead."}
...ignoring
TASK [debug] **************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'lcoation': line 51, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:\n ^ here\n"}
...ignoring
You are, frankly, making things very difficult for yourself. Ansible loops through hosts, use it.
decom.inv:
[decom]
vm1
vm2
vm3
decom.yml:
- name: check/power(on/off) hosts on vsphere
hosts: decom
gather_facts: no
tasks:
- name: check hosts on vsphere
vmware_guest_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
name: "{{ ansible_hostname }}"
schema: vsphere
datacenter: DC1
register: vm_fact
ignore_errors: True
failed_when: false
delegate_to: localhost
- name: Show results
debug:
var: vm_fact

Ansible playbook for restic

i was trying to setup Restic on a remote server using ansible but I keep getting this error
failed: [167.172.31.145] (item={'key': 'remote', 'value': {'location':
'ams3.digitaloceanspaces.com 167.172.31.145', 'password': '',
'aws_access_key': '', 'aws_secret_access_key': '',
'aws_default_region': '', 'init': True}}) => {"ansible_loop_var":
"item", "changed": false, "cmd": ["/usr/local/bin/restic", "init"],
"delta": "0:00:02.769841", "end": "2022-10-15 07:43:42.240541",
"failed_when_result": true, "item": {"key": "remote", "value":
{"aws_access_key": "", "aws_default_region": "",
"aws_secret_access_key": "", "init": true, "location":
"ams3.digitaloceanspaces.com 167.172.31.145", "password": ""}}, "msg":
"non-zero return code", "rc": 1, "start": "2022-10-15
07:43:39.470700", "stderr": "Fatal: create key in repository at
s3:ams3.digitaloceanspaces.com/resticspace/ failed: client.PutObject:
Access Denied.", "stderr_lines": ["Fatal: create key in repository at
s3:ams3.digitaloceanspaces.com/resticspace/ failed: client.PutObject:
Access Denied."], "stdout": "", "stdout_lines": []}
here's my play book
- hosts: testdrops
roles:
- role: do1jlr.restic
vars:
restic_create_schedule: true
restic_create_cron: true
restic_schedule_type: cronjob
restic_repos:
remote:
location: ams3.digitaloceanspaces.com {{ inventory_hostname }}
password: "{{ lookup('env', 'RESTIC_PASSWORD') }}"
aws_access_key: "{{ lookup('env', 'AWS_ACCESS_KEY_ID') }}"
aws_secret_access_key: "{{ lookup('env', 'AWS_SECRET_ACCESS_KEY') }}"
aws_default_region: "{{ lookup('env', 'AWS_DEFAULT_REGION') }}"
init: true
restic_backups:
etc:
name: etc
repo: remote
src: /etc/
scheduled: true
schedule_minute: 0
schedule_hour: 9
schedule_weekday: 1
schedule_month: '*'

Ansible Filter with_items list

I am using Ansible 2.10.7 and I need to filter a specific item in the with_items list.
Before using with_items msg looks like this:
"ansible_facts": {
"cvp_info": {
"version": "2020.2.3"
},
"devices": [
{
"architecture": "",
"bootupTimeStamp": 1615810038.137913,
"bootupTimestamp": 1615810038.137913,
"complianceCode": "",
Playbook:
---
- name: Playbook to demonstrate cv_container module.
hosts: cvp_servers
connection: local
gather_facts: no
collections:
- arista.cvp
vars:
vars_files:
- vars.yml
tasks:
- name: "collecting facts from CVP {{inventory_hostname}}"
arista.cvp.cv_facts:
facts:
devices
- name: "Print out facts from CVP"
debug:
msg: "{{item.name}}"
with_items: "{{devices}}"
After using the with_items: "{{devices}}", I see it is filtering the big list and then I get this output which I want to filter:
ok: [hq] => (item={'hostname': 'rd-sw055', 'danzEnabled': False, 'mlagEnabled': False, 'streamingStatus': 'active', 'status': 'Registered','bootupTimeStamp': 1605618537.210405, 'internalBuildId': '8c8dfbf2-a4d1-420a-9c9c-59f6aa67a14e', 'taskIdList': [], 'tempAction': None, 'memTotal': 0, 'memFree': 0, 'sslConfigAvailable': False, 'sslEnabledByCVP': False, 'lastSyncUp': 0, 'type': 'netelement', 'dcaKey': None, 'containerName': 'HQ',
'name': 'rd-sw055','deviceSpecificConfiglets': ['rd-sw055'], 'imageBundle': ''}) => {
"msg": "rd-sw055"
ok: [hq] => (item={'hostname': 'rd-sw01', 'danzEnabled': False, 'mlagEnabled': False, 'streamingStatus': 'active', 'status': 'Registered','bootupTimeStamp': 1605618537.210405, 'internalBuildId': '8c8dfbf2-a4d1-420a-9c9c-59f6aa67a14e', 'taskIdList': [], 'tempAction': None, 'memTotal': 0, 'memFree': 0, 'sslConfigAvailable': False, 'sslEnabledByCVP': False, 'lastSyncUp': 0, 'type': 'netelement', 'dcaKey': None, 'containerName': 'HQ',
'name': 'rd-sw01','deviceSpecificConfiglets': ['rd-sw01'], 'imageBundle': ''}) => {
"msg": "rd-sw01"
I want it to show only the item with the 'name': 'rd-sw01' how can I do it?
I have tried using
loop_control:
label: '{{ item.name }}'
At the end of the playbook but this will only show name value and not the whole item values.
End result wanted:
ok: [hq] => (item={'hostname': 'rd-sw01', 'danzEnabled': False, 'mlagEnabled': False, 'streamingStatus': 'active', 'status': 'Registered','bootupTimeStamp': 1605618537.210405, 'internalBuildId': '8c8dfbf2-a4d1-420a-9c9c-59f6aa67a14e', 'taskIdList': [], 'tempAction': None, 'memTotal': 0, 'memFree': 0, 'sslConfigAvailable': False, 'sslEnabledByCVP': False, 'lastSyncUp': 0, 'type': 'netelement', 'dcaKey': None, 'containerName': 'HQ',
'name': 'rd-sw01','deviceSpecificConfiglets': ['rd-sw01'], 'imageBundle': ''}) => {
"msg": "rd-sw01"
You do want a when condition here:
- debug:
var: item
loop: "{{ devices }}"
when: item.name == 'rd-sw01'
loop_control:
label: "{{ item.name }}"
Or even, simpler, skip the loop:
- debug:
var: devices | selectattr("name", "eq", "rd-sw01")

Ansible try to query an AWS TG using community-aws module to get TG status

I'm trying to query an AWS TG using the community-aws module to get TG status,
I want to query a specific TG every few seconds until I see that the state of that TG is "healthy".
So far I have this task in ansible:
- name: Gather information about the target group attached to a particular LB
vars:
ansible_python_interpreter: /usr/bin/python3.6
register: target_health
community.aws.elb_target_group_info:
region: "{{AWS_REGION}}"
target_group_arns: "{{TARGET_GROUP_ARN}}"
collect_targets_health: yes
delegate_to: 127.0.0.1
- debug: msg="return_target_health ={{target_health}}"
- name: iterate items
debug:
msg: "{{ item.targets_health_description }}"
with_items: "{{ target_health.target_groups }}"
The playbook output:
TASK [service : debug] ****************************************************
ok: [service.devbed-vpc.] => {
"msg": "return_target_health ={'target_groups': [{'target_group_arn': 'arn:aws:elasticloadbalancing:us-east-1:4795703XXXXX:targetgroup/Testbed-Vee-8124-TG/b8b282d82426331c', 'target_group_name': 'Testbed-Vee-8124-TG', 'protocol': 'HTTP', 'port': 8124, 'vpc_id': 'vpc-19333d7f', 'health_check_protocol': 'HTTP', 'health_check_port': '8124', 'health_check_enabled': True, 'health_check_interval_seconds': 10, 'health_check_timeout_seconds': 5, 'healthy_threshold_count': 5, 'unhealthy_threshold_count': 2, 'health_check_path': '/health', 'matcher': {'http_code': '200'}, 'load_balancer_arns': ['arn:aws:elasticloadbalancing:us-east-1:4795703XXXXX:loadbalancer/app/Testbed-Vee-ALB/e2b8546cb7196017'], 'target_type': 'instance', 'protocol_version': 'HTTP1', 'stickiness_enabled': 'false', 'deregistration_delay_timeout_seconds': '300', 'stickiness_type': 'lb_cookie', 'stickiness_lb_cookie_duration_seconds': '86400', 'slow_start_duration_seconds': '0', 'load_balancing_algorithm_type': 'round_robin', 'tags': {'Env': 'Testbed'}, 'targets_health_description': [{'target': {'id': 'i-0b9b6e5a2775bXXXX', 'port': 8124}, 'health_check_port': '8124', 'target_health': {'state': 'healthy'}}, {'target': {'id': 'i-0feb307f8bdf6XXXX', 'port': 8124}, 'health_check_port': '8124', 'target_health': {'state': 'healthy'}}]}], 'failed': False, 'changed': False}"
TASK [service : iterate items] ********************************************
ok: [service.devbed-vpc.] => (item={'target_group_arn': 'arn:aws:elasticloadbalancing:us-east-1:4795703XXXXX:targetgroup/Testbed-Vee-8124-TG/b8b282d82426331c', 'target_group_name': 'Testbed-Vee-8124-TG', 'protocol': 'HTTP', 'port': 8124, 'vpc_id': 'vpc-19333d7f', 'health_check_protocol': 'HTTP', 'health_check_port': '8124', 'health_check_enabled': True, 'health_check_interval_seconds': 10, 'health_check_timeout_seconds': 5, 'healthy_threshold_count': 5, 'unhealthy_threshold_count': 2, 'health_check_path': '/health', 'matcher': {'http_code': '200'}, 'load_balancer_arns': ['arn:aws:elasticloadbalancing:us-east-1:4795703XXXXX:loadbalancer/app/Testbed-Vee-ALB/e2b8546cb7196017'], 'target_type': 'instance', 'protocol_version': 'HTTP1', 'stickiness_enabled': 'false', 'deregistration_delay_timeout_seconds': '300', 'stickiness_type': 'lb_cookie', 'stickiness_lb_cookie_duration_seconds': '86400', 'slow_start_duration_seconds': '0', 'load_balancing_algorithm_type': 'round_robin', 'tags': {'Env': 'Testbed'}, 'targets_health_description': [{'target': {'id': 'i-0b9b6e5a2775bXXXX', 'port': 8124}, 'health_check_port': '8124', 'target_health': {'state': 'healthy'}}, {'target': {'id': 'i-0feb307f8bdf6XXXX', 'port': 8124}, 'health_check_port': '8124', 'target_health': {'state': 'healthy'}}]}) => {
"msg": [
{
"health_check_port": "8124",
"target": {
"id": "i-0b9b6e5a2775bXXXX",
"port": 8124
},
"target_health": {
"state": "UNhealthy"
}
},
{
"health_check_port": "8124",
"target": {
"id": "i-0feb307f8bdf6XXXX",
"port": 8124
},
"target_health": {
"state": "healthy"
}
}
]
}
I want to run this task until both "target_health:states" are healthy.
I wasn't able to do it, I was able to put the output to the file and then run a shell script that checks if the string "state": "healthy" is accruing more than once.
But then I realized the file is actually static and I write to it only once and only then I run the script in a loop which doesn't make any sense.
Is there a way for creating this query until I get the proper result I want without writing it to a file?
The retries:, delay:, and until: keywords will interest you
- name: Gather information about the target group attached to a particular LB
vars:
ansible_python_interpreter: /usr/bin/python3.6
register: target_health
community.aws.elb_target_group_info:
region: "{{AWS_REGION}}"
target_group_arns: "{{TARGET_GROUP_ARN}}"
collect_targets_health: yes
retries: 12
delay: 5
until: >-
{{ (target_health.target_groups[0].targets_health_description|length)
== target_health.target_groups[0].targets_health_description
| selectattr("target_health.state", "eq", "healthy") | list | length }}
delegate_to: 127.0.0.1
Alternatively, one could use awscli's wait, if you'd prefer to let awscli stall for you (it's not very ansible-y, but it makes for a ton less playbook log output as ansible retries)
- command: >-
aws --region {{ AWS_REGION }} elbv2 wait
target-in-service --target-group-arn {{ TARGET_GROUP_ARN | quote }}

Ansible: loop our shell command(Linux user group search) result and display the groups

Ansible: loop our shell command(Linux user group search) result and display the groups
Task to check if group exist
- name: "Checking if group doesn't exist"
shell: "grep -i {{ item.group }} /etc/group"
register: presence
loop: "{{ UserAddList.add_users }}"
ignore_errors: true
no_log: true
Json input file:
UserAddList is a json file
{
"add_users": [
{
"name": "test1_123",
"group": "test1_123",
"additional_groups":
[
"test2",
"group1"
],
"password" : "test1_newcdsaf",
"sudo_entry": "ALL=(ALL) NOPASSWD: ALL",
"comment": "test1"
}
],
"delete_users": [
]
}
Task to display the groups doesn't exist
- name: The following groups does't' exist
debug:
msg:
"{{ item._ansible_item_label.group }}"
loop: "{{ presence.results }}"
output:
(item={
'_ansible_parsed': True,
'stderr_lines': [
],
u'changed': True,
u'stdout': u'',
'_ansible_item_result': True,
u'msg': u'non-zero return code',
u'delta': u'0:00:00.008175',
'stdout_lines': [
],
'_ansible_item_label': {
u'comment': u'test1',
u'password': u'test1_newcdsaf',
u'group': u'test1_123',
u'name': u'test1_123',
u'sudo_entry': u'ALL=(ALL) NOPASSWD: ALL',
u'additional_groups': [
u'test2',
u'group1'
]
},
u'end': u'2019-12-10 14:23:15.725676',
'_ansible_no_log': True,
'item': {
u'comment': u'test1',
u'password': u'test1_newcdsaf',
u'group': u'test1_123',
u'name': u'test1_123',
u'sudo_entry': u'ALL=(ALL) NOPASSWD: ALL',
u'additional_groups': [
u'test2',
u'group1'
]
},
u'cmd': u'grep -i test1_123 /etc/group',
u'failed': True,
u'stderr': u'',
u'rc': 1,
u'invocation': {
u'module_args': {
u'warn': True,
u'executable': None,
u'_uses_shell': True,
u'_raw_params': u'grep -i test1_123 /etc/group',
u'removes': None,
u'argv': None,
u'creates': None,
u'chdir': None,
u'stdin': None
}
},
u'start': u'2019-12-10 14:23:15.717501'
})=>{
"changed": false,
"item": {
"changed": true,
"cmd": "grep -i test1_123 /etc/group",
"delta": "0:00:00.008175",
"end": "2019-12-10 14:23:15.725676",
"failed": true,
"invocation": {
"module_args": {
"_raw_params": "grep -i test1_123 /etc/group",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": {
"additional_groups": [
"test2",
"group1"
],
"comment": "test1",
"group": "test1_123",
"name": "test1_123",
"password": "test1_newcdsaf",
"sudo_entry": "ALL=(ALL) NOPASSWD: ALL"
},
"msg": "non-zero return code",
"rc": 1,
"start": "2019-12-10 14:23:15.717501",
"stderr": "",
"stderr_lines": [
],
"stdout": "",
"stdout_lines": [
]
},
"msg": "test1_123"
}
I don't want to display the whole output, I just want to display the groups information.
The debug is printing all the input data as well.
Please any suggestions
The debug is printing all the input data as well.
It's actually not the debug: task that is printing your data, ansible is showing you what it is looping over. However, you are using loop: over the top-level presence.results list, and .results contains not only the output you care about, but also the invocation parameters, success or failure, and the actual returned data that you care about
There are two ways of fixing that problem: tell ansible that you only want it to show something smaller in the loop label, or change the loop: to actually only loop over the deleted users
In the first way, loop_control: will do that (it even cites your exact circumstance in the docs saying When looping over complex data structures, the console output of your task can be enormous. To limit the displayed output, use the label directive with loop_control):
- name: The following groups does't' exist
debug:
msg:
"{{ item._ansible_item_label.group }}"
loop: "{{ presence.results }}"
loop_control:
label: "{{ item.item.name }}"
In the second way, just select out the group you care about and msg: it:
- name: The following groups does't' exist
debug:
msg:
"{{ item }}"
loop: "{{ presence.results | map(attribute='item') | map(attribute='group') | list }}"

Resources