I want to sum value from dict - ansible

I have the following output:
"vmoff2": [
{
"sec_sys": "CONT1",
"vm_na": {
"vm1": "Running",
"vm2": "Running",
"vm3": "Not Activated",
"vm4": "Not Activated",
"vm5": "Running",
"vm6": "Not Activated"
}
},
{
"sec_sys": "CONT2",
"vm_na": {
"vm1": "Not Activated",
"vm2": "Not Activated",
"vm3": "Running",
"vm4": "Running",
"vm5": "Not Activated",
"vm6": "Running"
}
}
]
---------------
"vmprof2": [
{
"proc": {
"vm1": "0.5",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.5",
"vm5": "0.5",
"vm6": "0.5"
},
"sec_sys": "CONT1"
},
{
"proc": {
"vm1": "1.0",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.7",
"vm5": "0.5",
"vm6": "0.7"
},
"sec_sys": "CONT2"
}
]
And want to sum the proc of the not activated VM, comparing with wmoff2, the out expected will be:
proc_steal:
- server: CONT1
proc: 1.7
- server: CONT2
proc: 2.4
I tried the following:
- name: create proc_steal list
set_fact:
proc_steal: >-
{{ proc_steal | default([])
+ [{
'sec_sys': item.sec_sys,
'proc': vmprof2
| selectattr('sec_sys', '==', item.sec_sys)
| selectattr('proc', '==', item.vm_na)
| sum(attribute='value')
| float
}]
}}
loop: "{{ vmoff2 }}"
loop_control:
label: "{{ item.sec_sys }}"
but i get:
"proc_steal": [
{
"proc": 0.0,
"sec_sys": "CONT1"
},
{
"proc": 0.0,
"sec_sys": "CONT2"
}
]
}
Is not making the sum, maybe because is not float, but when i tried to put float i got an error "float object is not iterable", so how can i sum that values?

For example, to sum all VM
- set_fact:
proc_steal: "{{ dict(_serv|zip(_proc)) }}"
vars:
_serv: "{{ vmprof2|json_query('[].sec_sys') }}"
_proc: "{{ vmprof2|json_query('[].proc.*')|
map('map', 'float')|
map('sum')|
map('round', 2)|list }}"
gives the dictionary
proc_steal:
CONT1: 3.7
CONT2: 4.6
You can convert it to a list if you want to
- set_fact:
proc_steal: "{{ dict(_serv|zip(_proc))|
dict2items(key_name='server', value_name='proc') }}"
vars:
_serv: "{{ vmprof2|json_query('[].sec_sys') }}"
_proc: "{{ vmprof2|json_query('[].proc.*')|
map('map', 'float')|
map('sum')|
map('round', 2)|list }}"
gives
proc_steal:
- proc: 3.7
server: CONT1
- proc: 4.6
server: CONT2
To sum the Not Activated VM only, create a dictionary first
- set_fact:
vm_na: "{{ dict(_serv|zip(_vmna)) }}"
vars:
_serv: "{{ vmoff2|json_query('[].sec_sys') }}"
_vmna: "{{ vmoff2|json_query('[].vm_na')|
map('dict2items')|
map('selectattr', 'value', 'eq', 'Not Activated')|
map('map', attribute='key') }}"
gives
vm_na:
CONT1:
- vm3
- vm4
- vm6
CONT2:
- vm1
- vm2
- vm5
Then use it to select the machines
- set_fact:
proc_steal: "{{ proc_steal|d({})|combine({item.sec_sys: _proc|float}) }}"
loop: "{{ vmprof2 }}"
vars:
_proc: "{{ vm_na[item.sec_sys]|map('extract', item.proc)|
map('float')|
sum|
round(2) }}"
gives the dictionary
proc_steal:
CONT1: 2.0
CONT2: 2.2
, or
- set_fact:
proc_steal: "{{ proc_steal|d([]) + [{'server': item.sec_sys,
'proc': _proc|float}] }}"
loop: "{{ vmprof2 }}"
vars:
_proc: "{{ vm_na[item.sec_sys]|map('extract', item.proc)|
map('float')|
sum|
round(2) }}"
gives the list if you want to
proc_steal:
- proc: 2.0
server: CONT1
- proc: 2.2
server: CONT2

