diff options
author | David Reyna <David.Reyna@windriver.com> | 2022-03-20 22:02:20 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2022-03-21 10:07:40 +0000 |
commit | 4769eaebb40772fca1af6d59b104cc0db00fbbc5 (patch) | |
tree | 9b47a42f01ce559370c19ef18c875bffb517c4dd | |
parent | e5ab3817aa98846c0a1c6d23feb47ff9404b0b90 (diff) | |
download | poky-4769eaebb40772fca1af6d59b104cc0db00fbbc5.tar.gz |
bitbake: toaster: detect when bitbake crashed
Add a polling check on tracebacks in a build's log. This
can for example indicate that bitbake crashed, which would
stop the event stream that Toaster normally uses to detect
build errors.
[YOCTO #14085]
(Bitbake rev: 32b1c0b3477e359d2e2a61a23a294e317e417f95)
Signed-off-by: David Reyna <David.Reyna@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py index 19f659ec41..834e32b36f 100644 --- a/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py +++ b/bitbake/lib/toaster/bldcontrol/management/commands/runbuilds.py | |||
@@ -180,6 +180,77 @@ class Command(BaseCommand): | |||
180 | except Exception as e: | 180 | except Exception as e: |
181 | logger.warning("runbuilds: schedule exception %s" % str(e)) | 181 | logger.warning("runbuilds: schedule exception %s" % str(e)) |
182 | 182 | ||
183 | # Test to see if a build pre-maturely died due to a bitbake crash | ||
184 | def check_dead_builds(self): | ||
185 | do_cleanup = False | ||
186 | try: | ||
187 | for br in BuildRequest.objects.filter(state=BuildRequest.REQ_INPROGRESS): | ||
188 | # Get the build directory | ||
189 | if br.project.builddir: | ||
190 | builddir = br.project.builddir | ||
191 | else: | ||
192 | builddir = '%s-toaster-%d' % (br.environment.builddir,br.project.id) | ||
193 | # Check log to see if there is a recent traceback | ||
194 | toaster_ui_log = os.path.join(builddir, 'toaster_ui.log') | ||
195 | test_file = os.path.join(builddir, '._toaster_check.txt') | ||
196 | os.system("tail -n 50 %s > %s" % (os.path.join(builddir, 'toaster_ui.log'),test_file)) | ||
197 | traceback_text = '' | ||
198 | is_traceback = False | ||
199 | with open(test_file,'r') as test_file_fd: | ||
200 | test_file_tail = test_file_fd.readlines() | ||
201 | for line in test_file_tail: | ||
202 | if line.startswith('Traceback (most recent call last):'): | ||
203 | traceback_text = line | ||
204 | is_traceback = True | ||
205 | elif line.startswith('NOTE: ToasterUI waiting for events'): | ||
206 | # Ignore any traceback before new build start | ||
207 | traceback_text = '' | ||
208 | is_traceback = False | ||
209 | elif line.startswith('Note: Toaster traceback auto-stop'): | ||
210 | # Ignore any traceback before this previous traceback catch | ||
211 | traceback_text = '' | ||
212 | is_traceback = False | ||
213 | elif is_traceback: | ||
214 | traceback_text += line | ||
215 | # Test the results | ||
216 | is_stop = False | ||
217 | if is_traceback: | ||
218 | # Found a traceback | ||
219 | errtype = 'Bitbake crash' | ||
220 | errmsg = 'Bitbake crash\n' + traceback_text | ||
221 | state = BuildRequest.REQ_FAILED | ||
222 | # Clean up bitbake files | ||
223 | bitbake_lock = os.path.join(builddir, 'bitbake.lock') | ||
224 | if os.path.isfile(bitbake_lock): | ||
225 | os.remove(bitbake_lock) | ||
226 | bitbake_sock = os.path.join(builddir, 'bitbake.sock') | ||
227 | if os.path.isfile(bitbake_sock): | ||
228 | os.remove(bitbake_sock) | ||
229 | if os.path.isfile(test_file): | ||
230 | os.remove(test_file) | ||
231 | # Add note to ignore this traceback on next check | ||
232 | os.system('echo "Note: Toaster traceback auto-stop" >> %s' % toaster_ui_log) | ||
233 | is_stop = True | ||
234 | # Add more tests here | ||
235 | #elif ... | ||
236 | # Stop the build request? | ||
237 | if is_stop: | ||
238 | brerror = BRError( | ||
239 | req = br, | ||
240 | errtype = errtype, | ||
241 | errmsg = errmsg, | ||
242 | traceback = traceback_text, | ||
243 | ) | ||
244 | brerror.save() | ||
245 | br.state = state | ||
246 | br.save() | ||
247 | do_cleanup = True | ||
248 | # Do cleanup | ||
249 | if do_cleanup: | ||
250 | self.cleanup() | ||
251 | except Exception as e: | ||
252 | logger.error("runbuilds: Error in check_dead_builds %s" % e) | ||
253 | |||
183 | def handle(self, **options): | 254 | def handle(self, **options): |
184 | pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."), | 255 | pidfile_path = os.path.join(os.environ.get("BUILDDIR", "."), |
185 | ".runbuilds.pid") | 256 | ".runbuilds.pid") |
@@ -187,10 +258,18 @@ class Command(BaseCommand): | |||
187 | with open(pidfile_path, 'w') as pidfile: | 258 | with open(pidfile_path, 'w') as pidfile: |
188 | pidfile.write("%s" % os.getpid()) | 259 | pidfile.write("%s" % os.getpid()) |
189 | 260 | ||
261 | # Clean up any stale/failed builds from previous Toaster run | ||
190 | self.runbuild() | 262 | self.runbuild() |
191 | 263 | ||
192 | signal.signal(signal.SIGUSR1, lambda sig, frame: None) | 264 | signal.signal(signal.SIGUSR1, lambda sig, frame: None) |
193 | 265 | ||
194 | while True: | 266 | while True: |
195 | signal.pause() | 267 | sigset = signal.sigtimedwait([signal.SIGUSR1], 5) |
196 | self.runbuild() | 268 | if sigset: |
269 | for sig in sigset: | ||
270 | # Consume each captured pending event | ||
271 | self.runbuild() | ||
272 | else: | ||
273 | # Check for build exceptions | ||
274 | self.check_dead_builds() | ||
275 | |||