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 /bitbake/lib | |
| 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>
Diffstat (limited to 'bitbake/lib')
| -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 | |||
