Amin Hassani | 8658343 | 2019-10-03 10:45:45 -0700 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
xixuan | a4f4e71 | 2017-05-08 15:17:54 -0700 | [diff] [blame] | 2 | # Copyright 2016 The Chromium OS Authors. All rights reserved. |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """An executable function cros-update for auto-update of a CrOS host. |
| 7 | |
| 8 | The reason to create this file is to let devserver to trigger a background |
| 9 | process for CrOS auto-update. Therefore, when devserver service is restarted |
| 10 | sometimes, the CrOS auto-update process is still running and the corresponding |
| 11 | provision task won't claim failure. |
| 12 | |
| 13 | It includes two classes: |
| 14 | a. CrOSUpdateTrigger: |
| 15 | 1. Includes all logics which identify which types of update need to be |
| 16 | performed in the current DUT. |
| 17 | 2. Responsible for write current status of CrOS auto-update process into |
| 18 | progress_tracker. |
| 19 | |
| 20 | b. CrOSAUParser: |
| 21 | 1. Pre-setup the required args for CrOS auto-update. |
| 22 | 2. Parse the input parameters for cmd that runs 'cros_update.py'. |
| 23 | """ |
| 24 | |
| 25 | from __future__ import print_function |
| 26 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 27 | import os |
David Riley | ef7aad1 | 2017-11-24 22:03:21 -0800 | [diff] [blame] | 28 | import re |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 29 | import sys |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 30 | import time |
xixuan | 28d9907 | 2016-10-06 12:24:16 -0700 | [diff] [blame] | 31 | import traceback |
Amin Hassani | 8658343 | 2019-10-03 10:45:45 -0700 | [diff] [blame] | 32 | import logging # pylint: disable=cros-logging-import |
| 33 | |
| 34 | import cros_update_logging |
| 35 | import cros_update_progress |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 36 | |
Amin Hassani | 8658343 | 2019-10-03 10:45:45 -0700 | [diff] [blame] | 37 | import setup_chromite # pylint: disable=unused-import |
Amin Hassani | e116396 | 2019-10-16 14:54:01 -0700 | [diff] [blame] | 38 | from chromite.lib import auto_updater |
| 39 | from chromite.lib import commandline |
| 40 | from chromite.lib import cros_build_lib |
| 41 | from chromite.lib import remote_access |
| 42 | from chromite.lib import timeout_util |
| 43 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 44 | |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 45 | # The build channel for recovering host's stateful partition |
| 46 | STABLE_BUILD_CHANNEL = 'stable-channel' |
| 47 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 48 | # Timeout for CrOS auto-update process. |
| 49 | CROS_UPDATE_TIMEOUT_MIN = 30 |
| 50 | |
| 51 | # The preserved path in remote device, won't be deleted after rebooting. |
| 52 | CROS_PRESERVED_PATH = ('/mnt/stateful_partition/unencrypted/' |
| 53 | 'preserve/cros-update') |
| 54 | |
| 55 | # Standard error tmeplate to be written into status tracking log. |
xixuan | 28d9907 | 2016-10-06 12:24:16 -0700 | [diff] [blame] | 56 | CROS_ERROR_TEMPLATE = cros_update_progress.ERROR_TAG + ' %s' |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 57 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 58 | # How long after a quick provision fails to wait before falling back to the |
| 59 | # standard provisioning flow. |
| 60 | QUICK_PROVISION_FAILURE_DELAY_SEC = 45 |
| 61 | |
xixuan | 27d5044 | 2017-08-09 10:38:25 -0700 | [diff] [blame] | 62 | # Setting logging level |
| 63 | logConfig = cros_update_logging.loggingConfig() |
| 64 | logConfig.ConfigureLogging() |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 65 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 66 | |
| 67 | class CrOSUpdateTrigger(object): |
| 68 | """The class for CrOS auto-updater trigger. |
| 69 | |
| 70 | This class is used for running all CrOS auto-update trigger logic. |
| 71 | """ |
| 72 | def __init__(self, host_name, build_name, static_dir, progress_tracker=None, |
xixuan | 3bc974e | 2016-10-18 17:21:43 -0700 | [diff] [blame] | 73 | log_file=None, au_tempdir=None, force_update=False, |
David Haddock | 2055961 | 2017-06-28 22:15:08 -0700 | [diff] [blame] | 74 | full_update=False, original_build=None, payload_filename=None, |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 75 | clobber_stateful=True, quick_provision=False, |
| 76 | devserver_url=None, static_url=None): |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 77 | self.host_name = host_name |
| 78 | self.build_name = build_name |
| 79 | self.static_dir = static_dir |
| 80 | self.progress_tracker = progress_tracker |
| 81 | self.log_file = log_file |
xixuan | 3bc974e | 2016-10-18 17:21:43 -0700 | [diff] [blame] | 82 | self.au_tempdir = au_tempdir |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 83 | self.force_update = force_update |
| 84 | self.full_update = full_update |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 85 | self.original_build = original_build |
David Haddock | 90e4944 | 2017-04-07 19:14:09 -0700 | [diff] [blame] | 86 | self.payload_filename = payload_filename |
David Haddock | 2055961 | 2017-06-28 22:15:08 -0700 | [diff] [blame] | 87 | self.clobber_stateful = clobber_stateful |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 88 | self.quick_provision = quick_provision |
| 89 | self.devserver_url = devserver_url |
| 90 | self.static_url = static_url |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 91 | |
| 92 | def _WriteAUStatus(self, content): |
| 93 | if self.progress_tracker: |
| 94 | self.progress_tracker.WriteStatus(content) |
| 95 | |
| 96 | def _StatefulUpdate(self, cros_updater): |
| 97 | """The detailed process in stateful update. |
| 98 | |
| 99 | Args: |
| 100 | cros_updater: The CrOS auto updater for auto-update. |
| 101 | """ |
| 102 | self._WriteAUStatus('pre-setup stateful update') |
| 103 | cros_updater.PreSetupStatefulUpdate() |
| 104 | self._WriteAUStatus('perform stateful update') |
| 105 | cros_updater.UpdateStateful() |
| 106 | self._WriteAUStatus('post-check stateful update') |
| 107 | cros_updater.PostCheckStatefulUpdate() |
| 108 | |
| 109 | def _RootfsUpdate(self, cros_updater): |
| 110 | """The detailed process in rootfs update. |
| 111 | |
| 112 | Args: |
| 113 | cros_updater: The CrOS auto updater for auto-update. |
| 114 | """ |
xixuan | a4f4e71 | 2017-05-08 15:17:54 -0700 | [diff] [blame] | 115 | self._WriteAUStatus('Check whether devserver can run before rootfs update') |
| 116 | cros_updater.CheckDevserverRun() |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 117 | self._WriteAUStatus('transfer rootfs update package') |
| 118 | cros_updater.TransferRootfsUpdate() |
| 119 | self._WriteAUStatus('pre-setup rootfs update') |
| 120 | cros_updater.PreSetupRootfsUpdate() |
| 121 | self._WriteAUStatus('rootfs update') |
| 122 | cros_updater.UpdateRootfs() |
| 123 | self._WriteAUStatus('post-check rootfs update') |
| 124 | cros_updater.PostCheckRootfsUpdate() |
| 125 | |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 126 | def _GetOriginalPayloadDir(self): |
| 127 | """Get the directory of original payload. |
| 128 | |
| 129 | Returns: |
| 130 | The directory of original payload, whose format is like: |
| 131 | 'static/stable-channel/link/3428.210.0' |
| 132 | """ |
| 133 | if self.original_build: |
| 134 | return os.path.join(self.static_dir, '%s/%s' % (STABLE_BUILD_CHANNEL, |
| 135 | self.original_build)) |
| 136 | else: |
| 137 | return None |
| 138 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 139 | def _MakeStatusUrl(self, devserver_url, host_name, pid): |
| 140 | """Generates a URL to post auto update status to. |
| 141 | |
| 142 | Args: |
| 143 | devserver_url: URL base for devserver RPCs. |
| 144 | host_name: Host to post status for. |
| 145 | pid: pid of the update process. |
| 146 | |
| 147 | Returns: |
| 148 | An unescaped URL. |
| 149 | """ |
| 150 | return '%s/post_au_status?host_name=%s&pid=%d' % (devserver_url, host_name, |
| 151 | pid) |
| 152 | |
| 153 | def _QuickProvision(self, device): |
| 154 | """Performs a quick provision of device. |
| 155 | |
| 156 | Returns: |
David Riley | ef7aad1 | 2017-11-24 22:03:21 -0800 | [diff] [blame] | 157 | A dictionary of extracted key-value pairs returned from the script |
| 158 | execution. |
| 159 | |
| 160 | Raises: |
| 161 | cros_build_lib.RunCommandError: error executing command or script |
| 162 | remote_access.SSHConnectionError: SSH connection error |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 163 | """ |
| 164 | pid = os.getpid() |
| 165 | pgid = os.getpgid(pid) |
| 166 | if self.progress_tracker is None: |
| 167 | self.progress_tracker = cros_update_progress.AUProgress(self.host_name, |
| 168 | pgid) |
| 169 | |
| 170 | dut_script = '/tmp/quick-provision' |
| 171 | status_url = self._MakeStatusUrl(self.devserver_url, self.host_name, pgid) |
| 172 | cmd = ('curl -o %s %s && bash ' |
| 173 | '%s --status_url %s %s %s') % ( |
| 174 | dut_script, os.path.join(self.static_url, 'quick-provision'), |
| 175 | dut_script, cros_build_lib.ShellQuote(status_url), |
| 176 | self.build_name, self.static_url |
| 177 | ) |
David Riley | f594119 | 2018-03-01 14:30:38 -0800 | [diff] [blame] | 178 | # Quick provision script issues a reboot and might result in the SSH |
| 179 | # connection being terminated so set ssh_error_ok so that output can |
| 180 | # still be captured. |
| 181 | results = device.RunCommand(cmd, log_output=True, capture_output=True, |
| 182 | ssh_error_ok=True) |
David Riley | ef7aad1 | 2017-11-24 22:03:21 -0800 | [diff] [blame] | 183 | key_re = re.compile(r'^KEYVAL: ([^\d\W]\w*)=(.*)$') |
| 184 | matches = [key_re.match(l) for l in results.output.splitlines()] |
| 185 | keyvals = {m.group(1): m.group(2) for m in matches if m} |
Amin Hassani | 8658343 | 2019-10-03 10:45:45 -0700 | [diff] [blame] | 186 | logging.info('DUT returned keyvals: %s', keyvals) |
David Riley | f594119 | 2018-03-01 14:30:38 -0800 | [diff] [blame] | 187 | |
| 188 | # If there was an SSH error, check the keyvals to see if it actually |
| 189 | # completed and suppress the error if so. |
| 190 | if results.returncode == remote_access.SSH_ERROR_CODE: |
| 191 | if 'COMPLETED' in keyvals: |
| 192 | logging.warning('Quick provision completed with ssh error, ignoring...') |
| 193 | else: |
| 194 | logging.error('Incomplete quick provision failed with ssh error') |
| 195 | raise remote_access.SSHConnectionError(results.error) |
| 196 | |
David Riley | ef7aad1 | 2017-11-24 22:03:21 -0800 | [diff] [blame] | 197 | return keyvals |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 198 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 199 | def TriggerAU(self): |
| 200 | """Execute auto update for cros_host. |
| 201 | |
| 202 | The auto update includes 4 steps: |
| 203 | 1. if devserver cannot run, restore the stateful partition. |
xixuan | 2aca0ac | 2016-07-29 12:02:06 -0700 | [diff] [blame] | 204 | 2. if possible, do stateful update first, but never raise errors, except |
| 205 | for timeout_util.TimeoutError caused by system.signal. |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 206 | 3. If required or stateful_update fails, first do rootfs update, then do |
| 207 | stateful_update. |
| 208 | 4. Post-check for the whole update. |
| 209 | """ |
| 210 | try: |
| 211 | with remote_access.ChromiumOSDeviceHandler( |
| 212 | self.host_name, port=None, |
| 213 | base_dir=CROS_PRESERVED_PATH, |
Luigi Semenzato | 8db8b3c | 2017-01-26 18:02:19 -0800 | [diff] [blame] | 214 | ping=False) as device: |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 215 | |
| 216 | logging.debug('Remote device %s is connected', self.host_name) |
| 217 | payload_dir = os.path.join(self.static_dir, self.build_name) |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 218 | original_payload_dir = self._GetOriginalPayloadDir() |
| 219 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 220 | chromeos_AU = auto_updater.ChromiumOSUpdater( |
xixuan | 2a0970a | 2016-08-10 12:12:44 -0700 | [diff] [blame] | 221 | device, self.build_name, payload_dir, |
| 222 | dev_dir=os.path.abspath(os.path.dirname(__file__)), |
xixuan | 3bc974e | 2016-10-18 17:21:43 -0700 | [diff] [blame] | 223 | tempdir=self.au_tempdir, |
xixuan | 2a0970a | 2016-08-10 12:12:44 -0700 | [diff] [blame] | 224 | log_file=self.log_file, |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 225 | original_payload_dir=original_payload_dir, |
David Haddock | 90e4944 | 2017-04-07 19:14:09 -0700 | [diff] [blame] | 226 | yes=True, |
David Haddock | 2055961 | 2017-06-28 22:15:08 -0700 | [diff] [blame] | 227 | payload_filename=self.payload_filename, |
| 228 | clobber_stateful=self.clobber_stateful) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 229 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 230 | # Allow fall back if the quick provision does not succeed. |
| 231 | invoke_autoupdate = True |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 232 | |
David Riley | 6c46725 | 2017-11-30 16:39:11 -0800 | [diff] [blame] | 233 | if (self.quick_provision and self.clobber_stateful and |
| 234 | not self.full_update): |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 235 | try: |
| 236 | logging.debug('Start CrOS quick provision process...') |
| 237 | self._WriteAUStatus('Start Quick Provision') |
David Riley | 6c46725 | 2017-11-30 16:39:11 -0800 | [diff] [blame] | 238 | keyvals = self._QuickProvision(device) |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 239 | logging.debug('Start CrOS check process...') |
David Riley | 8a7ed5c | 2018-02-22 11:16:47 -0800 | [diff] [blame] | 240 | self._WriteAUStatus('Finish Quick Provision, reboot') |
| 241 | chromeos_AU.AwaitReboot(keyvals.get('BOOT_ID')) |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 242 | self._WriteAUStatus('Finish Quick Provision, post-check') |
David Riley | 8a7ed5c | 2018-02-22 11:16:47 -0800 | [diff] [blame] | 243 | chromeos_AU.PostCheckCrOSUpdate() |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 244 | self._WriteAUStatus(cros_update_progress.FINISHED) |
| 245 | invoke_autoupdate = False |
| 246 | except (cros_build_lib.RunCommandError, |
David Riley | 8a7ed5c | 2018-02-22 11:16:47 -0800 | [diff] [blame] | 247 | remote_access.SSHConnectionError, |
| 248 | auto_updater.RebootVerificationError) as e: |
David Riley | f594119 | 2018-03-01 14:30:38 -0800 | [diff] [blame] | 249 | logging.warning( |
| 250 | 'Error during quick provision, falling back to legacy: %s: %s', |
| 251 | type(e).__name__, e) |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 252 | time.sleep(QUICK_PROVISION_FAILURE_DELAY_SEC) |
| 253 | |
| 254 | if invoke_autoupdate: |
| 255 | chromeos_AU.CheckPayloads() |
| 256 | |
| 257 | version_match = chromeos_AU.PreSetupCrOSUpdate() |
| 258 | self._WriteAUStatus('Transfer Devserver/Stateful Update Package') |
| 259 | chromeos_AU.TransferDevServerPackage() |
| 260 | chromeos_AU.TransferStatefulUpdate() |
| 261 | |
| 262 | restore_stateful = chromeos_AU.CheckRestoreStateful() |
| 263 | do_stateful_update = (not self.full_update) and ( |
| 264 | version_match and self.force_update) |
| 265 | stateful_update_complete = False |
| 266 | logging.debug('Start CrOS update process...') |
| 267 | try: |
| 268 | if restore_stateful: |
| 269 | self._WriteAUStatus('Restore Stateful Partition') |
| 270 | chromeos_AU.RestoreStateful() |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 271 | stateful_update_complete = True |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 272 | else: |
| 273 | # Whether to execute stateful update depends on: |
| 274 | # a. full_update=False: No full reimage is required. |
| 275 | # b. The update version is matched to the current version, And |
| 276 | # force_update=True: Update is forced even if the version |
| 277 | # installed is the same. |
| 278 | if do_stateful_update: |
| 279 | self._StatefulUpdate(chromeos_AU) |
| 280 | stateful_update_complete = True |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 281 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 282 | except timeout_util.TimeoutError: |
| 283 | raise |
| 284 | except Exception as e: |
| 285 | logging.debug('Error happens in stateful update: %r', e) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 286 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 287 | # Whether to execute rootfs update depends on: |
| 288 | # a. stateful update is not completed, or completed by |
| 289 | # update action 'restore_stateful'. |
| 290 | # b. force_update=True: Update is forced no matter what the current |
| 291 | # version is. Or, the update version is not matched to the current |
| 292 | # version. |
| 293 | require_rootfs_update = self.force_update or ( |
| 294 | not chromeos_AU.CheckVersion()) |
| 295 | if (not (do_stateful_update and stateful_update_complete) |
| 296 | and require_rootfs_update): |
| 297 | self._RootfsUpdate(chromeos_AU) |
| 298 | self._StatefulUpdate(chromeos_AU) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 299 | |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 300 | self._WriteAUStatus('post-check for CrOS auto-update') |
| 301 | chromeos_AU.PostCheckCrOSUpdate() |
| 302 | self._WriteAUStatus(cros_update_progress.FINISHED) |
David Riley | f594119 | 2018-03-01 14:30:38 -0800 | [diff] [blame] | 303 | |
| 304 | logging.debug('Provision successfully completed (%s)', |
| 305 | 'legacy' if invoke_autoupdate else 'quick provision') |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 306 | except Exception as e: |
| 307 | logging.debug('Error happens in CrOS auto-update: %r', e) |
xixuan | 28d9907 | 2016-10-06 12:24:16 -0700 | [diff] [blame] | 308 | self._WriteAUStatus(CROS_ERROR_TEMPLATE % str(traceback.format_exc())) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 309 | raise |
| 310 | |
| 311 | |
Amin Hassani | e116396 | 2019-10-16 14:54:01 -0700 | [diff] [blame] | 312 | def ParseArguments(argv): |
| 313 | """Returns a namespace for the CLI arguments.""" |
| 314 | parser = commandline.ArgumentParser(description=__doc__) |
| 315 | parser.add_argument('-d', action='store', type=str, dest='host_name', |
| 316 | help='host_name of a DUT') |
| 317 | parser.add_argument('-b', action='store', type=str, dest='build_name', |
| 318 | help='build name to be auto-updated') |
| 319 | parser.add_argument('--static_dir', action='store', type='path', |
| 320 | help='static directory of the devserver') |
| 321 | parser.add_argument('--force_update', action='store_true', default=False, |
| 322 | help=('force an update even if the version installed is ' |
| 323 | 'the same')) |
| 324 | parser.add_argument('--full_update', action='store_true', default=False, |
| 325 | help='force a rootfs update, skip stateful update') |
| 326 | parser.add_argument('--original_build', action='store', type=str, default='', |
| 327 | help=('force stateful update with the same version of ' |
| 328 | 'previous rootfs partition')) |
| 329 | parser.add_argument('--payload_filename', action='store', type=str, |
| 330 | default=None, help='A custom payload filename') |
| 331 | parser.add_argument('--clobber_stateful', action='store_true', default=False, |
| 332 | help='Whether to clobber stateful') |
| 333 | parser.add_argument('--quick_provision', action='store_true', default=False, |
| 334 | help='Whether to attempt quick provisioning path') |
| 335 | parser.add_argument('--devserver_url', action='store', type=str, default=None, |
| 336 | help='Devserver URL base for RPCs') |
| 337 | parser.add_argument('--static_url', action='store', type=str, default=None, |
| 338 | help='Devserver URL base for static files') |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 339 | |
Amin Hassani | e116396 | 2019-10-16 14:54:01 -0700 | [diff] [blame] | 340 | opts = parser.parse_args(argv) |
| 341 | opts.Freeze() |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 342 | |
Amin Hassani | e116396 | 2019-10-16 14:54:01 -0700 | [diff] [blame] | 343 | return opts |
| 344 | |
| 345 | |
| 346 | def main(argv): |
| 347 | options = ParseArguments(argv) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 348 | |
xixuan | 2a0970a | 2016-08-10 12:12:44 -0700 | [diff] [blame] | 349 | # Use process group id as the unique id in track and log files, since |
| 350 | # os.setsid is executed before the current process is run. |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 351 | pid = os.getpid() |
xixuan | 2a0970a | 2016-08-10 12:12:44 -0700 | [diff] [blame] | 352 | pgid = os.getpgid(pid) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 353 | |
| 354 | # Setting log files for CrOS auto-update process. |
| 355 | # Log file: file to record every details of CrOS auto-update process. |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 356 | log_file = cros_update_progress.GetExecuteLogFile(options.host_name, pgid) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 357 | logging.info('Writing executing logs into file: %s', log_file) |
| 358 | logConfig.SetFileHandler(log_file) |
| 359 | |
| 360 | # Create a progress_tracker for tracking CrOS auto-update progress. |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 361 | progress_tracker = cros_update_progress.AUProgress(options.host_name, pgid) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 362 | |
xixuan | 3bc974e | 2016-10-18 17:21:43 -0700 | [diff] [blame] | 363 | # Create a dir for temporarily storing devserver codes and logs. |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 364 | au_tempdir = cros_update_progress.GetAUTempDirectory(options.host_name, pgid) |
xixuan | 3bc974e | 2016-10-18 17:21:43 -0700 | [diff] [blame] | 365 | |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 366 | # Create cros_update instance to run CrOS auto-update. |
xixuan | ac89ce8 | 2016-11-30 16:48:20 -0800 | [diff] [blame] | 367 | cros_updater_trigger = CrOSUpdateTrigger( |
| 368 | options.host_name, options.build_name, options.static_dir, |
| 369 | progress_tracker=progress_tracker, |
| 370 | log_file=log_file, |
| 371 | au_tempdir=au_tempdir, |
| 372 | force_update=options.force_update, |
| 373 | full_update=options.full_update, |
David Haddock | 90e4944 | 2017-04-07 19:14:09 -0700 | [diff] [blame] | 374 | original_build=options.original_build, |
David Haddock | 2055961 | 2017-06-28 22:15:08 -0700 | [diff] [blame] | 375 | payload_filename=options.payload_filename, |
David Riley | 6382067 | 2017-11-02 10:46:42 -0700 | [diff] [blame] | 376 | clobber_stateful=options.clobber_stateful, |
| 377 | quick_provision=options.quick_provision, |
| 378 | devserver_url=options.devserver_url, |
| 379 | static_url=options.static_url) |
xixuan | 52c2fba | 2016-05-20 17:02:48 -0700 | [diff] [blame] | 380 | |
| 381 | # Set timeout the cros-update process. |
| 382 | try: |
| 383 | with timeout_util.Timeout(CROS_UPDATE_TIMEOUT_MIN*60): |
| 384 | cros_updater_trigger.TriggerAU() |
| 385 | except timeout_util.TimeoutError as e: |
| 386 | error_msg = ('%s. The CrOS auto-update process is timed out, thus will be ' |
| 387 | 'terminated' % str(e)) |
| 388 | progress_tracker.WriteStatus(CROS_ERROR_TEMPLATE % error_msg) |
| 389 | |
| 390 | |
| 391 | if __name__ == '__main__': |
Amin Hassani | e116396 | 2019-10-16 14:54:01 -0700 | [diff] [blame] | 392 | main(sys.argv) |