Related

Remove an item from a list of dict and splitting stdout_lines

Im trying to eliminate an item from a list of dicts, the one that have "No results were found":
"validar": [
{
"LPARNAME": [
"No results were found."
]
},
{
"LPARNAME": [
"server1",
"server2",
"server4"
]
},
{
"LPARNAME": [
"server3",
"server5",
"server7"
]
}
]
}
Im trying using rejectattr but is not working:
- name: clean
set_fact:
validar_: "{{ validar | rejectattr('LPARNAME', 'match', 'No results were found.') | list }}"
Also im trying to split stdout_lines of:
"output": [
{
"item": {
"Name": "CONT1"
},
"stdout_lines": [
"server1,1.05",
"server2,0.25"
]
},
{
"item": {
"Name": "CONT2"
},
"stdout_lines": [
"server3,0.05",
"server4,0.35"
]
},
{
"item": {
"Name": "PRD1"
},
"stdout_lines": [
"server4,1.15"
]
}
]
}
I got an error: {"msg": "'list object' has no attribute 'stdout_lines'"}
- name: list
set_fact:
lpar_proc: "{{ lpar_proc | default([]) + [{ 'lpar': item.[0] , 'proc': item[1] }]"
with_items: [ "{{ output.stdout_lines.split(',')[0]}}", "{{ output.stdout_lines.split(',')[1]" ]
the output expected:
Name: CONT1
vm: server1
proc: 1.05
Name: CONT1
vm: server2
proc: 0.25
... etc
you have list of list, so you cant use rejectattr as you do:
- name: testplaybook jinja2
hosts: localhost
gather_facts: no
vars:
validar:
- LPARNAME:
- No results were found.
- LPARNAME:
- server1
- server2
- server4
- LPARNAME:
- server3
- server5
- server7
tasks:
- name: clean
set_fact:
result: "{{ result | default([]) + [item] }}"
loop: "{{ validar }}"
when: '"No results were found." not in item.LPARNAME'
- name: set in validar
set_fact:
validar: "{{ result }}"
- name: debug
debug:
var: validar
result:
{
"validar": [
{
"LPARNAME": [
"server1",
"server2",
"server4"
]
},
{
"LPARNAME": [
"server3",
"server5",
"server7"
]
}
]
}
for the other problem:
- name: testplaybook
hosts: localhost
gather_facts: no
vars:
output:
- item:
Name: CONT1
stdout_lines:
- server1,1.05
- server2,0.25
- item:
Name: CONT2
stdout_lines:
- server3,0.05
- server4,0.35
- item:
Name: PRD1
stdout_lines:
- server4,1.15
tasks:
- name: m1
set_fact:
m1: "{{ m1 | d([]) + _p }}"
loop: "{{ output }}"
vars:
_p: "{{ [item['item']]| product(item.stdout_lines) }}"
- name: m2
set_fact:
result: "{{ result | d([]) + [_server] }}"
loop: "{{ m1 }}"
vars:
_vm: "{{ item.1.split(',')|first }}"
_proc: "{{ item.1.split(',')|last }}"
_server: "{{ item.0 | combine({'vm': _vm, 'proc': _proc}) }}"
- name: debug
debug:
var: result
result:
ok: [localhost] => {
"result": [
{
"Name": "CONT1",
"proc": "1.05",
"vm": "server1"
},
{
"Name": "CONT1",
"proc": "0.25",
"vm": "server2"
},
{
"Name": "CONT2",
"proc": "0.05",
"vm": "server3"
},
{
"Name": "CONT2",
"proc": "0.35",
"vm": "server4"
},
{
"Name": "PRD1",
"proc": "1.15",
"vm": "server4"
}
]
}
Given the data
validar:
- LPARNAME:
- No results were found.
- LPARNAME:
- server1
- server2
- server4
- LPARNAME:
- server3
- server5
- server7
The value of the attribute LPARNAME is a list. Use test contains instead of match. See Testing if a list contains a value
validar_: "{{ validar|
rejectattr('LPARNAME', 'contains', 'No results were found.') }}"
expands to
validar_:
- LPARNAME:
- server1
- server2
- server4
- LPARNAME:
- server3
- server5
- server7
Given the data
output:
- item:
Name: CONT1
stdout_lines:
- server1,1.05
- server2,0.25
- item:
Name: CONT2
stdout_lines:
- server3,0.05
- server4,0.35
- item:
Name: PRD1
stdout_lines:
- server4,1.1
Iterate with_subelements
- set_fact:
lpar_proc: "{{ lpar_proc|default([]) +
[item.0.item|
combine(dict(['vm', 'proc']|
zip(item.1.split(','))))] }}"
with_subelements:
- "{{ output }}"
- stdout_lines
gives
lpar_proc:
- {Name: CONT1, proc: '1.05', vm: server1}
- {Name: CONT1, proc: '0.25', vm: server2}
- {Name: CONT2, proc: '0.05', vm: server3}
- {Name: CONT2, proc: '0.35', vm: server4}
- {Name: PRD1, proc: '1.1', vm: server4}

