blob: d5c404dd820a35c10c61b7f7744c00a87be4668b [file] [log] [blame]
Zhizhou Yang5534af82020-01-15 16:25:04 -08001#!/usr/bin/env python3
Manoj Gupta1d1de432019-04-26 11:30:14 -07002# -*- coding: utf-8 -*-
Ahmad Sharif70de27b2011-06-15 17:51:24 -07003#
Manoj Gupta1d1de432019-04-26 11:30:14 -07004# Copyright 2019 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
Ahmad Sharif70de27b2011-06-15 17:51:24 -07008"""Script to image a ChromeOS device.
9
10This script images a remote ChromeOS device with a specific image."
11"""
12
Caroline Tice88272d42016-01-13 09:48:29 -080013from __future__ import print_function
14
Luis Lozanof2a3ef42015-12-15 13:49:30 -080015__author__ = 'asharif@google.com (Ahmad Sharif)'
Ahmad Sharif70de27b2011-06-15 17:51:24 -070016
Caroline Tice88272d42016-01-13 09:48:29 -080017import argparse
Ahmad Sharif70de27b2011-06-15 17:51:24 -070018import filecmp
Caroline Ticed0f7a732018-03-02 16:31:17 -080019import getpass
Ahmad Sharif70de27b2011-06-15 17:51:24 -070020import glob
Ahmad Sharif70de27b2011-06-15 17:51:24 -070021import os
Ahmad Shariff395c262012-10-09 17:48:09 -070022import re
Ahmad Sharif70de27b2011-06-15 17:51:24 -070023import shutil
24import sys
25import tempfile
Ahmad Sharif4467f002012-12-20 12:09:49 -080026import time
27
Caroline Tice88272d42016-01-13 09:48:29 -080028from cros_utils import command_executer
29from cros_utils import locks
30from cros_utils import logger
31from cros_utils import misc
32from cros_utils.file_utils import FileUtils
Ahmad Sharif70de27b2011-06-15 17:51:24 -070033
Luis Lozanof2a3ef42015-12-15 13:49:30 -080034checksum_file = '/usr/local/osimage_checksum_file'
35lock_file = '/tmp/image_chromeos_lock/image_chromeos_lock'
36
Ahmad Sharif70de27b2011-06-15 17:51:24 -070037
38def Usage(parser, message):
Caroline Tice88272d42016-01-13 09:48:29 -080039 print('ERROR: %s' % message)
Ahmad Sharif70de27b2011-06-15 17:51:24 -070040 parser.print_help()
41 sys.exit(0)
42
Ahmad Shariff395c262012-10-09 17:48:09 -070043
cmtice13909242014-03-11 13:38:07 -070044def CheckForCrosFlash(chromeos_root, remote, log_level):
45 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
cmtice0cc4e772014-01-30 15:52:37 -080046
Luis Lozano54db5382015-05-20 15:57:19 -070047 # Check to see if remote machine has cherrypy, ctypes
48 command = "python -c 'import cherrypy, ctypes'"
Caroline Ticef6ef4392017-04-06 17:16:05 -070049 ret = cmd_executer.CrosRunCommand(
50 command, chromeos_root=chromeos_root, machine=remote)
Han Shen96d936c2015-03-25 12:03:12 -070051 logger.GetLogger().LogFatalIf(
Caroline Tice88272d42016-01-13 09:48:29 -080052 ret == 255, 'Failed ssh to %s (for checking cherrypy)' % remote)
Luis Lozano54db5382015-05-20 15:57:19 -070053 logger.GetLogger().LogFatalIf(
Caroline Tice88272d42016-01-13 09:48:29 -080054 ret != 0, "Failed to find cherrypy or ctypes on remote '{}', "
Luis Lozanof2a3ef42015-12-15 13:49:30 -080055 'cros flash cannot work.'.format(remote))
Luis Lozano54db5382015-05-20 15:57:19 -070056
cmtice0cc4e772014-01-30 15:52:37 -080057
Manoj Gupta1282e842017-05-17 12:57:56 -070058def DisableCrosBeeps(chromeos_root, remote, log_level):
59 """Disable annoying chromebooks beeps after reboots."""
60 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
61
62 command = '/usr/share/vboot/bin/set_gbb_flags.sh 0x1'
63 logger.GetLogger().LogOutput('Trying to disable beeping.')
64
65 ret, o, _ = cmd_executer.CrosRunCommandWOutput(
66 command, chromeos_root=chromeos_root, machine=remote)
67 if ret != 0:
68 logger.GetLogger().LogOutput(o)
69 logger.GetLogger().LogOutput('Failed to disable beeps.')
70
71
Caroline Ticed0f7a732018-03-02 16:31:17 -080072def FindChromeOSImage(image_file, chromeos_root):
73 """Find path for ChromeOS image inside chroot.
74
75 This function could be called with image paths that are either inside
76 or outside the chroot. In either case the path needs to be translated
77 to an real/absolute path inside the chroot.
78 Example input paths:
79 /usr/local/google/home/uname/chromeos/chroot/tmp/my-test-images/image
80 ~/trunk/src/build/images/board/latest/image
81 /tmp/peppy-release/R67-1235.0.0/image
82
83 Corresponding example output paths:
84 /tmp/my-test-images/image
85 /home/uname/trunk/src/build/images/board/latest/image
86 /tmp/peppy-release/R67-1235.0,0/image
87 """
88
89 # Get the name of the user, for "/home/<user>" part of the path.
90 whoami = getpass.getuser()
91 # Get the full path for the chroot dir, including 'chroot'
92 real_chroot_dir = os.path.join(os.path.realpath(chromeos_root), 'chroot')
93 # Get the full path for the chromeos root, excluding 'chroot'
94 real_chromeos_root = os.path.realpath(chromeos_root)
95
96 # If path name starts with real_chroot_dir, remove that piece, but assume
97 # the rest of the path is correct.
98 if image_file.find(real_chroot_dir) != -1:
99 chroot_image = image_file[len(real_chroot_dir):]
100 # If path name starts with chromeos_root, excluding 'chroot', replace the
101 # chromeos_root with the prefix: '/home/<username>/trunk'.
102 elif image_file.find(real_chromeos_root) != -1:
103 chroot_image = image_file[len(real_chromeos_root):]
104 chroot_image = '/home/%s/trunk%s' % (whoami, chroot_image)
105 # Else assume the path is already internal, so leave it alone.
106 else:
107 chroot_image = image_file
108
109 return chroot_image
110
111
Ahmad Sharif4467f002012-12-20 12:09:49 -0800112def DoImage(argv):
Han Shenba649282015-08-05 17:19:55 -0700113 """Image ChromeOS."""
Ahmad Sharif4467f002012-12-20 12:09:49 -0800114
Caroline Tice88272d42016-01-13 09:48:29 -0800115 parser = argparse.ArgumentParser()
Caroline Ticef6ef4392017-04-06 17:16:05 -0700116 parser.add_argument(
117 '-c',
118 '--chromeos_root',
119 dest='chromeos_root',
120 help='Target directory for ChromeOS installation.')
Caroline Tice88272d42016-01-13 09:48:29 -0800121 parser.add_argument('-r', '--remote', dest='remote', help='Target device.')
122 parser.add_argument('-i', '--image', dest='image', help='Image binary file.')
Caroline Ticef6ef4392017-04-06 17:16:05 -0700123 parser.add_argument(
124 '-b', '--board', dest='board', help='Target board override.')
125 parser.add_argument(
126 '-f',
127 '--force',
128 dest='force',
129 action='store_true',
130 default=False,
131 help='Force an image even if it is non-test.')
132 parser.add_argument(
133 '-n',
134 '--no_lock',
135 dest='no_lock',
136 default=False,
137 action='store_true',
138 help='Do not attempt to lock remote before imaging. '
139 'This option should only be used in cases where the '
140 'exclusive lock has already been acquired (e.g. in '
141 'a script that calls this one).')
142 parser.add_argument(
143 '-l',
144 '--logging_level',
145 dest='log_level',
146 default='verbose',
147 help='Amount of logging to be used. Valid levels are '
148 "'quiet', 'average', and 'verbose'.")
Caroline Tice88272d42016-01-13 09:48:29 -0800149 parser.add_argument('-a', '--image_args', dest='image_args')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700150
Caroline Tice88272d42016-01-13 09:48:29 -0800151 options = parser.parse_args(argv[1:])
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700152
cmtice13909242014-03-11 13:38:07 -0700153 if not options.log_level in command_executer.LOG_LEVEL:
154 Usage(parser, "--logging_level must be 'quiet', 'average' or 'verbose'")
155 else:
156 log_level = options.log_level
157
158 # Common initializations
159 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
160 l = logger.GetLogger()
161
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700162 if options.chromeos_root is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800163 Usage(parser, '--chromeos_root must be set')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700164
165 if options.remote is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800166 Usage(parser, '--remote must be set')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700167
168 options.chromeos_root = os.path.expanduser(options.chromeos_root)
169
170 if options.board is None:
171 board = cmd_executer.CrosLearnBoard(options.chromeos_root, options.remote)
172 else:
173 board = options.board
174
175 if options.image is None:
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700176 images_dir = misc.GetImageDir(options.chromeos_root, board)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800177 image = os.path.join(images_dir, 'latest', 'chromiumos_test_image.bin')
Ahmad Shariffd356fb2012-05-07 12:02:16 -0700178 if not os.path.exists(image):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800179 image = os.path.join(images_dir, 'latest', 'chromiumos_image.bin')
David Sharpa20e0302016-01-25 16:00:02 -0800180 is_xbuddy_image = False
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700181 else:
182 image = options.image
David Sharpa20e0302016-01-25 16:00:02 -0800183 is_xbuddy_image = image.startswith('xbuddy://')
184 if not is_xbuddy_image:
cmtice0cc4e772014-01-30 15:52:37 -0800185 image = os.path.expanduser(image)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700186
David Sharpa20e0302016-01-25 16:00:02 -0800187 if not is_xbuddy_image:
cmtice0cc4e772014-01-30 15:52:37 -0800188 image = os.path.realpath(image)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700189
David Sharpa20e0302016-01-25 16:00:02 -0800190 if not os.path.exists(image) and not is_xbuddy_image:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800191 Usage(parser, 'Image file: ' + image + ' does not exist!')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700192
cmticee5bc63b2015-05-27 16:59:37 -0700193 try:
194 should_unlock = False
195 if not options.no_lock:
196 try:
Caroline Tice88272d42016-01-13 09:48:29 -0800197 _ = locks.AcquireLock(
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800198 list(options.remote.split()), options.chromeos_root)
cmticee5bc63b2015-05-27 16:59:37 -0700199 should_unlock = True
200 except Exception as e:
Caroline Tice9099a782016-07-22 16:28:12 -0700201 raise RuntimeError('Error acquiring machine: %s' % str(e))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700202
cmticee5bc63b2015-05-27 16:59:37 -0700203 reimage = False
204 local_image = False
David Sharpa20e0302016-01-25 16:00:02 -0800205 if not is_xbuddy_image:
cmticee5bc63b2015-05-27 16:59:37 -0700206 local_image = True
207 image_checksum = FileUtils().Md5File(image, log_level=log_level)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700208
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800209 command = 'cat ' + checksum_file
Caroline Tice88272d42016-01-13 09:48:29 -0800210 ret, device_checksum, _ = cmd_executer.CrosRunCommandWOutput(
Caroline Ticef6ef4392017-04-06 17:16:05 -0700211 command, chromeos_root=options.chromeos_root, machine=options.remote)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700212
cmticee5bc63b2015-05-27 16:59:37 -0700213 device_checksum = device_checksum.strip()
214 image_checksum = str(image_checksum)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700215
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800216 l.LogOutput('Image checksum: ' + image_checksum)
217 l.LogOutput('Device checksum: ' + device_checksum)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700218
cmticee5bc63b2015-05-27 16:59:37 -0700219 if image_checksum != device_checksum:
Caroline Ticef6ef4392017-04-06 17:16:05 -0700220 [found, located_image] = LocateOrCopyImage(
221 options.chromeos_root, image, board=board)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700222
cmticee5bc63b2015-05-27 16:59:37 -0700223 reimage = True
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800224 l.LogOutput('Checksums do not match. Re-imaging...')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700225
Caroline Ticed0f7a732018-03-02 16:31:17 -0800226 chroot_image = FindChromeOSImage(located_image, options.chromeos_root)
227
cmticee5bc63b2015-05-27 16:59:37 -0700228 is_test_image = IsImageModdedForTest(options.chromeos_root,
Caroline Ticed0f7a732018-03-02 16:31:17 -0800229 chroot_image, log_level)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700230
cmticee5bc63b2015-05-27 16:59:37 -0700231 if not is_test_image and not options.force:
Caroline Tice88272d42016-01-13 09:48:29 -0800232 logger.GetLogger().LogFatal('Have to pass --force to image a '
233 'non-test image!')
cmtice0cc4e772014-01-30 15:52:37 -0800234 else:
cmticee5bc63b2015-05-27 16:59:37 -0700235 reimage = True
236 found = True
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800237 l.LogOutput('Using non-local image; Re-imaging...')
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700238
cmticee5bc63b2015-05-27 16:59:37 -0700239 if reimage:
240 # If the device has /tmp mounted as noexec, image_to_live.sh can fail.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800241 command = 'mount -o remount,rw,exec /tmp'
Caroline Ticef6ef4392017-04-06 17:16:05 -0700242 cmd_executer.CrosRunCommand(
243 command, chromeos_root=options.chromeos_root, machine=options.remote)
cmticeb1340082014-01-13 13:22:37 -0800244
cmticee5bc63b2015-05-27 16:59:37 -0700245 # Check to see if cros flash will work for the remote machine.
246 CheckForCrosFlash(options.chromeos_root, options.remote, log_level)
247
Manoj Gupta1282e842017-05-17 12:57:56 -0700248 # Disable the annoying chromebook beeps after reboot.
249 DisableCrosBeeps(options.chromeos_root, options.remote, log_level)
250
Caroline Ticef6ef4392017-04-06 17:16:05 -0700251 cros_flash_args = [
Manoj Gupta1282e842017-05-17 12:57:56 -0700252 'cros', 'flash',
253 '--board=%s' % board, '--clobber-stateful', options.remote
Caroline Ticef6ef4392017-04-06 17:16:05 -0700254 ]
cmticee5bc63b2015-05-27 16:59:37 -0700255 if local_image:
David Sharpa20e0302016-01-25 16:00:02 -0800256 cros_flash_args.append(chroot_image)
cmticee5bc63b2015-05-27 16:59:37 -0700257 else:
David Sharpa20e0302016-01-25 16:00:02 -0800258 cros_flash_args.append(image)
cmticee5bc63b2015-05-27 16:59:37 -0700259
David Sharpa20e0302016-01-25 16:00:02 -0800260 command = ' '.join(cros_flash_args)
cmticee5bc63b2015-05-27 16:59:37 -0700261
262 # Workaround for crosbug.com/35684.
Zhizhou Yang5534af82020-01-15 16:25:04 -0800263 os.chmod(misc.GetChromeOSKeyFile(options.chromeos_root), 0o600)
cmticeb1340082014-01-13 13:22:37 -0800264
David Sharpa20e0302016-01-25 16:00:02 -0800265 if log_level == 'average':
266 cmd_executer.SetLogLevel('verbose')
cmticee5bc63b2015-05-27 16:59:37 -0700267 retries = 0
David Sharpa20e0302016-01-25 16:00:02 -0800268 while True:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800269 if log_level == 'quiet':
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800270 l.LogOutput('CMD : %s' % command)
Caroline Ticef6ef4392017-04-06 17:16:05 -0700271 ret = cmd_executer.ChrootRunCommand(
272 options.chromeos_root, command, command_timeout=1800)
David Sharpa20e0302016-01-25 16:00:02 -0800273 if ret == 0 or retries >= 2:
274 break
275 retries += 1
276 if log_level == 'quiet':
277 l.LogOutput('Imaging failed. Retry # %d.' % retries)
cmtice13909242014-03-11 13:38:07 -0700278
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800279 if log_level == 'average':
cmticee5bc63b2015-05-27 16:59:37 -0700280 cmd_executer.SetLogLevel(log_level)
cmtice0cc4e772014-01-30 15:52:37 -0800281
Caroline Tice88272d42016-01-13 09:48:29 -0800282 logger.GetLogger().LogFatalIf(ret, 'Image command failed')
cmticee5bc63b2015-05-27 16:59:37 -0700283
284 # Unfortunately cros_image_to_target.py sometimes returns early when the
285 # machine isn't fully up yet.
Caroline Tice88272d42016-01-13 09:48:29 -0800286 ret = EnsureMachineUp(options.chromeos_root, options.remote, log_level)
cmticee5bc63b2015-05-27 16:59:37 -0700287
Caroline Tice88272d42016-01-13 09:48:29 -0800288 # If this is a non-local image, then the ret returned from
cmticee5bc63b2015-05-27 16:59:37 -0700289 # EnsureMachineUp is the one that will be returned by this function;
Caroline Tice88272d42016-01-13 09:48:29 -0800290 # in that case, make sure the value in 'ret' is appropriate.
Denis Nikitin144f6992019-07-20 20:25:16 -0700291 if not local_image and ret:
Caroline Tice88272d42016-01-13 09:48:29 -0800292 ret = 0
cmticee5bc63b2015-05-27 16:59:37 -0700293 else:
Caroline Tice88272d42016-01-13 09:48:29 -0800294 ret = 1
cmticee5bc63b2015-05-27 16:59:37 -0700295
296 if local_image:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800297 if log_level == 'average':
298 l.LogOutput('Verifying image.')
299 command = 'echo %s > %s && chmod -w %s' % (image_checksum,
Caroline Ticef6ef4392017-04-06 17:16:05 -0700300 checksum_file, checksum_file)
Caroline Tice88272d42016-01-13 09:48:29 -0800301 ret = cmd_executer.CrosRunCommand(
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800302 command,
303 chromeos_root=options.chromeos_root,
304 machine=options.remote)
Caroline Tice88272d42016-01-13 09:48:29 -0800305 logger.GetLogger().LogFatalIf(ret, 'Writing checksum failed.')
cmticee5bc63b2015-05-27 16:59:37 -0700306
Caroline Ticed0f7a732018-03-02 16:31:17 -0800307 successfully_imaged = VerifyChromeChecksum(
308 options.chromeos_root, chroot_image, options.remote, log_level)
cmticee5bc63b2015-05-27 16:59:37 -0700309 logger.GetLogger().LogFatalIf(not successfully_imaged,
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800310 'Image verification failed!')
cmticee5bc63b2015-05-27 16:59:37 -0700311 TryRemountPartitionAsRW(options.chromeos_root, options.remote,
312 log_level)
Gabriel Marine2a920a2018-05-16 11:31:07 -0700313
Denis Nikitin144f6992019-07-20 20:25:16 -0700314 if not found:
Gabriel Marine2a920a2018-05-16 11:31:07 -0700315 temp_dir = os.path.dirname(located_image)
316 l.LogOutput('Deleting temp image dir: %s' % temp_dir)
317 shutil.rmtree(temp_dir)
Denis Nikitin144f6992019-07-20 20:25:16 -0700318 l.LogOutput('Image updated.')
cmticee5bc63b2015-05-27 16:59:37 -0700319 else:
Denis Nikitin144f6992019-07-20 20:25:16 -0700320 l.LogOutput('Checksums match, skip image update and reboot.')
Manoj Gupta1d1de432019-04-26 11:30:14 -0700321 command = 'reboot && exit'
322 _ = cmd_executer.CrosRunCommand(
323 command, chromeos_root=options.chromeos_root, machine=options.remote)
324 # Wait 30s after reboot.
325 time.sleep(30)
326
cmticee5bc63b2015-05-27 16:59:37 -0700327 finally:
328 if should_unlock:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800329 locks.ReleaseLock(list(options.remote.split()), options.chromeos_root)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700330
Denis Nikitin144f6992019-07-20 20:25:16 -0700331 return ret
332
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700333
334def LocateOrCopyImage(chromeos_root, image, board=None):
335 l = logger.GetLogger()
336 if board is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800337 board_glob = '*'
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700338 else:
339 board_glob = board
340
341 chromeos_root_realpath = os.path.realpath(chromeos_root)
342 image = os.path.realpath(image)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800343
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800344 if image.startswith('%s/' % chromeos_root_realpath):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700345 return [True, image]
346
347 # First search within the existing build dirs for any matching files.
Manoj Gupta1d1de432019-04-26 11:30:14 -0700348 images_glob = (
349 '%s/src/build/images/%s/*/*.bin' % (chromeos_root_realpath, board_glob))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700350 images_list = glob.glob(images_glob)
351 for potential_image in images_list:
352 if filecmp.cmp(potential_image, image):
Caroline Ticef6ef4392017-04-06 17:16:05 -0700353 l.LogOutput('Found matching image %s in chromeos_root.' % potential_image)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700354 return [True, potential_image]
cmtice13909242014-03-11 13:38:07 -0700355 # We did not find an image. Copy it in the src dir and return the copied
356 # file.
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700357 if board is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800358 board = ''
359 base_dir = ('%s/src/build/images/%s' % (chromeos_root_realpath, board))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700360 if not os.path.isdir(base_dir):
361 os.makedirs(base_dir)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800362 temp_dir = tempfile.mkdtemp(prefix='%s/tmp' % base_dir)
363 new_image = '%s/%s' % (temp_dir, os.path.basename(image))
364 l.LogOutput('No matching image found. Copying %s to %s' % (image, new_image))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700365 shutil.copyfile(image, new_image)
366 return [False, new_image]
367
368
Manoj Gupta1d1de432019-04-26 11:30:14 -0700369def GetImageMountCommand(image, rootfs_mp, stateful_mp):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700370 image_dir = os.path.dirname(image)
371 image_file = os.path.basename(image)
Zhizhou Yang5534af82020-01-15 16:25:04 -0800372 mount_command = ('cd /mnt/host/source/src/scripts &&'
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800373 './mount_gpt_image.sh --from=%s --image=%s'
374 ' --safe --read_only'
375 ' --rootfs_mountpt=%s'
Caroline Ticed0f7a732018-03-02 16:31:17 -0800376 ' --stateful_mountpt=%s' % (image_dir, image_file, rootfs_mp,
377 stateful_mp))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700378 return mount_command
379
380
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800381def MountImage(chromeos_root,
382 image,
383 rootfs_mp,
384 stateful_mp,
385 log_level,
Caroline Ticed0f7a732018-03-02 16:31:17 -0800386 unmount=False,
387 extra_commands=''):
cmtice13909242014-03-11 13:38:07 -0700388 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Manoj Gupta1d1de432019-04-26 11:30:14 -0700389 command = GetImageMountCommand(image, rootfs_mp, stateful_mp)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700390 if unmount:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800391 command = '%s --unmount' % command
Caroline Ticed0f7a732018-03-02 16:31:17 -0800392 if extra_commands:
393 command = '%s ; %s' % (command, extra_commands)
394 ret, out, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
Caroline Tice88272d42016-01-13 09:48:29 -0800395 logger.GetLogger().LogFatalIf(ret, 'Mount/unmount command failed!')
Caroline Ticed0f7a732018-03-02 16:31:17 -0800396 return out
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700397
398
cmtice13909242014-03-11 13:38:07 -0700399def IsImageModdedForTest(chromeos_root, image, log_level):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800400 if log_level != 'verbose':
401 log_level = 'quiet'
Caroline Ticed0f7a732018-03-02 16:31:17 -0800402 command = 'mktemp -d'
403 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
404 _, rootfs_mp, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
405 _, stateful_mp, _ = cmd_executer.ChrootRunCommandWOutput(
406 chromeos_root, command)
407 rootfs_mp = rootfs_mp.strip()
408 stateful_mp = stateful_mp.strip()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800409 lsb_release_file = os.path.join(rootfs_mp, 'etc/lsb-release')
Jian Cai5a143902019-06-21 14:39:42 -0700410 extra = ('grep CHROMEOS_RELEASE_TRACK %s | grep -i test' % lsb_release_file)
Caroline Ticed0f7a732018-03-02 16:31:17 -0800411 output = MountImage(
412 chromeos_root,
413 image,
414 rootfs_mp,
415 stateful_mp,
416 log_level,
417 extra_commands=extra)
418 is_test_image = re.search('test', output, re.IGNORECASE)
Caroline Ticef6ef4392017-04-06 17:16:05 -0700419 MountImage(
420 chromeos_root, image, rootfs_mp, stateful_mp, log_level, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700421 return is_test_image
422
423
cmtice13909242014-03-11 13:38:07 -0700424def VerifyChromeChecksum(chromeos_root, image, remote, log_level):
Caroline Ticed0f7a732018-03-02 16:31:17 -0800425 command = 'mktemp -d'
cmtice13909242014-03-11 13:38:07 -0700426 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Caroline Ticed0f7a732018-03-02 16:31:17 -0800427 _, rootfs_mp, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
428 _, stateful_mp, _ = cmd_executer.ChrootRunCommandWOutput(
429 chromeos_root, command)
430 rootfs_mp = rootfs_mp.strip()
431 stateful_mp = stateful_mp.strip()
432 chrome_file = '%s/opt/google/chrome/chrome' % rootfs_mp
433 extra = 'md5sum %s' % chrome_file
434 out = MountImage(
435 chromeos_root,
436 image,
437 rootfs_mp,
438 stateful_mp,
439 log_level,
440 extra_commands=extra)
441 image_chrome_checksum = out.strip().split()[0]
Caroline Ticef6ef4392017-04-06 17:16:05 -0700442 MountImage(
443 chromeos_root, image, rootfs_mp, stateful_mp, log_level, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700444
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800445 command = 'md5sum /opt/google/chrome/chrome'
Caroline Ticef6ef4392017-04-06 17:16:05 -0700446 [_, o, _] = cmd_executer.CrosRunCommandWOutput(
447 command, chromeos_root=chromeos_root, machine=remote)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700448 device_chrome_checksum = o.split()[0]
Manoj Gupta1d1de432019-04-26 11:30:14 -0700449 return image_chrome_checksum.strip() == device_chrome_checksum.strip()
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700450
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800451
Luis Lozanof81680c2013-03-15 14:44:13 -0700452# Remount partition as writable.
453# TODO: auto-detect if an image is built using --noenable_rootfs_verification.
cmtice13909242014-03-11 13:38:07 -0700454def TryRemountPartitionAsRW(chromeos_root, remote, log_level):
Luis Lozanof81680c2013-03-15 14:44:13 -0700455 l = logger.GetLogger()
cmtice13909242014-03-11 13:38:07 -0700456 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800457 command = 'sudo mount -o remount,rw /'
Caroline Tice88272d42016-01-13 09:48:29 -0800458 ret = cmd_executer.CrosRunCommand(\
459 command, chromeos_root=chromeos_root, machine=remote,
460 terminated_timeout=10)
461 if ret:
Luis Lozanof81680c2013-03-15 14:44:13 -0700462 ## Safely ignore.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800463 l.LogWarning('Failed to remount partition as rw, '
464 'probably the image was not built with '
Zhizhou Yang5534af82020-01-15 16:25:04 -0800465 '"--noenable_rootfs_verification", '
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800466 'you can safely ignore this.')
Luis Lozanof81680c2013-03-15 14:44:13 -0700467 else:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800468 l.LogOutput('Re-mounted partition as writable.')
Luis Lozanof81680c2013-03-15 14:44:13 -0700469
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700470
cmtice13909242014-03-11 13:38:07 -0700471def EnsureMachineUp(chromeos_root, remote, log_level):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800472 l = logger.GetLogger()
cmtice13909242014-03-11 13:38:07 -0700473 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800474 timeout = 600
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800475 magic = 'abcdefghijklmnopqrstuvwxyz'
476 command = 'echo %s' % magic
Ahmad Sharif4467f002012-12-20 12:09:49 -0800477 start_time = time.time()
478 while True:
479 current_time = time.time()
480 if current_time - start_time > timeout:
Caroline Ticef6ef4392017-04-06 17:16:05 -0700481 l.LogError(
482 'Timeout of %ss reached. Machine still not up. Aborting.' % timeout)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800483 return False
Caroline Ticef6ef4392017-04-06 17:16:05 -0700484 ret = cmd_executer.CrosRunCommand(
485 command, chromeos_root=chromeos_root, machine=remote)
Caroline Tice88272d42016-01-13 09:48:29 -0800486 if not ret:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800487 return True
488
489
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800490if __name__ == '__main__':
cmticee5bc63b2015-05-27 16:59:37 -0700491 retval = DoImage(sys.argv)
492 sys.exit(retval)