how to select values from lists - ansible

I have 6 hosts defined, these hosts have multiple IPv4's. I need a subset of IPv4's from these lists of IP's.
This is what I run
- hosts: gluster_mariadb
gather_facts: true
tasks:
- set_fact:
main_nodes_ips: "{{ groups.zicluster |
map('extract', hostvars, 'ansible_all_ipv4_addresses') |
list }}"
run_once: true
- debug:
var: main_nodes_ips
run_once: true
The response is:
ok: [zi04] => {
"main_nodes_ips": "[ ['172.18.0.1', '192.168.17.209', '172.17.0.1', '169.254.135.46', '169.254.74.141'], ['172.18.0.1', '192.168.17.208', '169.254.118.121', '169.254.53.186', '172.17.0.1'], ['172.18.0.1', '192.168.17.196', '172.17.0.1', '169.254.211.146', '169.254.1.199'], ['172.18.0.1', '192.168.17.159', '169.254.234.110', '169.254.150.56', '172.17.0.1'], ['172.18.0.1', '192.168.17.160', '172.17.0.1', '169.254.113.116', '169.254.97.143'], ['172.18.0.1', '192.168.17.161', '172.17.0.1', '169.254.240.6', '169.254.74.189']]"
}
I try to do a subselection with this:
- debug:
var:
main_nodes_ips | select('match', '^192') | list
This returns no data, I think because it is a list of lists.
So I try to do the subselection earlier. Like this:
- hosts: gluster_mariadb
gather_facts: true
tasks:
- set_fact:
main_nodes_ips: "{{ groups.zicluster |
map('extract', hostvars, 'ansible_all_ipv4_addresses') |
select('match', '^192') |
list }}"
run_once: true
- debug:
var: main_nodes_ips
run_once: true
This also returns no data.
ok: [zi04] => {
"main_nodes_ips": []
}
What I am looking for is something like this:
ok: [zi04] => {
"main_nodes_ips":
[
"192.168.17.100",
"192.168.17.101",
"192.168.17.102",
"192.168.17.103",
"192.168.17.104",
"192.168.17.105"
]
}

The variable main_nodes_ips is a list of lists
main_nodes_ips:
- - 172.18.0.1
- 192.168.17.209
- 172.17.0.1
- 169.254.135.46
- 169.254.74.141
- - 172.18.0.1
- 192.168.17.208
- 169.254.118.121
- 169.254.53.186
- 172.17.0.1
- - 172.18.0.1
- 192.168.17.196
- 172.17.0.1
- 169.254.211.146
- 169.254.1.199
- - 172.18.0.1
- 192.168.17.159
- 169.254.234.110
- 169.254.150.56
- 172.17.0.1
- - 172.18.0.1
- 192.168.17.160
- 172.17.0.1
- 169.254.113.116
- 169.254.97.143
- - 172.18.0.1
- 192.168.17.161
- 172.17.0.1
- 169.254.240.6
- 169.254.74.189
You can't use the filter select directly. You have to map the filter select to each item
main_nodes_192: "{{ main_nodes_ips|
map('select', 'match', '^192.*$')|
flatten }}"
gives
main_nodes_192:
- 192.168.17.209
- 192.168.17.208
- 192.168.17.196
- 192.168.17.159
- 192.168.17.160
- 192.168.17.161

Related

ansible get result from role and append to a list

