Ansible – Appending to Lists or Adding Keys to Dictionaries

ansible

(Related to Callbacks or hooks, and reusable series of tasks, in Ansible roles):

Is there any better way to append to a list or add a key to a dictionary in Ansible than (ab)using a jina2 template expression?

I know you can do something like:

- name: this is a hack
  shell: echo "{% originalvar.append('x') %}New value of originalvar is {{originalvar}}"

but is there really no sort of meta task or helper to do this?

It feels fragile, seems to be undocumented, and relies on lots of assumptions about how variables work in Ansible.

My use case is multiple roles (database server extensions) that each need to supply some configuration to a base role (the database server). It's not as simple as appending a line to the db server config file; each change applies to the same line, e.g. the extensions bdr and pg_stat_statements must both appear on a target line:

shared_preload_libaries = 'bdr, pg_stat_statements'

Is the Ansible way to do this to just process the config file multiple times (once per extension) with a regexp that extracts the current value, parses it, and then rewrites it? If so, how do you make that idempotent across multiple runs?

What if the config is harder than this to parse and it's not as simple as appending another comma-separated value? Think XML config files.

Best Answer

You can merge two lists in a variable with +. Say you have a group_vars file with this content:

---
# group_vars/all
pgsql_extensions:
  - ext1
  - ext2
  - ext3

And it's used in a template pgsql.conf.j2 like:

# {{ ansible_managed }}
pgsql_extensions={% for item in pgsql_extensions %}{{ item }}, {% endfor %}

You can then append extensions to the testing database servers like this:

---
# group_vars/testing_db
append_exts:
  - ext4
  - ext5
pgsql_extensions: "{{ pgsql_extensions + append_exts }}"

When the role is run in any of the testing servers, the aditional extensions will be added.

I'm not sure this works for dictionaries as well, and also be careful with spaces and leaving a dangling comma at the end of the line.