Pocking into other’s hostvars
Published in
2 min readDec 21, 2017
We all was told how to read other hosts vars:
hostvars['hostname']['variable_name']
But what if we want to change it? Or, precise, what if we want to change something deep inside their dicts?
I’ll show you a solution and then explain how it works. We want to add/change foo=bar
inside dictionary somedict for the host ‘other_host’:
- name: Messing with other hosts variables
set_fact:
somedict: '{{ hostvars[item]["somedict"]|default({})|combine( {"foo": "bar"} )}}'
delegate_facts: yes
delegate_to: '{{ item }}'
with_items: [other_host]
- We delegate this task to host
other_host
. It’s much easier to change own facts. - We use a
combine
(not my idea, I adopted it from here) filter to add/replace values in the existing dictionarysomedict
. - We delegate facts (
delegate_facts: yes
) to make those changes happens for ‘other_host
’. - We are forced to use
hostvars[item][“somedict”]
because if we use just ‘somedict
’, it will be ‘our’somedict
, not theother_host
’ssomedict
. - We use a
|default({})
filter to handle situation when ‘other_host
' has no such variable. In this casecombine
returns just an resulting dict (combining {} with our value). - The last thing is very important but completely obscure. We couldn’t use just a play notation (we can’t assign it to hosts like this ‘
- {host: foo, tasks: [set_fact: …]}
’) because it will not run under--limit
option. We use ‘delegate_to
’ to overcome--limit
. I use this trick in monitoring configuration where I need to process data from all hosts, and I want to be able to run this task even if I use--limit
for ‘monitoring host only’. In this case I want to configure th monitoring host only, but I need all cross-hosts calculation nevertheless.