Search code examples
ansiblejinja2

How to use Jinja2 loop index in Ansible hostvars?


I'm trying to get IP address from inventory using Jinja2 loop index inside hostvars (from Ansible):

Inventory is like:

all:
  hosts:
    host1:
      ansible_host: 192.168.1.1
    host2:
      ansible_host: 192.168.1.2
    host3:
      ansible_host: 192.168.1.3
    service_nodes:
      hosts:
        host1:
        host2:
        host3:

template.yml is like:

...
{% for host in service_nodes %}
  - {{ loop.index }}:{{ hostvars[groups.service_nodes[{{ loop.index }}]].ansible_host }}
...
{% endfor %}
...

I ran the playbook but encountered:

{"changed": false, "msg": "AnsibleError: template error while templating string: expected token ':', got '}'.

And I've checked on AnsibleError: template error while templating string: expected token 'end of statement block', got '{' but seems it's not my answer.

Also, I tried these on the template but failed:

{% set idx = loop.index %}
  - {{ loop.index }}:{{ hostvars[groups.service_nodes[{{ idx }}]].ansible_host }}

and

  - {{ loop.index }}:{{ hostvars[groups.service_nodes["{{ loop.index }}"]].ansible_host }}

Solution

  • Use the directive children to declare the group of hosts service_nodes

    shell> cat hosts
    all:
      hosts:
        host1:
          ansible_host: 192.168.1.1
        host2:
          ansible_host: 192.168.1.2
        host3:
          ansible_host: 192.168.1.3
      children:
        service_nodes:
          hosts:
            host1:
            host2:
            host3:
    

    Test it. See the output of the command

    shell> ansible-inventory -i hosts --list --yaml
    all:
      children:
        service_nodes:
          hosts:
            host1:
              ansible_host: 192.168.1.1
            host2:
              ansible_host: 192.168.1.2
            host3:
              ansible_host: 192.168.1.3
        ungrouped: {}
    

    Then the playbook below

    shell> cat playbook.yml
    - hosts: all
      tasks:
        - template:
            src: hosts.yml.j2
            dest: /tmp/hosts.yml
          delegate_to: localhost
          run_once: true
    

    and the template

    shell> cat hosts.yml.j2
    {% for host in groups.service_nodes %}
      - {{ loop.index }}:{{ hostvars[host]['ansible_host'] }}
    {% endfor %}
    

    give

    shell> cat /tmp/hosts.yml
      - 1:192.168.1.1
      - 2:192.168.1.2
      - 3:192.168.1.3