How to separate the output of register into dict

I have the following output:
TASK [debug] ***********************
ok: [localhost] => {
"output": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"item": {
"NAME": "server1",
"SEC_SYS": "CONT2"
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "vm1,Not Activated\nvm2,Not Activated\nvm3,Running\nvm4,Running\nvm5,Not Activated\nvm6,Running\n",
"stdout_lines": [
"vm1,Not Activated",
"vm2,Not Activated",
"vm3,Running",
"vm4,Running",
"vm5,Not Activated",
"vm6,Running"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"item": {
"NAME": "server2",
"SEC_SYS": "CONT1"
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "vm1,Running\nvm2,Running\nvm3,Not Activated\nvm4,Not Activated\nvm5,Running\nvm6,Not Activated\n",
"stdout_lines": [
"vm1,Running",
"vm2,Running",
"vm3,Not Activated",
"vm4,Not Activated",
"vm5,Running",
"vm6,Not Activated"
]
},
{
"ansible_loop_var": "item",
"changed": true,
"failed": false,
"item": {
"NAME": "server3",
"SEC_SYS": "CONT2"
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "vm1,Not Activated\nvm2,Not Activated\nvm3,Running\nvm4,Running\nvm5,Not Activated\nvm6,Running\n",
"stdout_lines": [
"vm1,Not Activated",
"vm2,Not Activated",
"vm3,Running",
"vm4,Running",
"vm5,Not Activated",
"vm6,Running"
]
}
]
}
}
I want to turn into the following list:
vm_off:
- SEC_SYS: CONT2
VM_NA:
- vm1
- vm2
- vm5
- SEC_SYS: CONT1
VM_NA:
- vm3
- vm4
- vm6
Then sum the proc of the Not Activated VM, comparing from the list:
vmlist:
- name: vm1
proc: 0.5
- name: vm2
proc: 0.7
- name: vm3
proc: 1.0
- name: vm4
proc: 0.5
- name: vm5
proc: 0.5
- name: vm6
proc: 0.5
The expected output will be:
proc_steal:
- server: CONT1
proc: 1.7
- server: CONT2
proc: 2.0
I cant separate the stdout_lines into a dict because it appear an error:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'results'\n\nThe error appears to be in '/etc/ansible/val.yml': line 17, 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 - set_fact:\n ^ here\n"}
My .yml:
- hosts: localhost
gather_facts: no
vars:
vmservers:
- NAME: server1
SEC_SYS: CONT2
- NAME: server2
SEC_SYS: CONT1
- NAME: server3
SEC_SYS: CONT2
tasks:
- name: get not activated vm
ansible.builtin.script: "vm.sh {{ item.SEC_SYS }}"
register: output
loop: "{{ vmservers }}"
- set_fact:
vm_all: "{{ vm_all | default([]) + [item.results.stdout_lines.split(',')] }}"
with_items: "{{ output }}"
- debug:
var: output
- debug:
var: vm_all
the vm.sh just take a list of vm and its state:
#!/bin/bash
if [ "$1" = "CONT1" ]; then
case $1 in
"CONT1") cat cont1.txt;;
esac
else
case $1 in
"CONT2") cat cont2.txt;;
esac
fi
root:ansible# cat cont1.txt
vm1,Running
vm2,Running
vm3,Not Activated
vm4,Not Activated
vm5,Running
vm6,Not Activated
I create the dict vmoff2 using the following:
- name: create Not Activated VM list
set_fact:
vmoff: >-
{{ vmoff | default([])
+ [{
'sec_sys': item.item.SEC_SYS,
'vm_na': dict(item.stdout_lines
| from_yaml
| select()
| map('split', ',')
| list)
}]
}}
loop: "{{ output.results }}"
loop_control:
label: "{{ item.item.SEC_SYS }}"
And eliminate the duplicate output with:
- name: eliminate duplicate
set_fact:
vmoff2: "{{ vmoff2 | default([]) + [{'sec_sys': item.1.0.sec_sys, 'vm_na': item.1.0.vm_na }] }}"
loop: "{{ vmoff|groupby('sec_sys') }}"
Finally i have the following dict:
"vmoff2": [
{
"sec_sys": "CONT1",
"vm_na": {
"vm1": "Running",
"vm2": "Running",
"vm3": "Not Activated",
"vm4": "Not Activated",
"vm5": "Running",
"vm6": "Not Activated"
}
},
{
"sec_sys": "CONT2",
"vm_na": {
"vm1": "Not Activated",
"vm2": "Not Activated",
"vm3": "Running",
"vm4": "Running",
"vm5": "Not Activated",
"vm6": "Running"
}
}
]
---------------
"vmprof2": [
{
"proc": {
"vm1": "0.5",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.5",
"vm5": "0.5",
"vm6": "0.5"
},
"sec_sys": "CONT1"
},
{
"proc": {
"vm1": "1.0",
"vm2": "0.7",
"vm3": "1.0",
"vm4": "0.7",
"vm5": "0.5",
"vm6": "0.7"
},
"sec_sys": "CONT2"
}
]
I want to sum the proc of the Not activated VM, and have the following output:
proc_steal:
- server: CONT1
proc: 1.7
- server: CONT2
proc: 2.4
I tried the following:
- name: create proc_steal list
set_fact:
proc_steal: >-
{{ proc_steal | default([])
+ [{
'sec_sys': item.sec_sys,
'proc': vmprof2
| selectattr('sec_sys', '==', item.sec_sys)
| selectattr('proc', '==', item.vm_na)
| sum(attribute='value')
| float
}]
}}
loop: "{{ vmoff2 }}"
loop_control:
label: "{{ item.sec_sys }}"
but i get:
"proc_steal": [
{
"proc": 0.0,
"sec_sys": "CONT1"
},
{
"proc": 0.0,
"sec_sys": "CONT2"
}
]
}
Is not making the sum, maybe because is not float, but when i tried to put float i have an error, any guess?

