Ansible for loop on csv file, break out title line

I have a playbook where I am using csv file to create a vars file. The for loop iterates through the csvfile, skips the first title line then splits each line into a list. Works fine, but I was hoping to instead of skipping the title line, to pull out the names and use as the variable name instead of hard coding the names like Type, Hostname, etc. This would allow me to input csv files that have different title names and more or less names.

csv file example:

Type,Hostname,IP_Address,Gateway,DNS_Server,NTP_Server
ubuntu,lab1,10.1.1.1,10.1.1.254,192.168.1.254.192.168.1.253
centos,lab2,10.1.1.2,10.1.1.254,192.168.1.254.192.168.1.253
rhel6,lab3,10.1.1.3,10.1.1.254,192.168.1.254.192.168.1.253
rhel7,lab4,10.1.1.4,10.1.1.254,192.168.1.254.192.168.1.253

loop code:

---
servers:
{% for item in csvfile.split("\n") %}
{%   if loop.index != 1 %}
{%     set list = item.split(",") %}
  {{ list[1]|trim() }}:
    Type: {{ list[0]|trim() }}
    Hostname: {{ list[1]|trim() }}
    IP_Address: {{ list[2]|trim() }}
    Gateway: {{ list[3]|trim() }}
    DNS_Server: {{ list[4]|trim() }}
    NTP_Server: {{ list[22]|trim() }}
{%   endif %}
{% endfor %}

Question I have is, how would I pull out loop.index. 1 and use the title names as variables? Something like this:

{{ title. }}: {{ list[0]|trim() }}
{{ title. }}: {{ list[1]|trim() }}
{{ title }}: {{ list[2]|trim() }}
{{ title }}: {{ list[3]|trim() }}
{{ title }}: {{ list[4]|trim() }}
{{ title }}: {{ list[22]|trim() }}

Can't you just do something like this?

{% if loop.index == 1 %}
{% set title = item.split(',') %}
{% endif %}

Then you can use title[0], title[1]...

I tried, but the title variable does not keep when looping from second row and on.

{% for item in csvfile.split(“\n”) %}
{% if loop.index == 1 %}
{% set title = item.split(‘,’) %}
{% else %}
{% set list = item.split(“,”) %}
{{ list[1]|trim() }}:
{{ title[0] }}: {{ list[0]|trim() }}
{{ title[1] }}: {{ list[1]|trim() }}
{{ title[2] }}: {{ list[2]|trim() }}
{{ title[3] }}: {{ list[3]|trim() }}
{{ title[4] }}: {{ list[4]|trim() }}
{{ title[5] }}: {{ list[5]|trim() }}
{% endif %}

{% endfor %}

The playbook output for task

TASK [Parse CSV To YAML] ***********************************************************************************************************
fatal: [localhost]: FAILED! => {“changed”: false, “failed”: true, “msg”: “AnsibleUndefinedVariable: ‘title’ is undefined”}

msg: AnsibleUndefinedVariable: ‘title’ is undefined

That's strange since the Jinja documentation have the following about scope:
"Please keep in mind that it is not possible to set variables inside a block and have them show up outside of it.
This also applies to loops. The only exception to that rule are if statements which do not introduce a scope."

Maybe it's a bug.

As a workaround since this i a scope issue, you could set the title outside of the for loop.

  {% set title = csvfile.split("\n")[0].split(',') %}
  {% for item in csvfile.split("\n")[1:] %}
  {% set list = item.split(",") %}
  {{ list[1]|trim() }}:
  {{ title[0] }}: {{ list[0]|trim() }}
  {{ title[1] }}: {{ list[1]|trim() }}
  {{ title[2] }}: {{ list[2]|trim() }}
  {{ title[3] }}: {{ list[3]|trim() }}
  {{ title[4] }}: {{ list[4]|trim() }}
  {{ title[5] }}: {{ list[5]|trim() }}
  {% endfor %}

Works perfectly! Thank you so much Kai Stian.

I do have one more question. Say I am not sure if the last list[6] variable is defined, how would I write that? I tried the below but did not work.

{% set title = csvfile.split(“\n”)[0].split(‘,’) %}
{% for item in csvfile.split(“\n”)[1:] %}
{% set list = item.split(“,”) %}
{{ list[1]|trim() }}:
{{ title[0] }}: {{ list[0]|trim() }}
{{ title[1] }}: {{ list[1]|trim() }}
{{ title[2] }}: {{ list[2]|trim() }}
{{ title[3] }}: {{ list[3]|trim() }}
{{ title[4] }}: {{ list[4]|trim() }}
{{ title[5] }}: {{ list[5]|trim() }}

