Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed by the Apache v2.0 license that can be | 2 # Use of this source code is governed by the Apache v2.0 license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Runs a Swarming task. | 5 """Runs a Swarming task. |
| 6 | 6 |
| 7 Downloads all the necessary files to run the task, executes the command and | 7 Downloads all the necessary files to run the task, executes the command and |
| 8 streams results back to the Swarming server. | 8 streams results back to the Swarming server. |
| 9 | 9 |
| 10 The process exit code is 0 when the task was executed, even if the task itself | 10 The process exit code is 0 when the task was executed, even if the task itself |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 """Returns the path to itself to run run_isolated. | 73 """Returns the path to itself to run run_isolated. |
| 74 | 74 |
| 75 Mocked in test to point to the real run_isolated.py script. | 75 Mocked in test to point to the real run_isolated.py script. |
| 76 """ | 76 """ |
| 77 return [sys.executable, THIS_FILE, 'run_isolated'] | 77 return [sys.executable, THIS_FILE, 'run_isolated'] |
| 78 | 78 |
| 79 | 79 |
| 80 def get_isolated_cmd( | 80 def get_isolated_cmd( |
| 81 work_dir, task_details, isolated_result, min_free_space): | 81 work_dir, task_details, isolated_result, min_free_space): |
| 82 """Returns the command to call run_isolated. Mocked in tests.""" | 82 """Returns the command to call run_isolated. Mocked in tests.""" |
| 83 assert (bool(task_details.command) != | |
| 84 bool(task_details.isolated and task_details.isolated.get('input'))) | |
| 83 bot_dir = os.path.dirname(work_dir) | 85 bot_dir = os.path.dirname(work_dir) |
| 84 if os.path.isfile(isolated_result): | 86 if os.path.isfile(isolated_result): |
| 85 os.remove(isolated_result) | 87 os.remove(isolated_result) |
| 86 cmd = get_run_isolated() | 88 cmd = get_run_isolated() |
| 89 | |
| 90 if task_details.isolated: # Almost certainly True. | |
|
M-A Ruel
2016/05/11 14:41:41
I don't think the command is useful.
nodir
2016/05/11 16:04:29
Done.
| |
| 91 cmd.extend( | |
| 92 [ | |
| 93 '-I', task_details.isolated['server'].encode('utf-8'), | |
| 94 '--namespace', task_details.isolated['namespace'].encode('utf-8'), | |
| 95 ]) | |
| 96 isolated_input = task_details.isolated.get('input') | |
| 97 if isolated_input: | |
| 98 cmd.extend( | |
| 99 [ | |
| 100 '--isolated', isolated_input, | |
| 101 ]) | |
| 102 | |
| 87 cmd.extend( | 103 cmd.extend( |
| 88 [ | 104 [ |
| 89 '--isolated', task_details.inputs_ref['isolated'].encode('utf-8'), | |
| 90 '--namespace', task_details.inputs_ref['namespace'].encode('utf-8'), | |
| 91 '-I', task_details.inputs_ref['isolatedserver'].encode('utf-8'), | |
| 92 '--json', isolated_result, | 105 '--json', isolated_result, |
| 93 '--log-file', os.path.join(bot_dir, 'logs', 'run_isolated.log'), | 106 '--log-file', os.path.join(bot_dir, 'logs', 'run_isolated.log'), |
| 94 '--cache', os.path.join(bot_dir, 'cache'), | 107 '--cache', os.path.join(bot_dir, 'cache'), |
| 95 '--root-dir', os.path.join(work_dir, 'isolated'), | 108 '--root-dir', os.path.join(work_dir, 'isolated'), |
| 96 ]) | 109 ]) |
| 97 if min_free_space: | 110 if min_free_space: |
| 98 cmd.extend(('--min-free-space', str(min_free_space))) | 111 cmd.extend(('--min-free-space', str(min_free_space))) |
| 99 | 112 |
| 100 if task_details.hard_timeout: | 113 if task_details.hard_timeout: |
| 101 cmd.extend(('--hard-timeout', str(task_details.hard_timeout))) | 114 cmd.extend(('--hard-timeout', str(task_details.hard_timeout))) |
| 102 if task_details.grace_period: | 115 if task_details.grace_period: |
| 103 cmd.extend(('--grace-period', str(task_details.grace_period))) | 116 cmd.extend(('--grace-period', str(task_details.grace_period))) |
| 104 if task_details.extra_args: | 117 if task_details.extra_args: |
| 105 cmd.append('--') | 118 cmd.append('--') |
| 106 cmd.extend(task_details.extra_args) | 119 cmd.extend(task_details.extra_args) |
| 107 return cmd | 120 return cmd |
| 108 | 121 |
| 109 | 122 |
| 110 class TaskDetails(object): | 123 class TaskDetails(object): |
| 111 def __init__(self, data): | 124 def __init__(self, data): |
| 112 """Loads the raw data. | 125 """Loads the raw data from a manifest file specified by --in-file.""" |
| 113 | |
| 114 It is expected to have at least: | |
| 115 - bot_id | |
| 116 - command as a list of str | |
| 117 - data as a list of urls | |
| 118 - env as a dict | |
| 119 - hard_timeout | |
| 120 - io_timeout | |
| 121 - task_id | |
| 122 """ | |
| 123 logging.info('TaskDetails(%s)', data) | 126 logging.info('TaskDetails(%s)', data) |
| 124 if not isinstance(data, dict): | 127 if not isinstance(data, dict): |
| 125 raise ValueError('Expected dict, got %r' % data) | 128 raise ValueError('Expected dict, got %r' % data) |
| 126 | 129 |
| 127 # Get all the data first so it fails early if the task details is invalid. | 130 # Get all the data first so it fails early if the task details is invalid. |
| 128 self.bot_id = data['bot_id'] | 131 self.bot_id = data['bot_id'] |
| 129 | 132 |
| 130 # Raw command. Only self.command or self.inputs_ref can be set. | 133 # Raw command. Only self.command or self.isolated.input can be set. |
| 131 self.command = data['command'] or [] | 134 self.command = data['command'] or [] |
| 132 | 135 |
| 133 # Isolated command. Is a serialized version of task_request.FilesRef. | 136 # Isolated command. Is a serialized version of task_request.FilesRef. |
| 134 self.inputs_ref = data['inputs_ref'] | 137 self.isolated = data['isolated'] |
| 135 self.extra_args = data['extra_args'] | 138 self.extra_args = data['extra_args'] |
| 136 | 139 |
| 137 self.env = { | 140 self.env = { |
| 138 k.encode('utf-8'): v.encode('utf-8') for k, v in data['env'].iteritems() | 141 k.encode('utf-8'): v.encode('utf-8') for k, v in data['env'].iteritems() |
| 139 } | 142 } |
| 140 self.grace_period = data['grace_period'] | 143 self.grace_period = data['grace_period'] |
| 141 self.hard_timeout = data['hard_timeout'] | 144 self.hard_timeout = data['hard_timeout'] |
| 142 self.io_timeout = data['io_timeout'] | 145 self.io_timeout = data['io_timeout'] |
| 143 self.task_id = data['task_id'] | 146 self.task_id = data['task_id'] |
| 144 | 147 |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 if task_details.env: | 322 if task_details.env: |
| 320 env = os.environ.copy() | 323 env = os.environ.copy() |
| 321 for key, value in task_details.env.iteritems(): | 324 for key, value in task_details.env.iteritems(): |
| 322 if not value: | 325 if not value: |
| 323 env.pop(key, None) | 326 env.pop(key, None) |
| 324 else: | 327 else: |
| 325 env[key] = value | 328 env[key] = value |
| 326 logging.info('cmd=%s', cmd) | 329 logging.info('cmd=%s', cmd) |
| 327 logging.info('env=%s', env) | 330 logging.info('env=%s', env) |
| 328 try: | 331 try: |
| 332 assert cmd and all(isinstance(a, basestring) for a in cmd) | |
| 329 proc = subprocess42.Popen( | 333 proc = subprocess42.Popen( |
| 330 cmd, | 334 cmd, |
| 331 env=env, | 335 env=env, |
| 332 cwd=work_dir, | 336 cwd=work_dir, |
| 333 detached=True, | 337 detached=True, |
| 334 stdout=subprocess42.PIPE, | 338 stdout=subprocess42.PIPE, |
| 335 stderr=subprocess42.STDOUT, | 339 stderr=subprocess42.STDOUT, |
| 336 stdin=subprocess42.PIPE) | 340 stdin=subprocess42.PIPE) |
| 337 except OSError as e: | 341 except OSError as e: |
| 338 stdout = 'Command "%s" failed to start.\nError: %s' % (' '.join(cmd), e) | 342 stdout = 'Command "%s" failed to start.\nError: %s' % (' '.join(cmd), e) |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 if options.start > now: | 530 if options.start > now: |
| 527 options.start = now | 531 options.start = now |
| 528 | 532 |
| 529 try: | 533 try: |
| 530 load_and_run( | 534 load_and_run( |
| 531 options.in_file, options.swarming_server, options.cost_usd_hour, | 535 options.in_file, options.swarming_server, options.cost_usd_hour, |
| 532 options.start, options.out_file, options.min_free_space) | 536 options.start, options.out_file, options.min_free_space) |
| 533 return 0 | 537 return 0 |
| 534 finally: | 538 finally: |
| 535 logging.info('quitting') | 539 logging.info('quitting') |
| OLD | NEW |