Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: scripts/slave/annotated_run.py

Issue 1879173003: annotated_run: extract robust_tempdir so it can be shared with kitchen_run (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: review Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | scripts/slave/robust_tempdir.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import argparse 6 import argparse
7 import collections 7 import collections
8 import contextlib 8 import contextlib
9 import json 9 import json
10 import logging 10 import logging
11 import os 11 import os
12 import shutil 12 import shutil
13 import socket 13 import socket
14 import subprocess 14 import subprocess
15 import sys 15 import sys
16 import tempfile 16 import tempfile
17 17
18 18
19 # Install Infra build environment. 19 # Install Infra build environment.
20 BUILD_ROOT = os.path.dirname(os.path.dirname(os.path.dirname( 20 BUILD_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(
21 os.path.abspath(__file__)))) 21 os.path.abspath(__file__))))
22 sys.path.insert(0, os.path.join(BUILD_ROOT, 'scripts')) 22 sys.path.insert(0, os.path.join(BUILD_ROOT, 'scripts'))
23 23
24 from common import annotator 24 from common import annotator
25 from common import chromium_utils 25 from common import chromium_utils
26 from common import env 26 from common import env
27 from common import master_cfg_utils 27 from common import master_cfg_utils
28 from slave import gce 28 from slave import gce
29 from slave import infra_platform 29 from slave import infra_platform
30 from slave import robust_tempdir
30 from slave import update_scripts 31 from slave import update_scripts
31 32
32 # Logging instance. 33 # Logging instance.
33 LOGGER = logging.getLogger('annotated_run') 34 LOGGER = logging.getLogger('annotated_run')
34 35
35 # Return codes used by Butler/Annotee to indicate their failure (as opposed to 36 # Return codes used by Butler/Annotee to indicate their failure (as opposed to
36 # a forwarded return code from the underlying process). 37 # a forwarded return code from the underlying process).
37 LOGDOG_ERROR_RETURNCODES = ( 38 LOGDOG_ERROR_RETURNCODES = (
38 # Butler runtime error. 39 # Butler runtime error.
39 250, 40 250,
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 # the recipe engine. 166 # the recipe engine.
166 Config = collections.namedtuple('Config', ( 167 Config = collections.namedtuple('Config', (
167 'run_cmd', 168 'run_cmd',
168 'logdog_host', 169 'logdog_host',
169 'logdog_pubsub_topic', 170 'logdog_pubsub_topic',
170 'logdog_max_buffer_age', 171 'logdog_max_buffer_age',
171 'logdog_platform', 172 'logdog_platform',
172 )) 173 ))
173 174
174 175
175 class Runtime(object):
176 """Runtime is the runtime context of the recipe execution.
177
178 It is a ContextManager that tracks generated files and cleans them up at
179 exit.
180 """
181
182 def __init__(self, leak=False):
183 self._tempdirs = []
184 self._leak = leak
185
186 def cleanup(self, path):
187 self._tempdirs.append(path)
188
189 def tempdir(self, base=None):
190 """Creates a temporary recipe-local working directory and yields it.
191
192 This creates a temporary directory for this annotation run. Directory
193 cleanup is appended to the supplied Runtime.
194
195 This creates two levels of directory:
196 <base>/.recipe_runtime
197 <base>/.recipe_runtime/tmpFOO
198
199 On termination, the entire "<base>/.recipe_runtime" directory is deleted,
200 removing the subdirectory created by this instance as well as cleaning up
201 any other temporary subdirectories leaked by previous executions.
202
203 Args:
204 rt (Runtime): Process-wide runtime.
205 base (str/None): The directory under which the tempdir should be created.
206 If None, the default temporary directory root will be used.
207 """
208 base = base or tempfile.gettempdir()
209 basedir = ensure_directory(base, '.recipe_runtime')
210 self.cleanup(basedir)
211 tdir = tempfile.mkdtemp(dir=basedir)
212 return tdir
213
214 def __enter__(self):
215 return self
216
217 def __exit__(self, _et, _ev, _tb):
218 self.close()
219
220 def close(self):
221 if self._leak:
222 LOGGER.warning('(--leak) Leaking temporary paths: %s', self._tempdirs)
223 else:
224 for path in reversed(self._tempdirs):
225 try:
226 if os.path.isdir(path):
227 LOGGER.debug('Cleaning up temporary directory [%s].', path)
228 chromium_utils.RemoveDirectory(path)
229 except BaseException:
230 LOGGER.exception('Failed to clean up temporary directory [%s].',
231 path)
232 del(self._tempdirs[:])
233
234
235 def get_config(): 176 def get_config():
236 """Returns (Config): The constructed Config object. 177 """Returns (Config): The constructed Config object.
237 178
238 The Config object is constructed by cascading the PLATFORM_CONFIG fields 179 The Config object is constructed by cascading the PLATFORM_CONFIG fields
239 together based on current OS/Architecture. 180 together based on current OS/Architecture.
240 181
241 Raises: 182 Raises:
242 KeyError: if a required configuration key/parameter is not available. 183 KeyError: if a required configuration key/parameter is not available.
243 """ 184 """
244 # Cascade the platform configuration. 185 # Cascade the platform configuration.
(...skipping 16 matching lines...) Expand all
261 path = os.path.join(*path) 202 path = os.path.join(*path)
262 if not os.path.isdir(path): 203 if not os.path.isdir(path):
263 os.makedirs(path) 204 os.makedirs(path)
264 return path 205 return path
265 206
266 207
267 def _logdog_get_streamserver_uri(rt, typ): 208 def _logdog_get_streamserver_uri(rt, typ):
268 """Returns (str): The Butler StreamServer URI. 209 """Returns (str): The Butler StreamServer URI.
269 210
270 Args: 211 Args:
271 rt (Runtime): Process-wide runtime. 212 rt (RobustTempdir): context for temporary directories.
272 typ (str): The type of URI to generate. One of: ['unix']. 213 typ (str): The type of URI to generate. One of: ['unix'].
273 Raises: 214 Raises:
274 LogDogBootstrapError: if |typ| is not a known type. 215 LogDogBootstrapError: if |typ| is not a known type.
275 """ 216 """
276 if typ == 'unix': 217 if typ == 'unix':
277 # We have to use a custom temporary directory here. This is due to the path 218 # We have to use a custom temporary directory here. This is due to the path
278 # length limitation on UNIX domain sockets, which is generally 104-108 219 # length limitation on UNIX domain sockets, which is generally 104-108
279 # characters. We can't make that assumption about our standard recipe 220 # characters. We can't make that assumption about our standard recipe
280 # temporary directory. 221 # temporary directory.
281 # 222 #
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 def _get_service_account_json(opts, credential_path): 279 def _get_service_account_json(opts, credential_path):
339 """Returns (str/None): If specified, the path to the service account JSON. 280 """Returns (str/None): If specified, the path to the service account JSON.
340 281
341 This method probes the local environment and returns a (possibly empty) list 282 This method probes the local environment and returns a (possibly empty) list
342 of arguments to add to the Butler command line for authentication. 283 of arguments to add to the Butler command line for authentication.
343 284
344 If we're running on a GCE instance, no arguments will be returned, as GCE 285 If we're running on a GCE instance, no arguments will be returned, as GCE
345 service account is implicitly authenticated. If we're running on Baremetal, 286 service account is implicitly authenticated. If we're running on Baremetal,
346 a path to those credentials will be returned. 287 a path to those credentials will be returned.
347 288
348 Args:
349 rt (RecipeRuntime): The runtime environment.
350 Raises: 289 Raises:
351 |LogDogBootstrapError| if no credentials could be found. 290 |LogDogBootstrapError| if no credentials could be found.
352 """ 291 """
353 path = opts.logdog_service_account_json 292 path = opts.logdog_service_account_json
354 if path: 293 if path:
355 return path 294 return path
356 295
357 if gce.Authenticator.is_gce(): 296 if gce.Authenticator.is_gce():
358 LOGGER.info('Running on GCE. No credentials necessary.') 297 LOGGER.info('Running on GCE. No credentials necessary.')
359 return None 298 return None
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
437 376
438 This method executes the recipe engine, bootstrapping it through 377 This method executes the recipe engine, bootstrapping it through
439 LogDog/Annotee so its output and annotations are streamed to LogDog. The 378 LogDog/Annotee so its output and annotations are streamed to LogDog. The
440 bootstrap is configured to tee the annotations through STDOUT/STDERR so they 379 bootstrap is configured to tee the annotations through STDOUT/STDERR so they
441 will still be sent to BuildBot. 380 will still be sent to BuildBot.
442 381
443 The overall setup here is: 382 The overall setup here is:
444 [annotated_run.py] => [logdog_butler] => [logdog_annotee] => [recipes.py] 383 [annotated_run.py] => [logdog_butler] => [logdog_annotee] => [recipes.py]
445 384
446 Args: 385 Args:
447 rt (Runtime): Process-wide runtime. 386 rt (RobustTempdir): context for temporary directories.
448 opts (argparse.Namespace): Command-line options. 387 opts (argparse.Namespace): Command-line options.
449 basedir (str): The base (non-temporary) recipe directory. 388 basedir (str): The base (non-temporary) recipe directory.
450 tempdir (str): The path to the session temporary directory. 389 tempdir (str): The path to the session temporary directory.
451 config (Config): Recipe runtime configuration. 390 config (Config): Recipe runtime configuration.
452 properties (dict): Build properties. 391 properties (dict): Build properties.
453 cmd (list): The recipe runner command list to bootstrap. 392 cmd (list): The recipe runner command list to bootstrap.
454 393
455 Returns (int): The return code of the recipe runner process. 394 Returns (int): The return code of the recipe runner process.
456 395
457 Raises: 396 Raises:
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
875 if opts.verbose == 0: 814 if opts.verbose == 0:
876 level = logging.INFO 815 level = logging.INFO
877 else: 816 else:
878 level = logging.DEBUG 817 level = logging.DEBUG
879 logging.getLogger().setLevel(level) 818 logging.getLogger().setLevel(level)
880 819
881 clean_old_recipe_engine() 820 clean_old_recipe_engine()
882 821
883 # Enter our runtime environment. 822 # Enter our runtime environment.
884 basedir = os.getcwd() 823 basedir = os.getcwd()
885 with Runtime(leak=opts.leak) as rt: 824 with robust_tempdir.RobustTempdir(
825 prefix='.recipe_runtime', leak=opts.leak) as rt:
886 tdir = rt.tempdir(base=basedir) 826 tdir = rt.tempdir(base=basedir)
887 LOGGER.debug('Using temporary directory: [%s].', tdir) 827 LOGGER.debug('Using temporary directory: [%s].', tdir)
888 828
889 # Load factory properties and configuration. 829 # Load factory properties and configuration.
890 # TODO(crbug.com/551165): remove flag "factory_properties". 830 # TODO(crbug.com/551165): remove flag "factory_properties".
891 use_factory_properties_from_disk = (opts.use_factory_properties_from_disk or 831 use_factory_properties_from_disk = (opts.use_factory_properties_from_disk or
892 bool(opts.factory_properties)) 832 bool(opts.factory_properties))
893 properties = get_recipe_properties( 833 properties = get_recipe_properties(
894 tdir, opts.build_properties, use_factory_properties_from_disk) 834 tdir, opts.build_properties, use_factory_properties_from_disk)
895 LOGGER.debug('Loaded properties: %s', properties) 835 LOGGER.debug('Loaded properties: %s', properties)
(...skipping 17 matching lines...) Expand all
913 # Re-execute with the updated annotated_run.py. 853 # Re-execute with the updated annotated_run.py.
914 rv, _ = _run_command([sys.executable] + argv) 854 rv, _ = _run_command([sys.executable] + argv)
915 return rv 855 return rv
916 else: 856 else:
917 return main(argv[1:]) 857 return main(argv[1:])
918 858
919 859
920 if __name__ == '__main__': 860 if __name__ == '__main__':
921 logging.basicConfig(level=logging.INFO) 861 logging.basicConfig(level=logging.INFO)
922 sys.exit(shell_main(sys.argv)) 862 sys.exit(shell_main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/robust_tempdir.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698