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

Side by Side Diff: scripts/common/cros_chromite.py

Issue 1402253002: CrOS: Load Chromite pins from JSON. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Rebase (without pin JSON). Created 5 years, 2 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 | « masters/master.chromiumos/chromiumos_board_config.py ('k') | scripts/common/env.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 python2.7 1 #!/usr/bin/env python2.7
2 # Copyright 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 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 """ 6 """
7 This module wraps ChromeOS's Chromite configuration, providing retrieval 7 This module wraps ChromeOS's Chromite configuration, providing retrieval
8 methods and Infra-aware introspection. 8 methods and Infra-aware introspection.
9 9
10 For any given ChromeOS build, Chromite may be pinned to a specific ChromeOS 10 For any given ChromeOS build, Chromite may be pinned to a specific ChromeOS
11 branch or unpinned at tip-of-tree. Consequently, one function of this module 11 branch or unpinned at tip-of-tree. Consequently, one function of this module
12 is to version Chromite and allow external scripts to retrieve a specific 12 is to version Chromite and allow external scripts to retrieve a specific
13 version of its configuration. 13 version of its configuration.
14 14
15 This file may also be run as a standalone executable to synchronize the pinned 15 This file may also be run as a standalone executable to synchronize the pinned
16 configurations in a cache directory. 16 configurations in a cache directory.
17 """ 17 """
18 18
19 import argparse 19 import argparse
20 import base64 20 import base64
21 import collections 21 import collections
22 import json 22 import json
23 import logging 23 import logging
24 import os
24 import sys 25 import sys
25 26
26 try: 27 try:
27 import requests 28 import requests
28 import requests.exceptions 29 import requests.exceptions
29 except ImportError: 30 except ImportError:
30 # TODO(dnj): Remove me. 31 # TODO(dnj): Remove me.
31 # 32 #
32 # crbug.com/452528: Inconsistent PYTHONPATH environments sometimes cause 33 # crbug.com/452528: Inconsistent PYTHONPATH environments sometimes cause
33 # slaves.cfg (and thus this file) to be parsed without 'third_party/requests' 34 # slaves.cfg (and thus this file) to be parsed without 'third_party/requests'
34 # present. We will add logic to gracefully become read-only when 'requests' 35 # present. We will add logic to gracefully become read-only when 'requests'
35 # is missing so bots don't show errors. 36 # is missing so bots don't show errors.
36 requests = None 37 requests = None
37 38
38 from common import configcache 39 # Add 'common' to our path.
40 from common import configcache, env
39 41
40 # The name of the branch associated with tip-of-tree. 42 # The name of the branch associated with tip-of-tree.
41 TOT_BRANCH = 'master' 43 TOT_BRANCH = 'master'
42 44
43 45
44 # A map of branch names to their pinned commits. These are maintained through 46 # Configure our pin locations. Because repository availability is dependent
45 # a DEPS hook in <build>/DEPS. In order to update a pinned revision: 47 # on checkout layout, pin descriptors are conditional on their repository's
46 # - Update the value here. 48 # availability.
49 #
50 # These are maintained via a DEPS hook in <build>/DEPS. In order to update a
51 # pinned revision:
52 # - Update the value in the respective JSON file.
47 # - Run "gclient runhooks --force". 53 # - Run "gclient runhooks --force".
48 PINS = collections.OrderedDict(( 54 PIN_JSON_PATH = os.path.join(env.Build, 'scripts', 'common',
49 (TOT_BRANCH, 'b2d341616f5043863449ad74d8e4fb06fe9a9b58'), 55 'cros_chromite_pins.json')
50
51 # Release waterfall branches.
52 #
53 # Note that the release waterfall instantiates only three releases. We will
54 # keep one branch around for stability, since internal waterfall updates are
55 # not atomic. Therefore, we should prune all but the FOUR newest release
56 # branches.
57 ('release-R47-7520.B', 'd047e007037383c04c4453beca4f69b82ea74188'),
58 ('release-R46-7390.B', '33959980025b477366d0792a4e14bfd7c0f0810c'),
59 ('release-R45-7262.B', 'd06f185c5383e4ffe884ca30e55df060b96b0c59'),
60 ('release-R44-7077.B', '6b12acdd58a3a506f58fb32bd0b78cbfe72506a3'),
61 ))
62 56
63 57
64 class ChromiteError(RuntimeError): 58 class ChromiteError(RuntimeError):
65 pass 59 pass
66 60
67 61
68 # Slave pool allocation types. 62 # Slave pool allocation types.
69 class SlaveType(object): 63 class SlaveType(object):
70 """Slave configuration expression enumeration.""" 64 """Slave configuration expression enumeration."""
71 BAREMETAL = 'baremetal' 65 BAREMETAL = 'baremetal'
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 site_params = config.pop('_site_params', None) 338 site_params = config.pop('_site_params', None)
345 chromite_config = cls(default, templates, site_params) 339 chromite_config = cls(default, templates, site_params)
346 for k, v in config.iteritems(): 340 for k, v in config.iteritems():
347 chromite_config.AddTarget(k, v) 341 chromite_config.AddTarget(k, v)
348 return chromite_config 342 return chromite_config
349 343
350 344
351 class ChromitePinManager(object): 345 class ChromitePinManager(object):
352 """Manages Chromite pinning associations.""" 346 """Manages Chromite pinning associations."""
353 347
354 def __init__(self, pinned, require=False): 348 def __init__(self, cache_name, pinned, require=False):
355 """Instantiates a new ChromitePinManager. 349 """Instantiates a new ChromitePinManager.
356 350
357 Args: 351 Args:
358 pinned: (dict) A dictionary of [branch-name] => [pinned revision] for 352 pinned: (dict) A dictionary of [branch-name] => [pinned revision] for
359 pinned branch lookup. 353 pinned branch lookup.
360 require: (bool) If False, a requested branch without a pinned match will 354 require: (bool) If False, a requested branch without a pinned match will
361 return that branch name; otherwise, a ChromiteError will be returned. 355 return that branch name; otherwise, a ChromiteError will be returned.
362 """ 356 """
357 self._cache_name = cache_name
363 self._pinned = pinned 358 self._pinned = pinned
364 self._require = require 359 self._require = require
365 360
361 @property
362 def cache_name(self):
363 return self._cache_name
364
365 @classmethod
366 def LoadFromJSON(cls, cache_name, path, **kwargs):
367 """Returns: (ChromitePinManager) a ChromitePinManager instance.
368
369 Loads a ChromitePinManager configuration from a pin JSON file.
370 """
371 logging.debug('Loading default pins from: %s', path)
372 with open(path, 'r') as fd:
373 pins = json.load(fd)
374 if not isinstance(pins, dict):
375 raise TypeError('JSON pins are not a dictionary: %s' % (path,))
376 return cls(cache_name, pins, **kwargs)
377
366 def iterpins(self): 378 def iterpins(self):
367 """Returns: an iterator over registered (pin, commit) tuples.""" 379 """Returns: an iterator over registered (pin, commit) tuples."""
368 return self._pinned.iteritems() 380 return self._pinned.iteritems()
369 381
370 def GetPinnedBranch(self, branch): 382 def GetPinnedBranch(self, branch):
371 """Returns: (str) the pinned version for a given branch, if available. 383 """Returns: (str) the pinned version for a given branch, if available.
372 384
373 Args: 385 Args:
374 branch: The pinned branch name to retrieve. 386 branch: The pinned branch name to retrieve.
375 387
376 This method will return the pinned version of a given branch name. If no 388 This method will return the pinned version of a given branch name. If no
377 pin for that branch is registered, the branch will be used directly. 389 pin for that branch is registered, the branch will be used directly.
378 """ 390 """
379 value = self._pinned.get(branch) 391 value = self._pinned.get(branch)
380 if not value: 392 if not value:
381 if self._require: 393 if self._require:
382 raise ChromiteError('No pinned Chromite commit for [%s]' % ( 394 raise ChromiteError('No pinned Chromite commit for [%s]' % (
383 branch,)) 395 branch,))
384 value = branch 396 value = branch
385 return value 397 return value
386 398
399 def Get(self, branch=None, allow_fetch=True):
400 """Returns: (ChromiteConfig) the Chromite configuration for a given branch.
401
402 Args:
403 branch: (str) The name of the branch to retrieve. If None, use
404 tip-of-tree.
405 allow_fetch: (bool) If True, allow a Get miss to fetch a new cache value.
406 """
407 cache_manager = _GetCacheManager(
408 self,
409 allow_fetch=allow_fetch)
410
411 try:
412 _UpdateCache(cache_manager, self)
413 except configcache.ReadOnlyError as e:
414 raise ChromiteError("Cannot update read-only config cache. Run "
415 "`gclient runhooks --force`: %s" % (e,))
416
417 return ChromiteConfigManager(
418 cache_manager,
419 pinned=self,
420 ).GetConfig(branch)
421
422 def List(self):
423 """Returns: (list) a list of the configured Chromite pin branch names."""
424 return self._pinned.keys()
425
387 426
388 class ChromiteConfigManager(object): 427 class ChromiteConfigManager(object):
389 """Manages Chromite configuration options and Chromite config fetching.""" 428 """Manages Chromite configuration options and Chromite config fetching."""
390 429
391 def __init__(self, cache_manager, pinned=None): 430 def __init__(self, cache_manager, pinned=None):
392 """Instantiates a new ChromiteConfigManager instance. 431 """Instantiates a new ChromiteConfigManager instance.
393 432
394 Args: 433 Args:
395 cache_manager: (cachemanager.CacheManager) The cache manager to use. 434 cache_manager: (cachemanager.CacheManager) The cache manager to use.
396 pinned: (ChromitePinManager) If not None, the pin manager to use to lookup 435 pinned: (ChromitePinManager) If not None, the pin manager to use to lookup
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 self.CHROMITE_CONFIG_PATH) 524 self.CHROMITE_CONFIG_PATH)
486 data = self._GetText(url) 525 data = self._GetText(url)
487 try: 526 try:
488 data = base64.b64decode(data) 527 data = base64.b64decode(data)
489 except (TypeError, UnicodeEncodeError) as e: 528 except (TypeError, UnicodeEncodeError) as e:
490 raise GitilesError(url, 'Failed to decode Base64: %s' % (e,)) 529 raise GitilesError(url, 'Failed to decode Base64: %s' % (e,))
491 return data, version 530 return data, version
492 531
493 532
494 # Default ChromitePinManager instance. 533 # Default ChromitePinManager instance.
495 DefaultChromitePinManager = ChromitePinManager(PINS) 534 _DEFAULT_PIN_MANAGER = None
535 def DefaultChromitePinManager():
536 global _DEFAULT_PIN_MANAGER
537 if not _DEFAULT_PIN_MANAGER:
538 _DEFAULT_PIN_MANAGER = ChromitePinManager.LoadFromJSON('chromite',
539 PIN_JSON_PATH)
540 return _DEFAULT_PIN_MANAGER
496 541
497 542
498 def Get(branch=None, allow_fetch=True): 543 def Get(branch=None, allow_fetch=True):
499 """Returns: (ChromiteConfig) the Chromite configuration for a given branch. 544 """Returns: (ChromiteConfig) the Chromite configuration for a given branch.
500 545
501 Args: 546 Args:
502 branch: (str) The name of the branch to retrieve. If None, use tip-of-tree. 547 branch: (str) The name of the branch to retrieve. If None, use tip-of-tree.
503 allow_fetch: (bool) If True, allow a Get miss to fetch a new cache value. 548 allow_fetch: (bool) If True, allow a Get miss to fetch a new cache value.
504 """ 549 """
505 cache_manager = _GetCacheManager( 550 return DefaultChromitePinManager().Get(
506 DefaultChromitePinManager, 551 branch=branch,
507 allow_fetch=allow_fetch) 552 allow_fetch=allow_fetch)
508 553
509 try:
510 _UpdateCache(cache_manager, DefaultChromitePinManager)
511 except configcache.ReadOnlyError as e:
512 raise ChromiteError("Cannot update read-only config cache. Run "
513 "`gclient runhooks --force`: %s" % (e,))
514 554
515 return ChromiteConfigManager( 555 def List():
516 cache_manager, 556 """Returns: (list) a list of the configured Chromite pin branch names."""
517 pinned=DefaultChromitePinManager, 557 return DefaultChromitePinManager().List()
518 ).GetConfig(branch)
519 558
520 559
521 def _UpdateCache(cache_manager, pin_manager, force=False): 560 def _UpdateCache(cache_manager, pin_manager, force=False):
522 """Fetches all default pinned versions. 561 """Fetches all default pinned versions.
523 562
524 Args: 563 Args:
525 cache_manager: (configcache.CacheManager) The cache manager to use. 564 cache_manager: (configcache.CacheManager) The cache manager to use.
526 pin_manager: (ChromitePinManager) The pin manager to use. 565 pin_manager: (ChromitePinManager) The pin manager to use.
527 force: (bool) If True, reload the entire cache instead of performing an 566 force: (bool) If True, reload the entire cache instead of performing an
528 incremental update. 567 incremental update.
(...skipping 17 matching lines...) Expand all
546 """Returns: (CacheManager) A CacheManager instance. 585 """Returns: (CacheManager) A CacheManager instance.
547 586
548 This function will return a configured CacheManager instance. If 'allow_fetch' 587 This function will return a configured CacheManager instance. If 'allow_fetch'
549 is None or if the 'requests' module could not be imported (crbug.com/452528), 588 is None or if the 'requests' module could not be imported (crbug.com/452528),
550 the returned CacheManager will be read-only (i.e., no ChromiteFetcher). 589 the returned CacheManager will be read-only (i.e., no ChromiteFetcher).
551 590
552 Args: 591 Args:
553 pin_manager: The ChromitePinManager to use. 592 pin_manager: The ChromitePinManager to use.
554 """ 593 """
555 return configcache.CacheManager( 594 return configcache.CacheManager(
556 'chromite', 595 pin_manager.cache_name,
557 # TODO(dnj): Remove the 'requests' test (crbug.com/452258). 596 # TODO(dnj): Remove the 'requests' test (crbug.com/452258).
558 fetcher=(ChromiteFetcher(pin_manager) if allow_fetch and requests 597 fetcher=(ChromiteFetcher(pin_manager) if allow_fetch and requests
559 else None), 598 else None),
560 **kwargs) 599 **kwargs)
561 600
562 601
563 def main(): 602 def main(argv, pin_manager_gen):
564 parser = argparse.ArgumentParser() 603 parser = argparse.ArgumentParser()
565 parser.add_argument('-v', '--verbose', action='count', default=0, 604 parser.add_argument('-v', '--verbose', action='count', default=0,
566 help='Increase process verbosity. This can be specified multiple times.') 605 help='Increase process verbosity. This can be specified multiple times.')
567 parser.add_argument('-D', '--cache-directory', 606 parser.add_argument('-D', '--cache-directory',
568 help='The base cache directory to download pinned configurations into.') 607 help='The base cache directory to download pinned configurations into.')
569 parser.add_argument('-f', '--force', action='store_true', 608 parser.add_argument('-f', '--force', action='store_true',
570 help='Forces an update, even if the cached already contains an artifact.') 609 help='Forces an update, even if the cached already contains an artifact.')
571 args = parser.parse_args() 610 args = parser.parse_args(argv)
572 611
573 # Handle verbosity. 612 # Handle verbosity.
574 if args.verbose == 0: 613 if args.verbose == 0:
575 loglevel = logging.WARNING 614 loglevel = logging.WARNING
576 elif args.verbose == 1: 615 elif args.verbose == 1:
577 loglevel = logging.INFO 616 loglevel = logging.INFO
578 else: 617 else:
579 loglevel = logging.DEBUG 618 loglevel = logging.DEBUG
580 logging.getLogger().setLevel(loglevel) 619 logging.getLogger().setLevel(loglevel)
581 620
582 pm = DefaultChromitePinManager 621 pm = pin_manager_gen()
583 cm = _GetCacheManager(pm, allow_fetch=True, cache_dir=args.cache_directory) 622 cm = _GetCacheManager(pm, allow_fetch=True, cache_dir=args.cache_directory)
584 updated = _UpdateCache(cm, pm, force=args.force) 623 updated = _UpdateCache(cm, pm, force=args.force)
585 logging.info('Updated %d cache artifact(s).', len(updated)) 624 logging.info('Updated %d cache artifact(s).', len(updated))
586 return 0 625 return 0
587 626
588 627
589 # Allow this script to be used as a bootstrap to fetch/cache Chromite 628 # Allow this script to be used as a bootstrap to fetch/cache Chromite
590 # artifacts (gclient runhooks). 629 # artifacts (gclient runhooks).
591 if __name__ == '__main__': 630 if __name__ == '__main__':
592 logging.basicConfig() 631 logging.basicConfig()
593 try: 632 try:
594 sys.exit(main()) 633 sys.exit(main(sys.argv[1:], DefaultChromitePinManager))
595 except Exception as e: 634 except Exception as e:
596 logging.exception("Uncaught execption: %s", e) 635 logging.exception("Uncaught execption: %s", e)
597 sys.exit(1) 636 sys.exit(1)
OLDNEW
« no previous file with comments | « masters/master.chromiumos/chromiumos_board_config.py ('k') | scripts/common/env.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698