blob: e55acd8747a891a73d087f0a634df2ccf393a070 [file] [log] [blame]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -04001# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Upload all debug symbols required for crash reporting purposes.
6
7This script need only be used to upload release builds symbols or to debug
8crashes on non-release builds (in which case try to only upload the symbols
Mike Frysinger02e1e072013-11-10 22:11:34 -05009for those executables involved).
10"""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040011
Mike Frysingera4fa1e82014-01-15 01:45:56 -050012from __future__ import print_function
13
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040014import ctypes
Mike Frysinger8ec8c502014-02-10 00:19:13 -050015import datetime
Mike Frysingerdad2a032014-05-11 23:05:11 -040016import errno
Mike Frysinger02e92402013-11-22 16:22:02 -050017import functools
Mike Frysinger0c0efa22014-02-09 23:32:23 -050018import hashlib
Mike Frysingera4fa1e82014-01-15 01:45:56 -050019import httplib
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040020import multiprocessing
21import os
Mike Frysinger094a2172013-08-14 12:54:35 -040022import poster
Mike Frysinger66e51e92014-05-03 16:52:00 -040023try:
24 import Queue
25except ImportError:
26 # Python-3 renamed to "queue". We still use Queue to avoid collisions
27 # with naming variables as "queue". Maybe we'll transition at some point.
28 # pylint: disable=F0401
29 import queue as Queue
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040030import random
Mike Frysinger66e51e92014-05-03 16:52:00 -040031import signal
Mike Frysingerfd355652014-01-23 02:57:48 -050032import socket
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040033import textwrap
34import tempfile
35import time
Mike Frysinger094a2172013-08-14 12:54:35 -040036import urllib2
Mike Frysingerd41938e2014-02-10 06:37:55 -050037import urlparse
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040038
Don Garrett88b8d782014-05-13 17:30:55 -070039from chromite.cbuildbot import constants
Mike Frysingerd41938e2014-02-10 06:37:55 -050040from chromite.lib import cache
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040041from chromite.lib import commandline
42from chromite.lib import cros_build_lib
Mike Frysingerd41938e2014-02-10 06:37:55 -050043from chromite.lib import gs
44from chromite.lib import osutils
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040045from chromite.lib import parallel
David Jamesc93e6a4d2014-01-13 11:37:36 -080046from chromite.lib import retry_util
Mike Frysinger66e51e92014-05-03 16:52:00 -040047from chromite.lib import signals
Mike Frysinger0c0efa22014-02-09 23:32:23 -050048from chromite.lib import timeout_util
Mike Frysinger69cb41d2013-08-11 20:08:19 -040049from chromite.scripts import cros_generate_breakpad_symbols
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040050
Mike Frysinger0c0efa22014-02-09 23:32:23 -050051# Needs to be after chromite imports.
52# TODO(build): When doing the initial buildbot bootstrap, we won't have any
53# other repos available. So ignore isolateserver imports. But buildbot will
54# re-exec itself once it has done a full repo sync and then the module will
55# be available -- it isn't needed that early. http://crbug.com/341152
56try:
57 import isolateserver
58except ImportError:
59 isolateserver = None
60
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -040061
62# URLs used for uploading symbols.
63OFFICIAL_UPLOAD_URL = 'http://clients2.google.com/cr/symbol'
64STAGING_UPLOAD_URL = 'http://clients2.google.com/cr/staging_symbol'
65
66
67# The crash server rejects files that are this big.
68CRASH_SERVER_FILE_LIMIT = 350 * 1024 * 1024
69# Give ourselves a little breathing room from what the server expects.
70DEFAULT_FILE_LIMIT = CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024)
71
72
Mike Frysinger0c0efa22014-02-09 23:32:23 -050073# The batch limit when talking to the dedup server. We avoid sending one at a
74# time as the round trip overhead will dominate. Conversely, we avoid sending
75# all at once so we can start uploading symbols asap -- the symbol server is a
76# bit slow and will take longer than anything else.
77# TODO: A better algorithm would be adaptive. If we have more than one symbol
78# in the upload queue waiting, we could send more symbols to the dedupe server
79# at a time.
80DEDUPE_LIMIT = 100
81
82# How long to wait for the server to respond with the results. Note that the
83# larger the limit above, the larger this will need to be. So we give it ~1
84# second per item max.
85DEDUPE_TIMEOUT = DEDUPE_LIMIT
86
Mike Frysinger4dd462e2014-04-30 16:21:51 -040087# How long to wait for the notification to finish (in minutes). If it takes
88# longer than this, we'll stop notifiying, but that's not a big deal as we
89# will be able to recover in later runs.
90DEDUPE_NOTIFY_TIMEOUT = 20
91
Mike Frysinger0c0efa22014-02-09 23:32:23 -050092# The unique namespace in the dedupe server that only we use. Helps avoid
93# collisions with all the hashed values and unrelated content.
94OFFICIAL_DEDUPE_NAMESPACE = 'chromium-os-upload-symbols'
95STAGING_DEDUPE_NAMESPACE = '%s-staging' % OFFICIAL_DEDUPE_NAMESPACE
96
97
Mike Frysingercd78a082013-06-26 17:13:04 -040098# How long to wait (in seconds) for a single upload to complete. This has
99# to allow for symbols that are up to CRASH_SERVER_FILE_LIMIT in size.
100UPLOAD_TIMEOUT = 30 * 60
101
102
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400103# Sleep for 200ms in between uploads to avoid DoS'ing symbol server.
104DEFAULT_SLEEP_DELAY = 0.2
105
106
107# Number of seconds to wait before retrying an upload. The delay will double
108# for each subsequent retry of the same symbol file.
109INITIAL_RETRY_DELAY = 1
110
111# Allow up to 7 attempts to upload a symbol file (total delay may be
112# 1+2+4+8+16+32=63 seconds).
113MAX_RETRIES = 6
114
Mike Frysingereb753bf2013-11-22 16:05:35 -0500115# Number of total errors, before uploads are no longer attempted.
116# This is used to avoid lots of errors causing unreasonable delays.
117# See the related, but independent, error values below.
118MAX_TOTAL_ERRORS_FOR_RETRY = 30
119
120# A watermark of transient errors which we allow recovery from. If we hit
121# errors infrequently, overall we're probably doing fine. For example, if
122# we have one failure every 100 passes, then we probably don't want to fail
123# right away. But if we hit a string of failures in a row, we want to abort.
124#
125# The watermark starts at 0 (and can never go below that). When this error
126# level is exceeded, we stop uploading. When a failure happens, we add the
127# fail adjustment, and when an upload succeeds, we add the pass adjustment.
128# We want to penalize failures more so that we ramp up when there is a string
129# of them, but then slowly back off as things start working.
130#
131# A quick example:
132# 0.0: Starting point.
133# 0.0: Upload works, so add -0.5, and then clamp to 0.
134# 1.0: Upload fails, so add 1.0.
135# 2.0: Upload fails, so add 1.0.
136# 1.5: Upload works, so add -0.5.
137# 1.0: Upload works, so add -0.5.
138ERROR_WATERMARK = 3.0
139ERROR_ADJUST_FAIL = 1.0
140ERROR_ADJUST_PASS = -0.5
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400141
142
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500143def SymUpload(upload_url, sym_item):
Mike Frysinger094a2172013-08-14 12:54:35 -0400144 """Upload a symbol file to a HTTP server
145
146 The upload is a multipart/form-data POST with the following parameters:
147 code_file: the basename of the module, e.g. "app"
148 code_identifier: the module file's identifier
149 debug_file: the basename of the debugging file, e.g. "app"
150 debug_identifier: the debug file's identifier, usually consisting of
151 the guid and age embedded in the pdb, e.g.
152 "11111111BBBB3333DDDD555555555555F"
153 version: the file version of the module, e.g. "1.2.3.4"
154 product: HTTP-friendly product name
155 os: the operating system that the module was built for
156 cpu: the CPU that the module was built for
157 symbol_file: the contents of the breakpad-format symbol file
158
159 Args:
Mike Frysinger094a2172013-08-14 12:54:35 -0400160 upload_url: The crash URL to POST the |sym_file| to
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500161 sym_item: A SymbolItem containing the path to the breakpad symbol to upload
Mike Frysinger094a2172013-08-14 12:54:35 -0400162 """
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500163 sym_header = sym_item.sym_header
164 sym_file = sym_item.sym_file
Mike Frysinger094a2172013-08-14 12:54:35 -0400165
166 fields = (
167 ('code_file', sym_header.name),
168 ('debug_file', sym_header.name),
169 ('debug_identifier', sym_header.id.replace('-', '')),
Mike Frysingerb8a966b2014-03-19 17:36:18 -0400170 # The product/version fields are used by the server only for statistic
171 # purposes. They do not impact symbolization, so they're safe to set
172 # to any value all the time.
173 # In this case, we use it to help see the load our build system is
174 # placing on the server.
175 # Not sure what to set for the version. Maybe the git sha1 of this file.
176 # Note: the server restricts this to 30 chars.
Mike Frysinger094a2172013-08-14 12:54:35 -0400177 #('version', None),
Mike Frysingerb8a966b2014-03-19 17:36:18 -0400178 ('product', 'ChromeOS'),
Mike Frysinger094a2172013-08-14 12:54:35 -0400179 ('os', sym_header.os),
180 ('cpu', sym_header.cpu),
181 poster.encode.MultipartParam.from_file('symbol_file', sym_file),
182 )
183
184 data, headers = poster.encode.multipart_encode(fields)
185 request = urllib2.Request(upload_url, data, headers)
186 request.add_header('User-agent', 'chromite.upload_symbols')
187 urllib2.urlopen(request, timeout=UPLOAD_TIMEOUT)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400188
189
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500190def TestingSymUpload(upload_url, sym_item):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400191 """A stub version of SymUpload for --testing usage"""
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500192 cmd = ['sym_upload', sym_item.sym_file, upload_url]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400193 # Randomly fail 80% of the time (the retry logic makes this 80%/3 per file).
194 returncode = random.randint(1, 100) <= 80
195 cros_build_lib.Debug('would run (and return %i): %s', returncode,
Matt Tennant7feda352013-12-20 14:03:40 -0800196 cros_build_lib.CmdToStr(cmd))
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400197 if returncode:
198 output = 'Failed to send the symbol file.'
199 else:
200 output = 'Successfully sent the symbol file.'
201 result = cros_build_lib.CommandResult(cmd=cmd, error=None, output=output,
202 returncode=returncode)
203 if returncode:
Mike Frysingera4fa1e82014-01-15 01:45:56 -0500204 exceptions = (
Mike Frysingerfd355652014-01-23 02:57:48 -0500205 socket.error('[socket.error] forced test fail'),
Mike Frysingera4fa1e82014-01-15 01:45:56 -0500206 httplib.BadStatusLine('[BadStatusLine] forced test fail'),
207 urllib2.HTTPError(upload_url, 400, '[HTTPError] forced test fail',
208 {}, None),
209 urllib2.URLError('[URLError] forced test fail'),
210 )
211 raise random.choice(exceptions)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400212 else:
213 return result
214
215
Mike Frysingereb753bf2013-11-22 16:05:35 -0500216def ErrorLimitHit(num_errors, watermark_errors):
217 """See if our error limit has been hit
218
219 Args:
220 num_errors: A multiprocessing.Value of the raw number of failures.
221 watermark_errors: A multiprocessing.Value of the current rate of failures.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500222
Mike Frysingereb753bf2013-11-22 16:05:35 -0500223 Returns:
224 True if our error limits have been exceeded.
225 """
226 return ((num_errors is not None and
227 num_errors.value > MAX_TOTAL_ERRORS_FOR_RETRY) or
228 (watermark_errors is not None and
229 watermark_errors.value > ERROR_WATERMARK))
230
231
232def _UpdateCounter(counter, adj):
233 """Update |counter| by |adj|
234
235 Handle atomic updates of |counter|. Also make sure it does not
236 fall below 0.
237
238 Args:
239 counter: A multiprocessing.Value to update
240 adj: The value to add to |counter|
241 """
242 def _Update():
243 clamp = 0 if type(adj) is int else 0.0
244 counter.value = max(clamp, counter.value + adj)
245
246 if hasattr(counter, 'get_lock'):
247 with counter.get_lock():
248 _Update()
249 elif counter is not None:
250 _Update()
251
252
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500253def UploadSymbol(upload_url, sym_item, file_limit=DEFAULT_FILE_LIMIT,
Mike Frysinger02e92402013-11-22 16:22:02 -0500254 sleep=0, num_errors=None, watermark_errors=None,
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500255 failed_queue=None, passed_queue=None):
256 """Upload |sym_item| to |upload_url|
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400257
258 Args:
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400259 upload_url: The crash server to upload things to
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500260 sym_item: A SymbolItem containing the path to the breakpad symbol to upload
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400261 file_limit: The max file size of a symbol file before we try to strip it
262 sleep: Number of seconds to sleep before running
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400263 num_errors: An object to update with the error count (needs a .value member)
Mike Frysingereb753bf2013-11-22 16:05:35 -0500264 watermark_errors: An object to track current error behavior (needs a .value)
Mike Frysinger02e92402013-11-22 16:22:02 -0500265 failed_queue: When a symbol fails, add it to this queue
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500266 passed_queue: When a symbol passes, add it to this queue
Mike Frysinger1a736a82013-12-12 01:50:59 -0500267
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400268 Returns:
269 The number of errors that were encountered.
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400270 """
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500271 sym_file = sym_item.sym_file
272 upload_item = sym_item
273
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400274 if num_errors is None:
275 num_errors = ctypes.c_int()
Mike Frysingereb753bf2013-11-22 16:05:35 -0500276 if ErrorLimitHit(num_errors, watermark_errors):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400277 # Abandon ship! It's on fire! NOoooooooooooOOOoooooo.
Mike Frysinger7f9be142014-01-15 02:16:42 -0500278 if failed_queue:
279 failed_queue.put(sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400280 return 0
281
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400282 if sleep:
283 # Keeps us from DoS-ing the symbol server.
284 time.sleep(sleep)
285
286 cros_build_lib.Debug('uploading %s' % sym_file)
287
288 # Ideally there'd be a tempfile.SpooledNamedTemporaryFile that we could use.
289 with tempfile.NamedTemporaryFile(prefix='upload_symbols',
290 bufsize=0) as temp_sym_file:
291 if file_limit:
292 # If the symbols size is too big, strip out the call frame info. The CFI
293 # is unnecessary for 32bit x86 targets where the frame pointer is used (as
294 # all of ours have) and it accounts for over half the size of the symbols
295 # uploaded.
296 file_size = os.path.getsize(sym_file)
297 if file_size > file_limit:
298 cros_build_lib.Warning('stripping CFI from %s due to size %s > %s',
299 sym_file, file_size, file_limit)
300 temp_sym_file.writelines([x for x in open(sym_file, 'rb').readlines()
301 if not x.startswith('STACK CFI')])
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500302
303 upload_item = FakeItem(sym_file=temp_sym_file.name,
304 sym_header=sym_item.sym_header)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400305
306 # Hopefully the crash server will let it through. But it probably won't.
307 # Not sure what the best answer is in this case.
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500308 file_size = os.path.getsize(upload_item.sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400309 if file_size > CRASH_SERVER_FILE_LIMIT:
310 cros_build_lib.PrintBuildbotStepWarnings()
Mike Frysinger02e92402013-11-22 16:22:02 -0500311 cros_build_lib.Warning('upload file %s is awfully large, risking '
312 'rejection by the symbol server (%s > %s)',
313 sym_file, file_size, CRASH_SERVER_FILE_LIMIT)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400314
315 # Upload the symbol file.
Mike Frysingereb753bf2013-11-22 16:05:35 -0500316 success = False
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400317 try:
Mike Frysinger9adcfd22013-10-24 12:01:40 -0400318 cros_build_lib.TimedCommand(
David Jamesc93e6a4d2014-01-13 11:37:36 -0800319 retry_util.RetryException,
Mike Frysinger9adcfd22013-10-24 12:01:40 -0400320 (urllib2.HTTPError, urllib2.URLError), MAX_RETRIES, SymUpload,
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500321 upload_url, upload_item, sleep=INITIAL_RETRY_DELAY,
Mike Frysinger9adcfd22013-10-24 12:01:40 -0400322 timed_log_msg='upload of %10i bytes took %%s: %s' %
323 (file_size, os.path.basename(sym_file)))
Mike Frysingereb753bf2013-11-22 16:05:35 -0500324 success = True
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500325
326 if passed_queue:
327 passed_queue.put(sym_item)
Mike Frysinger094a2172013-08-14 12:54:35 -0400328 except urllib2.HTTPError as e:
329 cros_build_lib.Warning('could not upload: %s: HTTP %s: %s',
330 os.path.basename(sym_file), e.code, e.reason)
Mike Frysingerfd355652014-01-23 02:57:48 -0500331 except (urllib2.URLError, httplib.HTTPException, socket.error) as e:
Mike Frysingerc4ab5782013-10-02 18:14:22 -0400332 cros_build_lib.Warning('could not upload: %s: %s',
333 os.path.basename(sym_file), e)
Mike Frysingereb753bf2013-11-22 16:05:35 -0500334 finally:
335 if success:
336 _UpdateCounter(watermark_errors, ERROR_ADJUST_PASS)
337 else:
338 _UpdateCounter(num_errors, 1)
339 _UpdateCounter(watermark_errors, ERROR_ADJUST_FAIL)
Mike Frysinger02e92402013-11-22 16:22:02 -0500340 if failed_queue:
341 failed_queue.put(sym_file)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400342
343 return num_errors.value
344
345
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500346# A dummy class that allows for stubbing in tests and SymUpload.
347FakeItem = cros_build_lib.Collection(
348 'FakeItem', sym_file=None, sym_header=None, content=lambda x: '')
349
350
351# TODO(build): Delete this if check. http://crbug.com/341152
352if isolateserver:
353 class SymbolItem(isolateserver.BufferItem):
354 """Turn a sym_file into an isolateserver.Item"""
355
356 ALGO = hashlib.sha1
357
358 def __init__(self, sym_file):
359 sym_header = cros_generate_breakpad_symbols.ReadSymsHeader(sym_file)
360 super(SymbolItem, self).__init__(str(sym_header), self.ALGO)
361 self.sym_header = sym_header
362 self.sym_file = sym_file
363
364
365def SymbolDeduplicatorNotify(dedupe_namespace, dedupe_queue):
366 """Send a symbol file to the swarming service
367
368 Notify the swarming service of a successful upload. If the notification fails
369 for any reason, we ignore it. We don't care as it just means we'll upload it
370 again later on, and the symbol server will handle that graciously.
371
372 This func runs in a different process from the main one, so we cannot share
373 the storage object. Instead, we create our own. This func stays alive for
374 the life of the process, so we only create one here overall.
375
376 Args:
377 dedupe_namespace: The isolateserver namespace to dedupe uploaded symbols.
378 dedupe_queue: The queue to read SymbolItems from
379 """
380 if dedupe_queue is None:
381 return
382
383 item = None
384 try:
Mike Frysinger650e6722014-04-28 18:29:15 -0400385 with timeout_util.Timeout(DEDUPE_TIMEOUT):
386 storage = isolateserver.get_storage_api(constants.ISOLATESERVER,
387 dedupe_namespace)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500388 for item in iter(dedupe_queue.get, None):
389 with timeout_util.Timeout(DEDUPE_TIMEOUT):
Mike Frysingerefef3672014-04-20 10:06:45 -0400390 cros_build_lib.Debug('sending %s to dedupe server', item.sym_file)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500391 storage.push(item, item.content(0))
Mike Frysinger66e51e92014-05-03 16:52:00 -0400392 cros_build_lib.Debug('sent %s', item.sym_file)
Mike Frysingerae298452014-03-24 22:45:23 -0400393 cros_build_lib.Info('dedupe notification finished; exiting')
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500394 except Exception:
395 sym_file = item.sym_file if (item and item.sym_file) else ''
396 cros_build_lib.Warning('posting %s to dedupe server failed',
397 os.path.basename(sym_file), exc_info=True)
398
Mike Frysinger58312e92014-03-18 04:18:36 -0400399 # Keep draining the queue though so it doesn't fill up.
400 while dedupe_queue.get() is not None:
401 continue
402
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500403
404def SymbolDeduplicator(storage, sym_paths):
405 """Filter out symbol files that we've already uploaded
406
407 Using the swarming service, ask it to tell us which symbol files we've already
408 uploaded in previous runs and/or by other bots. If the query fails for any
409 reason, we'll just upload all symbols. This is fine as the symbol server will
410 do the right thing and this phase is purely an optimization.
411
412 This code runs in the main thread which is why we can re-use the existing
413 storage object. Saves us from having to recreate one all the time.
414
415 Args:
416 storage: An isolateserver.StorageApi object
417 sym_paths: List of symbol files to check against the dedupe server
418
419 Returns:
420 List of symbol files that have not been uploaded before
421 """
422 if not sym_paths:
423 return sym_paths
424
425 items = [SymbolItem(x) for x in sym_paths]
426 if storage:
427 try:
428 with timeout_util.Timeout(DEDUPE_TIMEOUT):
429 items = storage.contains(items)
430 except Exception:
431 cros_build_lib.Warning('talking to dedupe server failed', exc_info=True)
432
433 return items
434
435
Mike Frysingerd41938e2014-02-10 06:37:55 -0500436def IsTarball(path):
437 """Guess if this is a tarball based on the filename."""
438 parts = path.split('.')
439 if len(parts) <= 1:
440 return False
441
442 if parts[-1] == 'tar':
443 return True
444
445 if parts[-2] == 'tar':
446 return parts[-1] in ('bz2', 'gz', 'xz')
447
448 return parts[-1] in ('tbz2', 'tbz', 'tgz', 'txz')
449
450
451def SymbolFinder(tempdir, paths):
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500452 """Locate symbol files in |paths|
453
454 Args:
Mike Frysingerd41938e2014-02-10 06:37:55 -0500455 tempdir: Path to use for temporary files (caller will clean up).
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500456 paths: A list of input paths to walk. Files are returned w/out any checks.
Mike Frysingerd41938e2014-02-10 06:37:55 -0500457 Dirs are searched for files that end in ".sym". Urls are fetched and then
458 processed. Tarballs are unpacked and walked.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500459
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500460 Returns:
461 Yield every viable sym file.
462 """
463 for p in paths:
Don Garrett25f309a2014-03-19 14:02:12 -0700464 # Pylint is confused about members of ParseResult.
Don Garrettf8bf7842014-03-20 17:03:42 -0700465
Mike Frysingerd41938e2014-02-10 06:37:55 -0500466 o = urlparse.urlparse(p)
Don Garrettf8bf7842014-03-20 17:03:42 -0700467 if o.scheme: # pylint: disable=E1101
Mike Frysingerd41938e2014-02-10 06:37:55 -0500468 # Support globs of filenames.
469 ctx = gs.GSContext()
470 for p in ctx.LS(p):
471 cros_build_lib.Info('processing files inside %s', p)
472 o = urlparse.urlparse(p)
473 cache_dir = commandline.GetCacheDir()
474 common_path = os.path.join(cache_dir, constants.COMMON_CACHE)
475 tar_cache = cache.TarballCache(common_path)
Don Garrettf8bf7842014-03-20 17:03:42 -0700476 key = ('%s%s' % (o.netloc, o.path)).split('/') # pylint: disable=E1101
Mike Frysingerd41938e2014-02-10 06:37:55 -0500477 # The common cache will not be LRU, removing the need to hold a read
478 # lock on the cached gsutil.
479 ref = tar_cache.Lookup(key)
480 try:
481 ref.SetDefault(p)
482 except cros_build_lib.RunCommandError as e:
483 cros_build_lib.Warning('ignoring %s\n%s', p, e)
484 continue
485 for p in SymbolFinder(tempdir, [ref.path]):
486 yield p
487
488 elif os.path.isdir(p):
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500489 for root, _, files in os.walk(p):
490 for f in files:
491 if f.endswith('.sym'):
492 yield os.path.join(root, f)
Mike Frysingerd41938e2014-02-10 06:37:55 -0500493
494 elif IsTarball(p):
495 cros_build_lib.Info('processing files inside %s', p)
496 tardir = tempfile.mkdtemp(dir=tempdir)
497 cache.Untar(os.path.realpath(p), tardir)
498 for p in SymbolFinder(tardir, [tardir]):
499 yield p
500
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500501 else:
502 yield p
503
504
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500505def WriteQueueToFile(listing, queue, relpath=None):
506 """Write all the items in |queue| to the |listing|.
507
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500508 Note: The queue must have a sentinel None appended to the end.
509
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500510 Args:
511 listing: Where to write out the list of files.
512 queue: The queue of paths to drain.
513 relpath: If set, write out paths relative to this one.
514 """
515 if not listing:
Mike Frysingera0ddac62014-03-14 10:30:25 -0400516 # Still drain the queue so we make sure the producer has finished
517 # before we return. Otherwise, the queue might get destroyed too
518 # quickly which will trigger a traceback in the producer.
519 while queue.get() is not None:
520 continue
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500521 return
522
523 with cros_build_lib.Open(listing, 'wb+') as f:
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500524 while True:
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500525 path = queue.get()
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500526 if path is None:
527 return
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500528 if relpath:
529 path = os.path.relpath(path, relpath)
530 f.write('%s\n' % path)
531
532
Mike Frysinger38647542014-09-12 18:15:39 -0700533def UploadSymbols(board=None, official=False, server=None, breakpad_dir=None,
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400534 file_limit=DEFAULT_FILE_LIMIT, sleep=DEFAULT_SLEEP_DELAY,
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500535 upload_limit=None, sym_paths=None, failed_list=None,
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500536 root=None, retry=True, dedupe_namespace=None):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400537 """Upload all the generated symbols for |board| to the crash server
538
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400539 You can use in a few ways:
540 * pass |board| to locate all of its symbols
541 * pass |breakpad_dir| to upload all the symbols in there
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500542 * pass |sym_paths| to upload specific symbols (or dirs of symbols)
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400543
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400544 Args:
545 board: The board whose symbols we wish to upload
546 official: Use the official symbol server rather than the staging one
Mike Frysinger38647542014-09-12 18:15:39 -0700547 server: Explicit server to post symbols to
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400548 breakpad_dir: The full path to the breakpad directory where symbols live
549 file_limit: The max file size of a symbol file before we try to strip it
550 sleep: How long to sleep in between uploads
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500551 upload_limit: If set, only upload this many symbols (meant for testing)
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500552 sym_paths: Specific symbol files (or dirs of sym files) to upload,
553 otherwise search |breakpad_dir|
Mike Frysinger7f9be142014-01-15 02:16:42 -0500554 failed_list: Write the names of all sym files we did not upload; can be a
555 filename or file-like object.
Mike Frysinger118d2502013-08-19 03:36:56 -0400556 root: The tree to prefix to |breakpad_dir| (if |breakpad_dir| is not set)
Mike Frysinger02e92402013-11-22 16:22:02 -0500557 retry: Whether we should retry failures.
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500558 dedupe_namespace: The isolateserver namespace to dedupe uploaded symbols.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500559
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400560 Returns:
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400561 The number of errors that were encountered.
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400562 """
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500563 # TODO(build): Delete this assert.
564 assert isolateserver, 'Missing isolateserver import http://crbug.com/341152'
565
Mike Frysinger38647542014-09-12 18:15:39 -0700566 if server is None:
567 if official:
568 upload_url = OFFICIAL_UPLOAD_URL
569 else:
570 cros_build_lib.Warning('unofficial builds upload to the staging server')
571 upload_url = STAGING_UPLOAD_URL
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400572 else:
Mike Frysinger38647542014-09-12 18:15:39 -0700573 upload_url = server
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400574
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500575 if sym_paths:
576 cros_build_lib.Info('uploading specified symbols to %s', upload_url)
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400577 else:
578 if breakpad_dir is None:
Mike Frysinger118d2502013-08-19 03:36:56 -0400579 breakpad_dir = os.path.join(
580 root,
581 cros_generate_breakpad_symbols.FindBreakpadDir(board).lstrip('/'))
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400582 cros_build_lib.Info('uploading all symbols to %s from %s', upload_url,
583 breakpad_dir)
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500584 sym_paths = [breakpad_dir]
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400585
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500586 # We use storage_query to ask the server about existing symbols. The
587 # storage_notify_proc process is used to post updates to the server. We
588 # cannot safely share the storage object between threads/processes, but
589 # we also want to minimize creating new ones as each object has to init
590 # new state (like server connections).
Mike Frysinger650e6722014-04-28 18:29:15 -0400591 storage_query = None
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500592 if dedupe_namespace:
593 dedupe_limit = DEDUPE_LIMIT
594 dedupe_queue = multiprocessing.Queue()
Mike Frysinger650e6722014-04-28 18:29:15 -0400595 try:
596 with timeout_util.Timeout(DEDUPE_TIMEOUT):
597 storage_query = isolateserver.get_storage_api(constants.ISOLATESERVER,
598 dedupe_namespace)
599 except Exception:
600 cros_build_lib.Warning('initializing dedupe server connection failed',
601 exc_info=True)
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500602 else:
603 dedupe_limit = 1
Mike Frysinger650e6722014-04-28 18:29:15 -0400604 dedupe_queue = None
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500605 # Can't use parallel.BackgroundTaskRunner because that'll create multiple
606 # processes and we want only one the whole time (see comment above).
607 storage_notify_proc = multiprocessing.Process(
608 target=SymbolDeduplicatorNotify, args=(dedupe_namespace, dedupe_queue))
609
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400610 bg_errors = multiprocessing.Value('i')
Mike Frysingereb753bf2013-11-22 16:05:35 -0500611 watermark_errors = multiprocessing.Value('f')
Mike Frysinger02e92402013-11-22 16:22:02 -0500612 failed_queue = multiprocessing.Queue()
613 uploader = functools.partial(
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500614 UploadSymbol, upload_url, file_limit=file_limit, sleep=sleep,
615 num_errors=bg_errors, watermark_errors=watermark_errors,
616 failed_queue=failed_queue, passed_queue=dedupe_queue)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400617
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500618 start_time = datetime.datetime.now()
619 Counters = cros_build_lib.Collection(
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500620 'Counters', upload_limit=upload_limit, uploaded_count=0, deduped_count=0)
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500621 counters = Counters()
622
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500623 def _Upload(queue, counters, files):
624 if not files:
625 return
626
627 missing_count = 0
628 for item in SymbolDeduplicator(storage_query, files):
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500629 missing_count += 1
Mike Frysingerd42e5f02014-03-14 11:19:37 -0400630
631 if counters.upload_limit == 0:
632 continue
633
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500634 queue.put((item,))
635 counters.uploaded_count += 1
636 if counters.upload_limit is not None:
637 counters.upload_limit -= 1
638
639 counters.deduped_count += (len(files) - missing_count)
640
Mike Frysinger13870082014-03-14 10:41:20 -0400641 try:
Mike Frysingerd41938e2014-02-10 06:37:55 -0500642 storage_notify_proc.start()
Mike Frysinger02e92402013-11-22 16:22:02 -0500643
Mike Frysinger13870082014-03-14 10:41:20 -0400644 with osutils.TempDir(prefix='upload_symbols.') as tempdir:
645 # For the first run, we collect the symbols that failed. If the
646 # overall failure rate was low, we'll retry them on the second run.
647 for retry in (retry, False):
648 # We need to limit ourselves to one upload at a time to avoid the server
649 # kicking in DoS protection. See these bugs for more details:
650 # http://crbug.com/209442
651 # http://crbug.com/212496
652 with parallel.BackgroundTaskRunner(uploader, processes=1) as queue:
Mike Frysingerd41938e2014-02-10 06:37:55 -0500653 dedupe_list = []
Mike Frysinger13870082014-03-14 10:41:20 -0400654 for sym_file in SymbolFinder(tempdir, sym_paths):
655 dedupe_list.append(sym_file)
656 dedupe_len = len(dedupe_list)
657 if dedupe_len < dedupe_limit:
658 if (counters.upload_limit is None or
659 dedupe_len < counters.upload_limit):
660 continue
Mike Frysinger02e92402013-11-22 16:22:02 -0500661
Mike Frysinger1010a892014-03-14 11:24:17 -0400662 # We check the counter before _Upload so that we don't keep talking
663 # to the dedupe server. Otherwise, we end up sending one symbol at
664 # a time to it and that slows things down a lot.
665 if counters.upload_limit == 0:
666 break
667
Mike Frysinger13870082014-03-14 10:41:20 -0400668 _Upload(queue, counters, dedupe_list)
669 dedupe_list = []
670 _Upload(queue, counters, dedupe_list)
Mike Frysingerd41938e2014-02-10 06:37:55 -0500671
Mike Frysinger13870082014-03-14 10:41:20 -0400672 # See if we need to retry, and if we haven't failed too many times yet.
673 if not retry or ErrorLimitHit(bg_errors, watermark_errors):
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500674 break
Mike Frysinger5e6dd712014-03-07 22:21:17 -0500675
Mike Frysinger13870082014-03-14 10:41:20 -0400676 sym_paths = []
677 failed_queue.put(None)
678 while True:
679 sym_path = failed_queue.get()
680 if sym_path is None:
681 break
682 sym_paths.append(sym_path)
Mike Frysinger02e92402013-11-22 16:22:02 -0500683
Mike Frysinger13870082014-03-14 10:41:20 -0400684 if sym_paths:
685 cros_build_lib.Warning('retrying %i symbols', len(sym_paths))
686 if counters.upload_limit is not None:
687 counters.upload_limit += len(sym_paths)
688 # Decrement the error count in case we recover in the second pass.
689 assert bg_errors.value >= len(sym_paths), \
690 'more failed files than errors?'
691 bg_errors.value -= len(sym_paths)
692 else:
693 # No failed symbols, so just return now.
694 break
Mike Frysinger7f9be142014-01-15 02:16:42 -0500695
Mike Frysinger13870082014-03-14 10:41:20 -0400696 # If the user has requested it, save all the symbol files that we failed to
697 # upload to a listing file. This should help with recovery efforts later.
698 failed_queue.put(None)
699 WriteQueueToFile(failed_list, failed_queue, breakpad_dir)
700
701 finally:
Mike Frysingerae298452014-03-24 22:45:23 -0400702 cros_build_lib.Info('finished uploading; joining background process')
Mike Frysinger13870082014-03-14 10:41:20 -0400703 if dedupe_queue:
704 dedupe_queue.put(None)
Mike Frysinger4dd462e2014-04-30 16:21:51 -0400705
706 # The notification might be slow going, so give it some time to finish.
707 # We have to poll here as the process monitor is watching for output and
708 # will kill us if we go silent for too long.
709 wait_minutes = DEDUPE_NOTIFY_TIMEOUT
710 while storage_notify_proc.is_alive() and wait_minutes > 0:
Aviv Keshetd1f04632014-05-09 11:33:46 -0700711 if dedupe_queue:
712 qsize = str(dedupe_queue.qsize())
713 else:
714 qsize = '[None]'
715 cros_build_lib.Info('waiting up to %i minutes for ~%s notifications',
716 wait_minutes, qsize)
Mike Frysinger4dd462e2014-04-30 16:21:51 -0400717 storage_notify_proc.join(60)
718 wait_minutes -= 1
719
720 # The process is taking too long, so kill it and complain.
721 if storage_notify_proc.is_alive():
Mike Frysinger4dd462e2014-04-30 16:21:51 -0400722 cros_build_lib.Warning('notification process took too long')
723 cros_build_lib.PrintBuildbotStepWarnings()
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500724
Mike Frysinger66e51e92014-05-03 16:52:00 -0400725 # Kill it gracefully first (traceback) before tacking it down harder.
726 pid = storage_notify_proc.pid
727 for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGKILL):
728 cros_build_lib.Warning('sending %s to %i', signals.StrSignal(sig), pid)
Mike Frysingerdad2a032014-05-11 23:05:11 -0400729 # The process might have exited between the last check and the
730 # actual kill below, so ignore ESRCH errors.
731 try:
732 os.kill(pid, sig)
733 except OSError as e:
734 if e.errno == errno.ESRCH:
735 break
736 else:
737 raise
Mike Frysinger66e51e92014-05-03 16:52:00 -0400738 time.sleep(5)
Mike Frysingerdad2a032014-05-11 23:05:11 -0400739 if not storage_notify_proc.is_alive():
Mike Frysinger66e51e92014-05-03 16:52:00 -0400740 break
741
742 # Drain the queue so we don't hang when we finish.
743 try:
Mike Frysinger4f5ea832014-05-12 00:54:28 -0400744 cros_build_lib.Warning('draining the notify queue manually')
745 with timeout_util.Timeout(60):
746 try:
747 while dedupe_queue.get_nowait():
748 pass
749 except Queue.Empty:
750 pass
751 except timeout_util.TimeoutError:
752 cros_build_lib.Warning('draining the notify queue failed; trashing it')
753 dedupe_queue.cancel_join_thread()
Mike Frysinger66e51e92014-05-03 16:52:00 -0400754
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500755 cros_build_lib.Info('uploaded %i symbols (%i were deduped) which took: %s',
756 counters.uploaded_count, counters.deduped_count,
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500757 datetime.datetime.now() - start_time)
758
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500759 return bg_errors.value
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400760
761
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400762def main(argv):
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500763 # TODO(build): Delete this assert.
764 assert isolateserver, 'Missing isolateserver import http://crbug.com/341152'
765
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400766 parser = commandline.ArgumentParser(description=__doc__)
767
Mike Frysingerd41938e2014-02-10 06:37:55 -0500768 parser.add_argument('sym_paths', type='path_or_uri', nargs='*', default=None,
769 help='symbol file or directory or URL or tarball')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400770 parser.add_argument('--board', default=None,
771 help='board to build packages for')
772 parser.add_argument('--breakpad_root', type='path', default=None,
773 help='root directory for breakpad symbols')
774 parser.add_argument('--official_build', action='store_true', default=False,
775 help='point to official symbol server')
Mike Frysinger38647542014-09-12 18:15:39 -0700776 parser.add_argument('--server', type=str, default=None,
777 help='URI for custom symbol server')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400778 parser.add_argument('--regenerate', action='store_true', default=False,
779 help='regenerate all symbols')
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500780 parser.add_argument('--upload-limit', type=int, default=None,
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400781 help='only upload # number of symbols')
782 parser.add_argument('--strip_cfi', type=int,
783 default=CRASH_SERVER_FILE_LIMIT - (10 * 1024 * 1024),
784 help='strip CFI data for files above this size')
Mike Frysinger7f9be142014-01-15 02:16:42 -0500785 parser.add_argument('--failed-list', type='path',
786 help='where to save a list of failed symbols')
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500787 parser.add_argument('--dedupe', action='store_true', default=False,
788 help='use the swarming service to avoid re-uploading')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400789 parser.add_argument('--testing', action='store_true', default=False,
790 help='run in testing mode')
791 parser.add_argument('--yes', action='store_true', default=False,
792 help='answer yes to all prompts')
793
794 opts = parser.parse_args(argv)
Mike Frysinger90e49ca2014-01-14 14:42:07 -0500795 opts.Freeze()
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400796
Mike Frysinger9b2ff5c2013-11-22 10:01:12 -0500797 if opts.sym_paths:
Mike Frysinger9dcf9ae2013-08-10 15:17:09 -0400798 if opts.regenerate:
799 cros_build_lib.Die('--regenerate may not be used with specific files')
800 else:
801 if opts.board is None:
802 cros_build_lib.Die('--board is required')
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400803
804 if opts.breakpad_root and opts.regenerate:
805 cros_build_lib.Die('--regenerate may not be used with --breakpad_root')
806
807 if opts.testing:
808 # TODO(build): Kill off --testing mode once unittests are up-to-snuff.
809 cros_build_lib.Info('running in testing mode')
810 # pylint: disable=W0601,W0603
811 global INITIAL_RETRY_DELAY, SymUpload, DEFAULT_SLEEP_DELAY
812 INITIAL_RETRY_DELAY = DEFAULT_SLEEP_DELAY = 0
813 SymUpload = TestingSymUpload
814
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500815 dedupe_namespace = None
816 if opts.dedupe:
817 if opts.official_build and not opts.testing:
818 dedupe_namespace = OFFICIAL_DEDUPE_NAMESPACE
819 else:
820 dedupe_namespace = STAGING_DEDUPE_NAMESPACE
821
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400822 if not opts.yes:
Mike Frysingerc5de9602014-02-09 02:42:36 -0500823 prolog = '\n'.join(textwrap.wrap(textwrap.dedent("""
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400824 Uploading symbols for an entire Chromium OS build is really only
825 necessary for release builds and in a few cases for developers
826 to debug problems. It will take considerable time to run. For
827 developer debugging purposes, consider instead passing specific
828 files to upload.
Mike Frysingerc5de9602014-02-09 02:42:36 -0500829 """), 80)).strip()
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400830 if not cros_build_lib.BooleanPrompt(
831 prompt='Are you sure you want to upload all build symbols',
Mike Frysingerc5de9602014-02-09 02:42:36 -0500832 default=False, prolog=prolog):
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400833 cros_build_lib.Die('better safe than sorry')
834
835 ret = 0
836 if opts.regenerate:
Mike Frysinger69cb41d2013-08-11 20:08:19 -0400837 ret += cros_generate_breakpad_symbols.GenerateBreakpadSymbols(
838 opts.board, breakpad_dir=opts.breakpad_root)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400839
840 ret += UploadSymbols(opts.board, official=opts.official_build,
Mike Frysinger38647542014-09-12 18:15:39 -0700841 server=opts.server, breakpad_dir=opts.breakpad_root,
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400842 file_limit=opts.strip_cfi, sleep=DEFAULT_SLEEP_DELAY,
Mike Frysinger8ec8c502014-02-10 00:19:13 -0500843 upload_limit=opts.upload_limit, sym_paths=opts.sym_paths,
Mike Frysinger0c0efa22014-02-09 23:32:23 -0500844 failed_list=opts.failed_list,
845 dedupe_namespace=dedupe_namespace)
Mike Frysingerd5fcb3a2013-05-30 21:10:50 -0400846 if ret:
847 cros_build_lib.Error('encountered %i problem(s)', ret)
848 # Since exit(status) gets masked, clamp it to 1 so we don't inadvertently
849 # return 0 in case we are a multiple of the mask.
850 ret = 1
851
852 return ret
Mike Frysinger094a2172013-08-14 12:54:35 -0400853
854
855# We need this to run once per process. Do it at module import time as that
856# will let us avoid doing it inline at function call time (see SymUpload) as
857# that func might be called by the multiprocessing module which means we'll
858# do the opener logic multiple times overall. Plus, if you're importing this
859# module, it's a pretty good chance that you're going to need this.
860poster.streaminghttp.register_openers()