Allow for searching handler subdir for included tasks (#73809)
* Allow for searching handler subdir for included tasks
This commit is contained in:
parent
3098022146
commit
1e5ccb326f
7 changed files with 81 additions and 47 deletions
2
changelogs/fragments/73809-search-handler-subdir.yml
Normal file
2
changelogs/fragments/73809-search-handler-subdir.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- A handler defined within a role will now search handlers subdir for included tasks (issue https://github.com/ansible/ansible/issues/71222).
|
|
@ -24,6 +24,7 @@ import os
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.playbook.handler import Handler
|
||||||
from ansible.playbook.task_include import TaskInclude
|
from ansible.playbook.task_include import TaskInclude
|
||||||
from ansible.playbook.role_include import IncludeRole
|
from ansible.playbook.role_include import IncludeRole
|
||||||
from ansible.template import Templar
|
from ansible.template import Templar
|
||||||
|
@ -114,60 +115,63 @@ class IncludedFile:
|
||||||
|
|
||||||
if original_task.action in C._ACTION_ALL_INCLUDE_TASKS:
|
if original_task.action in C._ACTION_ALL_INCLUDE_TASKS:
|
||||||
include_file = None
|
include_file = None
|
||||||
if original_task:
|
if original_task.static:
|
||||||
if original_task.static:
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
if original_task._parent:
|
if original_task._parent:
|
||||||
# handle relative includes by walking up the list of parent include
|
# handle relative includes by walking up the list of parent include
|
||||||
# tasks and checking the relative result to see if it exists
|
# tasks and checking the relative result to see if it exists
|
||||||
parent_include = original_task._parent
|
parent_include = original_task._parent
|
||||||
cumulative_path = None
|
cumulative_path = None
|
||||||
while parent_include is not None:
|
while parent_include is not None:
|
||||||
if not isinstance(parent_include, TaskInclude):
|
if not isinstance(parent_include, TaskInclude):
|
||||||
parent_include = parent_include._parent
|
parent_include = parent_include._parent
|
||||||
continue
|
continue
|
||||||
if isinstance(parent_include, IncludeRole):
|
if isinstance(parent_include, IncludeRole):
|
||||||
parent_include_dir = parent_include._role_path
|
parent_include_dir = parent_include._role_path
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
|
parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
|
||||||
|
except AnsibleError as e:
|
||||||
|
parent_include_dir = ''
|
||||||
|
display.warning(
|
||||||
|
'Templating the path of the parent %s failed. The path to the '
|
||||||
|
'included file may not be found. '
|
||||||
|
'The error was: %s.' % (original_task.action, to_text(e))
|
||||||
|
)
|
||||||
|
if cumulative_path is not None and not os.path.isabs(cumulative_path):
|
||||||
|
cumulative_path = os.path.join(parent_include_dir, cumulative_path)
|
||||||
|
else:
|
||||||
|
cumulative_path = parent_include_dir
|
||||||
|
include_target = templar.template(include_result['include'])
|
||||||
|
if original_task._role:
|
||||||
|
new_basedir = os.path.join(original_task._role._role_path, 'tasks', cumulative_path)
|
||||||
|
candidates = [loader.path_dwim_relative(original_task._role._role_path, 'tasks', include_target),
|
||||||
|
loader.path_dwim_relative(new_basedir, 'tasks', include_target)]
|
||||||
|
for include_file in candidates:
|
||||||
try:
|
try:
|
||||||
parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
|
# may throw OSError
|
||||||
except AnsibleError as e:
|
os.stat(include_file)
|
||||||
parent_include_dir = ''
|
# or select the task file if it exists
|
||||||
display.warning(
|
break
|
||||||
'Templating the path of the parent %s failed. The path to the '
|
except OSError:
|
||||||
'included file may not be found. '
|
pass
|
||||||
'The error was: %s.' % (original_task.action, to_text(e))
|
else:
|
||||||
)
|
include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target)
|
||||||
if cumulative_path is not None and not os.path.isabs(cumulative_path):
|
|
||||||
cumulative_path = os.path.join(parent_include_dir, cumulative_path)
|
|
||||||
else:
|
|
||||||
cumulative_path = parent_include_dir
|
|
||||||
include_target = templar.template(include_result['include'])
|
|
||||||
if original_task._role:
|
|
||||||
new_basedir = os.path.join(original_task._role._role_path, 'tasks', cumulative_path)
|
|
||||||
candidates = [loader.path_dwim_relative(original_task._role._role_path, 'tasks', include_target),
|
|
||||||
loader.path_dwim_relative(new_basedir, 'tasks', include_target)]
|
|
||||||
for include_file in candidates:
|
|
||||||
try:
|
|
||||||
# may throw OSError
|
|
||||||
os.stat(include_file)
|
|
||||||
# or select the task file if it exists
|
|
||||||
break
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target)
|
|
||||||
|
|
||||||
if os.path.exists(include_file):
|
if os.path.exists(include_file):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
parent_include = parent_include._parent
|
parent_include = parent_include._parent
|
||||||
|
|
||||||
if include_file is None:
|
if include_file is None:
|
||||||
if original_task._role:
|
if original_task._role:
|
||||||
include_target = templar.template(include_result['include'])
|
include_target = templar.template(include_result['include'])
|
||||||
include_file = loader.path_dwim_relative(original_task._role._role_path, 'tasks', include_target)
|
include_file = loader.path_dwim_relative(
|
||||||
|
original_task._role._role_path,
|
||||||
|
'handlers' if isinstance(original_task, Handler) else 'tasks',
|
||||||
|
include_target,
|
||||||
|
is_role=True)
|
||||||
else:
|
else:
|
||||||
include_file = loader.path_dwim(include_result['include'])
|
include_file = loader.path_dwim(include_result['include'])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
- debug: msg="handler with tasks from A.yml called"
|
|
@ -0,0 +1,5 @@
|
||||||
|
- name: role-based handler from handler subdir
|
||||||
|
include_tasks: A.yml
|
||||||
|
|
||||||
|
- name: role-based handler from tasks subdir
|
||||||
|
include_tasks: B.yml
|
|
@ -0,0 +1 @@
|
||||||
|
- debug: msg="handler with tasks from B.yml called"
|
|
@ -87,6 +87,9 @@ set -e
|
||||||
# https://github.com/ansible/ansible/issues/47287
|
# https://github.com/ansible/ansible/issues/47287
|
||||||
[ "$(ansible-playbook test_handlers_including_task.yml -i ../../inventory -v "$@" | grep -E -o 'failed=[0-9]+')" = "failed=0" ]
|
[ "$(ansible-playbook test_handlers_including_task.yml -i ../../inventory -v "$@" | grep -E -o 'failed=[0-9]+')" = "failed=0" ]
|
||||||
|
|
||||||
|
# https://github.com/ansible/ansible/issues/71222
|
||||||
|
ansible-playbook test_role_handlers_including_tasks.yml -i ../../inventory -v "$@"
|
||||||
|
|
||||||
# https://github.com/ansible/ansible/issues/27237
|
# https://github.com/ansible/ansible/issues/27237
|
||||||
set +e
|
set +e
|
||||||
result="$(ansible-playbook test_handlers_template_run_once.yml -i inventory.handlers "$@" 2>&1)"
|
result="$(ansible-playbook test_handlers_template_run_once.yml -i inventory.handlers "$@" 2>&1)"
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
- name: Verify a role handler can include other tasks from handlers and tasks subdirs
|
||||||
|
hosts: testhost
|
||||||
|
roles:
|
||||||
|
- test_role_handlers_include_tasks
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: notify a role-based handler (include tasks from handler subdir)
|
||||||
|
debug:
|
||||||
|
msg: notifying role handler
|
||||||
|
changed_when: yes
|
||||||
|
notify: role-based handler from handler subdir
|
||||||
|
|
||||||
|
- name: notify a role-based handler (include tasks from tasks subdir)
|
||||||
|
debug:
|
||||||
|
msg: notifying another role handler
|
||||||
|
changed_when: yes
|
||||||
|
notify: role-based handler from tasks subdir
|
Loading…
Reference in a new issue