3

Setup

I have several roles which declare role dependencies and sometimes use handlers from roles they depend on. A simplified version of my setup looks like this (This is the output of head inventory **/*.yml and it shows all path names and the full contents of the files):

==> inventory <==
[app]
server1 ansible_host=192.168.2.113
[db]
server2 ansible_host=192.168.2.153

==> playbook.yml <==
- hosts: all
  roles:
    - { role: app, when: "inventory_hostname in groups['app']" }
    - { role: db,  when: "inventory_hostname in groups['db']"  }

==> roles/app/handlers/main.yml <==
- name: app handler
  command: echo app handler

==> roles/app/meta/main.yml <==
dependencies: [base]

==> roles/app/tasks/main.yml <==
- command: /bin/true
  notify: [app handler, base handler]

==> roles/base/handlers/main.yml <==
- name: base handler
  command: echo base handler

==> roles/base/tasks/main.yml <==
- command: /bin/true

==> roles/db/handlers/main.yml <==
- name: db handler
  command: echo db handler

==> roles/db/meta/main.yml <==
dependencies: [base]

==> roles/db/tasks/main.yml <==
- command: /bin/true
  notify: [db handler, base handler]

Now I run ansible-playbook -i inventory playbook.yml which results in

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

TASK [Gathering Facts] **********************************************************
ok: [server1]
ok: [server2]

TASK [base : command] ***********************************************************
skipping: [server2]
changed: [server1]

TASK [app : command] ************************************************************
skipping: [server2]
changed: [server1]

TASK [base : command] ***********************************************************
changed: [server2]

TASK [db : command] *************************************************************
skipping: [server1]
changed: [server2]

RUNNING HANDLER [base : base handler] *******************************************
skipping: [server2]
changed: [server1]

RUNNING HANDLER [app : app handler] *********************************************
changed: [server1]

RUNNING HANDLER [db : db handler] ***********************************************
changed: [server2]

PLAY RECAP **********************************************************************
server1                    : ok=5    changed=4    unreachable=0    failed=0   
server2                    : ok=4    changed=3    unreachable=0    failed=0   

Problem

My problem is that I expected both servers to execute the base handler. But apparently it is skipped on server2. If I add -v to the ansible command I get the unhelpful comment that skipping: [server2] => {"changed": false, "skip_reason": "Conditional result was False"}.

What also puzzles me is that the base role seems to be included twice and each server skips one or the other inclusion of the role respectively.

Question

  • Is there any way I can ensure that the handlers are fired correctly?

EDIT

  • Is it a bug that the handler is not fired or is that behavior documented somewhere?

/EDIT

minor questions

  • Is there any way to declare dependencies in a way that does not yield many inclusions which are only picked up by one server and ignored by all others although the others will include the same role through their own dependencies at some other point? This results in a lot of skipped tasks when I have some more servers and roles. (after reading the docs on role inclusion I suspect not)
  • Is there some other way to handle role dependencies and handlers with ansible? I came up with this setup after reading https://medium.com/@ibrahimgunduz34/parallel-playbook-execution-in-ansible-30799ccda4e0

Sidenote

I would like to avoid the group_by technique described in the docs, or more generally executing each role in their own playbook for the correct subset of the servers only, because I have a lot of servers and I want to speed up the run of the playbook by using strategy: free.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Lucas
  • 685
  • 4
  • 19
  • I strongly recommend that you put `name` on all your tasks so you can follow which is which, rather than having a bunch that (unhelpfully) say `command`. – Jack Apr 11 '19 at 18:51
  • 2
    @Jack in my original playbooks I do that but for the post I reduced the code as much as possible to make the final post a little shorter. Also: every task is prefixed with its role and there is only one task per role in this example so it should already be unique. – Lucas Apr 12 '19 at 08:07
  • Splitting the playbook to 2 plays seems to be the only option. The order of tasks would be the same. Role db skipping server1 and role app skipping server2. Splitting the playbook to 2 playbooks and running them in parallel would be the same as strategy: free. – Vladimir Botka Apr 12 '19 at 09:54
  • @VladimirBotka Do you mean running them in parallel in a shell script? That would reduce the execution time compared to linear execution of two playbooks with ansible. But the output of the two playbooks would be mixed and the stats at the end would not be combined and might end up somewhere higher up in the terminal scrollback inbetween the output of a longer running playbook. Or is there a solution to this? – Lucas Apr 12 '19 at 09:57
  • @Lucas: Yes, I mean running them in parallel for example in a shell script. An option to deal with mixed output would be to set dedicated [ANSIBLE_LOG_PATH](https://docs.ansible.com/ansible/latest/reference_appendices/config.html?highlight=log_path#envvar-ANSIBLE_LOG_PATH) for each playbook. – Vladimir Botka Apr 12 '19 at 11:00
  • Is this question maybe better suited for serverfault? – Lucas Apr 16 '19 at 12:12

0 Answers0