How to run an ansible task only once regardless of how many targets there are

9.5k views Asked by At

Consider the following Ansible task:

- name: stop tomcat
  gather_facts: false
  hosts: pod1
  pre_tasks:
  - include_vars:
      dir: "vars/{{ environment }}"
  vars:
    hipchat_message: "stop tomcat pod1 done."
    hipchat_notify: "yes"
  tasks:
    - include: tasks/stopTomcat8AndClearCache.yml
    - include: tasks/stopHttpd.yml
    - include: tasks/hipchatNotification.yml

This stops tomcat on n number of servers. What I want it to do is send a hipchat notification when it's done doing this. However, this code sends a separate hipchat message for each server the task happens on. This floods the hipchat window with redundant messages. Is there a way to make the hipchat task happen once after the stop tomcat/stop httpd tasks have been done on all the targets? I want the task to shut down tomcat on all the servers, then send one hip chat message saying "tomcat stopped on pod 1".

2

There are 2 answers

2
Nick On

You can conditionally run the hipchat notification task on only one of the pod1 hosts.

- include: tasks/hipChatNotification.yml
  when: inventory_hostname == groups.pod1[0]

Alternately you could only run it on localhost if you don't need any of the variables from the previous play.

- name: Run notification
  gather_facts: false
  hosts: localhost
  tasks:
  - include: tasks/hipchatNotification.yml

You also could use the run_once flag on the task itself.

- name: Do a thing on the first host in a group.
  debug: 
    msg: "Yay only prints once"
  run_once: true

- name: Run this block only once per host group
  block:
  - name: Do a thing on the first host in a group.
    debug: 
      msg: "Yay only prints once"
  run_once: true
0
Tj Kellie On

Ansible handlers are made for this type of problem where you want to run a task once at the end of an operation even though it may have been triggered multiple times in the play.

You can define a handler section in your playbook and notify it in the tasks, the handlers will not run unless notified by a task, and will only run once regardless of how many times they are notified.

handlers:
    - name: hipchat notify
      hipchat:
        room: someroom
        msg: tomcat stopped on pod 1

In your play tasks just include a "notify" on the tasks that should trigger the handler and if they change it will run the handler after all tasks have executed.

- name: Stop service httpd, if started
  service:
    name: httpd
    state: stopped
  notify: 
    - hipchat notify