Jinja2 for item in list change to upper case - ansible

I am trying to generate configuration using jinja2 and ansible. ansible read csv and set facts.
{%- for item in facts_csv %}
Hello {{ item.abc}}
{% endfor %}
in the csv file "abc" has a value "mike". When i run the play book its generating "Hello mike".
Now i want to print "Hello MIKE", without changing the CSV file values?
seems item.abc|upper and item.abc.upper() did not work. Any other solutions?

The template works as expected
{%- for item in facts_csv %}
Hello {{ item.abc }}
{% endfor %}
{%- for item in facts_csv %}
Hello {{ item.abc|upper }}
{% endfor %}
gives
Hello mike
Hello MIKE

Related

How to trim last character when using ansible jinja loop

My template like as blow
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
zookeeperServers={% for host in {{ groups[{{ target_hosts }}] %}}
"{{ hostvars[host].inventory_hostname }}:2181,"
{% endfor %}
{% endif %}
output ishost1:2181,host2:2181,host3:2181,
How to trim last comma
There are several possible gotchas in your above template regarding variables access. Moreover, rather than trimming the last character in your string, the best solution is probably not to write it. Here is a better solution IMO in my below example fixing all the problems I'm referring to:
{% set zookeeperServers=[] %}
{% if hostvars[inventory_hostname].local_zk_server_id is defined %}
{% for host in groups[target_hosts] %}
{% zookeeperServers.append(hostvars[host].inventory_hostname + ":2181") %}
{% endfor %}
zookeeperServers="{{ zookeeperServers | join(',') }}"
{% endif %}

assignment of undefined variables in Jinja2

I got this piece of YAML and i want jinja2 to assign and create item.menu, if it is not previously defined.
data:
- name: bar
menu: blah
- name: foo
This is my code, the error-output ist "template error while templating string: expected token 'end of statement block'"
{% for item in data %}
{% if item.menu is not defined %}
{% set item.menu=item.name %}
{% endif %}
{% endfor %}
Any Help about what I did wrong would be much apretiated :)
Greetings, Hendrik
You're question is not clear but here is my answer. I'll make everything explicit :
{% for item in data %}
{% if item.menu is not defined %}
{{ item.nameĀ }}
{% else %}
{{ item.menu }}
{% endif %}
{% endfor %}

Ansible loop over range of letters in template

I'm trying to generate an Ansible template that increments on letters alphabetically rather than numbers. Is there a function similar to range(x) that could help me?
pseudo code example
{% for letter in range(a, d) %}
{{ letter }}
{% endfor %}
expected output
a
b
c
d
Alternatively is there a way to convert a number into it's alphabetical equivalent in Ansible?
{% for i in range(6) %}
{{ convert(i) }}
{% endfor %}
UPDATE
For those who are curious, here's how I ended up applying #zigam's solution. The goal was to create xml tags with every host from a hostgroup.
In my role defaults:
ids: "ABCDEFGHIGJKLMNPQRSTUVWXYZ"
In my template:
{% for host in groups['some_group'] %}
<host-id="{{ ids[loop.index] }}" hostName="{{ host }}" port="8888" />
{% endfor %}
You can iterate over a string:
{% for letter in 'abcd' %}
{{ letter }}
{% endfor %}
If you want to iterate over a range of the alphabet:
{% set letters='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' %}
{% for letter in letters[:6] %} {# first 6 chars #}
{{ letter }}
{% endfor %}
you can use a custom filter plugin to do what you want
in filter_plugins/scratch_filter.py:
def scratch_filter(n):
return chr(n)
class FilterModule(object):
''' Number to Character filter '''
def filters(self):
return {
'scratch_filter': scratch_filter
}
in scratch-template.j2:
{% for x in range(101, 113) %}
{{ x|scratch_filter }}
{% endfor %}
in scratch_playbook.yml
---
- hosts: localhost
tasks:
- name: test loop
template:
src: "{{ playbook_dir }}/scratch-template.j2"
dest: "{{ playbook_dir }}/scratch-template-output.txt"

Ansible: get list of hosts in comma separated value

I have the following loop in a template:
{% for host in groups['dbnodes'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
the issue is that it gives the output in list of ip's and I need it in comma separated value. Any idea how to achieve that?
the answer I get look like this:
10.0.0.190
10.0.0.117
10.0.0.151
but I need it like this:
10.0.0.190,10.0.0.117,10.0.0.151
A quick fix to your Jinja2 template:
{% for host in groups['dbnodes'] -%}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}{% if not loop.last %},{% endif %}
{%- endfor %}

Multiple groups when iterating in a template file

This article from Ansible.com shows how you can iterate over a group inside of a template file: https://support.ansible.com/hc/en-us/articles/201957887-How-to-loop-over-a-list-of-hosts-in-a-group-inside-of-a-template-
It shows the following code:
{% for host in groups['db_servers'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
It works beautifully, but the servers I want to iterate over are defined by being in multiple groups. So imagine that I want to iterate over all of the servers that are in BOTH the db_servers and qa groups. How can I do this?
I tried to specify the intersection of the group in the same manner I do in my playbook, but that doesn't work. So, when I try:
{% for host in groups['db_servers:&qa'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
I get the following error:
fatal: [54.173.247.115] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'dict object' has no attribute 'db_servers:&qa'", 'failed': True}
Any suggestions on how to iterate over multiple groups in a template file?
Ansible has the intersect filter. See Set Theory Filters.
{% for host in groups['db_servers'] | intersect(groups['qa']) %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
You could wrap your loop in another for the two server groups:
{% for svrs in ['db_servers', 'qa'] %}
{% for host in groups[svrs] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
{% endfor %}

Resources