Ansible/Jinja2 array concatenation changes in Debian Bookworm

Posted: 2023-07-24 21:50:19 by Alasdair Keyes

Direct Link | RSS feed


When I was first getting into Ansible, I read this article https://www.jeffgeerling.com/blog/2017/adding-strings-array-ansible by Jeff Geerling on how to add items to arrays a playbook using Jinja2 and I ended up incorporating it into my playbooks.

It's worth reading the article but essentially the code is...

hosts: localhost
connection: local
gather_facts: false

vars:
  my_messages: []

tasks:
  - name: Add to array
    ansible.builtin.set_fact:
      my_messages: "{{ my_messages }} + ['Message added to array: {{ item }}']"
    loop:
      - element one
      - something else
      - 3
      - false

  - name: Display messages
    ansible.builtin.debug:
      var: my_messages

This produced the following debug output

ok: [127.0.0.1] => {
    "my_messages": [
        "Message added to array: element one",
        "Message added to array: something else",
        "Message added to array: 3",
        "Message added to array: False"
    ]
}

I found this useful for any post-run reminders. The debug block was added at the end of the playbook and could prompt me to perform any other tasks that might be required.

After I upgraded from Debian Bullseye (11) to Bookworm (12) this feature was now no-longer working correctly. The code wouldn't error but the output would be one continuous string including the [] characters.

ok: [127.0.0.1] => {
    "my_messages": "[] + [ 'Message added to array: element one' ] + [ 'Message added to array: something else' ] + [ 'Message added to array: 3' ] + [ 'Message added to array: False' ]"
}

The change has occurred somewhere between Ansible 2.10.7 (with Jinja 2.11.3) and Ansible 2.14.3 (with Jinja 3.1.2).

To resolve this, the correct code is now...

hosts: localhost
connection: local
gather_facts: false

vars:
  my_messages: []

tasks:
  - name: Add to array
    ansible.builtin.set_fact:
      my_messages: "{{ my_messages + ['Message added to array: ' + item | string] }}"
    loop:
      - element one
      - something else
      - 3
      - false

  - name: Display messages
    ansible.builtin.debug:
      var: my_messages

The only line that has changed is the my_messages: fact setting. The array manipulation is now performed entirely within the {{ }} Jinja2 tags. This has a couple of knock-on effects that you will need to be aware of...

  1. You cannot use a loop variable with {{ item }} method as you will be using tags within tags and Ansible will throw an undefined variable error. You will have to concatenate your string/variables using the + operator.

  2. Because you are not using the {{ }} tags (because of point 1) but instead the concatenation operator +. It expects that you are only concatenating strings. As such you will need to ensure that any variables being joined are strings. If they are not, convert them with the | string modifier.

The second example shows both these methods being used to work correctly with later versions of Ansible/Jinja2

Depending on your use-case it's a little more messy, but won't take too much effort to convert.


If you found this useful, please feel free to donate via bitcoin to 1NT2ErDzLDBPB8CDLk6j1qUdT6FmxkMmNz

© Alasdair Keyes

IT Consultancy Services

I'm now available for IT consultancy and software development services - Cloudee LTD.



Happy user of Digital Ocean (Affiliate link)


Version:master-3093fcc3d4


Validate HTML 5