blob: ce28126eaaee4027be73aad2b2d449a8638e5ca0 [file] [log] [blame]
Don Garrett8db752c2014-10-17 16:56:55 -07001#!/usr/bin/python
2# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Runs on autotest servers from a cron job to self update them.
7
8This script is designed to run on all autotest servers to allow them to
9automatically self-update based on the manifests used to create their (existing)
10repos.
11"""
12
13from __future__ import print_function
14
15import ConfigParser
Don Garrett03432d62014-11-19 18:18:35 -080016import argparse
Don Garrett8db752c2014-10-17 16:56:55 -070017import os
Don Garrett699b4b32014-12-11 13:10:15 -080018import re
Dan Shicf278042016-04-06 21:16:34 -070019import socket
Don Garrett8db752c2014-10-17 16:56:55 -070020import subprocess
21import sys
22import time
23
24import common
25
26from autotest_lib.client.common_lib import global_config
Dan Shiac6fdbf2016-04-09 17:36:28 -070027from autotest_lib.server import utils as server_utils
Dan Shicf278042016-04-06 21:16:34 -070028from autotest_lib.server.cros.dynamic_suite import frontend_wrappers
Don Garrett8db752c2014-10-17 16:56:55 -070029
Dan Shiac6fdbf2016-04-09 17:36:28 -070030
Don Garrettd0321722014-11-18 16:03:33 -080031# How long after restarting a service do we watch it to see if it's stable.
Don Garrett6073ba92015-07-23 15:01:39 -070032SERVICE_STABILITY_TIMER = 120
Don Garrettd0321722014-11-18 16:03:33 -080033
Dan Shicf278042016-04-06 21:16:34 -070034# A list of commands that only applies to primary server. For example,
35# test_importer should only be run in primary master scheduler. If two servers
36# are both running test_importer, there is a chance to fail as both try to
37# update the same table.
38PRIMARY_ONLY_COMMANDS = ['test_importer']
Shuqian Zhaoa3438a52016-09-20 15:11:02 -070039# A dict to map update_commands defined in config file to repos or files that
40# decide whether need to update these commands. E.g. if no changes under
41# frontend repo, no need to update afe.
Aviv Keshet85622032016-10-03 03:17:26 -070042COMMANDS_TO_REPOS_DICT = {'afe': 'frontend/',
43 'tko': 'tko/'}
Allen Li43b275a2016-10-04 15:14:11 -070044# Services present on all hosts.
Allen Lida9e81c2016-10-18 18:43:04 -070045# TODO(ayatane): Temporarily stop starting sysmon
46# UNIVERSAL_SERVICES = ['sysmon']
47UNIVERSAL_SERVICES = []
Dan Shicf278042016-04-06 21:16:34 -070048
Dan Shiac6fdbf2016-04-09 17:36:28 -070049AFE = frontend_wrappers.RetryingAFE(
50 server=server_utils.get_global_afe_hostname(), timeout_min=5,
51 delay_sec=10)
Don Garrett8db752c2014-10-17 16:56:55 -070052
53class DirtyTreeException(Exception):
Don Garrettd0321722014-11-18 16:03:33 -080054 """Raised when the tree has been modified in an unexpected way."""
Don Garrett8db752c2014-10-17 16:56:55 -070055
56
57class UnknownCommandException(Exception):
Don Garrettd0321722014-11-18 16:03:33 -080058 """Raised when we try to run a command name with no associated command."""
Don Garrett8db752c2014-10-17 16:56:55 -070059
60
61class UnstableServices(Exception):
Don Garrettd0321722014-11-18 16:03:33 -080062 """Raised if a service appears unstable after restart."""
Don Garrett8db752c2014-10-17 16:56:55 -070063
64
Don Garrett35711212014-12-18 14:33:41 -080065def strip_terminal_codes(text):
66 """This function removes all terminal formatting codes from a string.
67
68 @param text: String of text to cleanup.
69 @returns String with format codes removed.
70 """
71 ESC = '\x1b'
72 return re.sub(ESC+r'\[[^m]*m', '', text)
73
74
Don Garrett8db752c2014-10-17 16:56:55 -070075def verify_repo_clean():
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070076 """This function cleans the current repo then verifies that it is valid.
Don Garrett8db752c2014-10-17 16:56:55 -070077
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070078 @raises DirtyTreeException if the repo is still not clean.
Don Garrett8db752c2014-10-17 16:56:55 -070079 @raises subprocess.CalledProcessError on a repo command failure.
80 """
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070081 subprocess.check_output(['git', 'reset', '--hard'])
Don Garrett8db752c2014-10-17 16:56:55 -070082 out = subprocess.check_output(['repo', 'status'], stderr=subprocess.STDOUT)
Don Garrett35711212014-12-18 14:33:41 -080083 out = strip_terminal_codes(out).strip()
Don Garrett699b4b32014-12-11 13:10:15 -080084
Shuqian Zhao8754a1a2016-08-24 12:54:11 -070085 if not 'working directory clean' in out:
Dan Shicf278042016-04-06 21:16:34 -070086 raise DirtyTreeException(out)
Don Garrett8db752c2014-10-17 16:56:55 -070087
Don Garrett8db752c2014-10-17 16:56:55 -070088
89def repo_versions():
90 """This function collects the versions of all git repos in the general repo.
91
Don Garrettfa2c1c42014-12-11 12:11:49 -080092 @returns A dictionary mapping project names to git hashes for HEAD.
Don Garrett8db752c2014-10-17 16:56:55 -070093 @raises subprocess.CalledProcessError on a repo command failure.
94 """
Don Garrettfa2c1c42014-12-11 12:11:49 -080095 cmd = ['repo', 'forall', '-p', '-c', 'pwd && git log -1 --format=%h']
Don Garrett35711212014-12-18 14:33:41 -080096 output = strip_terminal_codes(subprocess.check_output(cmd))
Don Garrettfa2c1c42014-12-11 12:11:49 -080097
98 # The expected output format is:
99
100 # project chrome_build/
101 # /dir/holding/chrome_build
102 # 73dee9d
103 #
104 # project chrome_release/
105 # /dir/holding/chrome_release
106 # 9f3a5d8
107
108 lines = output.splitlines()
109
110 PROJECT_PREFIX = 'project '
111
112 project_heads = {}
113 for n in range(0, len(lines), 4):
114 project_line = lines[n]
115 project_dir = lines[n+1]
116 project_hash = lines[n+2]
117 # lines[n+3] is a blank line, but doesn't exist for the final block.
118
119 # Convert 'project chrome_build/' -> 'chrome_build'
120 assert project_line.startswith(PROJECT_PREFIX)
121 name = project_line[len(PROJECT_PREFIX):].rstrip('/')
122
123 project_heads[name] = (project_dir, project_hash)
124
125 return project_heads
Don Garrett8db752c2014-10-17 16:56:55 -0700126
127
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700128def repo_versions_to_decide_whether_run_cmd_update():
129 """Collect versions of repos/files defined in COMMANDS_TO_REPOS_DICT.
130
131 For the update_commands defined in config files, no need to run the command
132 every time. Only run it when the repos/files related to the commands have
133 been changed.
134
135 @returns A set of tuples: {(cmd, repo_version), ()...}
136 """
137 results = set()
138 for cmd, repo in COMMANDS_TO_REPOS_DICT.iteritems():
139 version = subprocess.check_output(
140 ['git', 'log', '-1', '--pretty=tformat:%h',
141 '%s/%s' % (common.autotest_dir, repo)])
142 results.add((cmd, version.strip()))
143 return results
144
145
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700146def repo_sync(update_push_servers=False):
Don Garrett8db752c2014-10-17 16:56:55 -0700147 """Perform a repo sync.
148
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700149 @param update_push_servers: If True, then update test_push servers to ToT.
150 Otherwise, update server to prod branch.
Don Garrett8db752c2014-10-17 16:56:55 -0700151 @raises subprocess.CalledProcessError on a repo command failure.
152 """
Don Garrettd0321722014-11-18 16:03:33 -0800153 subprocess.check_output(['repo', 'sync'])
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700154 if update_push_servers:
155 print('Updating push servers, checkout cros/master')
156 subprocess.check_output(['git', 'checkout', 'cros/master'])
157 else:
158 print('Updating server to prod branch')
159 subprocess.check_output(['git', 'checkout', 'cros/prod'])
Don Garrett8db752c2014-10-17 16:56:55 -0700160
161
Don Garrettd0321722014-11-18 16:03:33 -0800162def discover_update_commands():
163 """Lookup the commands to run on this server.
Don Garrett8db752c2014-10-17 16:56:55 -0700164
Don Garrettd0321722014-11-18 16:03:33 -0800165 These commonly come from shadow_config.ini, since they vary by server type.
Don Garrett8db752c2014-10-17 16:56:55 -0700166
Don Garrettd0321722014-11-18 16:03:33 -0800167 @returns List of command names in string format.
Don Garrett8db752c2014-10-17 16:56:55 -0700168 """
Don Garrett8db752c2014-10-17 16:56:55 -0700169 try:
Don Garrettd0321722014-11-18 16:03:33 -0800170 return global_config.global_config.get_config_value(
Don Garrett8db752c2014-10-17 16:56:55 -0700171 'UPDATE', 'commands', type=list)
172
173 except (ConfigParser.NoSectionError, global_config.ConfigError):
Don Garrettd0321722014-11-18 16:03:33 -0800174 return []
Don Garrett8db752c2014-10-17 16:56:55 -0700175
Don Garrettd0321722014-11-18 16:03:33 -0800176
177def discover_restart_services():
178 """Find the services that need restarting on the current server.
179
180 These commonly come from shadow_config.ini, since they vary by server type.
181
182 @returns List of service names in string format.
183 """
Allen Li43b275a2016-10-04 15:14:11 -0700184 services = list(UNIVERSAL_SERVICES)
Don Garrett8db752c2014-10-17 16:56:55 -0700185 try:
Allen Li43b275a2016-10-04 15:14:11 -0700186 # Look up services from shadow_config.ini.
187 extra_services = global_config.global_config.get_config_value(
Don Garrett8db752c2014-10-17 16:56:55 -0700188 'UPDATE', 'services', type=list)
Allen Li43b275a2016-10-04 15:14:11 -0700189 services.extend(extra_services)
Don Garrett8db752c2014-10-17 16:56:55 -0700190 except (ConfigParser.NoSectionError, global_config.ConfigError):
Allen Li43b275a2016-10-04 15:14:11 -0700191 pass
192 return services
Don Garrett8db752c2014-10-17 16:56:55 -0700193
Don Garrett8db752c2014-10-17 16:56:55 -0700194
Don Garrett03432d62014-11-19 18:18:35 -0800195def update_command(cmd_tag, dryrun=False):
Don Garrettd0321722014-11-18 16:03:33 -0800196 """Restart a command.
Don Garrett8db752c2014-10-17 16:56:55 -0700197
Don Garrettd0321722014-11-18 16:03:33 -0800198 The command name is looked up in global_config.ini to find the full command
199 to run, then it's executed.
Don Garrett8db752c2014-10-17 16:56:55 -0700200
Don Garrettd0321722014-11-18 16:03:33 -0800201 @param cmd_tag: Which command to restart.
Don Garrett03432d62014-11-19 18:18:35 -0800202 @param dryrun: If true print the command that would have been run.
Don Garrett8db752c2014-10-17 16:56:55 -0700203
Don Garrettd0321722014-11-18 16:03:33 -0800204 @raises UnknownCommandException If cmd_tag can't be looked up.
205 @raises subprocess.CalledProcessError on a command failure.
206 """
207 # Lookup the list of commands to consider. They are intended to be
208 # in global_config.ini so that they can be shared everywhere.
209 cmds = dict(global_config.global_config.config.items(
210 'UPDATE_COMMANDS'))
Don Garrett8db752c2014-10-17 16:56:55 -0700211
Don Garrettd0321722014-11-18 16:03:33 -0800212 if cmd_tag not in cmds:
213 raise UnknownCommandException(cmd_tag, cmds)
Don Garrett8db752c2014-10-17 16:56:55 -0700214
Don Garrettd0321722014-11-18 16:03:33 -0800215 expanded_command = cmds[cmd_tag].replace('AUTOTEST_REPO',
216 common.autotest_dir)
Don Garrett8db752c2014-10-17 16:56:55 -0700217
Don Garrett699b4b32014-12-11 13:10:15 -0800218 print('Running: %s: %s' % (cmd_tag, expanded_command))
Don Garrett03432d62014-11-19 18:18:35 -0800219 if dryrun:
Don Garrett699b4b32014-12-11 13:10:15 -0800220 print('Skip: %s' % expanded_command)
Don Garrett03432d62014-11-19 18:18:35 -0800221 else:
Don Garrett4769c902015-01-05 15:58:56 -0800222 try:
223 subprocess.check_output(expanded_command, shell=True,
224 stderr=subprocess.STDOUT)
225 except subprocess.CalledProcessError as e:
226 print('FAILED:')
227 print(e.output)
228 raise
Don Garrett8db752c2014-10-17 16:56:55 -0700229
Don Garrett8db752c2014-10-17 16:56:55 -0700230
Don Garrett03432d62014-11-19 18:18:35 -0800231def restart_service(service_name, dryrun=False):
Don Garrettd0321722014-11-18 16:03:33 -0800232 """Restart a service.
233
234 Restarts the standard service with "service <name> restart".
235
236 @param service_name: The name of the service to restart.
Don Garrett03432d62014-11-19 18:18:35 -0800237 @param dryrun: Don't really run anything, just print out the command.
Don Garrettd0321722014-11-18 16:03:33 -0800238
239 @raises subprocess.CalledProcessError on a command failure.
240 """
Don Garrett03432d62014-11-19 18:18:35 -0800241 cmd = ['sudo', 'service', service_name, 'restart']
Don Garrett699b4b32014-12-11 13:10:15 -0800242 print('Restarting: %s' % service_name)
Don Garrett03432d62014-11-19 18:18:35 -0800243 if dryrun:
Don Garrett699b4b32014-12-11 13:10:15 -0800244 print('Skip: %s' % ' '.join(cmd))
Don Garrett03432d62014-11-19 18:18:35 -0800245 else:
Don Garrett03432d62014-11-19 18:18:35 -0800246 subprocess.check_call(cmd)
Don Garrettd0321722014-11-18 16:03:33 -0800247
248
249def service_status(service_name):
250 """Return the results "status <name>" for a given service.
251
252 This string is expected to contain the pid, and so to change is the service
253 is shutdown or restarted for any reason.
254
255 @param service_name: The name of the service to check on.
Don Garrett03432d62014-11-19 18:18:35 -0800256
Don Garrettd0321722014-11-18 16:03:33 -0800257 @returns The output of the external command.
258 Ex: autofs start/running, process 1931
259
260 @raises subprocess.CalledProcessError on a command failure.
261 """
262 return subprocess.check_output(['sudo', 'status', service_name])
263
264
Dan Shi57d4c732015-01-22 18:38:50 -0800265def restart_services(service_names, dryrun=False, skip_service_status=False):
Don Garrettd0321722014-11-18 16:03:33 -0800266 """Restart services as needed for the current server type.
267
268 Restart the listed set of services, and watch to see if they are stable for
269 at least SERVICE_STABILITY_TIMER. It restarts all services quickly,
270 waits for that delay, then verifies the status of all of them.
271
272 @param service_names: The list of service to restart and monitor.
Don Garrett03432d62014-11-19 18:18:35 -0800273 @param dryrun: Don't really restart the service, just print out the command.
Dan Shi57d4c732015-01-22 18:38:50 -0800274 @param skip_service_status: Set to True to skip service status check.
275 Default is False.
Don Garrettd0321722014-11-18 16:03:33 -0800276
277 @raises subprocess.CalledProcessError on a command failure.
Don Garrett03432d62014-11-19 18:18:35 -0800278 @raises UnstableServices if any services are unstable after restart.
Don Garrettd0321722014-11-18 16:03:33 -0800279 """
280 service_statuses = {}
281
Don Garrett03432d62014-11-19 18:18:35 -0800282 if dryrun:
283 for name in service_names:
284 restart_service(name, dryrun=True)
285 return
286
Don Garrettd0321722014-11-18 16:03:33 -0800287 # Restart each, and record the status (including pid).
288 for name in service_names:
289 restart_service(name)
290 service_statuses[name] = service_status(name)
291
Dan Shi57d4c732015-01-22 18:38:50 -0800292 # Skip service status check if --skip-service-status is specified. Used for
293 # servers in backup status.
294 if skip_service_status:
295 print('--skip-service-status is specified, skip checking services.')
296 return
297
Don Garrettd0321722014-11-18 16:03:33 -0800298 # Wait for a while to let the services settle.
299 time.sleep(SERVICE_STABILITY_TIMER)
300
301 # Look for any services that changed status.
302 unstable_services = [n for n in service_names
303 if service_status(n) != service_statuses[n]]
304
305 # Report any services having issues.
306 if unstable_services:
307 raise UnstableServices(unstable_services)
Don Garrett8db752c2014-10-17 16:56:55 -0700308
309
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700310def run_deploy_actions(cmds_skip=set(), dryrun=False,
311 skip_service_status=False):
Don Garrettfa2c1c42014-12-11 12:11:49 -0800312 """Run arbitrary update commands specified in global.ini.
Don Garrett8db752c2014-10-17 16:56:55 -0700313
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700314 @param cmds_skip: cmds no need to run since the corresponding repo/file
315 does not change.
Don Garrett03432d62014-11-19 18:18:35 -0800316 @param dryrun: Don't really restart the service, just print out the command.
Dan Shi57d4c732015-01-22 18:38:50 -0800317 @param skip_service_status: Set to True to skip service status check.
318 Default is False.
Don Garrett8db752c2014-10-17 16:56:55 -0700319
Don Garrett03432d62014-11-19 18:18:35 -0800320 @raises subprocess.CalledProcessError on a command failure.
321 @raises UnstableServices if any services are unstable after restart.
322 """
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700323 defined_cmds = set(discover_update_commands())
324 cmds = defined_cmds - cmds_skip
Don Garrettd0321722014-11-18 16:03:33 -0800325 if cmds:
326 print('Running update commands:', ', '.join(cmds))
327 for cmd in cmds:
Dan Shicf278042016-04-06 21:16:34 -0700328 if (cmd in PRIMARY_ONLY_COMMANDS and
329 not AFE.run('get_servers', hostname=socket.getfqdn(),
330 status='primary')):
331 print('Command %s is only applicable to primary servers.' % cmd)
332 continue
Don Garrett03432d62014-11-19 18:18:35 -0800333 update_command(cmd, dryrun=dryrun)
Don Garrettd0321722014-11-18 16:03:33 -0800334
335 services = discover_restart_services()
336 if services:
Don Garrett03432d62014-11-19 18:18:35 -0800337 print('Restarting Services:', ', '.join(services))
Dan Shi57d4c732015-01-22 18:38:50 -0800338 restart_services(services, dryrun=dryrun,
339 skip_service_status=skip_service_status)
Don Garrett03432d62014-11-19 18:18:35 -0800340
341
Don Garrettfa2c1c42014-12-11 12:11:49 -0800342def report_changes(versions_before, versions_after):
343 """Produce a report describing what changed in all repos.
344
345 @param versions_before: Results of repo_versions() from before the update.
346 @param versions_after: Results of repo_versions() from after the update.
347
348 @returns string containing a human friendly changes report.
349 """
350 result = []
351
Don Garrett35711212014-12-18 14:33:41 -0800352 if versions_after:
353 for project in sorted(set(versions_before.keys() + versions_after.keys())):
354 result.append('%s:' % project)
Don Garrettfa2c1c42014-12-11 12:11:49 -0800355
Don Garrett35711212014-12-18 14:33:41 -0800356 _, before_hash = versions_before.get(project, (None, None))
357 after_dir, after_hash = versions_after.get(project, (None, None))
Don Garrettfa2c1c42014-12-11 12:11:49 -0800358
Don Garrett35711212014-12-18 14:33:41 -0800359 if project not in versions_before:
360 result.append('Added.')
Don Garrettfa2c1c42014-12-11 12:11:49 -0800361
Don Garrett35711212014-12-18 14:33:41 -0800362 elif project not in versions_after:
363 result.append('Removed.')
Don Garrettfa2c1c42014-12-11 12:11:49 -0800364
Don Garrett35711212014-12-18 14:33:41 -0800365 elif before_hash == after_hash:
366 result.append('No Change.')
Don Garrettfa2c1c42014-12-11 12:11:49 -0800367
Don Garrett35711212014-12-18 14:33:41 -0800368 else:
369 hashes = '%s..%s' % (before_hash, after_hash)
370 cmd = ['git', 'log', hashes, '--oneline']
371 out = subprocess.check_output(cmd, cwd=after_dir,
372 stderr=subprocess.STDOUT)
373 result.append(out.strip())
Don Garrettfa2c1c42014-12-11 12:11:49 -0800374
Don Garrett35711212014-12-18 14:33:41 -0800375 result.append('')
376 else:
377 for project in sorted(versions_before.keys()):
378 _, before_hash = versions_before[project]
379 result.append('%s: %s' % (project, before_hash))
Don Garrettfa2c1c42014-12-11 12:11:49 -0800380 result.append('')
381
382 return '\n'.join(result)
383
384
Don Garrett03432d62014-11-19 18:18:35 -0800385def parse_arguments(args):
386 """Parse command line arguments.
387
388 @param args: The command line arguments to parse. (ususally sys.argsv[1:])
389
Don Garrett40036362014-12-08 15:52:44 -0800390 @returns An argparse.Namespace populated with argument values.
Don Garrett03432d62014-11-19 18:18:35 -0800391 """
392 parser = argparse.ArgumentParser(
393 description='Command to update an autotest server.')
394 parser.add_argument('--skip-verify', action='store_false',
395 dest='verify', default=True,
396 help='Disable verification of a clean repository.')
397 parser.add_argument('--skip-update', action='store_false',
398 dest='update', default=True,
399 help='Skip the repository source code update.')
400 parser.add_argument('--skip-actions', action='store_false',
401 dest='actions', default=True,
402 help='Skip the post update actions.')
403 parser.add_argument('--skip-report', action='store_false',
404 dest='report', default=True,
405 help='Skip the git version report.')
Don Garrette3718912014-12-05 13:11:44 -0800406 parser.add_argument('--actions-only', action='store_true',
407 help='Run the post update actions (restart services).')
Don Garrett03432d62014-11-19 18:18:35 -0800408 parser.add_argument('--dryrun', action='store_true',
409 help='Don\'t actually run any commands, just log.')
Dan Shi57d4c732015-01-22 18:38:50 -0800410 parser.add_argument('--skip-service-status', action='store_true',
411 help='Skip checking the service status.')
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700412 parser.add_argument('--update_push_servers', action='store_true',
413 help='Indicate to update test_push server. If not '
414 'specify, then update server to production.')
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700415 parser.add_argument('--force_update', action='store_true',
416 help='Force to run the update commands for afe, tko '
417 'and build_externals')
Don Garrett03432d62014-11-19 18:18:35 -0800418
419 results = parser.parse_args(args)
420
Don Garrette3718912014-12-05 13:11:44 -0800421 if results.actions_only:
422 results.verify = False
423 results.update = False
424 results.report = False
425
Don Garrett03432d62014-11-19 18:18:35 -0800426 # TODO(dgarrett): Make these behaviors support dryrun.
427 if results.dryrun:
428 results.verify = False
429 results.update = False
430
431 return results
432
433
Allen Lie8c4ea42016-10-05 18:08:29 -0700434class ChangeDir(object):
435
436 """Context manager for changing to a directory temporarily."""
437
438 def __init__(self, dir):
439 self.new_dir = dir
440 self.old_dir = None
441
442 def __enter__(self):
443 self.old_dir = os.getcwd()
444 os.chdir(self.new_dir)
445
446 def __exit__(self, exc_type, exc_val, exc_tb):
447 os.chdir(self.old_dir)
448
449
Allen Li1f5a1682016-10-06 15:23:06 -0700450def update_chromeos():
451 """Update /usr/local/google/chromeos repo."""
452 print('Updating /usr/local/google/chromeos')
453 with ChangeDir('/usr/local/google/chromeos'):
454 ret = subprocess.call(['repo', 'sync'])
Allen Lie8c4ea42016-10-05 18:08:29 -0700455 if ret != 0:
456 print('Update failed, exited with status: %d' % ret)
457
458
Don Garrett03432d62014-11-19 18:18:35 -0800459def main(args):
460 """Main method."""
461 os.chdir(common.autotest_dir)
462 global_config.global_config.parse_config_file()
463
464 behaviors = parse_arguments(args)
465
466 if behaviors.verify:
Don Garrettd0321722014-11-18 16:03:33 -0800467 try:
Don Garrett03432d62014-11-19 18:18:35 -0800468 print('Checking tree status:')
469 verify_repo_clean()
470 print('Clean.')
471 except DirtyTreeException as e:
472 print('Local tree is dirty, can\'t perform update safely.')
473 print()
474 print('repo status:')
Don Garrettd0321722014-11-18 16:03:33 -0800475 print(e.args[0])
476 return 1
Don Garrett8db752c2014-10-17 16:56:55 -0700477
Don Garrett35711212014-12-18 14:33:41 -0800478 versions_before = repo_versions()
479 versions_after = {}
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700480 cmd_versions_before = repo_versions_to_decide_whether_run_cmd_update()
481 cmd_versions_after = {}
Don Garrettfa2c1c42014-12-11 12:11:49 -0800482
Don Garrett03432d62014-11-19 18:18:35 -0800483 if behaviors.update:
Don Garrett03432d62014-11-19 18:18:35 -0800484 print('Updating Repo.')
Shuqian Zhao8754a1a2016-08-24 12:54:11 -0700485 repo_sync(behaviors.update_push_servers)
Don Garrettfa2c1c42014-12-11 12:11:49 -0800486 versions_after = repo_versions()
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700487 cmd_versions_after = repo_versions_to_decide_whether_run_cmd_update()
Don Garrett03432d62014-11-19 18:18:35 -0800488
Allen Li1f5a1682016-10-06 15:23:06 -0700489 update_chromeos()
Allen Lie8c4ea42016-10-05 18:08:29 -0700490
Don Garrett03432d62014-11-19 18:18:35 -0800491 if behaviors.actions:
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700492 # If the corresponding repo/file not change, no need to run the cmd.
493 cmds_skip = (set() if behaviors.force_update else
494 {t[0] for t in cmd_versions_before & cmd_versions_after})
Don Garrett03432d62014-11-19 18:18:35 -0800495 try:
Dan Shi57d4c732015-01-22 18:38:50 -0800496 run_deploy_actions(
Shuqian Zhaoa3438a52016-09-20 15:11:02 -0700497 cmds_skip, behaviors.dryrun, behaviors.skip_service_status)
Don Garrett03432d62014-11-19 18:18:35 -0800498 except UnstableServices as e:
499 print('The following services were not stable after '
500 'the update:')
501 print(e.args[0])
502 return 1
503
Don Garrett35711212014-12-18 14:33:41 -0800504 if behaviors.report:
Don Garrettfa2c1c42014-12-11 12:11:49 -0800505 print('Changes:')
506 print(report_changes(versions_before, versions_after))
Don Garrett8db752c2014-10-17 16:56:55 -0700507
508
509if __name__ == '__main__':
Don Garrett03432d62014-11-19 18:18:35 -0800510 sys.exit(main(sys.argv[1:]))