OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # |
| 3 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Wrapper that does auto-retry and stats logging for command invocation. |
| 8 |
| 9 Various command line tools in use: gsutil, curl have spurious failure. |
| 10 This wrapper will track stats to an AppEngine based service to |
| 11 help track down the cause of failures, as well as add retry logic. |
| 12 """ |
| 13 |
| 14 |
| 15 import optparse |
| 16 import os |
| 17 import subprocess |
| 18 import sys |
| 19 import time |
| 20 import urllib |
| 21 import uuid |
| 22 |
| 23 |
| 24 def LogCommand(options, command_id, |
| 25 attempt, cmd, returncode, stdout, stderr, runtime): |
| 26 """Log a command invocation and result to a central location. |
| 27 |
| 28 Arguments: |
| 29 options: parsed options |
| 30 command_id: unique id for this command (shared by all retries) |
| 31 attempt: which try numbered from 0 |
| 32 cmd: command run |
| 33 returncode: return code from running command |
| 34 stdout: text of stdout |
| 35 stderr: text of stderr |
| 36 runtime: command runtime in seconds |
| 37 """ |
| 38 uname = os.uname() |
| 39 params = urllib.urlencode({ |
| 40 'attempt': str(attempt), |
| 41 'cwd': os.getcwd(), |
| 42 'command_id': command_id, |
| 43 'command': cmd, |
| 44 'returncode': str(returncode), |
| 45 'stdout': stdout[:400], |
| 46 'stderr': stderr[:400], |
| 47 'runtime': str(runtime), |
| 48 'retries': str(options.retries), |
| 49 'uname_sysname': uname[0], |
| 50 'uname_nodename': uname[1], |
| 51 'uname_release': uname[2], |
| 52 'uname_version': uname[3], |
| 53 'uname_machine': uname[4], |
| 54 }) |
| 55 f = urllib.urlopen(options.logurl, params) |
| 56 f.read() |
| 57 f.close() |
| 58 |
| 59 |
| 60 def main(argv): |
| 61 parser = optparse.OptionParser() |
| 62 parser.add_option('-r', '--retries', dest='retries', |
| 63 type='int', default=10, |
| 64 help='number of times to retry on failure') |
| 65 parser.add_option('-u', '--logurl', dest='logurl', |
| 66 default='https://command-wrapper.appspot.com/log', |
| 67 help='URL to log invocations/failures to') |
| 68 (options, args) = parser.parse_args(args=argv[1:]) |
| 69 |
| 70 command_id = uuid.uuid1() |
| 71 cmd = ' '.join(args) |
| 72 for r in range(options.retries): |
| 73 tm = time.time() |
| 74 p = subprocess.Popen(cmd, shell=True, |
| 75 stdout=subprocess.PIPE, |
| 76 stderr=subprocess.PIPE) |
| 77 (p_stdout, p_stderr) = p.communicate() |
| 78 sys.stdout.write(p_stdout) |
| 79 sys.stderr.write(p_stderr) |
| 80 runtime = time.time() - tm |
| 81 LogCommand(options, command_id, r, cmd, |
| 82 p.returncode, p_stdout, p_stderr, runtime) |
| 83 if p.returncode == 0: |
| 84 return 0 |
| 85 print 'Command %s failed with retcode %d, try %d.' % ( |
| 86 ' '.join(args), p.returncode, r + 1) |
| 87 print 'Command %s failed %d retries, giving up.' % ( |
| 88 ' '.join(args), options.retries) |
| 89 |
| 90 return p.returncode |
| 91 |
| 92 |
| 93 if __name__ == '__main__': |
| 94 sys.exit(main(sys.argv)) |
OLD | NEW |