I have an inventory with three host groups, something like:
[all:vars]
ansible_user = myuser
ansible_port = 22
[A]
XXX.XXX.XXX.XX ansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'
[B]
XXX.XXX.XXX.XX ansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'
[C]
XXX.XXX.XXX.XX ansible_ssh_common_args='-o StrictHostKeyChecking=accept-new'
Each group has a single host. I have a playlist with multiple task lists, hived off into blocks. I want to run a task list against one host in group A. If that list fails, I want to run a different task list against all the machines in group A and B.
I'm using Ansible v2.16.4.
I thought I might be able to do something like:
- hosts: "[A, B]" tags: always tasks: - name: Execute against A block: - name: Do something against A ansible.builtin.include_tasks: file: ./task_lists/a_tasks.yaml run_once: true delegate_to: "{{ groups['A'][0] }}" rescue: - name: Do something against A and B ansible.builtin.include_tasks: file: ./task_lists/ab_tasks.yaml
but this causes my plays to fail. The output seem to show the plays being executed from A onto B, but I'm not entirely sure what [A -> B]
means or what it's doing. As far as I can tell from the docs, I would have assumed the output to have been something like [localhost -> A]
for the first bit and then [localhost -> A] [localhost -> B]
for the second rescue block.
Does anyone have a better approach?
Thanks
Well, it shouldn't work at all because:
[A, B]
is not a valid host pattern and it couldn't be parsed. The square brackets define the host ranges, not a list: both A and B groups would be selected as A, B
, and the first host in A group would be A[0]
.delegate_to
cannot be used on include
.A quick solution to your problem would be to avoid delegation and adding a when
condition that checks the host instead (run_once
could be omitted as it wouldn't make any sense anymore):
- hosts: A, B
tags: always
tasks:
- name: Execute against A
block:
- name: Do something against A
ansible.builtin.include_tasks:
file: ./task_lists/a_tasks.yaml
when: ansible_host == groups['A'][0]
rescue:
- name: Do something against A and B
ansible.builtin.include_tasks:
file: ./task_lists/ab_tasks.yaml
Another, a bit more explicit option is to set some fact that would become a trigger for the AB tasks in case of failure in A tasks, and delegate it to the implicit localhost that is available everywhere:
- hosts: A[0]
tags: always
tasks:
- name: Execute against A
block:
- name: Do something against A
ansible.builtin.include_tasks:
file: ./task_lists/a_tasks.yaml
rescue:
- name: Trigger something against A and B
ansible.builtin.set_fact:
run_smth_against_ab: true
delegate_to: localhost
delegate_facts: true
- hosts: A,B
tags: always
tasks:
- name: Do something against A and B
ansible.builtin.include_tasks:
file: ./task_lists/ab_tasks.yaml
when:
- hostvars['localhost'].run_smth_against_ab is defined
- hostvars['localhost'].run_smth_against_ab