Skip to content

Instantly share code, notes, and snippets.

@richard-scott
Forked from halberom/00_description
Created December 13, 2016 10:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richard-scott/85db2d050a3e2c06ddb59e568bfe3fef to your computer and use it in GitHub Desktop.
Save richard-scott/85db2d050a3e2c06ddb59e568bfe3fef to your computer and use it in GitHub Desktop.
ansible - example of using filters to change each item in a list
The problem:
I wanted to use the jinja 'map' filter to modify each item in a string, in this simple
example, adding '.conf' to each item.
The 'format' filter in jinja takes arguments (value, *args, **kwargs). Unfortunately,
it uses 'value' as the pattern. When called inside map 'value' is the current item in
the list, or in other words *args as far as format is concerned. So it's the wrong way
around.
The following example creates a simple filter that has the format args in an order we
can use when calling 'map'. Note this is extremely simplestic, and only allows for
adding a prefix or suffix to an item. i.e. prefix%s or %ssuffix. You can't do more
advanced ones like '%s - %s' with this example as that requires passing the current
item as an array and (at least in python 2x), variable length args have to come after
named args.
_Note: A better approach might be to use the ansible regex_replace filter within map,
but when I tried that, it returned \u0001.conf, so I'm guessing that there's some
unicode foo (or lack thereof) happening. i.e. I tried
mylist2: "{{ mylist | map('regex_replace', '^(.*)$', '\\1.conf' ) | list }}"
# plugins/filter/map_format.py (check path in ansible.cfg)
# This code is essentially a direct copy of the jinja 'format' filter with
# some minor mods to the args and their use, see do_format in
# https://github.com/mitsuhiko/jinja2/blob/master/jinja2/filters.py
# for the original
from jinja2.utils import soft_unicode
def map_format(value, pattern):
"""
Apply python string formatting on an object:
.. sourcecode:: jinja
{{ "%s - %s"|format("Hello?", "Foo!") }}
-> Hello? - Foo!
"""
return soft_unicode(pattern) % (value)
class FilterModule(object):
''' jinja2 filters '''
def filters(self):
return {
'map_format': map_format,
}
---
- hosts: all
remote_user: vagrant
sudo: true
vars:
mylist:
- Alice
- Bob
- Carol
mylist2: "{{ mylist | map('map_format', '%s.conf' ) | list }}"
tasks:
- debug: var=mylist2
...
TASK: [debug var=mylist2] *****************************************************
ok: [vagrant] => {
"var": {
"mylist2": [
"Alice.conf",
"Bob.conf",
"Carol.conf"
]
}
}
...
@scuben
Copy link

scuben commented Nov 16, 2021

This seems to be incompatible with jinja2 v3. Have you already solved this problem yet?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment