Loop through inventory group and reference index of host

I have an inventory file defined as follows:

[app] app1.service.com ansible_host=192.168.1.1 app2.service.com ansible_host=192.168.1.2 app3.service.com ansible_host=192.168.1.3

I need to generate multiple configuration files for each of those hosts. The current task looks like this:

`

  • name: Create node-specific csync2 config files
    template:
    src: “templates/etc/csync2_node.cfg”
    dest: “/etc/csync2_{{ hostvars[item][‘ansible_hostname’] }}.cfg”
    owner: root
    group: root
    backup: no
    with_items: “{{ groups[csync2_cluster_nodes_group] }}”
    `

And my template looks like this:

nossl * *; group {{ hostvars[item]['ansible_hostname'] }} { {% for host in groups[csync2_cluster_nodes_group] %} {% if host != hostvars[item]['ansible_nodename'] %} host ({{ host }}); {% else %} host {{ host }}; {% endif %} {% endfor %} key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

This works correctly to generate template files like this:

group app1 { host app1.service.com; host (app2.service.com); host (app3.service.com); key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

The problem is that this configuration is causing race conditions, so I need to chain the configurations. What I mean by this is that I need the app1 configuration file to look similar to

group app1 { host app1.service.com; host (app2.service.com); key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

And the app2 config to look like:

group app2 { host app2.service.com; host (app3.service.com); key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

And the app3 config to look like:

group app3 { host app3.service.com; host (app1.service.com); key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

The best way to do this, so far as I can tell, is to utilize the index of the host within the template. The problem is that I’m not sure what the syntax would be to do so. I would like, in the config file, to do something like (Pseudo code since I don’t know the syntax for this)

nossl * *; group {{ hostvars[item]['ansible_hostname'] }} { {% for host in groups[csync2_cluster_nodes_group] %} {% if host != hostvars[item]['ansible_nodename'] %} {# This "item" isn't the current "host", so check to see if this is the last item in the group #} {% if group.last == item %} {# this is the last host in the group, so pull the FIRST host from the group #} host ({{ hostvars[groups['app'][0]]['ansible_nodename'] }}); {# OK, this isn't the last host in the group, so pull the NEXT host from the group #} {% else %} host ({{ hostvars[groups['app'][groups.app.index(host)+1]]['ansible_nodename'] }}); {% endif %} {% else %} host {{ host }}; {% endif %} {% endfor %} key /etc/csync2/csync2.key; include /home; exclude *.log; exclude *.swp; exclude /home/ansible; auto younger; }

I hope I’m explaining the problem clearly enough. I’m sure this is possible to achieve, but I’m just stuck on the proper syntax for achieving it.

Hi Kevin

I'm assuming you're putting a config file for each server on some central server
(it's not clear where the play is targeted, but it would explain hostvars).

[ even so, maybe you can replace:

    hostvars[item]['ansible_hostname']

with just

     item

? ]

It looks like you want each template to include the group member, plus the next
member (unless it's the last, in which case go back to the first).

I've committed my share of template logic crimes, so this is from
bitter experience: Jinja2 is limited for a good reason.

Why not just set a csync2_backup_member = x host var for each host?

It's pretty easy to see what's going on from glancing at the inventory that way,
and you might find you need that information elsewhere sometime too
(e.g. rolling upgrades or similar). And the template becomes trivial
and readable.

Granted, you need to explicitly set a hostvar each time you add a
host, but I promise
future generations of sysadmins (or you in 3 months) will thank you
for the clarity.