Hello Developer Community!
I have been working on developing some Ansible playbooks to manage Citrix NetScaler configuration and would like to get some help about the following. I have the following data structure defined in a variable named nsapp_lb_server:
nsapp_lb_server:
- name: "SRV-1"
ipaddress: "10.102.102.1"
comment: "Chewbacca"
- name: "SRV-2"
ipaddress: "10.102.102.2"
comment: "C-3PO"
- name: "SRV-3"
ipaddress: "10.102.102.3"
comment: "Obi-Wan Kenobi"
...
[+ another 1200 item...]
and I have the follow task:
- name: "Check variables (loop)"
ansible.builtin.assert:
that:
- ( (item.name is defined) and (item.name | length > 0) )
- ( (item.ipaddress is defined) and (item.ipaddress | ipaddr() == item.ipaddress) )
- ( (item.comment | length > 0) if (item.comment is defined) else omit )
loop: "{{ nsapp_lb_server }}"
My problem is that, when I have thousands of records in the nsapp_lb_server variable, the loop is incredibly slow. The task finishes in 30 minutes, which is a very long time... :-(
After some digging on the Internet, it seems, the issue is caused by Ansible "loop" function, so I would like to check if there are any other methods what I can use instead of loop.
Are there any alternatives of Ansible "loop" which can provide the same result (looping over the entries of the variable)? I was thinking about using json_query, but still do not know how to implement it in this specific case.
My environment:
$ ansible --version
ansible [core 2.12.6]
config file = /home/ansible/.ansible.cfg
configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/ansible/ansible/lib/python3.9/site-packages/ansible
ansible collection location = /home/ansible/.ansible/collections:/usr/share/ansible/collections
executable location = /home/ansible/ansible/bin/ansible
python version = 3.9.7 (default, Sep 21 2021, 00:13:39) [GCC 8.5.0 20210514 (Red Hat 8.5.0-3)]
jinja version = 3.0.3
libyaml = True
Could anyone please point me to the right direction? I have been working on my code set for a very long time and after testing the code with large data, the code seems to be useless, because of the running time. I have also checked the hardware resource allocated to the VM where Ansible controller is running on, nothing problematic.
Many thanks in advance!
Running this validation as thousands of individual tasks is very slow because it adds a lot of execution and callback overhead. You can instead do it in a single task, with the caveat that it will be harder to track down the invalid list item(s):
- hosts: localhost
gather_facts: false
vars:
nsapp_lb_server: "{{ nsapp_lb_samples * 10000 }}"
nsapp_lb_samples:
- name: "SRV-1"
ipaddress: "10.102.102.1"
comment: "Chewbacca"
- name: "SRV-2"
ipaddress: "10.102.102.2"
comment: "C-3PO"
- name: "SRV-3"
ipaddress: "10.102.102.3"
comment: "Obi-Wan Kenobi"
tasks:
- assert:
that:
- nsapp_lb_server | rejectattr('name') | length == 0
- (nsapp_lb_server | map(attribute='ipaddress') | map('ipaddr')) == (nsapp_lb_server | map(attribute='ipaddress'))
- nsapp_lb_server | selectattr('comment', 'defined') | rejectattr('comment') | length == 0
This runs in ~5 seconds for the 30,000 test entries I fed it.
To make it easier to find the bad values without making the task extremely ugly, you can split it up into a series of tasks:
- hosts: localhost
gather_facts: false
vars:
nsapp_lb_server: "{{ nsapp_lb_samples * 10000 }}"
nsapp_lb_samples:
- name: "SRV-1"
ipaddress: "10.102.102.1"
comment: "Chewbacca"
- name: "SRV-2"
ipaddress: "10.102.102.2"
comment: "C-3PO"
- name: "SRV-3"
ipaddress: "10.102.102.3"
comment: "Obi-Wan Kenobi"
tasks:
- name: Check for missing names
assert:
that: nsapp_lb_server | rejectattr('name', 'defined') | length == 0
fail_msg: "Bad entries: {{ nsapp_lb_server | rejectattr('name', 'defined') }}"
- name: Check for bad names
assert:
that: nsapp_lb_server | rejectattr('name') | length == 0
fail_msg: "Bad entries: {{ nsapp_lb_server | rejectattr('name') }}"
- name: Check for missing IP addresses
assert:
that: nsapp_lb_server | rejectattr('ipaddress', 'defined') | length == 0
fail_msg: "Bad entries: {{ nsapp_lb_server | rejectattr('ipaddress', 'defined') }}"
- name: Check for bad IP addresses
assert:
that: (nsapp_lb_server | map(attribute='ipaddress') | map('ipaddr')) == (nsapp_lb_server | map(attribute='ipaddress'))
fail_msg: "Suspicious values: {{ nsapp_lb_server | map(attribute='ipaddress') | map('ipaddr') | symmetric_difference(nsapp_lb_server | map(attribute='ipaddress')) }}"
- name: Check for bad comments
assert:
that: nsapp_lb_server | selectattr('comment', 'defined') | rejectattr('comment') | length == 0
fail_msg: "Bad entries: {{ nsapp_lb_server | selectattr('comment', 'defined') | rejectattr('comment') }}"
This runs in ~12 seconds for the same list of 30,000 test entries.
Related
I have made an ansible script to collect IP in the nginx log and then the IP that has been collected will be analyzed, if a malicious IP is detected it will be blocked.
The idea is that in the ansible script each IP analyzed is not created individually but using a loop function
But I'm having a hard time making a looping script in ansible, can anyone help?
Here is the script that i have created
- name: Execute a command using the shell module
shell: awk '{print $1}' /var/log/nginx/*.log | sort | uniq -c | sort -nr| head -5
register: results
- debug: var=results.stdout_lines
- name: Write Output
local_action: shell echo "{{ results.stdout_lines }}" > /tmp/output
#Collect IP
- name: Check 1st IP
local_action: shell cat /tmp/output | awk '{ print $3 }'| sed 's/.$//'|sed 's/.$//'
register: ip1
- debug: var=ip1.stdout
- name: Check 2nd IP
local_action: shell cat /tmp/output | awk '{ print $6 }'| sed 's/.$//'|sed 's/.$//'
register: ip2
- debug: var=ip2.stdout
- name: Check 3rd IP
local_action: shell cat /tmp/output | awk '{ print $9 }'| sed 's/.$//'|sed 's/.$//'
register: ip3
- debug: var=ip3.stdout
- name: Check 4th IP
local_action: shell cat /tmp/output | awk '{ print $12 }'| sed 's/.$//'|sed 's/.$//'
register: ip4
- debug: var=ip4.stdout
- name: Check 5th IP
local_action: shell cat /tmp/output | awk '{ print $15 }'| sed 's/.$//'|sed 's/.$//'
register: ip5
- debug: var=ip5.stdout
#Anlyze IP
- name: Analyze 1st IP
local_action: shell /usr/bin/abuseipdb -C {{ ip1.stdout }} -o plaintext
register: vb1
- debug: var=vb1.stdout
- name: Analyze 2nd IP
local_action: shell /usr/bin/abuseipdb -C {{ ip2.stdout }} -o plaintext
register: vb2
- debug: var=vb2.stdout
- name: Analyze 3rd IP
local_action: shell /usr/bin/abuseipdb -C {{ ip3.stdout }} -o plaintext
register: vb3
- debug: var=vb3.stdout
- name: Analyze 4th IP
local_action: shell /usr/bin/abuseipdb -C {{ ip4.stdout }} -o plaintext
register: vb4
- debug: var=vb4.stdout
- name: Analyze 5th IP
local_action: shell /usr/bin/abuseipdb -C {{ ip5.stdout }} -o plaintext
register: vb5
- debug: var=vb5.stdout
##Block IP if score more than 25
- name: Check 1rst IP and Block IP if score more than 25
shell: /sbin/route add "{{ ip1.stdout }}" gw 127.0.0.1 lo
when: "{{ vb1.stdout }} >= 25"
- name: Check 2nd IP and Block IP if score more than 25
shell: /sbin/route add "{{ ip2.stdout }}" gw 127.0.0.1 lo
when: "{{ vb2.stdout }} >= 25"
- name: Check 3rd IP and Block IP if score more than 25
shell: /sbin/route add "{{ ip3.stdout }}" gw 127.0.0.1 lo
when: "{{ vb3.stdout }} >= 25"
- name: Check 4th IP and Block IP if score more than 25
shell: /sbin/route add "{{ ip4.stdout }}" gw 127.0.0.1 lo
when: "{{ vb4.stdout }} >= 25"
- name: Check 5th IP and Block IP if score more than 25
shell: /sbin/route add "{{ ip5.stdout }}" gw 127.0.0.1 lo
when: "{{ vb5.stdout }} >= 25"
#Check Route
- name: Make Sure the IP has been blocked
shell: /sbin/route -n
register: route
- debug: var=route.stdout_lines
Here is the /tmp/output
└─$ cat /tmp/output
[' 40545 87.250.224.147', ' 20873 87.250.224.126', ' 16665 213.180.203.67', ' 15420 87.250.224.142', ' 14503 13.81.52.25']
Here is the output when running
└─$ cat /tmp/output | awk '{ print $3 }'| sed 's/.$//'|sed 's/.$//'
87.250.224.147
└─$ cat /tmp/output | awk '{ print $6 }'| sed 's/.$//'|sed 's/.$//'
87.250.224.126
└─$ cat /tmp/output | awk '{ print $9 }'| sed 's/.$//'|sed 's/.$//'
213.180.203.67
└─$ cat /tmp/output | awk '{ print $12 }'| sed 's/.$//'|sed 's/.$//'
87.250.224.142
└─$ cat /tmp/output | awk '{ print $15 }'| sed 's/.$//'|sed 's/.$//'
13.81.52.25
It is probably better to generate a JAML file from your Nginx log in order to use include_vars after that.
Btw: The idea of Ansible is to be platform independent. Because of that, it is better to have most of the platform specific stuff in an external script and not in the playbook. When you change the platform, you just have to migrate the external script, instead of rewriting the playbook.
Another alternative is to use scripted inventories. You can create a dynamic inventory by reading the IP addresses to block from your Nginx log. If you put the hosts to block into a group, you can define a single task for the group and delegate it to the firewall, where you block the hosts. You do not need to care about iterations. It is the job of Ansible to iterate.
This is much easier to maintain, than the playbook in your question. And it is extremely inefficient to put every line of a shell script into one local action. Don't do it.
PS: Yes you can program in a playbook, somehow. But try to avoid it. A playbook is not a useful programming language. You can not abstract with procedures and it has almost no scope. When you work with Ansible you have to change the way you think. Do not think about procedures. Instead thing about data. Take your data and arrange the data in a way, that is suitable for Ansible. If the data does not fit, use Jinja filters to rearrange the data until it fits. But avoid "programming" in a playbook by all means. And if you need to program, better do it in Jinja statements or Python.
so you could use range to loop over your command shell, i show you an example: when you loop with register, it records all output in list.
- name: "tips2"
hosts: localhost
tasks:
- name: Check 1st IP
local_action: shell echo {{ item }}
register: result
loop: "{{ range(0, 4 + 1, 2)|list }}" #loop from 0 to 4 with a step 2
- debug: var=result
#then you build your final list
- set_fact:
ips: "{{ ips | d([]) + item.stdout_lines }}"
loop: "{{ result.results }}"
- debug: var=ips
display variable result:
ok: [localhost] => {
"result": {
"changed": true,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
:
:
}
},
"item": 0,
"rc": 0,
"start": "2022-01-21 09:38:12.092426",
"stderr": "",
"stderr_lines": [],
"stdout": "0",
"stdout_lines": [
"0"
]
},
{
"ansible_loop_var": "item",
:
:
}
},
"item": 2,
"rc": 0,
"start": "2022-01-21 09:38:12.348007",
"stderr": "",
"stderr_lines": [],
"stdout": "2",
"stdout_lines": [
"2"
]
},
{
"ansible_loop_var": "item",
:
:
}
},
"item": 4,
"rc": 0,
"start": "2022-01-21 09:38:12.607555",
"stderr": "",
"stderr_lines": [],
"stdout": "4",
"stdout_lines": [
"4"
]
}
]
}
}
and result final ips after set_fact:
ok: [localhost] => {
"ips": [
"0",
"2",
"4"
]
}
just adapt the solution to your case: as i dont know your output, check the value of register...
- name: Check All IPs
local_action: shell cat /tmp/output | awk '{ print ${{item}} }'| sed 's/.$//'|sed 's/.$//'
register: result
loop: "{{ range(3, 15 + 1, 3)|list }}" #loop from 3 to 15 with a step 3
- set_fact:
ips: "{{ ips | d([]) + item.stdout_lines }}"
loop: "{{ result.results }}"
- name: Analyze All IPs
local_action: shell /usr/bin/abuseipdb -C {{ item }} -o plaintext
register: vbresult
loop: "{{ ips }}"
- debug: var=vbresult
another solution will be to trap alls your ips from your file in one task..
but you have to know your output, but the solution i show is easily adaptable to your case quickly
EDITED:
following your output, you could work directly from your result.stdout_lines:
- name: simulate your output result.stdout_lines
set_fact:
values:
- ' 40545 87.250.224.147'
- ' 20873 87.250.224.126'
- ' 16665 213.180.203.67'
- ' 15420 87.250.224.142'
- ' 14503 13.81.52.25'
- name: trap ips values
set_fact:
ips: "{{ ips | d([]) + [_ip] }}"
loop: "{{ values }}"
vars:
_ip: "{{ (item | trim).split(' ') | last }}"
- debug:
var: ips
result:
ok: [localhost] => {
"ips": [
"87.250.224.147",
"87.250.224.126",
"213.180.203.67",
"87.250.224.142",
"13.81.52.25"
]
}
I am facing issue while writing nested loops in ansible, for below iteration I am getting error
ansible role I am using looks like below
The conditional check 'item[0]['value']['from'] == COMPONENT_NAME' failed. The error was: error while evaluating conditional (item[0]['value']['from'] == COMPONENT_NAME): 'item' is undefined
Role
- name: create config file
template:
src: "{{template_source}}/{{COMPONENT_NAME}}/sessions/{{ item[0]['value']['protocol']}}/{{item[0]['value']['from_template']}}"
dest: "{{dest_folder}}/{{app}}/{{instance_name}}/{{COMPONENT_NAME}}/{{VENUE}}/Config/Repo/session/{{item[0]['value']['protocol']}}/{{item[1]}}.json"
mode: 0755
vars:
dest_file_name: "{{instance_name}}_{{COMPONENT_NAME}}_{{VENUE}}_{{item[0]['key']}}"
mbFlag: "{{item[0]['value']['broker'] | default('False')}}"
when: item[0]['value']['from'] == COMPONENT_NAME
with_nested:
- "{{ connections | dict2items }}"
- "{{myFileList['from_' + COMPONENT_NAME +'_'+ VENUE +'_'+ item[0]['value']['to']].split(',') }}"
yml file having below variable and I am iterating over it.
myFileList:
{
from_et_AG_zp: DevOpsTest_et_zp_AG_zp,
from_et_AG_sSP: 'DevOpsTest_et_sSP_AG_US,DevOpsTest_et_sSP_AG_BA,DevOpsTest_et_sSP_AG_chex',
from_et_AG_esb: DevOpsTest_et_esb_AG_ABC,
from_et_BA_Y_zp: DevOpsTest_et_zp_BA_Y_zp,
from_et_BA_Y_sSP: 'DevOpsTest_et_sSP_BA_Y_US,DevOpsTest_et_sSP_BA_Y_BA,DevOpsTest_et_sSP_BA_Y_chex',
from_et_BA_Y_esb: DevOpsTest_et_esb_BA_Y_ABC,
from_et_BA_zp: DevOpsTest_et_zp_BA_zp,
from_et_BA_sSP: 'DevOpsTest_et_sSP_BA_US,DevOpsTest_et_sSP_BA_BA,DevOpsTest_et_sSP_BA_chex',
from_et_BA_esb: DevOpsTest_et_esb_BA_ABC,
from_zp_zp_esb: DevOpsTest_zp_esb_zp_ABC,
from_SP_SP_esb: DevOpsTest_SP_esb_SP_ABC,
from_SSS_SSS_esb: DevOpsTest_SSS_esb_SSS_ABC,
to_zp_zp_es: DevOpsTest_et_zp_zp_es,
to_sSP_BA_es: DevOpsTest_et_sSP_BA_es,
to_sSP_chex_es: DevOpsTest_et_sSP_chex_es,
to_sSP_US_es: DevOpsTest_et_sSP_US_es,
to_esb_ABC_es: DevOpsTest_et_esb_ABC_es,
to_esb_ABC_zp: DevOpsTest_zp_esb_ABC_zp,
to_esb_ABC_SP: DevOpsTest_SP_esb_ABC_SP,
to_esb_ABC_SSS: DevOpsTest_SSS_esb_ABC_SSS
}
connections:
et_etb:
from: et
to: etb
from_template: et_etb.json
to_template: etb_et.json
protocol: ZERO
After too many permutation and combination, I realize that we can not pass outer loop variable value from outer loop to inner loop, So as work around I write first loop in first role and second loop in another role and call second role from first by iterating over first loop that full fill my ends
---
- name: create config file
include_role:
name: patch_template
vars:
file_key: "{{ 'from_' + COMPONENT_NAME +'_'+ VENUE +'_'+ role_item.value.to }}"
myprotocol: "{{role_item.value.protocol}}"
myTemplate: "{{role_item.value.from_template}}"
subComponent: "{{VENUE}}"
when: role_item.value.from == COMPONENT_NAME
with_items: "{{ connections | dict2items }}"
loop_control:
loop_var: role_item
patch_template role file
- name: patch template
template:
src: "{{template_source}}/{{COMPONENT_NAME}}/sessions/{{myprotocol}}/{{myTemplate}}"
dest: "{{dest_folder}}/{{app}}/{{instance_name}}/{{COMPONENT_NAME}}/{{subComponent}}/Config/Repo/session/{{myprotocol}}/{{item}}.json"
mode: 0755
vars:
dest_file_name: "{{item}}"
with_items:
- "{{ myFileList[file_key].split(',') }}"
Trying to extract a key pair value from a .yaml file and populate it into a variable:
/etc/puppetlabs/puppet/csr_attributes.yaml
File Example:
extension_requests:
pp_service: 'private'
pp_instance_id: 'blah'
pp_image_name: 'RedHat 7.7 Base'
pp_project: 'TBT'
pp_application: 'xxxxx'
pp_environment: 'dev'
pp_role: 'base_stuff'
pp_software_version: '2020-04-30'
pp_provisioner: 'Ansible Tower'
pp_datacenter: 'DC2'
pp_zone: 'C6600_NPE_RS'
pp_cloudplatform: 'esx'
pp_apptier: 'dev'
pp_securitypolicy: 'Stuff'
1.3.6.1.4.1.34380.1.2.1: ''
1.3.6.1.4.1.34380.1.2.2: '8'
1.3.6.1.4.1.34380.1.2.3: '77504'
I can do it via the line number, but I need it to be more dynamic as the lines are different from server to server:
Current individual line code:
- name: cat file
shell: cat /etc/puppetlabs/puppet/csr_attributes.yaml
register: cat_content_file
- set_fact:
pp_service: "pp_service: {{ cat_content_file.stdout_lines[2].split()[1] }}"
pp_application: "pp_application: {{ cat_content_file.stdout_lines[6].split()[1] }}"
- debug:
msg:
- "{{ pp_service }}"
- "{{ pp_application }}"
I think I need to convert the output into a dict, but I'm completely stuck on how to do it.
Any advice would be appreciated.
You could use a combination of file and from_yaml:
- set_fact:
your_variable: "{{ lookup('file','/etc/puppetlabs/puppet/csr_attributes.yaml') | from_yaml }}"
- debug: var=your_variable.extension_requests.pp_service
Variable file
I have a variable file
fruits:
- apple
- banana
- orange
- strawberry
- grapes
- papaya
users:
- user_name: 'john'
user_age: 45
- user_name: 'yash'
user_age: 95
- user_name: 'srk'
user_age: 52
- user_name: 'alia'
user_age: 26
Playbook Tasks
and my ansible tasks, just trying to make a text file and adding variables in file in vertical order.
- hosts: localhost
gather_facts: true
vars_files:
- variables.var # this is my variable file in the same dir that playbook have.
tasks:
- name: add fruits to the list
lineinfile:
create: yes
line: "{{ item }}"
path: /home/ansible/ansible-demo2/fruits.txt
loop:
- "{{ fruits|flatten }}"
- name: add uses to the list
lineinfile:
create: yes
line: "{{ item.user_name }} ==> {{ item.user_age }}"
path: /home/ansible/ansible-demo2/users.txt
loop:
- "{{ users|flatten(levels=1) }}"
Errors
But I am getting weird behavior. Below is the output of fruits task and error of the users task.
TASK [add fruits to the list] ***************************************************************************************************************************
ok: [localhost] => (item=[u'apple', u'banana', u'orange', u'strawberry', u'grapes', u'papaya'])
[WARNING]: The value ['apple', 'banana', 'orange', 'strawberry', 'grapes', 'papaya'] (type list) in a string field was converted to u"['apple',
'banana', 'orange', 'strawberry', 'grapes', 'papaya']" (type string). If this does not look like what you expect, quote the entire value to ensure it
does not change.
TASK [add uses to the list] *****************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'user_name'
\n\nThe error appears to be in '/home/ansible/ansible-demo2/myansible.yml': line 18, column 7, but may\nbe elsewhere in the file depending on the exact s
yntax problem.\n\nThe offending line appears to be:\n\n\n - name: add uses to the list\n ^ here\n"}
Expected Output
List in vertical order in text file.
Comment on question:
I am amazed every thing works fine with with_items and not with loop, even user_name variable is defined but still it is saying undefined. Now I unable to find out what's wrong going on.
Reference:
Here is the doc that I am referencing : Migrating from with_X to loop
Edit: Variables debug output
I debug the variables. output is below
TASK [debug] ********************************************************************************************************************************************
ok: [localhost] => {
"fruits": [
"apple",
"banana",
"orange",
"strawberry", "grapes", "papaya"
]
}
TASK [debug] ********************************************************************************************************************************************
ok: [localhost] => {
"users": [
{
"user_age": 45,
"user_name": "john"
},
{
"user_age": 95,
"user_name": "yash"
},
{
"user_age": 52,
"user_name": "srk"
},
{
"user_age": 26,
"user_name": "alia"
}
]
}
Q: *"[WARNING]: The value ['apple', ... ] (type list) in a string field was converted to u"['apple', ... ]" (type string).
A: From the code, it's not clear what is the reason for this conversion. The data and the playbook below work as expected.
shell> cat data.yml
fruits:
- apple
- banana
- orange
- strawberry
- grapes
- papaya
users:
- user_name: 'john'
user_age: 45
- user_name: 'yash'
user_age: 95
- user_name: 'srk'
user_age: 52
- user_name: 'alia'
user_age: 26
shell> cat playbook.yml
- hosts: localhost
vars_files:
- data.yml
tasks:
- name: add fruits to the list
lineinfile:
create: yes
line: "{{ item }}"
path: fruits.txt
loop: "{{ fruits }}"
- name: add uses to the list
lineinfile:
create: yes
line: "{{ item.user_name }} ==> {{ item.user_age }}"
path: users.txt
loop: "{{ users }}"
Give
shell> cat fruits.txt
apple
banana
orange
strawberry
grapes
papaya
shell> cat users.txt
john ==> 45
yash ==> 95
srk ==> 52
alia ==> 26
Q: "2 variables fruits1 and fruits2 ... append their data into single file ... in single task with 2 vars"
A: With the modified data
shell> cat data.yml
fruits1:
- apple
- banana
- orange
fruits2:
- strawberry
- grapes
- papaya
this task gives the same result
- name: add fruits to the list
lineinfile:
create: yes
line: "{{ item }}"
path: fruits.txt
loop: "{{ fruits1 + fruits2 }}"
See Append list variable to another list in Ansible.
Comment on the question: "I am amazed everything works fine with with_items and not with loop"
A: See Comparing loop and with_*.
Suppose I have the following playbook:
---
- hosts: all
gather_facts: False
vars:
group: 'dev'
tasks:
- name: Just loop through a group and group_vars
debug:
msg: 'group is {{group}} target is {{item.0}} port is {{item.1}}'
loop: >
{{ groups[group] |
product(hostvars[groups[group][0]]["ports"]) |
list }}
How can I change the loop part in case I have the variable named "group" defined as list and not as a single variable? For example:
vars:
group:
- 'dev'
- 'int'
Thanks and regards.
Stef
loop: >
{{ groups | dict2items |
selectattr("key", "in", group_list ) |
map(attribute="value") | list |
### and then the rest of your pipeline }}
I think will do what you want