summaryrefslogtreecommitdiff
path: root/chromium/tools/infra/clobber_cache_utils.py
blob: ba180373d2246da2c1501ae5310c42a30be82e29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Utility functions for cache clobbering scripts."""

from __future__ import print_function

import os
import subprocess
import sys
import textwrap

_SRC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
_SWARMING_CLIENT = os.path.join(_SRC_ROOT, 'tools', 'swarming_client',
                                'swarming.py')
_SWARMING_SERVER = 'chromium-swarm.appspot.com'


def _get_bots(swarming_server, pool, cache):
  cmd = [
      sys.executable,
      _SWARMING_CLIENT,
      'bots',
      '-b',
      '-S',
      swarming_server,
      '-d',
      'caches',
      cache,
      '-d',
      'pool',
      pool,
  ]
  return subprocess.check_output(cmd).splitlines()


def _trigger_clobber(swarming_server, pool, cache, bot, mount_rel_path,
                     dry_run):
  cmd = [
      sys.executable,
      _SWARMING_CLIENT,
      'trigger',
      '-S',
      swarming_server,
      '-d',
      'pool',
      pool,
      '-d',
      'id',
      bot,
      '--cipd-package',
      'cpython:infra/python/cpython/${platform}:latest',
      '--named-cache',
      cache,
      mount_rel_path,
      '--priority=10',
      '--raw-cmd',
      '--',
      'cpython/bin/python${EXECUTABLE_SUFFIX}',
      '-c',
      textwrap.dedent('''\
          import os, shutil, stat

          def remove_readonly(func, path, _):
              "Clear the readonly bit and reattempt the removal"
              os.chmod(path, stat.S_IWRITE)
              func(path)

          shutil.rmtree({mount_rel_path!r}, onerror=remove_readonly)
          '''.format(mount_rel_path=mount_rel_path)),
  ]
  if dry_run:
    print('Would run `%s`' % ' '.join(cmd))
  else:
    subprocess.check_call(cmd)


def add_common_args(argument_parser):
  """Add common arguments to the argument parser used for cache clobber scripts.

  The following arguments will be added to the argument parser:
    * swarming_server (-S/--swarming-server) - The swarming server instance to
      lookup bots to clobber caches on, with a default of the
      chromium-swarm.appspot.com.
    * dry_run (-n/--dry-run) - Whether a dry-run should be performed rather than
      actually clobbering caches, defaults to False.
  """
  argument_parser.add_argument(
      '-S', '--swarming-server', default=_SWARMING_SERVER)
  argument_parser.add_argument('-n', '--dry-run', action='store_true')


def clobber_caches(swarming_server,
                   pool,
                   cache,
                   mount_rel_path,
                   dry_run,
                   bot_id=None):
  """Clobber caches on bots.

  The set of bots in `pool` in `swarming_server` with a cache named `cache` will
  be looked up and printed out then the user will be asked to confirm that the
  caches should be clobbered. If the user confirms, tasks that clobber the cache
  will be triggered on each bot or if `dry_run` is true, the command that would
  trigger such a task is printed instead.

  Args:
    * swarming_server - The swarming_server instance to lookup bots to clobber
      caches on.
    * pool - The pool of machines to lookup bots to clobber caches on.
    * cache - The name of the cache to clobber.
    * mount_rel_path - The relative path to mount the cache to when clobbering.
    * dry_run - Whether a dry-run should be performed where the commands that
      would be executed to trigger the clobber task are printed rather than
      actually triggering the clobber task.
    * bot_id - optional, the id of the bot that you wish to clobber.
  """
  if bot_id:
    bots = [bot_id]
  else:
    bots = _get_bots(swarming_server, pool, cache)

  print('The following bots will be clobbered:')
  print()
  for bot in bots:
    print('  %s' % bot)
  print()
  val = raw_input('Proceed? [Y/n] ')
  if val and not val[0] in ('Y', 'y'):
    print('Cancelled.')
    return 1

  for bot in bots:
    _trigger_clobber(swarming_server, pool, cache, bot, mount_rel_path, dry_run)