ansibleansible-inventoryansible-tower

Ansible: Listing inventory group members


I have what I'm hoping is a simple question to answer, we have multiple groups of servers that patch monthly with Ansible Tower. The morning prior to a group being patched I have Ansible send out an email to the respective groups that would work on those servers so they are aware prior to the patches.

Currently, I have the playbooks written manually where I have typed out the name of every server in each group, but as groups grow and change, this becomes a pain as I'm having to edit these playbooks each time.

How can I have Ansible populate the names of servers in a group without me having to type them out? Here's my example playbook:

- name: Alert for pending updates 
  hosts: localhost
  tasks:

    - name: Send email to groups
      community.general.mail:
        to:
        - 'email address 1'
        - 'email address 2'
        - 'email address 3'
        cc:
        - 'email address 1'
        - 'email address 2'
        subject: Scheduled Update Alert
        body: "Monthly OS patches will begin tonight at 9pm CST on the following systems: Server 1, Server 2, Server 3, Server 4, Server 5, and Server 6"
        sender: "ansible.updates@domain.com"
        headers: 'Reply-To=email@domain.com'
      delegate_to: localhost

I'm not sure if this is relevant, but we do not use static inventory files, our inventories are synced with vCenter and the groups are created using tags in vCenter.

Thanks to anyone who takes time to help!

Edit

Using @U880D playbook:

---
- name: Test output of hosts in a group
  hosts: localhost
  gather_facts: false

  tasks: 

    - name: Show Facts
      debug:
        msg: "{{ groups }}"
...

I'm using Ansible Tower, so the inventory in my original question is dynamically created from VMware and I use tags on the VMs in vCenter to create groups in my Ansible inventory, so rather than using the dynamically created inventory and having a massive output of groups and servers, I used a static "test" inventory with one server in it. I created a few different test groups and left some of them empty and populated others with the test server.

Here's the output of that:

ok: [localhost] => {
    "msg": {
        "Test_Group_1": [
            "test server 1"
        ],
        "Test_Group_2": [],
        "Test_Group_3": [
            "test server 1"
        ],
        "all": [
            "test server 1"
        ],
        "ungrouped": []
    }
}

How do you now filter this output down to a single group? Currently using this method it just prints all groups and their members. I want to be able to tell Ansible to select, for example Test_Group_3 and list it's members in my email body.


Solution

  • Ansible provides Specical Variables like groups_names and groups

    A dictionary/map with all the groups in inventory and each group has the list of hosts that belong to it

    An inventory like

    [test]
    test.example.com
    
    ansible-inventory --graph
    @all:
      |--@test:
      |  |--test.example.com
      |--@ungrouped:
    
    ansible-inventory --list
    {
        "_meta": {
            "hostvars": {}
        },
        "all": {
            "children": [
                "test",
                "ungrouped"
            ]
        },
        "test": {
            "hosts": [
                "test.example.com"
            ]
        }
    }
    

    has Default groups and a sample playbook like

    ---
    - hosts: test
      become: false
      gather_facts: false
    
      tasks:
    
      - name: Show Facts
        debug:
          msg: "{{ groups }}"
    

    will result into an output of

    TASK [Show Facts] *******
    ok: [test.example.com] =>
      msg:
        all:
        - test.example.com
        test:
        - test.example.com
        ungrouped: []
    

    How can I have Ansible populate the names of servers in a group without me having to type them out?

    The above mentioned approach could be the first step to get a list of hostnames for an email body.


    How do you now filter this output down to a single group? Currently using this method it just prints all groups and their members. I want to be able to tell Ansible to select, for example test group and list it's members in my email body.

    For this have a look into the following approach

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        PATCHGROUP: 'test'
    
      tasks:
    
      - name: Show Facts
        debug:
          msg: "{{ groups[PATCHGROUP] | join(', ') }}"
    

    which will result into an output of

    TASK [Show Facts] **********************************************************************************************************************************
    ok: [localhost] =>
      msg: test.example.com, added.example.com
    

    In other words, one need just to define the group dynamically and make a string out of the list by simply joining the elements and in the case shown probably end up with something like

    body: "Monthly OS patches will begin tonight at 9pm CST on the following systems: {{ groups[PATCHGROUP] | join(', ') }}"
    

    Here it was used Referencing nested variables from Dictionary variables and Manipulating strings.