From 7d18ea5e93ccccfc415328430898c8d06e325f87 Mon Sep 17 00:00:00 2001 From: Sam Doran Date: Tue, 9 Feb 2021 12:43:59 -0500 Subject: [PATCH] default callback - add "show_task_path_on_failure" option (#73260) When running in verbosity <2, display the file and line number for tasks that fail. This provides useful information without having to run at increased verbosity. * Move _print_task_path to CallbackBase class * Add integration tests * Add color parameter to _print_task_path() * Keep color output consistent for now Currently the path is display with COLOR_DEBUG formatting with verbosity >= 2. Instead of the color of the path changing based on verbosity level, just keep it at the currently behavior of COLOR_DEBUG. Having the color of the same information change based on verbosity level seems incorrect and makes visual parsing of the information more difficult. Co-authored-by: tahar.jegham --- ...e-path-on-task-failure-callback-option.yml | 5 + lib/ansible/plugins/callback/__init__.py | 5 + lib/ansible/plugins/callback/default.py | 9 +- .../plugins/doc_fragments/default_callback.py | 13 +++ ...default.out.display_path_on_failure.stderr | 2 + ...default.out.display_path_on_failure.stdout | 100 ++++++++++++++++++ .../targets/callback_default/runme.sh | 11 +- 7 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/64625-show-file-path-on-task-failure-callback-option.yml create mode 100644 test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stderr create mode 100644 test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stdout diff --git a/changelogs/fragments/64625-show-file-path-on-task-failure-callback-option.yml b/changelogs/fragments/64625-show-file-path-on-task-failure-callback-option.yml new file mode 100644 index 00000000000..a06bcf6f5b8 --- /dev/null +++ b/changelogs/fragments/64625-show-file-path-on-task-failure-callback-option.yml @@ -0,0 +1,5 @@ +minor_changes: + - >- + default callback - add ``show_task_path_on_failure`` option to display file and + line number of tasks only on failed tasks when running at + normal verbosity level (https://github.com/ansible/ansible/issues/64625) diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py index 317494ad6c5..7a06698c7a0 100644 --- a/lib/ansible/plugins/callback/__init__.py +++ b/lib/ansible/plugins/callback/__init__.py @@ -259,6 +259,11 @@ class CallbackBase(AnsiblePlugin): for hidme in self._hide_in_debug: result.pop(hidme, None) + def _print_task_path(self, task, color=C.COLOR_DEBUG): + path = task.get_path() + if path: + self._display.display(u"task path: %s" % path, color=color) + def set_play_context(self, play_context): pass diff --git a/lib/ansible/plugins/callback/default.py b/lib/ansible/plugins/callback/default.py index 9087aacdf2d..9a4f7b2253c 100644 --- a/lib/ansible/plugins/callback/default.py +++ b/lib/ansible/plugins/callback/default.py @@ -91,10 +91,14 @@ class CallbackModule(CallbackBase): else: if delegated_vars: + if self._display.verbosity < 2 and self.get_option('show_task_path_on_failure'): + self._print_task_path(result._task) self._display.display("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'], self._dump_results(result._result)), color=C.COLOR_ERROR, stderr=self.display_failed_stderr) else: + if self._display.verbosity < 2 and self.get_option('show_task_path_on_failure'): + self._print_task_path(result._task) self._display.display("fatal: [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)), color=C.COLOR_ERROR, stderr=self.display_failed_stderr) @@ -225,10 +229,9 @@ class CallbackModule(CallbackBase): else: checkmsg = "" self._display.banner(u"%s [%s%s]%s" % (prefix, task_name, args, checkmsg)) + if self._display.verbosity >= 2: - path = task.get_path() - if path: - self._display.display(u"task path: %s" % path, color=C.COLOR_DEBUG) + self._print_task_path(task) self._last_task_banner = task._uuid diff --git a/lib/ansible/plugins/doc_fragments/default_callback.py b/lib/ansible/plugins/doc_fragments/default_callback.py index df3966b937c..fd17b260bbb 100644 --- a/lib/ansible/plugins/doc_fragments/default_callback.py +++ b/lib/ansible/plugins/doc_fragments/default_callback.py @@ -82,4 +82,17 @@ class ModuleDocFragment(object): ini: - key: check_mode_markers section: defaults + show_task_path_on_failure: + name: Show file path on failed tasks + description: + When a task fails, display the path to the file containing the failed task and the line number. + This information is displayed automatically for every task when running with C(-vv) or greater verbosity. + type: bool + default: no + env: + - name: ANSIBLE_SHOW_TASK_PATH_ON_FAILURE + ini: + - key: show_task_path_on_failure + section: defaults + version_added: '2.11' ''' diff --git a/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stderr b/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stderr new file mode 100644 index 00000000000..d3e07d472db --- /dev/null +++ b/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stderr @@ -0,0 +1,2 @@ ++ ansible-playbook -i inventory test.yml +++ set +x diff --git a/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stdout b/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stdout new file mode 100644 index 00000000000..d9ffd575537 --- /dev/null +++ b/test/integration/targets/callback_default/callback_default.out.display_path_on_failure.stdout @@ -0,0 +1,100 @@ + +PLAY [testhost] **************************************************************** + +TASK [Changed task] ************************************************************ +changed: [testhost] + +TASK [Ok task] ***************************************************************** +ok: [testhost] + +TASK [Failed task] ************************************************************* +task path: TEST_PATH/test.yml:16 +fatal: [testhost]: FAILED! => {"changed": false, "msg": "no reason"} +...ignoring + +TASK [Skipped task] ************************************************************ +skipping: [testhost] + +TASK [Task with var in name (foo bar)] ***************************************** +changed: [testhost] + +TASK [Loop task] *************************************************************** +changed: [testhost] => (item=foo-1) +changed: [testhost] => (item=foo-2) +changed: [testhost] => (item=foo-3) + +TASK [debug loop] ************************************************************** +changed: [testhost] => (item=debug-1) => { + "msg": "debug-1" +} +failed: [testhost] (item=debug-2) => { + "msg": "debug-2" +} +ok: [testhost] => (item=debug-3) => { + "msg": "debug-3" +} +skipping: [testhost] => (item=debug-4) +task path: TEST_PATH/test.yml:38 +fatal: [testhost]: FAILED! => {"msg": "One or more items failed"} +...ignoring + +TASK [EXPECTED FAILURE Failed task to be rescued] ****************************** +task path: TEST_PATH/test.yml:54 +fatal: [testhost]: FAILED! => {"changed": false, "msg": "Failed as requested from task"} + +TASK [Rescue task] ************************************************************* +changed: [testhost] + +TASK [include_tasks] *********************************************************** +included: .../test/integration/targets/callback_default/include_me.yml for testhost => (item=1) + +TASK [debug] ******************************************************************* +ok: [testhost] => { + "item": 1 +} + +TASK [copy] ******************************************************************** +changed: [testhost] + +TASK [replace] ***************************************************************** +--- before: .../test_diff.txt ++++ after: .../test_diff.txt +@@ -1 +1 @@ +-foo +\ No newline at end of file ++bar +\ No newline at end of file + +changed: [testhost] + +TASK [replace] ***************************************************************** +ok: [testhost] + +RUNNING HANDLER [Test handler 1] *********************************************** +changed: [testhost] + +RUNNING HANDLER [Test handler 2] *********************************************** +ok: [testhost] + +RUNNING HANDLER [Test handler 3] *********************************************** +changed: [testhost] + +PLAY [testhost] **************************************************************** + +TASK [First free task] ********************************************************* +changed: [testhost] + +TASK [Second free task] ******************************************************** +changed: [testhost] + +TASK [Include some tasks] ****************************************************** +included: .../test/integration/targets/callback_default/include_me.yml for testhost => (item=1) + +TASK [debug] ******************************************************************* +ok: [testhost] => { + "item": 1 +} + +PLAY RECAP ********************************************************************* +testhost : ok=19 changed=11 unreachable=0 failed=0 skipped=1 rescued=1 ignored=2 + diff --git a/test/integration/targets/callback_default/runme.sh b/test/integration/targets/callback_default/runme.sh index 934586d7252..b5c98ef72b8 100755 --- a/test/integration/targets/callback_default/runme.sh +++ b/test/integration/targets/callback_default/runme.sh @@ -16,7 +16,7 @@ set -eux run_test() { local testname=$1 - # outout was recorded w/o cowsay, ensure we reproduce the same + # output was recorded w/o cowsay, ensure we reproduce the same export ANSIBLE_NOCOWS=1 # The shenanigans with redirection and 'tee' are to capture STDOUT and @@ -29,6 +29,7 @@ run_test() { sed -i -e 's/included: .*\/test\/integration/included: ...\/test\/integration/g' "${OUTFILE}.${testname}.stdout" sed -i -e 's/@@ -1,1 +1,1 @@/@@ -1 +1 @@/g' "${OUTFILE}.${testname}.stdout" sed -i -e 's/: .*\/test_diff\.txt/: ...\/test_diff.txt/g' "${OUTFILE}.${testname}.stdout" + sed -i -e "s#${ANSIBLE_PLAYBOOK_DIR}#TEST_PATH#g" "${OUTFILE}.${testname}.stdout" diff -u "${ORIGFILE}.${testname}.stdout" "${OUTFILE}.${testname}.stdout" || diff_failure diff -u "${ORIGFILE}.${testname}.stderr" "${OUTFILE}.${testname}.stderr" || diff_failure @@ -147,6 +148,14 @@ export ANSIBLE_DISPLAY_OK_HOSTS=1 export ANSIBLE_DISPLAY_FAILED_STDERR=1 run_test failed_to_stderr +export ANSIBLE_DISPLAY_FAILED_STDERR=0 + + +# Test displaying task path on failure +export ANSIBLE_SHOW_TASK_PATH_ON_FAILURE=1 +run_test display_path_on_failure +export ANSIBLE_SHOW_TASK_PATH_ON_FAILURE=0 + # Default settings with unreachable tasks export ANSIBLE_DISPLAY_SKIPPED_HOSTS=1