6

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.

Konstantin Kelemen
  • 85
  • 1
  • 1
  • 11
  • what is wrong with `with_items: "{{ groups['satellites'] }}"`? – stacksonstacks Mar 26 '18 at 04:15
  • 1
    @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 group – Tarun Lalwani Mar 26 '18 at 04:18

2 Answers2

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"
    ]
stacksonstacks
  • 8,613
  • 6
  • 28
  • 44
  • 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'. – Konstantin Kelemen Mar 29 '18 at 12:57
  • Here's what I get exactly: https://gist.github.com/konstantin-kelemen/91c3d47edba0ea77736edf03df7616f6 Expected output: ```{ "nl", "us" }``` – Konstantin Kelemen Mar 29 '18 at 13:00
  • 1
    @KonstantinKelemen I've updated the answer to create a subgroups list. – stacksonstacks Mar 30 '18 at 03:40
  • Hi, thanks for the update, the example you provided works exactly as expected! I'm marking it as accepted. Thanks for your help! – Konstantin Kelemen Mar 30 '18 at 15:36
  • 1
    Hi, good reply, but there is a problem when `nl` or `us` are part of other groups: those other groups will appear in the list – ady8531 Jan 17 '22 at 10:37
  • 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 below – Iskren P. May 02 '22 at 14:42
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
Iskren P.
  • 148
  • 1
  • 10