Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: tools/utils.py

Issue 2645963004: Buildbot: Only archive core dumps from unexpected crashes. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 # for details. All rights reserved. Use of this source code is governed by a 2 # for details. All rights reserved. Use of this source code is governed by a
3 # BSD-style license that can be found in the LICENSE file. 3 # BSD-style license that can be found in the LICENSE file.
4 4
5 # This file contains a set of utilities functions used by other Python-based 5 # This file contains a set of utilities functions used by other Python-based
6 # scripts. 6 # scripts.
7 7
8 import commands 8 import commands
9 import datetime 9 import datetime
10 import glob 10 import glob
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 667
668 def __enter__(self): 668 def __enter__(self):
669 self._old_cwd = os.getcwd() 669 self._old_cwd = os.getcwd()
670 print "Enter directory = ", self._working_directory 670 print "Enter directory = ", self._working_directory
671 os.chdir(self._working_directory) 671 os.chdir(self._working_directory)
672 672
673 def __exit__(self, *_): 673 def __exit__(self, *_):
674 print "Enter directory = ", self._old_cwd 674 print "Enter directory = ", self._old_cwd
675 os.chdir(self._old_cwd) 675 os.chdir(self._old_cwd)
676 676
677 # This class finds and archives all core.* files from the current working 677 class CoreDump(object):
678 # directory and all binaries copied by UnexpectedCrashDumpArchiver into 678 def __init__(self, test, core, binary):
679 # the current working directory (see tools/testing/dart/test_progress.dart). 679 self.test = test
680 self.core = core
681 self.binary = binary
682
683 def __str__(self):
684 return "%s: %s %s" % (self.test, self.binary, self.core)
685
686 # This class reads coredumps file written by UnexpectedCrashDumpArchiver into
687 # the current working directory and uploads all cores and binaries
688 # listed in it into Cloud Storage (see tools/testing/dart/test_progress.dart).
680 class CoreDumpArchiver(object): 689 class CoreDumpArchiver(object):
681 def __init__(self, args): 690 def __init__(self, args):
682 self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux' 691 self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux'
683 self._search_dir = os.getcwd() 692 self._search_dir = os.getcwd()
684 self._bucket = 'dart-temp-crash-archive' 693 self._bucket = 'dart-temp-crash-archive'
685 self._old_limits = None 694 self._old_limits = None
686 695
687 def __enter__(self): 696 def __enter__(self):
688 if not self._enabled: 697 if not self._enabled:
689 return 698 return
690 699
691 # Cleanup any stale coredumps 700 # Cleanup any stale coredumps
692 coredumps = self._find_coredumps() 701 if self._cleanup():
693 if coredumps: 702 print "WARNING: Found and removed stale coredumps"
694 print "WARNING: Found stale coredumps, removing"
695 MarkCurrentStepWarning()
696 self._remove_coredumps(coredumps)
697 703
698 self._old_limits = resource.getrlimit(resource.RLIMIT_CORE) 704 self._old_limits = resource.getrlimit(resource.RLIMIT_CORE)
699 705
700 # Bump core limits to unlimited if core_pattern is correctly configured. 706 # Bump core limits to unlimited if core_pattern is correctly configured.
701 if self._check_core_dump_pattern(fatal=False): 707 if self._check_core_dump_pattern(fatal=False):
702 resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) 708 resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
703 709
704 def __exit__(self, *_): 710 def __exit__(self, *_):
705 if not self._enabled: 711 if not self._enabled:
706 return 712 return
707 713
708 # Restore old core limit. 714 try:
709 resource.setrlimit(resource.RLIMIT_CORE, self._old_limits) 715 # Restore old core limit.
716 resource.setrlimit(resource.RLIMIT_CORE, self._old_limits)
710 717
711 # Check that kernel was correctly configured to use core.%p 718 # Check that kernel was correctly configured to use core.%p
712 # core_pattern. 719 # core_pattern.
713 self._check_core_dump_pattern(fatal=True) 720 self._check_core_dump_pattern(fatal=True)
714 721
715 coredumps = self._find_coredumps() 722 coredumps = self._find_coredumps()
716 if coredumps: 723 if coredumps:
717 # If we get a ton of crashes, only archive 10 dumps. 724 # If we get a ton of crashes, only archive 10 dumps.
718 archive_coredumps = coredumps[:10] 725 archive_coredumps = coredumps[:10]
719 print 'Archiving coredumps: %s' % ', '.join(archive_coredumps) 726 print 'Archiving coredumps:'
720 sys.stdout.flush() 727 for core in archive_coredumps:
721 self._archive(archive_coredumps) 728 print '----> %s' % core
722 self._remove_coredumps(coredumps)
723 coredumps = self._find_coredumps()
724 assert not coredumps
725 729
730 sys.stdout.flush()
731 self._archive(archive_coredumps)
732
733 finally:
734 self._cleanup()
735
736 def _cleanup(self):
737 found = False
738 for core in glob.glob(os.path.join(self._search_dir, 'core.*')):
739 found = True
740 os.unlink(core)
741 for binary in glob.glob(os.path.join(self._search_dir, 'binary.*')):
742 found = True
743 os.unlink(binary)
744 try:
745 os.unlink(os.path.join(self._search_dir, 'coredumps'))
746 found = True
747 except:
748 pass
749
750 return found
751
752 # Load coredumps file. Each line has the following format:
753 #
754 # test-name,core-file,binary-file
755 #
kustermann 2017/01/20 14:56:55 Normally python docs are like def _find_core_dump
Vyacheslav Egorov (Google) 2017/01/20 16:44:45 Done.
726 def _find_coredumps(self): 756 def _find_coredumps(self):
727 return glob.glob(os.path.join(self._search_dir, 'core.*')) 757 try:
728 758 with open('coredumps') as f:
729 def _remove_coredumps(self, coredumps): 759 return [CoreDump(*ln.strip('\n').split(',')) for ln in f.readlines()]
730 for name in coredumps: 760 except:
731 os.unlink(name) 761 return []
732 762
733 def _archive(self, coredumps): 763 def _archive(self, coredumps):
764 files = set()
765 for core in coredumps:
766 files.add(core.core)
767 files.add(core.binary)
768 self._upload(files)
769
770 def _upload(self, files):
734 bot_utils = GetBotUtils() 771 bot_utils = GetBotUtils()
735 gsutil = bot_utils.GSUtil() 772 gsutil = bot_utils.GSUtil()
736 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4()) 773 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4())
737 gs_prefix = 'gs://%s' % storage_path 774 gs_prefix = 'gs://%s' % storage_path
738 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path 775 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path
739 776
740 for core in coredumps: 777 print '\n--- Uploading into %s (%s) ---' % (gs_prefix, http_prefix)
778 for core in files:
741 # Sanitize the name: actual cores follow 'core.%d' pattern, crashed 779 # Sanitize the name: actual cores follow 'core.%d' pattern, crashed
742 # binaries are copied next to cores and named 'core.<binary_name>'. 780 # binaries are copied next to cores and named 'core.<binary_name>'.
kustermann 2017/01/20 14:56:55 The binaries are now named: "binary.${mode}_${arch
Vyacheslav Egorov (Google) 2017/01/20 16:44:46 Done.
743 suffix = os.path.basename(core).split('.')[1] 781 parts = os.path.basename(core).split('.')
kustermann 2017/01/20 14:56:55 Maybe simpler: (prefix, rest) = 'a.b.c.d'.split('
Vyacheslav Egorov (Google) 2017/01/20 16:44:46 Done.
744 try: 782 if parts[0] == 'binary':
745 # Check if suffix is an integer - in this case it's an actual core. 783 clean_name = '.'.join(parts[1:])
746 clean_name = 'core.%d' % int(suffix) 784 else:
747 except: 785 clean_name = os.path.basename(core)
748 # This is not a coredump but a crashed binary.
749 clean_name = suffix
750 786
751 tarname = '%s.tar.gz' % clean_name 787 tarname = '%s.tar.gz' % clean_name
752 788
753 # Create a .tar.gz archive out of a crash folder that contains 789 # Create a .tar.gz archive out of a crash folder that contains
754 # both binary and the core dump. 790 # both binary and the core dump.
755 tar = tarfile.open(tarname, mode='w:gz') 791 tar = tarfile.open(tarname, mode='w:gz')
756 tar.add(core, arcname=clean_name) 792 tar.add(core, arcname=clean_name)
757 tar.close() 793 tar.close()
758 794
759 # Remove / from absolute path to not have // in gs path. 795 # Remove / from absolute path to not have // in gs path.
760 gs_url = '%s%s' % (gs_prefix, tarname) 796 gs_url = '%s%s' % (gs_prefix, tarname)
761 http_url = '%s%s' % (http_prefix, tarname) 797 http_url = '%s%s' % (http_prefix, tarname)
762 798
763 try: 799 try:
764 gsutil.upload(tarname, gs_url) 800 gsutil.upload(tarname, gs_url)
765 print '@@@STEP_LOG_LINE@coredumps@%s (%s)@@@' % (gs_url, http_url) 801 print '+++ Uploaded %s (%s)' % (gs_url, http_url)
766 except Exception as error: 802 except Exception as error:
767 message = "Failed to upload coredump %s, error: %s" % (tarname, error) 803 print '!!! Failed to upload %s, error: %s' % (tarname, error)
768 print '@@@STEP_LOG_LINE@coredumps@%s@@@' % message
769 804
770 os.unlink(tarname) 805 os.unlink(tarname)
771 806 print '--- Done ---\n'
772 print '@@@STEP_LOG_END@coredumps@@@'
773 MarkCurrentStepWarning()
774 807
775 def _check_core_dump_pattern(self, fatal=False): 808 def _check_core_dump_pattern(self, fatal=False):
776 core_pattern_file = '/proc/sys/kernel/core_pattern' 809 core_pattern_file = '/proc/sys/kernel/core_pattern'
777 core_pattern = open(core_pattern_file).read() 810 core_pattern = open(core_pattern_file).read()
778 811
779 expected_core_pattern = 'core.%p' 812 expected_core_pattern = 'core.%p'
780 if core_pattern.strip() != expected_core_pattern: 813 if core_pattern.strip() != expected_core_pattern:
781 if fatal: 814 if fatal:
782 message = ("Invalid core_pattern configuration. " 815 message = ('Invalid core_pattern configuration. '
783 "The configuration of core dump handling is *not* correct for " 816 'The configuration of core dump handling is *not* correct for '
784 "a buildbot. The content of {0} must be '{1}' instead of '{2}'." 817 'a buildbot. The content of {0} must be "{1}" instead of "{2}".'
785 .format(core_pattern_file, expected_core_pattern, core_pattern)) 818 .format(core_pattern_file, expected_core_pattern, core_pattern))
786 raise Exception(message) 819 raise Exception(message)
787 else: 820 else:
788 return False 821 return False
789 return True 822 return True
790 823
791 def MarkCurrentStepWarning():
792 print "@@@STEP_WARNINGS@@@"
793 sys.stdout.flush()
794
795 if __name__ == "__main__": 824 if __name__ == "__main__":
796 import sys 825 import sys
797 Main() 826 Main()
OLDNEW
« tools/testing/dart/test_progress.dart ('K') | « tools/testing/dart/test_progress.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698