Reputation: 3824
I have a playbook that targets a small set of hosts, and a task there that changes some configuration files on one or more of these hosts, depending on how I've set my variables.
A simplified example result of running this task:
TASK [somerole : create config file] *************************************
ok: [server1] => (item=foo.conf)
changed: [server2] => (item=foo.conf)
changed: [server3] => (item=foo.conf)
If I use register
on this task and then debug
the variable it creates, the output of the debug: var=varname
would look something like this (considerably simplified):
TASK [somerole : debug] **************************************************
ok: [server1] => {
"varname": {
"changed": false,
"results": [{...}]
}
}
ok: [server2] => {
"varname": {
"changed": true,
"results": [{...}]
}
}
ok: [server3] => {
"varname": {
"changed": true,
"results": [{...}]
}
}
The config change necessitates a service restart that currently has to be done manually by a human (there's a manual eyeballing validation step). To help with this, I would like to use the pause
module at the end of the playbook to display a prompt to the user, looking something like this:
- pause:
prompt: |-
The configuration has changed on the following servers: {{ changed_servers|join(', ' }}
Please restart service X on these servers after validating Y and Z.
So, how do I build the changed_servers
variable? Given the examples above, it would be this list:["server2", "server3"]
(since they were the hosts changed by the task this time).
I first thought I'd try to combine the varname
variable that register
produced for each host affected by the task, looking at the changed
boolean in each, but the name of the host is not present anywhere inside varname
so that I could combine the changed
attribute with the name of the corresponding host.
Is there actually a way to do this?
Upvotes: 1
Views: 782
Reputation: 67959
Q: "Store all hosts affected by a task in a variable"
A: Register a variable with the result of the task. Then use extract to collect the results. For example, the playbook below creates the file foo.conf registers the result and creates the dictionary dict_foo_conf
- hosts: test_11,test_12,test_13
tasks:
- command:
cmd: touch foo.conf
creates: foo.conf
warn: false
register: result_foo_conf
- set_fact:
dict_foo_conf: "{{ dict(ansible_play_hosts_all|zip(my_results)) }}"
vars:
my_results: "{{ ansible_play_hosts_all|
map('extract', hostvars, ['result_foo_conf', 'changed'])|
list }}"
run_once: true
gives
TASK [command] *************************************************************
changed: [test_11]
changed: [test_12]
changed: [test_13]
dict_foo_conf:
test_11: true
test_12: true
test_13: true
There are no changes when you run the playbook again
TASK [command] ******************************************************************
ok: [test_13]
ok: [test_11]
ok: [test_12]
dict_foo_conf:
test_11: false
test_12: false
test_13: false
Let's remove the files from hosts test_12 and test_13
shell> ssh admin@test_12 rm foo.conf
shell> ssh admin@test_13 rm foo.conf
The playbook gives
TASK [command] ******************************************************************
changed: [test_12]
ok: [test_11]
changed: [test_13]
dict_foo_conf:
test_11: false
test_12: true
test_13: true
Then select hosts that changed, for example
- set_fact:
changed_hosts: "{{ dict_foo_conf|dict2items|json_query('[?value].key') }}"
gives
changed_hosts:
- test_12
- test_13
Upvotes: 2