{% if {{ list[6] }} %}
{{ title[6] }}: {{ list[6]|trim() }}

{% endif %}
{% endfor %}

You can't use {{ }} inside then template code, since you are in template mode it understand that list[6] is a variable.
Try this

{% if list[6] is defined %}
    {{ title[6] }}: {{ list[6]|trim() }}
{% endif %}

That worked, thanks again for you help.

Sorry, one more thing. I want to identify if the title equals Hostname and both the title and list index match. I have it working below, but was hoping there is a cleaner way of doing this.

{% set title = csvfile.split(“\n”)[0].split(‘,’) %}

{% for item in csvfile.split(“\n”)[1:] %}
{% set list = item.split(“,”) %}

{% if title[0] == “Hostname” and list[0] %}
{{ list[0]|trim() }}:
{% elif title[1] == “Hostname” and list[1] %}
{{ list[1]|trim() }}:
{% elif title[1] == “Hostname” and list[1] %}
{{ list[1]|trim() }}:
{% elif title[2] == “Hostname” and list[2] %}
{{ list[2]|trim() }}:
{% elif title[3] == “Hostname” and list[3] %}
{{ list[3]|trim() }}:
{% elif title[4] == “Hostname” and list[4] %}
{{ list[4]|trim() }}:
{% elif title[5] == “Hostname” and list[5] %}
{{ list[5]|trim() }}:
{% endif %}

{{ title[0] }}: {{ list[0]|trim() }}
{{ title[1] }}: {{ list[1]|trim() }}
{{ title[2] }}: {{ list[2]|trim() }}
{{ title[3] }}: {{ list[3]|trim() }}
{{ title[4] }}: {{ list[4]|trim() }}
{{ title[5] }}: {{ list[5]|trim() }}
{% endfor %}

Sorry, one more thing. I want to identify if the title equals Hostname and
both the title and list index match.

I don't understand what your mean, could you rephrase.

I have it working below, but was
hoping there is a cleaner way of doing this.

{% set title = csvfile.split("\n")[0].split(',') %}
  {% for item in csvfile.split("\n")[1:] %}
  {% set list = item.split(",") %}

  {% if title[0] == "Hostname" and list[0] %}
    {{ list[0]|trim() }}:
  {% elif title[1] == "Hostname" and list[1] %}
    {{ list[1]|trim() }}:
  {% elif title[1] == "Hostname" and list[1] %}
    {{ list[1]|trim() }}:
  {% elif title[2] == "Hostname" and list[2] %}
    {{ list[2]|trim() }}:
  {% elif title[3] == "Hostname" and list[3] %}
    {{ list[3]|trim() }}:
  {% elif title[4] == "Hostname" and list[4] %}
    {{ list[4]|trim() }}:
  {% elif title[5] == "Hostname" and list[5] %}
    {{ list[5]|trim() }}:
  {% endif %}

To me, it looks like this code just print out the value correspond to the "Hostname".
If that is the goal, then this for loop does that.

   {% for element in range(list | count) %}
   {% if title[element] == "Hostname" %}
     {{ list[element]|trim }}:
   {% endif %}
   {% endfor %}

  {{ title[0] }}: {{ list[0]|trim() }}
  {{ title[1] }}: {{ list[1]|trim() }}
  {{ title[2] }}: {{ list[2]|trim() }}
  {{ title[3] }}: {{ list[3]|trim() }}
  {{ title[4] }}: {{ list[4]|trim() }}
  {{ title[5] }}: {{ list[5]|trim() }}

This section can be replaced with this for loop, it's dynamic so it will work with any number for column in the csv file.

   {% for element in range(list | count) %}
   {{ title[element] }}: {{ list[element] | trim }}
   {% endfor %}

Thanks Kai Stian, that is exactly what I was looking for.

Kai Stian, I hope you can help with one more question. I searched but could not find out how to insert an ansible variable into the django loop.

I found out how. I created a variable for the {{ inventory_hostname }} first.

vars:
vsrx: “{{ inventory_hostname }}”

{% set title = csvfile.split(“\n”)[0].split(‘,’) %}
{% for item in csvfile.split(“\n”)[1:] %}
{% if vsrx in item %}
{% set list = item.split(“,”) %}
{% for element in range(list | count) %}
{{ title[element]|trim }}: {{ list[element]|trim }}
{% endfor %}
{% endif %}
{% endfor %}

You don't need to do that, just use inventory_hostname directly, it's already a variable.

{% if inventory_hostname in item %}