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.
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.