Extract hostvar list

I'm trying to get secondary ip addresses from hosts in a group and set them to a fact.
my hostvars contain
{
"network_interfaces": [
{
"private_ip_address": "10.224.1.48",
"private_ip_addresses": [
{
"primary": true,
"private_dns_name": "ip-10-224-1-48.us-east-2.compute.internal",
"private_ip_address": "10.224.1.48"
},
{
"primary": false,
"private_dns_name": "ip-10-224-1-66.us-east-2.compute.internal",
"private_ip_address": "10.224.1.66"
},
{
"primary": false,
"private_dns_name": "ip-10-224-1-135.us-east-2.compute.internal",
"private_ip_address": "10.224.1.135"
}
],
"source_dest_check": true,
"status": "in-use",
"subnet_id": "subnet-0cfc6e2da31b9cf50",
"vpc_id": "vpc-123456"
}
],
}
Something like
set_fact:
private_ips: "{{ groups['database'] | map('extract', hostvars, ['network_interfaces[0]','private_ip_addresses[1]','private_ip_address']) | join(',') }}"
which doesn't work.
set_fact:
private_ips: "{{ groups['database'] | map('extract', hostvars, ['network_interfaces']) | map(attribute='private_ip_addresses') }}"
ends up with "private_ips": "[AnsibleUndefined, AnsibleUndefined]"
I'm looking for the result to be just a single IP out of private_ip_addresses from each host in the group
Create the list of IPs at each host
- set_fact:
my_ip: "{{ network_interfaces|json_query(_query) }}"
vars:
_query: '[].private_ip_addresses[].private_ip_address'
gives for the data from the example
my_ip:
- 10.224.1.48
- 10.224.1.66
- 10.224.1.135
Then, select the second item from the lists of all hosts in the group database
- set_fact:
private_ips: "{{ groups.database|
map('extract', hostvars, 'my_ip')|
map(attribute=1)|list }}"
run_once: true

