Jinja2: format + join the items of a list

18,075

Solution 1

In ansible you can use regex_replace filter:

{{ play_hosts | map('regex_replace', '^(.*)$', 'rabbitmq@\\1') | list }}

Solution 2

You can create custom filter

# /usr/share/ansible/plugins/filter/format_list.py (check filter_plugins path in ansible.cfg)

def format_list(list_, pattern):
    return [pattern % s for s in list_]


class FilterModule(object):
    def filters(self):
        return {
            'format_list': format_list,
        }

and use it

{{ play_hosts | format_list('rabbitmq@%s') }}

Solution 3

I believe another way would be using the joiner global function, as you can read in http://jinja.pocoo.org/docs/2.9/templates/#list-of-global-functions:

A joiner is passed a string and will return that string every time it’s called, except the first time (in which case it returns an empty string). You can use this to join things

So your code would be something like:

[
{% set comma = joiner(",") %}    
{% for host in play_hosts %}
    {{ comma() }}
    {{ "rabbitmq@%s"|format(host) }}
{% endfor %}
]

Solution 4

You could simply join not only by , but also add the prefix together with it. Now that's not very pythonic or sophisticated but a very simple working solution:

[rabbitmq@{{ play_hosts | join(', rabbitmq@') }}]
Share:
18,075

Related videos on Youtube

Cignul9
Author by

Cignul9

Updated on August 03, 2022

Comments

  • Cignul9
    Cignul9 almost 2 years

    play_hosts is a list of all machines for a play. I want to take these and use something like format() to rewrite them like rabbitmq@%s and then join them together with something like join(). So:

    {{ play_hosts|format(???)|join(', ') }}
    

    All the examples of format use piping where the input is the format string and not a list. Is there a way to use these (or something else) to accomplish what I want? The output should looks something like:

    ['rabbitmq@server1', 'rabbitmq@server2', rabbitmq@server3', ...]
    

    The jinja2 doc describes format like this:

    format(value, *args, **kwargs)
    

    Apply python string formatting on an object:

    {{ "%s - %s"|format("Hello?", "Foo!") }}
    -> Hello? - Foo!
    

    So it gives three kinds of input but doesn't describe those inputs in the example, which shows one in the pipe and the other two passed in via args. Is there a keyword arg to specify the string that's piped? Please help, python monks!

  • rumdrums
    rumdrums about 8 years
    I think this is the best solution. Your Jinja2 code will quickly get unwieldy if you try to do it all within your playbook.
  • geekQ
    geekQ almost 7 years
    Repetition is not nice, but looks cleaner than regex_replace. Really missing a clean filter in jinja2. +1 for the workaround
  • geekQ
    geekQ almost 7 years
    Such format_list should be really part of Jinja2!
  • lmNt
    lmNt over 6 years
    This however will leave a dangling rabbitmq@ in case of an empty list.
  • Jiří Baum
    Jiří Baum over 3 years
    Simplification: {{ play_hosts | map('regex_replace', '^', 'rabbitmq@') | list }}