Chromium Code Reviews| 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 json | 10 import json |
| 11 import os | 11 import os |
| 12 import platform | 12 import platform |
| 13 import re | 13 import re |
| 14 import shutil | 14 import shutil |
| 15 import subprocess | 15 import subprocess |
| 16 import tempfile | 16 import tempfile |
| 17 import sys | 17 import sys |
| 18 import uuid | |
| 19 | |
| 20 try: | |
| 21 import resource | |
| 22 import tarfile | |
| 23 from bots import bot_utils | |
| 24 from glob import glob | |
|
kustermann
2017/01/18 17:12:36
Does this need to be in the try?
Vyacheslav Egorov (Google)
2017/01/18 19:57:00
Done.
| |
| 25 except: | |
| 26 pass | |
| 18 | 27 |
| 19 class Version(object): | 28 class Version(object): |
| 20 def __init__(self, channel, major, minor, patch, prerelease, | 29 def __init__(self, channel, major, minor, patch, prerelease, |
| 21 prerelease_patch): | 30 prerelease_patch): |
| 22 self.channel = channel | 31 self.channel = channel |
| 23 self.major = major | 32 self.major = major |
| 24 self.minor = minor | 33 self.minor = minor |
| 25 self.patch = patch | 34 self.patch = patch |
| 26 self.prerelease = prerelease | 35 self.prerelease = prerelease |
| 27 self.prerelease_patch = prerelease_patch | 36 self.prerelease_patch = prerelease_patch |
| (...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 650 | 659 |
| 651 def __enter__(self): | 660 def __enter__(self): |
| 652 self._old_cwd = os.getcwd() | 661 self._old_cwd = os.getcwd() |
| 653 print "Enter directory = ", self._working_directory | 662 print "Enter directory = ", self._working_directory |
| 654 os.chdir(self._working_directory) | 663 os.chdir(self._working_directory) |
| 655 | 664 |
| 656 def __exit__(self, *_): | 665 def __exit__(self, *_): |
| 657 print "Enter directory = ", self._old_cwd | 666 print "Enter directory = ", self._old_cwd |
| 658 os.chdir(self._old_cwd) | 667 os.chdir(self._old_cwd) |
| 659 | 668 |
| 669 # This class finds and archives all core.* files from the current working | |
| 670 # directory and all binaries copied by UnexpectedCrashDumpArchiver into | |
|
kustermann
2017/01/18 17:12:35
add `(from tools/testing/dart/test_progress.dart)`
Vyacheslav Egorov (Google)
2017/01/18 19:57:00
Done.
| |
| 671 # the current working directory. | |
| 672 class CoreDumpArchiver(object): | |
| 673 def __init__(self, args): | |
| 674 self._enabled = '--copy-coredumps' in args and GuessOS() == 'linux' | |
| 675 self._search_dir = os.getcwd() | |
| 676 self._bucket = 'dart-temp-crash-archive' | |
| 677 self._old_limits = None | |
| 678 | |
| 679 def __enter__(self): | |
| 680 if not self._enabled: | |
| 681 return | |
| 682 | |
| 683 # Cleanup any stale coredumps | |
| 684 coredumps = self._find_coredumps() | |
| 685 if coredumps: | |
| 686 print "WARNING: Found stale coredumps, removing" | |
| 687 MarkCurrentStepWarning() | |
| 688 self._remove_coredumps(coredumps) | |
| 689 | |
| 690 self._old_limits = resource.getrlimit(resource.RLIMIT_CORE) | |
| 691 | |
| 692 # Bump core limits to unlimited if core_pattern is correctly configured. | |
| 693 if self._check_core_dump_pattern(fatal=False): | |
| 694 resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) | |
| 695 | |
| 696 def __exit__(self, *_): | |
| 697 if not self._enabled: | |
| 698 return | |
| 699 | |
| 700 # Restore old core limit. | |
| 701 resource.setrlimit(resource.RLIMIT_CORE, self._old_limits) | |
| 702 | |
| 703 # Check that kernel was correctly configured to use core.%p | |
| 704 # core_pattern. | |
| 705 self._check_core_dump_pattern(fatal=True) | |
| 706 | |
| 707 coredumps = self._find_coredumps() | |
| 708 if coredumps: | |
| 709 # If we get a ton of crashes, only archive 10 dumps. | |
| 710 archive_coredumps = coredumps[:10] | |
|
Bill Hesse
2017/01/24 16:01:21
Do we want to make sure the binaries are in archiv
Vyacheslav Egorov (Google)
2017/01/24 16:12:13
Nice catch Bill!
Though we changed the way this c
| |
| 711 print 'Archiving coredumps: %s' % ', '.join(archive_coredumps) | |
| 712 sys.stdout.flush() | |
| 713 self._archive(archive_coredumps) | |
| 714 self._remove_coredumps(coredumps) | |
| 715 coredumps = self._find_coredumps() | |
| 716 assert not coredumps | |
| 717 | |
| 718 def _find_coredumps(self): | |
| 719 return glob(os.path.join(self._search_dir, 'core.*')) | |
| 720 | |
| 721 def _remove_coredumps(self, coredumps): | |
| 722 for name in coredumps: | |
| 723 os.unlink(name) | |
| 724 | |
| 725 def _archive(self, coredumps): | |
| 726 gsutil = bot_utils.GSUtil() | |
| 727 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4()) | |
| 728 gs_prefix = 'gs://%s' % storage_path | |
| 729 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path | |
| 730 | |
| 731 for core in coredumps: | |
| 732 # Sanitize the name: actual cores follow 'core.%d' pattern, crashed | |
| 733 # binaries are copied next to cores and named 'core.<binary_name>'. | |
| 734 suffix = os.path.basename(core).split('.')[1] | |
| 735 try: | |
| 736 # Check if suffix is an integer - in this case it's an actual core. | |
| 737 clean_name = 'core.%d' % int(suffix) | |
| 738 except: | |
| 739 # This is not a coredump but a crashed binary. | |
| 740 clean_name = suffix | |
| 741 | |
| 742 tarname = '%s.tar.gz' % clean_name | |
| 743 | |
| 744 # Create a .tar.gz archive out of a crash folder that contains | |
| 745 # both binary and the core dump. | |
| 746 tar = tarfile.open(tarname, mode='w:gz') | |
| 747 tar.add(core, arcname=clean_name) | |
| 748 tar.close() | |
|
kustermann
2017/01/18 17:12:35
Strictly speaking, we don't need .tar.gz we just n
Vyacheslav Egorov (Google)
2017/01/18 19:57:00
Acknowledged.
| |
| 749 | |
| 750 # Remove / from absolute path to not have // in gs path. | |
| 751 gs_url = '%s%s' % (gs_prefix, tarname.lstrip('/')) | |
| 752 http_url = '%s%s' % (http_prefix, tarname.lstrip('/')) | |
|
kustermann
2017/01/18 17:12:35
How could [tarname] ever contain a '/' ?
Vyacheslav Egorov (Google)
2017/01/18 19:57:00
Now it can't - it used to use an absolute path.
| |
| 753 | |
| 754 try: | |
| 755 gsutil.upload(tarname, gs_url) | |
| 756 print '@@@STEP_LOG_LINE@coredumps@%s (%s)@@@' % (gs_url, http_url) | |
| 757 except Exception as error: | |
| 758 message = "Failed to upload coredump %s, error: %s" % (tarname, error) | |
| 759 print '@@@STEP_LOG_LINE@coredumps@%s@@@' % message | |
| 760 | |
| 761 os.unlink(tarname) | |
| 762 | |
| 763 print '@@@STEP_LOG_END@coredumps@@@' | |
| 764 MarkCurrentStepWarning() | |
| 765 | |
| 766 def _check_core_dump_pattern(self, fatal=False): | |
| 767 core_pattern_file = '/proc/sys/kernel/core_pattern' | |
| 768 core_pattern = open(core_pattern_file).read() | |
| 769 | |
| 770 expected_core_pattern = 'core.%p' | |
| 771 if core_pattern.strip() != expected_core_pattern: | |
| 772 if fatal: | |
| 773 message = ("Invalid core_pattern configuration. " | |
| 774 "The configuration of core dump handling is *not* correct for " | |
| 775 "a buildbot. The content of {0} must be '{1}' instead of '{2}'." | |
| 776 .format(core_pattern_file, expected_core_pattern, core_pattern)) | |
| 777 raise Exception(message) | |
| 778 else: | |
| 779 return False | |
| 780 return True | |
| 781 | |
| 782 def MarkCurrentStepWarning(): | |
| 783 print "@@@STEP_WARNINGS@@@" | |
| 784 sys.stdout.flush() | |
| 660 | 785 |
| 661 if __name__ == "__main__": | 786 if __name__ == "__main__": |
| 662 import sys | 787 import sys |
| 663 Main() | 788 Main() |
| OLD | NEW |