multiple variables in same for loop (Jinja2, Yaml) - ansible

I have a list in yaml file
users:
name:
- abc
- pqr
age:
- 10
- 12
I want to iterate over above values in jinja2 template.
Member in name is associated with member in age of same index. So I want to iterate over both in single line only.
{% for n in users['name'] and for a in users['age'] %}
{{ n }}
{{ a }}
{% endfor %}
For loop in this code isn't working.
I checked official documentation but I could not find any example like this.
Can anyone please help me with this?

The template below
{% for item in users.name|zip(users.age)|list %}
{{ item.0 }}
{{ item.1 }}
{% endfor %}
gives:
$ cat test.txt
abc
10
pqr
12

Related

Jinja2 for item in list change to upper case

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

Creating text file from jinja template with inputs from csv file

I'm trying to create a text file which goes through the CSV file and populates variables into specific fields.
playbook.yml:
- hosts: localhost
tasks:
- name: "Reading user information"
read_csv:
path: /home/test/vlans.csv
delimiter: ','
register: vlans
- debug: var=vlans
- name: Creating VLANs configuration
template:
src: vlan.conf.j2
dest: /tmp/vlan.conf
Jinja2 Template vlan.conf.j2:
{% for item in vlans %}
!
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
interface nve1
member vni {{ item.VNI }}
{% endfor %}
and this is a test vlans.csv file:
Tenant,VRF ,VLAN,VNI,Subnet,Description,Good to go
Test,,5,20005,,LAB-Checkpoint-FW-Mgmt,Yes
Test,,208,20208,,LAB-DMZ,Yes Test,,209,20209,,LAB-CSR-MGMT,Yes
Test,10000,210,20210,192.168.12.1/28,LAB-VRF-to-FW,Yes
Prod,,761,20761,,PROD-CORE,Yes
Prod,105,840,20840,172.18.33.1/24,Backups,Yes
Prod,,841,20841,,Transport,Yes
I want to end up with file like in jinja2 template and not repeating line "interface nve 1"
In your question, interface nve1 is inside a loop. It will repeat multiple times in the resulting vlan.conf file.
Use multiple loops in the jinja template to decide what is repeated and what isn't:
{% for item in vlans.list %}
vlan {{ item.VLAN }}
name {{ item.Description }}
vn-segment {{ item.VNI }}
{% endfor %}
interface nve1
{% for item in vlans.list %}
member vni {{ item.VNI }}
{% endfor %}
Note that I've referred to vlans.list in the start of the loops instead of vlans. This is correct as per documentation, but different to the example in the question so it may need adjusting.

How to create dynamic files?

i´m trying to rename ethernet-interfaces on Linux. Each interface with the name enp0s* have to be eth*. First, i create udev-rules for renaming. that works fine. Secondly i have to create new configuration-files for each interface ( ' etc/sysconfig/network-scripts/ifcfg-eth* ' ). I don´t know, how to create the loop to place parameters in each interface. Can somneone help me?
Thats an extract of my playbook:
- name: Get new interface-names of the new created udev-rules
become: yes
shell: cat /etc/udev/rules.d/70-persisten-ipoib.rules.cfg | egrep -i 'eth.'
register: car
- name: Create new-ifcfg-eth* files
template:
with_items: "{{ car.stdout_lines }}"
register: cat
template: src= roles/configure_network/templates/create_ifcfg.cfg.j2 dest=/etc/sysconfig/network-scripts/ifcfg-{{ item }}
# Template: roles/configure_network/templates/create_ifcfg.cfg.j2
{% for interface in cat.results %}
NAME="eth{{ item.name }}
TYPE=Ethernet
BOOTPROTO={{item.bootproto|default('dhcp')}}
IPV4_FAILURE_FATAL=no
IPV6INIT=no
{% if item.ipaddress is defined %}
IPADDR={{item.ipaddress}}
{% endif %}
{% if item.netmask is defined %}
NETMASK={{item.netmask}}
{% endif %}
{% if item.gateway is defined %}
GATEWAY={{item.gateway}}
{% endif %}
PEERDNS=no
{% if item.dns is defined %}
DNS1={{item.dns}}
{% endif %}
ONBOOT={{item.onboot|default('yes')}}
{% endfor %}
Just fix your syntax:
- name: Create new-ifcfg-eth* files
template:
src: create_ifcfg.cfg.j2
dest: /etc/sysconfig/network-scripts/ifcfg-{{ item }}
with_items: "{{ car.stdout_lines }}"
register: cat
Remove double template call, use relative path (no need to define full path to role's own templates), use YAML syntax instead of key=value (you had spaces in them, which are not allowed).

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"

how to iterate csv file in ansible

i have a jinja2 template including a section that need data from a csv file
how can i read a csv file and split it into a list then iterate it in the jinja2 template? sth. like this:
{% for line in csv_data %}
{{ line[0] }} = {{ line[1] }}
{% endfor %}
in my task file, i am trying to use lookup to read the csv file into csv_data, but it seems lookup can only query and get one line not the whole file, or just the whole file in raw format
vars:
csv_data: "{{ lookup('file', 'test.csv') }}"
figured a not so good method:
{% for line in csv_data.split("\n") %}
{% set list = line.split(",") %}
{{ list[0] }}={{ list[1] }}
{% endfor %}

Resources