| 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 contextlib | 9 import contextlib |
| 10 import datetime | 10 import datetime |
| (...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 os.chdir(self._old_cwd) | 693 os.chdir(self._old_cwd) |
| 694 | 694 |
| 695 | 695 |
| 696 class UnexpectedCrash(object): | 696 class UnexpectedCrash(object): |
| 697 def __init__(self, test, pid, binary): | 697 def __init__(self, test, pid, binary): |
| 698 self.test = test | 698 self.test = test |
| 699 self.pid = pid | 699 self.pid = pid |
| 700 self.binary = binary | 700 self.binary = binary |
| 701 | 701 |
| 702 def __str__(self): | 702 def __str__(self): |
| 703 return "%s: %s %s" % (self.test, self.binary, self.pid) | 703 return "Crash(%s: %s %s)" % (self.test, self.binary, self.pid) |
| 704 | 704 |
| 705 class SiteConfigBotoFileDisabler(object): | 705 class SiteConfigBotoFileDisabler(object): |
| 706 def __init__(self): | 706 def __init__(self): |
| 707 self._old_aws = None | 707 self._old_aws = None |
| 708 self._old_boto = None | 708 self._old_boto = None |
| 709 | 709 |
| 710 def __enter__(self): | 710 def __enter__(self): |
| 711 self._old_aws = os.environ.get('AWS_CREDENTIAL_FILE', None) | 711 self._old_aws = os.environ.get('AWS_CREDENTIAL_FILE', None) |
| 712 self._old_boto = os.environ.get('BOTO_CONFIG', None) | 712 self._old_boto = os.environ.get('BOTO_CONFIG', None) |
| 713 | 713 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 | 824 |
| 825 class BaseCoreDumpArchiver(object): | 825 class BaseCoreDumpArchiver(object): |
| 826 """This class reads coredumps file written by UnexpectedCrashDumpArchiver | 826 """This class reads coredumps file written by UnexpectedCrashDumpArchiver |
| 827 into the current working directory and uploads all cores and binaries | 827 into the current working directory and uploads all cores and binaries |
| 828 listed in it into Cloud Storage (see tools/testing/dart/test_progress.dart). | 828 listed in it into Cloud Storage (see tools/testing/dart/test_progress.dart). |
| 829 """ | 829 """ |
| 830 | 830 |
| 831 # test.dart will write a line for each unexpected crash into this file. | 831 # test.dart will write a line for each unexpected crash into this file. |
| 832 _UNEXPECTED_CRASHES_FILE = "unexpected-crashes" | 832 _UNEXPECTED_CRASHES_FILE = "unexpected-crashes" |
| 833 | 833 |
| 834 def __init__(self): | 834 def __init__(self, search_dir): |
| 835 self._bucket = 'dart-temp-crash-archive' | 835 self._bucket = 'dart-temp-crash-archive' |
| 836 self._binaries_dir = os.getcwd() | 836 self._binaries_dir = os.getcwd() |
| 837 self._search_dir = search_dir |
| 837 | 838 |
| 838 def __enter__(self): | 839 def __enter__(self): |
| 839 # Cleanup any stale files | 840 # Cleanup any stale files |
| 840 if self._cleanup(): | 841 if self._cleanup(): |
| 841 print "WARNING: Found and removed stale coredumps" | 842 print "WARNING: Found and removed stale coredumps" |
| 842 | 843 |
| 843 def __exit__(self, *_): | 844 def __exit__(self, *_): |
| 844 try: | 845 try: |
| 845 crashes = self._find_unexpected_crashes() | 846 crashes = self._find_unexpected_crashes() |
| 846 if crashes: | 847 if crashes: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 864 files = set() | 865 files = set() |
| 865 missing = [] | 866 missing = [] |
| 866 for crash in crashes: | 867 for crash in crashes: |
| 867 files.add(crash.binary) | 868 files.add(crash.binary) |
| 868 core = self._find_coredump_file(crash) | 869 core = self._find_coredump_file(crash) |
| 869 if core: | 870 if core: |
| 870 files.add(core) | 871 files.add(core) |
| 871 else: | 872 else: |
| 872 missing.append(crash) | 873 missing.append(crash) |
| 873 self._upload(files) | 874 self._upload(files) |
| 875 |
| 874 if missing: | 876 if missing: |
| 875 raise Exception('Missing crash dumps for: %s' % ', '.join( | 877 self._report_missing_crashes(missing, throw=True) |
| 876 [str(c) for c in missing])) | 878 |
| 879 def _report_missing_crashes(self, missing, throw=True): |
| 880 missing_as_string = ', '.join([str(c) for c in missing]) |
| 881 other_files = list(glob.glob(os.path.join(self._search_dir, '*'))) |
| 882 print >> sys.stderr, ( |
| 883 "Could not find crash dumps for '%s' in search directory '%s'.\n" |
| 884 "Existing files which *did not* match the pattern inside the search " |
| 885 "directory are are:\n %s" |
| 886 % (missing_as_string, self._search_dir, '\n '.join(other_files))) |
| 887 if throw: |
| 888 raise Exception('Missing crash dumps for: %s' % missing_as_string) |
| 877 | 889 |
| 878 def _upload(self, files): | 890 def _upload(self, files): |
| 879 bot_utils = GetBotUtils() | 891 bot_utils = GetBotUtils() |
| 880 gsutil = bot_utils.GSUtil() | 892 gsutil = bot_utils.GSUtil() |
| 881 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4()) | 893 storage_path = '%s/%s/' % (self._bucket, uuid.uuid4()) |
| 882 gs_prefix = 'gs://%s' % storage_path | 894 gs_prefix = 'gs://%s' % storage_path |
| 883 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path | 895 http_prefix = 'https://storage.cloud.google.com/%s' % storage_path |
| 884 | 896 |
| 885 print '\n--- Uploading into %s (%s) ---' % (gs_prefix, http_prefix) | 897 print '\n--- Uploading into %s (%s) ---' % (gs_prefix, http_prefix) |
| 886 for file in files: | 898 for file in files: |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 if os.path.exists(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE): | 939 if os.path.exists(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE): |
| 928 os.unlink(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE) | 940 os.unlink(BaseCoreDumpArchiver._UNEXPECTED_CRASHES_FILE) |
| 929 found = True | 941 found = True |
| 930 for binary in glob.glob(os.path.join(self._binaries_dir, 'binary.*')): | 942 for binary in glob.glob(os.path.join(self._binaries_dir, 'binary.*')): |
| 931 found = True | 943 found = True |
| 932 os.unlink(binary) | 944 os.unlink(binary) |
| 933 return found | 945 return found |
| 934 | 946 |
| 935 class LinuxCoreDumpArchiver(BaseCoreDumpArchiver): | 947 class LinuxCoreDumpArchiver(BaseCoreDumpArchiver): |
| 936 def __init__(self): | 948 def __init__(self): |
| 937 super(self.__class__, self).__init__() | 949 super(self.__class__, self).__init__(os.getcwd()) |
| 938 self._search_dir = os.getcwd() | |
| 939 | 950 |
| 940 def _cleanup(self): | 951 def _cleanup(self): |
| 941 found = super(self.__class__, self)._cleanup() | 952 found = super(self.__class__, self)._cleanup() |
| 942 for core in glob.glob(os.path.join(self._search_dir, 'core.*')): | 953 for core in glob.glob(os.path.join(self._search_dir, 'core.*')): |
| 943 found = True | 954 found = True |
| 944 os.unlink(core) | 955 os.unlink(core) |
| 945 return found | 956 return found |
| 946 | 957 |
| 947 def _find_coredump_file(self, crash): | 958 def _find_coredump_file(self, crash): |
| 948 core_filename = os.path.join(self._search_dir, 'core.%s' % crash.pid) | 959 core_filename = os.path.join(self._search_dir, 'core.%s' % crash.pid) |
| 949 if os.path.exists(core_filename): | 960 if os.path.exists(core_filename): |
| 950 return core_filename | 961 return core_filename |
| 951 | 962 |
| 952 class WindowsCoreDumpArchiver(BaseCoreDumpArchiver): | 963 class WindowsCoreDumpArchiver(BaseCoreDumpArchiver): |
| 953 def __init__(self): | 964 def __init__(self): |
| 954 super(self.__class__, self).__init__() | 965 super(self.__class__, self).__init__(os.path.join( |
| 955 self._search_dir = os.path.join( | 966 os.getcwd(), WindowsCoredumpEnabler.WINDOWS_COREDUMP_FOLDER)) |
| 956 os.getcwd(), WindowsCoredumpEnabler.WINDOWS_COREDUMP_FOLDER) | |
| 957 | 967 |
| 958 def _cleanup(self): | 968 def _cleanup(self): |
| 959 found = super(self.__class__, self)._cleanup() | 969 found = super(self.__class__, self)._cleanup() |
| 960 for core in glob.glob(os.path.join(self._search_dir, '*')): | 970 for core in glob.glob(os.path.join(self._search_dir, '*')): |
| 961 found = True | 971 found = True |
| 962 os.unlink(core) | 972 os.unlink(core) |
| 963 return found | 973 return found |
| 964 | 974 |
| 965 def _find_coredump_file(self, crash): | 975 def _find_coredump_file(self, crash): |
| 966 pattern = os.path.join(self._search_dir, '*.%s.*' % crash.pid) | 976 pattern = os.path.join(self._search_dir, '*.%s.*' % crash.pid) |
| 967 for core_filename in glob.glob(pattern): | 977 for core_filename in glob.glob(pattern): |
| 968 return core_filename | 978 return core_filename |
| 969 | 979 |
| 980 def _report_missing_crashes(self, missing, throw=True): |
| 981 # Let's only print the debugging information and not throw. We'll do more |
| 982 # validation for werfault.exe and throw afterwards. |
| 983 super(self.__class__, self)._report_missing_crashes(missing, throw=False) |
| 984 |
| 985 # Let's check again for the image execution options for werfault. Maybe |
| 986 # puppet came a long during testing and reverted our change. |
| 987 try: |
| 988 import winreg |
| 989 except ImportError: |
| 990 import _winreg as winreg |
| 991 for wowbit in [winreg.KEY_WOW64_64KEY, winreg.KEY_WOW64_32KEY]: |
| 992 try: |
| 993 with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, |
| 994 WindowsCoredumpEnabler.IMGEXEC_NAME, |
| 995 0, |
| 996 winreg.KEY_READ | wowbit) as handle: |
| 997 raise Exception( |
| 998 "Found werfault.exe was disabled. Probably by puppet. Too bad") |
| 999 except OSError: |
| 1000 # If the open did not work the werfault.exe execution setting is as it |
| 1001 # should be. |
| 1002 pass |
| 1003 |
| 1004 if throw: |
| 1005 missing_as_string = ', '.join([str(c) for c in missing]) |
| 1006 raise Exception('Missing crash dumps for: %s' % missing_as_string) |
| 1007 |
| 970 @contextlib.contextmanager | 1008 @contextlib.contextmanager |
| 971 def NooptCoreDumpArchiver(): | 1009 def NooptCoreDumpArchiver(): |
| 972 yield | 1010 yield |
| 973 | 1011 |
| 974 | 1012 |
| 975 def CoreDumpArchiver(args): | 1013 def CoreDumpArchiver(args): |
| 976 enabled = '--copy-coredumps' in args | 1014 enabled = '--copy-coredumps' in args |
| 977 | 1015 |
| 978 if not enabled: | 1016 if not enabled: |
| 979 return NooptCoreDumpArchiver() | 1017 return NooptCoreDumpArchiver() |
| 980 | 1018 |
| 981 osname = GuessOS() | 1019 osname = GuessOS() |
| 982 if osname == 'linux': | 1020 if osname == 'linux': |
| 983 return contextlib.nested(PosixCoredumpEnabler(), | 1021 return contextlib.nested(PosixCoredumpEnabler(), |
| 984 LinuxCoreDumpArchiver()) | 1022 LinuxCoreDumpArchiver()) |
| 985 elif osname == 'win32': | 1023 elif osname == 'win32': |
| 986 return contextlib.nested(WindowsCoredumpEnabler(), | 1024 return contextlib.nested(WindowsCoredumpEnabler(), |
| 987 WindowsCoreDumpArchiver()) | 1025 WindowsCoreDumpArchiver()) |
| 988 else: | 1026 else: |
| 989 # We don't have support for MacOS yet. | 1027 # We don't have support for MacOS yet. |
| 990 assert osname == 'macos' | 1028 assert osname == 'macos' |
| 991 return NooptCoreDumpArchiver() | 1029 return NooptCoreDumpArchiver() |
| 992 | 1030 |
| 993 if __name__ == "__main__": | 1031 if __name__ == "__main__": |
| 994 import sys | 1032 import sys |
| 995 Main() | 1033 Main() |
| OLD | NEW |