How to prepend every string in a list with a prefix in Ansible

George Shuklin
OpsOps
Published in
2 min readDec 16, 2019

Let’s say you have an external dict (hostvars) where you take one element by a key (f.e. hostvars[host].foobar). This element is a list. You need to keep it as list and prepend (add at front) a string. Moreover, you need to join those lists together.

Here my answer. To simplify our task we will have: hv as imitation of hostvars, and, a list of keys for hv, imitation of groups.groupname. We want to join all foobars from hv with keys from gr, prepending every element with a fixed prefix prefix.

My solution:

---
- hosts: localhost
gather_facts: false
tasks:
-set_fact:
x: '{{ x|d([]) + [p]|product(hv[item].foo)|map("join")|list }}'
with_items: '{{ gr }}'
- debug: var=x
vars:
hv:
host1:
foobar:
- element one
- element two
junk:
- to annoy you
host2:
foobar:
- element 42
host3:
foobar: []
junk: to annoy you
host4:
- should be ignored
gr:
- host1
- host2
- host3
p: 'The '

Output is:

ok: [localhost] => {
"output": [
"The element one",
"The element two",
"The element 42"
]
}

Explanation

  1. hv[item].foo is an imitation of a normal hostvars[item].foo
  2. [p]|product(any_list) produces pairs of p and the next each next element of any_list (Cartesian product). (I use ‘p’ for prefix to fit the expression on the one line).
  3. map(“join”)|list apply join function to each pair, producing a string “{p}{element}” (it is applied to each pair from step 2). Additionally, list converts from generator to list.
  4. x|d([]) + everything else uses d (default) filter to assign x to empty list if x is undefined and adds every next expression into it.

Word of caution

You should be really careful with such tricks. Putting too many filters in one line makes code unreadable.

--

--

George Shuklin
OpsOps

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