May I suggest a few tweaks? First off is this variable initialization:
vars:
hostlist: "{{ hostlist.split(',') }}"
If you’re passing in hostlist
as an --extra-vars
, this isn’t going to work.
It looks like you’re redefining the variable hostlist
in terms of itself, but it doesn’t do that. Instead, it defines a new Play var (precedence 12) which has the same name as an Extra var (precedence 22). That doesn’t make the Extra var go away. Since Extra vars have the highest precedence, the identically named Play var’s value will never be seen. (It may “work” for you in older Ansibles, but it behaves as I’ve described above in my Ansible core 2.18.6.)
I recommend a different Extra var name, say hostlist_in
, so your variable initialization becomes
hostlist: "{{ hostlist_in.split(',') }}"
This next one is personal preference, but I like to avoid creating index variables when filters can manipulate the data directly into the form I need. In this case, you want to create pairs of host names where the first or left host in each pair is always hostlist[0]
and the second or right host is in turn each of the other hostlist
hosts. The product
filter will do exactly that.
loop: "{{ [hostlist[0]] | product(hostlist[1:]) }}"
Lastly, when posting code (or editing a prior post containing code - hint, hint) to the forum, precede and follow the code with lines containing only three back-ticks (“```”). You can include a syntax highlighting hint on the first line, like this:
```yaml
- name: Code never looked so good
ansible.builtin.admire: |
Hey, I can read this easily!
```
With the above changes, here’s my re-working of your test/example. Note that both hosts:
and the Play var hostlist
are derived from the same Extra var hostlist_in
. It would be neat if you could use the ansible_play_hosts
special variable which will contain the same hosts as your limit:
and hostlist_in
; then you wouldn’t have to pass in the hosts twice. Alas, ansible_play_hosts
is a sorted list, and we must distinguish the first host from the others. (Which we could do, but that adds more code which kind of defeats the purpose.)
# test-playbook.yml
- name: Test the list of tasks
hosts: "{{ hostlist_in | split(',') }}"
gather_facts: false
vars:
hostlist: "{{ hostlist_in.split(',') }}"
tasks:
- name: Testing the use case
ansible.builtin.include_role:
name: test-usecase
loop: "{{ [hostlist[0]] | product(hostlist[1:]) }}"
loop_control:
loop_var: hostpair
---
# role/test-usecase/tasks/main.yml
- name: Document this role inclusion
ansible.builtin.debug:
msg: "test-usecase -- primary: {{ hostpair[0] }}, secondary: {{ hostpair[1] }}"
run_once: true
- name: Test block for primary host {{ hostpair[0] }}
block:
- name: Primary is {{ hostpair[0] }}
ansible.builtin.shell: hostname
when: inventory_hostname == hostpair[0]
- name: Test block for secondary host {{ hostpair[1] }}
block:
- name: Secondary is {{ hostpair[1] }}
ansible.builtin.shell: hostname
when: inventory_hostname == hostpair[1]