OLD | NEW |
---|---|
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 Loading... | |
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() |
OLD | NEW |