Jaydeep Chaudhari
Jaydeep Chaudhari

Reputation: 430

Skip other hosts if first host is reachable in Ansible

I am having file consists of Ip address I using below method to to make this inventory for my tasks

ips.text

192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4

main.yml

    - name: Add Instance IP Addresses to temporary inventory groups
      shell: cat ~/ips.text
      register: serverlist
    - debug: msg={{ serverlist.stdout_lines }}
    - name: Add Instance IP Addresses to temporary inventory groups
    add_host
        groups: working_hosts
        hostname: "{{item}}"
      with_items: "{{ serverlist.stdout_lines }}"

- hosts: working_hosts
  become: yes

Now I want to make it like if 192.168.0.1 is reachable then it should skip rest of the ips from that file and if 192.168.0.1 is unreachable then only goes to next 192.168.0.2.

How can we achieve this?

Upvotes: 1

Views: 1469

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68274

Q: "If 192.168.0.1 is reachable then it should skip the rest of the IPs."

A: Let's wait_for_connection on all hosts in the block and store the connection status in the variable reachable. Then use the variable reachable to create the group of reachable hosts reachable and run new play with the first host from the group groups.reachable.0. For example

- name: Test reachable hosts
  hosts: working_hosts
  gather_facts: false
  vars:
    connection_timeout: "10"
  tasks:
    - block:
        - wait_for_connection:
            timeout: "{{ connection_timeout }}"
      rescue:
        - set_fact:
            reachable: false
        - meta: clear_host_errors
        - meta: end_host
    - set_fact:
        reachable: true

    - add_host:
        name: '{{ item }}'
        groups: 'reachable'
      loop: "{{ hostvars|dict2items|json_query('[?value.reachable].key') }}"
      run_once: true

- hosts: "{{ groups.reachable.0 }}"
  tasks:
    - debug:
        msg: "{{ inventory_hostname }}"

Upvotes: 3

Jack
Jack

Reputation: 6198

Well, order your host as you want them in the inventory, set gather_facts: yes, and run_once: yes of the tasks, and you're good to go:

---
- hosts: all
  gather_facts: yes
  tasks:
  - debug:
      var: ansible_hostname
    run_once: yes

Run this playbook on a set of hosts, with the first few in your list powered down, and you will see the task only runs on the first host that is responding.

Another option is similar to what Vladimir suggested, but using the (lack of) results from gather_facts:

---
- hosts: all
  gather_facts: yes
  tasks:
  - set_fact:
      first_good_host: "{{ ansible_play_hosts | map('extract', hostvars) | list | json_query(query) | first }}"
    run_once: yes
    delegate_to: localhost
    vars:
      query: "[?ansible_facts!=''].inventory_hostname"

  - debug:
      var: first_good_host
    delegate_to: localhost

  - add_host:
      name: '{{ first_good_host }}'
      groups: 'reachable'
    run_once: yes

- hosts: reachable
  gather_facts: yes
  tasks:
  - debug:
      msg: "{{ inventory_hostname }}"

Good luck!

Upvotes: 1

Related Questions