How can I get a list of child groups in Ansible?
Asked Answered
J

2

7

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.

Johns answered 23/9, 2016 at 7:46 Comment(2)
what is wrong with with_items: "{{ groups['satellites'] }}"?Marchese
@stacksonstacks, even I posted that comment and then deleted it. Because the question How can I get a list of the groups that have satellites as their parent?, it will not give the groups. It give the hosts inside that groupKristiankristiansand
M
7

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"
    ]
Marchese answered 26/3, 2018 at 5:51 Comment(6)
Thanks for the reply! The issue I've got with this is that in the result it only outputs a child 'satellite' group a certain host is in. What I need to get is a list of the 'satellite' subgroups, in my case, 'nl' and 'us'.Johns
Here's what I get exactly: gist.github.com/konstantin-kelemen/… Expected output: { "nl", "us" }Johns
@KonstantinKelemen I've updated the answer to create a subgroups list.Marchese
Hi, thanks for the update, the example you provided works exactly as expected! I'm marking it as accepted. Thanks for your help!Johns
Hi, good reply, but there is a problem when nl or us are part of other groups: those other groups will appear in the listTurbary
This is a valid answer but with one caveat - if a host is member of more than one parent group then you get all parents not the one that you are looking up from. For exact parent children see my answer belowYongyoni
Y
0

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
Yongyoni answered 2/5, 2022 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.