Filter debug msg

I am using Ansible 2.9.13 and I have this playbook:
---
- hosts: localhost
connection: local
vars:
ansible_python_interpreter: /usr/bin/env python3
vars_files:
- vars.yml
tasks:
- name: Get Tags from given VM Name
vmware_vm_info:
validate_certs: no
hostname: '{{ vcenter_server }}'
username: '{{ vcenter_user }}'
password: '{{ vcenter_pass }}'
folder: '{{ provision_folder }}'
delegate_to: localhost
register: vm_info
- debug:
msg: "{{ vm_info.virtual_machines | json_query(query) }}"
vars:
query: "[?guest_name=='C97A1612171478']"
When I run it I am getting this output:
ok: [localhost] => {
"msg": [
{
"attributes": {},
"cluster": "xxx01",
"esxi_hostname": "xxxx",
"guest_fullname": "Microsoft Windows 10 (64-bit)",
"guest_name": "C97A1612171478",
"ip_address": "10.x.x.x",
"mac_address": [
"0x:x:x:x:xd:x"
],
"power_state": "poweredOn",
"tags": [],
"uuid": "420xxaf-xxx-xe2-9xe-a5xxxxxa3c",
"vm_network": {
"0x:x:x:xa:x:x": {
"ipv4": [
"169.x.x.x"
],
"ipv6": [
"x::x:x:x:xc"
]
},
"x:x:x:x:x0:x1": {
"ipv4": [
"169.x.x.x"
],
"ipv6": [
"x::x7:xf:x:x"
]
},
"0x:5x:x:x:ax:x": {
"ipv4": [
"10.x.x.x"
],
"ipv6": [
"x::1xx:x:8xx:x"
]
}
}
}
]
}
How can I filter the output to make it show only the "ip_address": "10.x.x.x".
In the end only the 10.x.x.x.
I have tried some ways adding the key ip_address in the message code but all of them gave me an error.
I can filter the msg using Python but if there's a way to get it using Ansible I would like to know how.
If you want to get this information without a loop:
If you need an object as a result:
- debug:
msg: "{{ vm_info.virtual_machines | json_query(query) }}"
vars:
query: "[?guest_name=='C97A1612171478'] | [0].{ip_address: ip_address}"
will yield
{
"ip_address": "10.x.x.x"
}
If you need a string as a result:
- debug:
msg: "{{ vm_info.virtual_machines | json_query(query) }}"
vars:
query: "[?guest_name=='C97A1612171478'] | [0].ip_address"
will yield
"10.x.x.x"
I can't test this properly, but try to fiddle around with the following code:
- debug:
msg: "{{ item.ip_address | json_query(query) }}"
loop: "{{ vm_info.virtual_machines }}"
vars:
query: "[?guest_name=='C97A1612171478']"

Ansible set_fact is overwriting the items

