'How can I get a list of child groups in Ansible?
I have an inventory file that looks like this:
[master]
host01
[nl]
host02
[us]
host03
[satellites:children]
nl
us
How can I get a list of groups that have satellites
as their parent?
I am looking for a solution that works similar to this:
- debug: msg="{{ item }}"
with_items: "{{ groups['satellites:children'] }}"
Update:
The only solution I was able to come with is this:
- debug: {{ item }}
with_items: "{{ groups }}"
when: item != "master" and item != "satellites" and item != "all" and item != "ungrouped"
But that is not very flexible.
Solution 1:[1]
You can try the following approaches:
vars:
parent: 'satellites'
tasks:
# functional style
- debug: msg="{{hostvars[item].group_names | select('ne', parent) | first}}"
with_items: "{{groups[parent]}}"
# set style
- debug: msg="{{hostvars[item].group_names | difference(parent) | first}}"
with_items: "{{groups[parent]}}"
Also select('ne', parent)
is interchangeable with reject('equalto', parent)
depending on what is more readable to you.
Links:
set theory operator
select and reject filters
Updated answer based on comments. inspiration from this thread.
vars:
parent: 'satellites'
tasks:
- name: build a subgroups list
set_fact: subgroups="{{ ((subgroups | default([])) + hostvars[item].group_names) | difference(parent) }}"
with_items: "{{groups[parent]}}"
- debug: var=subgroups
output:
"subgroups": [
"nl",
"us"
]
Solution 2:[2]
There is also another way where you process the file as text file with bash commands like awk
If file is with contents like
cat /tmp/test.ini
[group1]
host1
host2
[group2]
host3
host4
[first_two_groups:children]
group1
group2
[group3]
host5
host6
[group4]
host7
host8
Then you can use one command like this for when file has Linux EOL:
awk "/first_two_groups\:children/,/^$/" /tmp/test.ini | grep -v children
group1
group2
Where group to find children of is called first_two_groups
and it can be anywhere in the file. Command works as long as after the group definition there is empty line which is used as anchor to end the awk stream. I think most people add empty line in an ansible inventory file for readability and we can leverage that fact.
If the file happens to have Windows EOL then command is
awk "/first_two_groups\:children/,/^[\\r]$/" /tmp/test.ini | grep -v children
with ansible example something like this:
- name: get group children
shell: awk "/first_two_groups\:children/,/^$/" /tmp/test.ini | grep -v children
register: chlldren
#returns list of the children groups to loop through later
- debug: var=children.stdout_lines
Above is not fully tested but if an issue then it could be at the most with the escaping of special chars in the shell module. REMEMBER - when you pass special chars in ansible shell module like colon use jinja expansion - instead of :
use {{ ':' }}
Also for consistent bash behavior is recommended to pass explicitly the executable by tacking at the end of the task
args:
executable: /bin/bash
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |