Browse Source

Log exception on module failure with empty stdout

In the zuul_stream callback we check for 'MODULE FAILURE' and then log
stdout, exception or stderr whichever we find first. However in some
cases stdout exists but is empty. In this case we don't log the error
reason and the user needs to look into the json log which contains the
correct information. This can be easily fixed by checking if stdout is
empty.

Change-Id: I8019d40e2e99310eaeab03f652368dac66e1ee17
tags/3.6.0
Tobias Henkel 2 months ago
parent
commit
6f754dd878
No account linked to committer's email address

+ 16
- 0
tests/fixtures/config/remote-zuul-stream/git/org_project/playbooks/command.yaml View File

@@ -82,3 +82,19 @@
82 82
         - failed_in_loop1
83 83
         - failed_in_loop2
84 84
       ignore_errors: True
85
+
86
+- hosts: all
87
+  tasks:
88
+    - name: Remote shell task with python exception
89
+      command: echo foo
90
+      args:
91
+        chdir: /remote-shelltask/somewhere/that/does/not/exist
92
+      failed_when: false
93
+
94
+- hosts: localhost
95
+  tasks:
96
+    - name: Local shell task with python exception
97
+      command: echo foo
98
+      args:
99
+        chdir: /local-shelltask/somewhere/that/does/not/exist
100
+      failed_when: false

+ 9
- 0
tests/remote/test_remote_zuul_stream.py View File

@@ -133,6 +133,15 @@ class TestZuulStream(AnsibleZuulTestCase):
133 133
             self.assertLogLine(r'compute1 \| failed_in_loop2', text)
134 134
             self.assertLogLine(r'compute1 \| ok: Item: failed_in_loop2 '
135 135
                                r'Result: 1', text)
136
+            self.assertLogLine(r'localhost \| .*No such file or directory: .*'
137
+                               r'\'/local-shelltask/somewhere/'
138
+                               r'that/does/not/exist\'', text)
139
+            self.assertLogLine(r'compute1 \| .*No such file or directory: .*'
140
+                               r'\'/remote-shelltask/somewhere/'
141
+                               r'that/does/not/exist\'', text)
142
+            self.assertLogLine(r'controller \| .*No such file or directory: .*'
143
+                               r'\'/remote-shelltask/somewhere/'
144
+                               r'that/does/not/exist\'', text)
136 145
             self.assertLogLine(
137 146
                 r'controller \| ok: Runtime: \d:\d\d:\d\d\.\d\d\d\d\d\d', text)
138 147
             self.assertLogLine('PLAY RECAP', text)

+ 20
- 34
zuul/ansible/callback/zuul_stream.py View File

@@ -182,6 +182,20 @@ class CallbackModule(default.CallbackModule):
182 182
             self._log("%s | %s " % (host, ln), ts=ts)
183 183
             return False
184 184
 
185
+    def _log_module_failure(self, result, result_dict):
186
+        if 'module_stdout' in result_dict and result_dict['module_stdout']:
187
+            self._log_message(
188
+                result, status='MODULE FAILURE',
189
+                msg=result_dict['module_stdout'])
190
+        elif 'exception' in result_dict and result_dict['exception']:
191
+            self._log_message(
192
+                result, status='MODULE FAILURE',
193
+                msg=result_dict['exception'])
194
+        elif 'module_stderr' in result_dict:
195
+            self._log_message(
196
+                result, status='MODULE FAILURE',
197
+                msg=result_dict['module_stderr'])
198
+
185 199
     def v2_playbook_on_start(self, playbook):
186 200
         self._playbook_name = os.path.splitext(playbook._file_name)[0]
187 201
 
@@ -311,18 +325,7 @@ class CallbackModule(default.CallbackModule):
311 325
             # items have their own events
312 326
             pass
313 327
         elif (result_dict.get('msg') == 'MODULE FAILURE'):
314
-            if 'module_stdout' in result_dict:
315
-                self._log_message(
316
-                    result, status='MODULE FAILURE',
317
-                    msg=result_dict['module_stdout'])
318
-            elif 'exception' in result_dict:
319
-                self._log_message(
320
-                    result, status='MODULE FAILURE',
321
-                    msg=result_dict['exception'])
322
-            elif 'module_stderr' in result_dict:
323
-                self._log_message(
324
-                    result, status='MODULE FAILURE',
325
-                    msg=result_dict['module_stderr'])
328
+            self._log_module_failure(result, result_dict)
326 329
         else:
327 330
             self._log_message(
328 331
                 result=result, status='ERROR', result_dict=result_dict)
@@ -388,18 +391,7 @@ class CallbackModule(default.CallbackModule):
388 391
             pass
389 392
 
390 393
         elif (result_dict.get('msg') == 'MODULE FAILURE'):
391
-            if 'module_stdout' in result_dict:
392
-                self._log_message(
393
-                    result, status='MODULE FAILURE',
394
-                    msg=result_dict['module_stdout'])
395
-            elif 'exception' in result_dict:
396
-                self._log_message(
397
-                    result, status='MODULE FAILURE',
398
-                    msg=result_dict['exception'])
399
-            elif 'module_stderr' in result_dict:
400
-                self._log_message(
401
-                    result, status='MODULE FAILURE',
402
-                    msg=result_dict['module_stderr'])
394
+            self._log_module_failure(result, result_dict)
403 395
         elif result._task.action == 'debug':
404 396
             # this is a debug statement, handle it special
405 397
             for key in [k for k in result_dict
@@ -454,11 +446,8 @@ class CallbackModule(default.CallbackModule):
454 446
         else:
455 447
             status = 'ok'
456 448
 
457
-        if (result_dict.get('msg') == 'MODULE FAILURE' and
458
-                'module_stdout' in result_dict):
459
-            self._log_message(
460
-                result, status='MODULE FAILURE',
461
-                msg="Item: {item}\n{module_stdout}".format(**result_dict))
449
+        if result_dict.get('msg') == 'MODULE FAILURE':
450
+            self._log_module_failure(result, result_dict)
462 451
         elif result._task.action not in ('command', 'shell',
463 452
                                          'win_command', 'win_shell'):
464 453
             if 'msg' in result_dict:
@@ -493,11 +482,8 @@ class CallbackModule(default.CallbackModule):
493 482
         result_dict = dict(result._result)
494 483
         self._process_result_for_localhost(result, is_task=False)
495 484
 
496
-        if (result_dict.get('msg') == 'MODULE FAILURE' and
497
-                'module_stdout' in result_dict):
498
-            self._log_message(
499
-                result, status='MODULE FAILURE',
500
-                msg="Item: {item}\n{module_stdout}".format(**result_dict))
485
+        if result_dict.get('msg') == 'MODULE FAILURE':
486
+            self._log_module_failure(result, result_dict)
501 487
         elif result._task.action not in ('command', 'shell',
502 488
                                          'win_command', 'win_shell'):
503 489
             self._log_message(

Loading…
Cancel
Save