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

Side by Side Diff: tools/utils.py

Issue 2645963004: Buildbot: Only archive core dumps from unexpected crashes. (Closed)
Patch Set: Address Martin's comments 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
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
680 class CoreDumpArchiver(object): 686 class CoreDumpArchiver(object):
687 """This class reads coredumps file written by UnexpectedCrashDumpArchiver
688 into the current working directory and uploads all cores and binaries
689 listed in it into Cloud Storage (see tools/testing/dart/test_progress.dart).
690 """
691
681 def __init__(self, args): 692 def __init__(self, args):
682 self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux' 693 self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux'
683 self._search_dir = os.getcwd() 694 self._search_dir = os.getcwd()
684 self._bucket = 'dart-temp-crash-archive' 695 self._bucket = 'dart-temp-crash-archive'
685 self._old_limits = None 696 self._old_limits = None
686 697
687 def __enter__(self): 698 def __enter__(self):
688 if not self._enabled: 699 if not self._enabled:
689 return 700 return
690 701
691 # Cleanup any stale coredumps 702 # Cleanup any stale coredumps
692 coredumps = self._find_coredumps() 703 if self._cleanup():
693 if coredumps: 704 print "WARNING: Found and removed stale coredumps"
694 print "WARNING: Found stale coredumps, removing"
695 MarkCurrentStepWarning()
696 self._remove_coredumps(coredumps)
697 705
698 self._old_limits = resource.getrlimit(resource.RLIMIT_CORE) 706 self._old_limits = resource.getrlimit(resource.RLIMIT_CORE)
699 707
700 # Bump core limits to unlimited if core_pattern is correctly configured. 708 # Bump core limits to unlimited if core_pattern is correctly configured.
701 if self._check_core_dump_pattern(fatal=False): 709 if self._check_core_dump_pattern(fatal=False):
702 resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) 710 resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
703 711
704 def __exit__(self, *_): 712 def __exit__(self, *_):
705 if not self._enabled: 713 if not self._enabled:
706 return 714 return
707 715
708 # Restore old core limit. 716 try:
709 resource.setrlimit(resource.RLIMIT_CORE, self._old_limits) 717 # Restore old core limit.
718 resource.setrlimit(resource.RLIMIT_CORE, self._old_limits)
710 719
711 # Check that kernel was correctly configured to use core.%p 720 # Check that kernel was correctly configured to use core.%p
712 # core_pattern. 721 # core_pattern.
713 self._check_core_dump_pattern(fatal=True) 722 self._check_core_dump_pattern(fatal=True)
714 723
715 coredumps = self._find_coredumps() 724 coredumps = self._find_coredumps()
716 if coredumps: 725 if coredumps:
717 # If we get a ton of crashes, only archive 10 dumps. 726 # If we get a ton of crashes, only archive 10 dumps.
718 archive_coredumps = coredumps[:10] 727 archive_coredumps = coredumps[:10]
719 print 'Archiving coredumps: %s' % ', '.join(archive_coredumps) 728 print 'Archiving coredumps:'
720 sys.stdout.flush() 729 for core in archive_coredumps:
721 self._archive(archive_coredumps) 730 print '----> %s' % core
722 self._remove_coredumps(coredumps) 731
723 coredumps = self._find_coredumps() 732 sys.stdout.flush()
724 assert not coredumps 733 self._archive(archive_coredumps)
734
735 finally:
736 self._cleanup()
737
738 def _cleanup(self):
739 found = False
740 for core in glob.glob(os.path.join(self._search_dir, 'core.*')):
741 found = True
742 os.unlink(core)
743 for binary in glob.glob(os.path.join(self._search_dir, 'binary.*')):
744 found = True
745 os.unlink(binary)
746 try:
747 os.unlink(os.path.join(self._search_dir, 'coredumps'))
748 found = True
749 except:
750 pass
751
752 return found
725 753
726 def _find_coredumps(self): 754 def _find_coredumps(self):
727 return glob.glob(os.path.join(self._search_dir, 'core.*')) 755 """Load coredumps file. Each line has the following format:
728 756
729 def _remove_coredumps(self, coredumps): 757 test-name,core-file,binary-file
730 for name in coredumps: 758 """
731 os.unlink(name) 759 try:
760 with open('coredumps') as f:
761 return [CoreDump(*ln.strip('\n').split(',')) for ln in f.readlines()]
762 except:
763 return []
732 764
733 def _archive(self, coredumps): 765 def _archive(self, coredumps):
766 files = set()
767 for core in coredumps:
768 files.add(core.core)
769 files.add(core.binary)
770 self._upload(files)
771
772 def _upload(self, files):
734 bot_utils = GetBotUtils() 773 bot_utils = GetBotUtils()
735 gsutil = bot_utils.GSUtil() 774 gsutil = bot_utils.GSUtil()
736 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4()) 775 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4())
737 gs_prefix = 'gs://%s' % storage_path 776 gs_prefix = 'gs://%s' % storage_path
738 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path 777 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path
739 778
740 for core in coredumps: 779 print '\n--- Uploading into %s (%s) ---' % (gs_prefix, http_prefix)
780 for file in files:
741 # Sanitize the name: actual cores follow 'core.%d' pattern, crashed 781 # Sanitize the name: actual cores follow 'core.%d' pattern, crashed
742 # binaries are copied next to cores and named 'core.<binary_name>'. 782 # binaries are copied next to cores and named 'binary.<binary_name>'.
743 suffix = os.path.basename(core).split('.')[1] 783 name = os.path.basename(file)
744 try: 784 (prefix, suffix) = name.split('.', 1)
745 # Check if suffix is an integer - in this case it's an actual core. 785 if prefix == 'binary':
746 clean_name = 'core.%d' % int(suffix) 786 name = suffix
747 except:
748 # This is not a coredump but a crashed binary.
749 clean_name = suffix
750 787
751 tarname = '%s.tar.gz' % clean_name 788 tarname = '%s.tar.gz' % name
752 789
753 # Create a .tar.gz archive out of a crash folder that contains 790 # Compress the file.
754 # 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(file, arcname=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
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698