Search code examples
ansibleansible-2.xansible-handlers

Ansible won't see a handler when using the group_by


I used to have simple playbook (something like this) which I run on all over my machines (RH & Debian based) to update them, and for each machine which was updated run a script (notify handler).

Recently I tried to test a new module called group_by, so instead using the when condition to run yum update when ansible_distribution == "CentOS", I will first gather the facts and group the host based on there ansible_pkg_mgr as key and then I was looking to run yum update on all the hosts which the key is PackageManager_yum , see the play book example:

---
- hosts: all
  gather_facts: false
  remote_user: root
  tasks:

    - name: Gathering facts
      setup:

    - name: Create a group of all hosts by operating system
      group_by: key=PackageManager_{{ansible_pkg_mgr}}

- hosts: PackageManager_apt
  gather_facts: false
  tasks:
    - name: Update DEB Family
      apt: 
        upgrade=dist
        autoremove=yes
        install_recommends=no
        update_cache=yes
      when: ansible_os_family == "Debian"
      register: update_status
      notify: updateX
      tags: 
        - deb
        - apt_update
        - update

- hosts: PackageManager_yum
  gather_facts: false
  tasks:
    - name: Update RPM Family
      yum: name=* state=latest
      when: ansible_os_family == "RedHat"
      register: update_status
      notify: updateX
      tags: 
        - rpm
        - yum
        - yum_update

  handlers:
    - name: updateX
      command: /usr/local/bin/update

And this is the error message I get,

PLAY [all] ********************************************************************

TASK [Gathering facts] *********************************************************
Wednesday 21 December 2016  11:26:17 +0200 (0:00:00.031)       0:00:00.031 **** 
....

TASK [Create a group of all hosts by operating system] *************************
Wednesday 21 December 2016  11:26:26 +0200 (0:00:01.443)       0:00:09.242 **** 

TASK [Update DEB Family] *******************************************************
Wednesday 21 December 2016  11:26:26 +0200 (0:00:00.211)       0:00:09.454 **** 
ERROR! The requested handler 'updateX' was not found in either the main handlers list nor in the listening handlers list

thanks in advance.


Solution

  • You defined handlers only in one of your plays. It's quite clear if you look at the indentation.

    The play which you execute for PackageManager_apt does not have the handlers at all (it has no access to the updateX handler defined in a separate play), so Ansible complains.

    If you don't want to duplicate the code, you can save the handler to a separate file (let's name it handlers.yml) and include in both plays with:

      handlers:
        - name: Include common handlers
          include: handlers.yml
    

    Note: there's a remark in Handlers: Running Operations On Change section regarding including handlers:

    You cannot notify a handler that is defined inside of an include. As of Ansible 2.1, this does work, however the include must be static.


    Finally, you should rather consider converting your playbook to a role.

    A common method to achieve what you want is to include the tasks (in tasks/main.yml) using file names with the architecture in their names:

    - include: "{{ architecture_specific_tasks_file }}"
      with_first_found:
        - "tasks-for-{{ ansible_distribution }}.yml"
        - "tasks-for-{{ ansible_os_family }}.yml"
      loop_control:
        loop_var: architecture_specific_tasks_file
    

    Handlers are then defined in handlers/main.yml.