Here is my main.yml
---
- name: Gathering VCenter facts
vmware_vm_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: false
register: vcenter_facts
delegate_to: localhost
- debug:
var: vcenter_facts.virtual_machines
- name: Find all test-vms to run IO
set_fact:
vm_ip: "{{ item.ip_address }}"
loop: "{{ vcenter_facts.virtual_machines }}"
when: item.guest_name is regex("test_vm*")
- name: print vm_ip variable value
debug:
var: vm_ip
- name: Mount 16TB dropbox in each test vm
shell: mount-16tb-dropbox.sh
args:
chdir: /usr/local/bin/
with_items: "{{ vm_ip }}"
And here is the recap:
ok: [localhost] => {
"vcenter_facts.virtual_machines": [
{
"attributes": {},
"cluster": "Compute Cluster",
"esxi_hostname": "100.80.90.179",
"guest_fullname": "CentOS 7 (64-bit)",
"guest_name": "test_vm4",
"ip_address": "192.168.202.13",
"mac_address": [
"00:50:56:9d:d2:99"
],
"power_state": "poweredOn",
"tags": [],
"uuid": "421d7b54-1359-14e8-3ec4-74b568cb96d2",
"vm_network": {
"00:50:56:9d:d2:99": {
"ipv4": [
"192.168.202.13"
],
"ipv6": [
"fe80::44f6:a395:cde3:4dd1",
"fe80::a357:a163:e44f:2086",
"fe80::cd0c:e7d7:1356:2830"
]
}
}
},
{
"attributes": {},
"cluster": "Compute Cluster",
"esxi_hostname": "100.80.90.178",
"guest_fullname": "CentOS 7 (64-bit)",
"guest_name": "test_vm3",
"ip_address": "192.168.202.12",
"mac_address": [
"00:50:56:9d:a9:e8"
],
"power_state": "poweredOn",
"tags": [],
"uuid": "421d9239-0980-80c1-bca4-540efd726452",
"vm_network": {
"00:50:56:9d:a9:e8": {
"ipv4": [
"192.168.202.12"
],
"ipv6": [
"fe80::cd0c:e7d7:1356:2830"
]
}
}
},
{
"attributes": {},
"cluster": "Compute Cluster",
"esxi_hostname": "100.80.90.178",
"guest_fullname": "CentOS 7 (64-bit)",
"guest_name": "Test_Automation_CentOS8_Linux_VM",
"ip_address": "192.168.202.6",
"mac_address": [
"00:50:56:9d:13:14"
],
"power_state": "poweredOn",
"tags": [],
"uuid": "421d53ba-4824-57e4-06fd-fba0f2b1dbea",
"vm_network": {
"00:50:56:9d:13:14": {
"ipv4": [
"192.168.202.6"
],
"ipv6": [
"fe80::cd0c:e7d7:1356:2830",
"fe80::44f6:a395:cde3:4dd1"
]
}
}
},
{
"attributes": {},
"cluster": "Compute Cluster",
"esxi_hostname": "100.80.90.180",
"guest_fullname": "CentOS 7 (64-bit)",
"guest_name": "test_vm5",
"ip_address": "192.168.202.14",
"mac_address": [
"00:50:56:9d:85:b6"
],
"power_state": "poweredOn",
"tags": [],
"uuid": "421d6855-e60e-cd80-f113-39f11927d63b",
"vm_network": {
"00:50:56:9d:85:b6": {
"ipv4": [
"192.168.202.14"
],
"ipv6": [
"fe80::44f6:a395:cde3:4dd1",
"fe80::cd0c:e7d7:1356:2830",
"fe80::a357:a163:e44f:2086"
]
}
}
}
]
}
I am not able to loop through all the ip_address variable (i.e. 192.168.202.12, 192.168.202.13, 192.168.202.14).
It just reads the last item (i.e. 192.168.202.14).
What am I possibly doing wrong with set_fact that it is not reading all the variable and performing the set of tasks that follows?
An alternate solution using json_query
---
- name: Gathering VCenter facts
vmware_vm_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: false
register: vcenter_facts
delegate_to: localhost
- name: Mount 16TB dropbox in each test vm
shell: mount-16tb-dropbox.sh
args:
chdir: /usr/local/bin/
vars:
query: >-
[?contains("guest_name", 'test_vm')].ip_address[]
with_items: "{{ vcenter_facts.virtual_machines | to_json | from_json | json_query(query) | list }}"
Note: to_json | from_json is a workaround for a bug between ansible and jmespath so that all values can be converted to real strings and can be used with the jmespath contains function.
This should give all the IP. You correctly assumed where the code may need correction. In the code, vm_ip variable was overwritten by each loop and the last IP remained. What you need is a list and then append each IP to the list.
- set_fact:
vm_ip: "{{ vm_ip | default([]) + [item.ip_address] }}"
loop: "{{ vcenter_facts.virtual_machines | flatten }}"
when: item.guest_name is regex("test_vm*")
- debug:
var: vm_ip
Alternative solution using Jinja2 filters.
- set_fact:
vm_ip: >-
{{ vcenter_facts.virtual_machines | flatten
| rejectattr('guest_name', 'match', '^(?!test_vm).*')
| map(attribute='ip_address') | list }}

Resources