I have a play like this
---
- name: List images in ACRs
any_errors_fatal: true
hosts:
- localhost
gather_facts: false
vars:
acrs: ["registry1", "registry2"]
tasks:
- name: list repos
with_items: "{{ acrs }}"
include_role:
name: list_docker_image_repos
vars:
registry_name: "{{ item }}"
list_docker_image_repos will do set_fact which a list of dicts.
How can I append all the facts (from every iteration) to a list?
Or is there are different way to do this?
thanks
In each iteration put the list into a dictionary. For example, given the role
shell> cat roles/list_docker_image_repos/tasks/main.yml
- set_fact:
docker_image_repos: "{{ ['repo1', 'repo2', 'repo3']|
product([registry_name])|
map('join', '-')|
list }}"
- set_fact:
my_lists: "{{ my_lists|
combine({registry_name: docker_image_repos}) }}"
the playbook
- hosts: localhost
vars:
acrs: [reg1, reg2]
my_lists: {}
tasks:
- name: list repos
include_role:
name: list_docker_image_repos
loop: "{{ acrs }}"
vars:
registry_name: "{{ item }}"
- debug:
var: my_lists
gives the dictionary
my_lists:
reg1:
- repo1-reg1
- repo2-reg1
- repo3-reg1
reg2:
- repo1-reg2
- repo2-reg2
- repo3-reg2
A dictionary is a more suitable structure for this purpose compared with a list. There are many ways how to use it. For example, you can
extract the lists
- debug:
msg: "{{ acrs|map('extract', my_lists)|list }}"
gives
msg:
- - repo1-reg1
- repo2-reg1
- repo3-reg1
- - repo1-reg2
- repo2-reg2
- repo3-reg2
Use the filter flatten to put all items into a single list
- debug:
msg: "{{ acrs|map('extract', my_lists)|flatten }}"
gives
msg:
- repo1-reg1
- repo2-reg1
- repo3-reg1
- repo1-reg2
- repo2-reg2
- repo3-reg2
Use the filter dict2items to iterate items
- debug:
var: item
loop: "{{ my_lists|dict2items }}"
gives (abridged)
item:
key: reg1
value:
- repo1-reg1
- repo2-reg1
- repo3-reg1
item:
key: reg2
value:
- repo1-reg2
- repo2-reg2
- repo3-reg2
Or, use the lookup plugin subelements to iterate the items of the lists as well
- debug:
var: item
with_subelements:
- "{{ my_lists|dict2items }}"
- value
gives (abridged)
item:
- key: reg1
- repo1-reg1
item:
- key: reg1
- repo2-reg1
item:
- key: reg1
- repo3-reg1
item:
- key: reg2
- repo1-reg2
item:
- key: reg2
- repo2-reg2
item:
- key: reg2
- repo3-reg2
Example of a complete playbook for testing
- hosts: localhost
vars:
acrs: [reg1, reg2]
my_lists: {}
tasks:
- name: list repos
include_role:
name: list_docker_image_repos
loop: "{{ acrs }}"
vars:
registry_name: "{{ item }}"
- debug:
var: my_lists
- debug:
msg: "{{ acrs|map('extract', my_lists)|list }}"
- debug:
msg: "{{ acrs|map('extract', my_lists)|flatten }}"
- debug:
var: item
loop: "{{ my_lists|dict2items }}"
- debug:
var: item
with_subelements:
- "{{ my_lists|dict2items }}"
- value

unable to naviate data structure in ansible using with_subelements

Can someone please explain why this code does not work? I want to expand it to a larger dataset, but I can't get this simple version working. It looks the same as an example I found to me.
1 ---
2
3 - hosts: localhost
4 vars:
5 GENERAL:
6 - CE_HOSTNAME: ROUTER1
7 CE_NEW: true
8
9 tasks:
10
11 - debug: debug
12 msg: "{{ item.0.CE_HOSTNAME }}"
13 with_subelements:
14 - "{{ GENERAL }}"
There are no sublists (nested lists) in the list GENERAL. with_subelements can't work here. Use simple loop instead. For example,
- hosts: localhost
vars:
GENERAL:
- CE_HOSTNAME: ROUTER1
CE_NEW: true
tasks:
- debug:
var: item
loop: "{{ GENERAL }}"
gives (abridged)
item:
CE_HOSTNAME: ROUTER1
CE_NEW: true
with_subelements can be used if there are nested lists. For example
- hosts: localhost
vars:
GENERAL:
- CE_HOSTNAME: ROUTER1
CE_NEW: true
CE_LIST:
- item1
- item2
- item3
tasks:
- debug:
var: item
with_subelements:
- "{{ GENERAL }}"
- CE_LIST
gives the product of the lists (abridged)
item:
- CE_HOSTNAME: ROUTER1
CE_NEW: true
- item1
item:
- CE_HOSTNAME: ROUTER1
CE_NEW: true
- item2
item:
- CE_HOSTNAME: ROUTER1
CE_NEW: true
- item3

How to reduce a list against another list of patterns?

