Right way to execute task on host

Viewed 242

I have an inventory with the following hosts and which is given below( 1st cluster)

[elasticsearch-cluster-india]
elasticsearch-01-mumbai ansible_host=10.0.87.19
elasticsearch-02-mumbai ansible_host=10.0.87.20
elasticsearch-03-mumbai ansible_host=10.0.87.21

and I have different cluster which is below

[elasticsearch-cluster-kyrgyzstan]
elasticsearch-01-bishkek ansible_host=10.0.92.2
elasticsearch-02-bishkek ansible_host=10.0.92.3
elasticsearch-03-bishkek ansible_host=10.0.92.4

and I want to run the following task

- name: Set up snapshot cron job
  cron:
    name: "Elasticsearch backup"
    minute: 59
    hour: 23
    job: "{{ es_snapshot_snapshot_script_path }}/snapshot_es.sh"

so how to execute this task only on first hosts in my group? i want to execute this task only on hosts elasticsearch-01-bishkek and elasticsearch-01-mumbai

2 Answers

Add a variable to the host:

[elasticsearch-cluster-india]
elasticsearch-01-mumbai ansible_host=10.0.87.19 do_backup=yes
elasticsearch-02-mumbai ansible_host=10.0.87.20
elasticsearch-03-mumbai ansible_host=10.0.87.21

Then check for it:

- name: Set up snapshot cron job
  cron:
    name: "Elasticsearch backup"
    minute: 59
    hour: 23
    job: "{{ es_snapshot_snapshot_script_path }}/snapshot_es.sh"
  when: do_backup|default(false)|bool

This will still not be exhaustive, but after my comment to @anemyte answer, I wanted to add a few alternative solutions so that users passing by could see there are different ways to acheive the same requirement and make a wise choice. As stated in my comment, @anemyte solution definitely works and should be added to the below propositions.

Notes:

  • I used simple debug tasks for illustration below since the real task you run does not really matter for the answer.
  • I fixed the group names using underscores (_) as dashes (-) are deprecated.
  • I used the term "master" to describe first host in group. This is not really adapted to Elasticsearch architecture but I hope you will still get the point.

Check if we run on first host in a group

The goal here is dynamically create a list containing the first element of each cluster group and see if the current target matches. I made that in a single task below but you can do easily extend with vars in your playbook/inventory.

This will work without any changes to the example inventory in the question (besides the fixed group naming using underscores as stated in my notes).

- name: Run a task if host is first on a set of groups
  debug:
    msg: "I'm a host on top of a cluster group"
  var:
    cluster_groups:
      - elasticsearch_cluster_india
      - elasticsearch_cluster_kyrgyzstan
    first_hosts: "{{ cluster_groups | map('extract', groups) | map('first') | flatten }}"
  when: inventory_hostname in first_hosts

Refactor inventory with specialized groups

Here we modify the inventory to add the "master" servers in specific groups. The inventory I propose is a simple example and can be tuned to specific needs. Example in yaml format

---
elasticsearch_cluster_india_masters:
  hosts:
    elasticsearch-01-mumbai:
      ansible_host: 10.0.87.19

elasticsearch_cluster_india_clients:
  hosts:
    elasticsearch-02-mumbai:
      ansible_host: 10.0.87.20
    elasticsearch-03-mumbai:
      ansible_host: 10.0.87.21

elasticsearch_cluster_india:
  children:
    elasticsearch_cluster_india_masters:
    elasticsearch_cluster_india_clients:


elasticsearch_cluster_kyrgyzstan_masters:
  hosts:
    elasticsearch-01-bishkek:
      ansible_host: 10.0.92.2

elasticsearch_cluster_kyrgyzstan_clients:
  hosts:
    elasticsearch-02-bishkek:
      ansible_host: 10.0.92.3
    elasticsearch-03-bishkek:
      ansible_host: 10.0.92.4

elasticsearch_cluster_kyrgyzstan:
  children:
    elasticsearch_cluster_kyrgyzstan_masters:
    elasticsearch_cluster_kyrgyzstan_clients:

elasticsearch_cluster_masters:
  children:
    elasticsearch_cluster_india_masters:
    elasticsearch_cluster_kyrgyzstan_masters:

elasticsearch_cluster_clients:
  children:
    elasticsearch_cluster_india_clients:
    elasticsearch_cluster_kyrgyzstan_clients:

elasticsearch_cluster:
  children:
    elasticsearch_cluster_masters:
    elasticsearch_cluster_clients:

You can then have much more granularity in your playbook:

---
- name: A play on all cluster hosts
  hosts: elasticsearch_cluster
  gather_facts: false

  tasks:
    - name: A task played on all hosts
      debug:
        msg: "Task played on all hosts"

    - name: A task played on masters only
      debug:
        msg: "I will play on masters only"
      when: inventory_hostname in groups['elasticsearch_cluster_masters']

- name: A play targeted to cluster masters only
  hosts: elasticsearch_cluster_masters
  gather_facts: false

  tasks:
    - name: A task for all master hosts
      debug:
        msg: "I don't need a when since play targets masters only"

    - name: An other tasks for masters only
      debug:
        msg: "Yet an other task"
Related