Pocking into other’s hostvars

George Shuklin
OpsOps
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]
  1. We delegate this task to host other_host. It’s much easier to change own facts.
  2. We use a combine (not my idea, I adopted it from here) filter to add/replace values in the existing dictionary somedict.
  3. We delegate facts (delegate_facts: yes) to make those changes happens for ‘other_host’.
  4. We are forced to use hostvars[item][“somedict”] because if we use just ‘somedict’, it will be ‘our’ somedict, not the other_host’s somedict.
  5. We use a |default({}) filter to handle situation when ‘other_host' has no such variable. In this case combine returns just an resulting dict (combining {} with our value).
  6. 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.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.