I need to write with Ansible's built in filters and tests the similar logic of shell one-liner:
for path in $(find PATH_TO_DIR); do for pattern in $PATTERNS; do echo $path | grep -v $pattern; done; done
---
- hosts: localhost
connection: local
gather_facts: False
vars:
paths:
- "/home/vagrant/.ansible"
- path-one
- path-two
- path-three
- "/home/vagrant/.ssh"
- "/home/vagratn/"
patterns:
- ".*ssh.*"
- ".*ansible.*"
- ".*one.*"
tasks:
- name: set empty list
set_fact:
files_to_be_removed: [ ]
In the end I would like to have a list like this:
ok: [localhost] => {
"msg": [
"path-two",
"path-three",
"/home/vagratn/"
]
}
With this form I getting a list where only last item from patterns is applied.
- set_fact:
files_to_be_removed: |
{{ paths
|reject("search", item)
|list }}
with_items:
- "{{ patterns }}"
The tasks below do the job
- set_fact:
files_to_be_removed: "{{ paths }}"
- set_fact:
files_to_be_removed: "{{ files_to_be_removed|
reject('search', item)|
list }}"
loop: "{{ patterns }}"
- debug:
var: files_to_be_removed
give
"files_to_be_removed": [
"path-two",
"path-three",
"/home/vagratn/"
]

Combining lists of strings in Ansible

I have two lists of strings in Ansible:
vars:
pre:
- one
- two
post:
- alpha
- beta
I can get the cartesian product of these lists easily:
set_fact: prods="{{pre|product(post)|list}}"
How do I then combine the individual parts to get a list like this:
prods:
- one-alpha
- one-beta
- two-alpha
- two-beta
With a loop!
---
- hosts: localhost
gather_facts: false
vars:
pre:
- one
- two
post:
- alpha
- beta
tasks:
- set_fact:
prods: "{{ prods|default([]) + ['{}-{}'.format(item.0, item.1)] }}"
loop: "{{ pre|product(post)|list }}"
- debug:
var: prods
This will produce as output:
TASK [debug] **********************************************************************************
ok: [localhost] => {
"prods": [
"one-alpha",
"one-beta",
"two-alpha",
"two-beta"
]
}

VARIABLE IS NOT DEFINED when trying to register output in playbook

I'm trying to register a variable with the output to a query of a F5 pool and I'm getting this error:
"<type 'list'>": "VARIABLE IS NOT DEFINED!",
What is that I'm doing wrong?
Any help appreciated.
Thanks!
---
- name: GRAB F5 FACTS
hosts: f5
connection: local
gather_facts: no
tasks:
- name: Collect BIG-IP facts
bigip_device_facts:
gather_subset: ltm-pools
provider: "{{ prov }}"
register: bigip_device_facts
- name: FACTS OUTPUT
debug:
var: "{{ item.members | rejectattr('state', 'match', '^present$') | map(attribute='name') | list }}"
register: jkout
with_items: "{{ bigip_device_facts.ltm_pools }}"
when: item.full_path == "/Common/mypool"
- name: Set a variable
debug:
msg: "jkvar={{ jkout }}"
You are using the debug: module with the option var: and this expects a variable, not a jinja2 template.
So either change it to:
debug:
var: item.members
or
debug:
msg: "{{ item.members }}"
Like said by #dgw, the problem is with the var option of debug module.
https://docs.ansible.com/ansible/latest/modules/debug_module.html#parameters
This playbooks works:
- name: test rejectattr
hosts: localhost
gather_facts: no
vars:
members:
- { name: "one", state: "present" }
- { name: "two", state: "absent" }
- { name: "three", state: "present" }
tasks:
- name: FACTS OUTPUT
debug:
msg: "{{ members | rejectattr('state', 'match', '^present$') | map(attribute='name') | list }}"
Thanks for your responses. I'll investigate it further.
Apart from that, I think I've been able to solve it another way.
- name: FACTS OUTPUT
set_fact:
listado: "{{ item.members | rejectattr('state', 'match', '^present$') | map(attribute='name') | list }}"
with_items: "{{ bigip_device_facts.ltm_pools }}"
when: item.full_path == "/Common/mypool"
- debug: msg={{ listado }}
register: jkout
- name: Set a variable
debug:
msg: "jkvar={{ jkout }}"
Is that a right way to do it?
Thanks!!

Resources