Reputation: 171
The handlers I have are not being run by the playbook or tasks
I have the following directory structur:
<project>
- playbook.yml
- <roles>
-<handler>
- main.yml
-<meta>
-<tasks>
-main.yml
The problem is the handler is never called.
tasks/main.yml:
- name: run task1
command: run_task
notify: "test me now"
handler/main.yml:
- name: tested
register: val1
listen: "test me now"
The playbook just calls the task/main.yml and has host:all
Do I ned an include/import? I tried in playbook but it didn't help
Upvotes: 9
Views: 12186
Reputation: 68024
The play below works as expected
- hosts: all
tasks:
- include_tasks: tasks/main.yml
- meta: flush_handlers
- debug:
var: val1.stdout
handlers:
- import_tasks: handlers/main.yml
A module is missing in handler/main.yml. This would cause:
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
Use some module in handler/main.yml. For example:
- name: tested
command: "echo 'running handler'"
register: val1
listen: "test me now"
Running such play gives
val1.stdout: running handler
Example of a complete playbook for testing
shell> cat playbook.yml
- hosts: localhost
tasks:
- include_tasks: tasks/main.yml
handlers:
- import_tasks: handlers/main.yml
shell> cat tasks/main.yml
- command: date
register: result
notify: test me now
shell> cat handlers/main.yml
- name: test me now
debug:
msg: "{{ result.stdout }} Running handler."
gives
shell> ansible-playbook playbook.yml
PLAY [localhost] *****************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [localhost]
TASK [include_tasks] *************************************************************************
included: /export/scratch/tmp8/test-801/tasks/main.yml for localhost
TASK [command] *******************************************************************************
changed: [localhost]
RUNNING HANDLER [test me now] ****************************************************************
ok: [localhost] =>
msg: Mon 25 Apr 2022 04:59:02 PM CEST Running handler.
PLAY RECAP ***********************************************************************************
localhost: ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Upvotes: 11
Reputation: 20870
Handlers folder
with no imports
❌The question of wether handlers
in handlers
folder are loaded automatically. Like it's the case with roles.
Answer:
NO
, they are not loaded automatically
- you have to import them
- main.yml # playbook
- handlers
- simple.yml
- some.yml
And you don't import any handler. None will be loaded and available for notification.
Importing
handlers ✅import them in handlers:
of a playbook
import them with import_tasks
✅
include_tasks
❌import_tasks
include_tasks
What about flushing
them ?
2.15.4
Where i tested)
flushed
flush_handlers
is automatically run once the tasks finish.
flushing
flush_handlers
give us control to flush at the time that we want.notified handlers
list)Q: Can we import the file with a name and notify that name to run all handlers inside
No
=> The import basically register the handler inside as if they were copied. (c++ and php, and conf include
)
All will be resolved to a list of handlers
and you can refer any of the final resolved handlers by there names.
v2.8
Beginning in version 2.8, a task cannot notify import_tasks or a static include that is specified in handlers.
The goal of a static import is to act as a pre-processor, where the import is replaced by the tasks defined within the imported file. When using an import, a task can notify any of the named tasks within the imported file, but not the name of the import itself.
To achieve the results of notifying a single name but running multiple handlers, utilize include_tasks, or listen Handlers: running operations on change.
Q: What happens if two handlers in separate files have the same name ?
Q: Can we import roles within handlers ?
NO
we can't, it's a limitation of handlers
Q: Can we use include_tasks
for handlers
Depends
include_tasks:
works is that the name of the block, is a handler itself.
include_tasks
fileinclude_tasks
(vs import)handlers:
- name: Include Handler
include_tasks: handlers/restart.yml
- name: Import other handlers
import_tasks: handlers/some.yml
- name: Import another list of handlers
import_tasks: handlers/another.yml
In the above
import
one will register the tasks in the files as handlers.
imports
are processed statically. At the parsing time.Import other handlers
or Import another list of handlers
are not handlers themselves. But only the resolved handlers within the files ( recursively
for all static imports)include
one is a handler itself (no resolving). There is no importing handlers in other files.
Include Handler
above.include
flush_handlers
is used. Or multiple ones. At each flush
the notified one will be run. And after task another default flush_handlers
will be called as well# restarts.yml
- name: Restart apache
ansible.builtin.service:
name: apache
state: restarted
- name: Restart mysql
ansible.builtin.service:
name: mysql
state: restarted
- name: Trigger an included (dynamic) handler
hosts: localhost
handlers:
- name: Restart services
include_tasks: restarts.yml
tasks:
- command: "true"
notify: Restart services
Restart services
That's a handler itself. Not something that import. At it's run. It would run all tasks within the file.
import
ones are not handlers themselves. But what is imported are. Resolving recursively. Till building the whole list.Example
and running testsLet's take this structure
- main.yml # playbook
- handlers
- simple.yml
- simple2.yml
Handlers list
simple.yml
- name: "Test_it"
ansible.builtin.debug:
msg: "JUST SAYING HI - from simple 1"
- name: "Another handler"
ansible.builtin.command:
cmd: "echo 'Hello la frindo'"
changed_when: true
simple2.yml
a clone of simple.yml
- from simple 2
The playbook main.yml
---
- name: "Local testing"
gather_facts: false
hosts: localhost
connection: local
tasks:
- name: Notify simple handler
ansible.builtin.debug:
msg: "About to notify the simple handler"
changed_when: true # will be notified on change
# changed_when: false # will not if no change (no running)
notify:
- "Test_it"
- "Another handler"
handlers:
- name: Simple handler
import_tasks: "handlers/simple.yml"
Output
and conclusionssimple.yml
onlyPLAY [Setup bitwol server] ************************************************
TASK [Notify simple handler in handlers folder (without any import) - Are files in handlers folder loaded in the playbook (not role ????)] ***
changed: [localhost] => {
"msg": "About to notify th e simple handler"
}
RUNNING HANDLER [Test_it] ************************************************
ok: [localhost] => {
"msg": "JUST SAYING HI - from simple 1"
}
RUNNING HANDLER [Another handler] ************************************************
changed: [localhost]
PLAY RECAP **********************************************************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The
handlers
runperfectly
change_when
to false
changed_when: false
The
handlers
doesn't run
. And as expected when the tasks doesn't change. Nothing get notified.
import
simple2.yml
as wellhandlers:
- name: Simple handler
ansible.builtin.import_tasks: "handlers/simple.yml"
- name: Simple handler 2
ansible.builtin.import_tasks: "handlers/simple2.yml"
Output >
PLAY [Setup bitwol server] ******************************
TASK [Notify simple handler in handlers folder (without any import) - Are files in handlers folder loaded in the playbook (not role ????)] ***
changed: [localhost] => {
"msg": "About to notify th e simple handler"
}
RUNNING HANDLER [Test_it] ******************************
ok: [localhost] => {
"msg": "JUST SAYING HI - from simple 1"
}
RUNNING HANDLER [Another handler] ******************************
changed: [localhost]
PLAY RECAP ********************************************************************************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can see that in both
simple1.yml
andsimple2.yml
there is the same handlerTest_it
.
- Only the one from the first file was run
simple1.yml
handlers:
- name: Simple handler 2
ansible.builtin.import_tasks: "handlers/simple2.yml"
- name: Simple handler
ansible.builtin.import_tasks: "handlers/simple.yml"
Output >
PLAY [Setup bitwol server] *****************************************************
TASK [Notify simple handler in handlers folder (without any import) - Are files in handlers folder loaded in the playbook (not role ????)] ***
changed: [localhost] => {
"msg": "About to notify th e simple handler"
}
RUNNING HANDLER [Test_it] ******************************************************
ok: [localhost] => {
"msg": "JUST SAYING HI - from simple 2"
}
RUNNING HANDLER [Another handler] **********************************************
changed: [localhost]
PLAY RECAP ********************************************************************************************************************************
localhost
2
is the one that got to run.Conclusion if handlers with same name cross files are notified. Only the first one will execute.
- Files import order first
- Then Tasks in file order (in short the order after handlers list resolution)
- You should always name the handlers uniquely
handlers
folderhundlers:
block in the playbookOutput>
PLAY [Setup bitwol server] ***********************************************
TASK [Notify simple handler in handlers folder (without any import) - Are files in handlers folder loaded in the playbook (not role ????)] ***
ERROR! The requested handler 'Test_it' was not found in either the main handlers list nor in the listening handlers list
No handlers were automatically loaded
ERROR! The requested handler 'Test_it' was not found in either the main handlers list nor in the listening handlers list
Not like
roles
. You need toimport
andno automatic loading
.
flush_handlers
Doc ref
By default handlers run at the end after tasks finish
flush_handlers
allow us to run the already notified handlers. At the moment of flush_handlers
call. Handlers will run. Than after them, the list of tasks to run continue.
Handlers by default if tasks fail will not be run. If you want to force handlers to run at a specific time. For whatever reason. You can use flush_handlers
run
flush_handlers
or not
get notified
flush_handlers
does run already notified handlersnotified
, and get notified if the task
with notify
block, does change
notify
block but doesn't change
the handler
will not run.notifying task
did change
changed_when: true
- name: Notify simple handler
ansible.builtin.debug:
msg: "About to notify the simple handler"
changed_when: true
# changed_when: false
notify:
- "Test_it"
- "Another handler"
in roles
We can add .yml
files to handlers
folder within the role folder. And they would automatically be loaded. No import needed.
PR
Upvotes: 4
Reputation: 81
You should have the structure described in https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html thus the directory should be called handlers
(and not handler
)
Upvotes: 4