blob: bea6fe57081b5b5c42e279745bc8ac1877c9d37f [file] [log] [blame]
Caroline Ticef6ef4392017-04-06 17:16:05 -07001#!/usr/bin/env python2
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.
263 os.chmod(misc.GetChromeOSKeyFile(options.chromeos_root), 0600)
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.
Manoj Gupta1d1de432019-04-26 11:30:14 -0700291 if not local_image and ret is True:
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
Manoj Gupta1d1de432019-04-26 11:30:14 -0700314 if found is False:
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)
cmticee5bc63b2015-05-27 16:59:37 -0700318 else:
Manoj Gupta1d1de432019-04-26 11:30:14 -0700319 l.LogOutput('Checksums match. Skipping reimage, doing a reboot.')
320 command = 'reboot && exit'
321 _ = cmd_executer.CrosRunCommand(
322 command, chromeos_root=options.chromeos_root, machine=options.remote)
323 # Wait 30s after reboot.
324 time.sleep(30)
325
Caroline Tice88272d42016-01-13 09:48:29 -0800326 return ret
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
331
332def LocateOrCopyImage(chromeos_root, image, board=None):
333 l = logger.GetLogger()
334 if board is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800335 board_glob = '*'
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700336 else:
337 board_glob = board
338
339 chromeos_root_realpath = os.path.realpath(chromeos_root)
340 image = os.path.realpath(image)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800341
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800342 if image.startswith('%s/' % chromeos_root_realpath):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700343 return [True, image]
344
345 # First search within the existing build dirs for any matching files.
Manoj Gupta1d1de432019-04-26 11:30:14 -0700346 images_glob = (
347 '%s/src/build/images/%s/*/*.bin' % (chromeos_root_realpath, board_glob))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700348 images_list = glob.glob(images_glob)
349 for potential_image in images_list:
350 if filecmp.cmp(potential_image, image):
Caroline Ticef6ef4392017-04-06 17:16:05 -0700351 l.LogOutput('Found matching image %s in chromeos_root.' % potential_image)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700352 return [True, potential_image]
cmtice13909242014-03-11 13:38:07 -0700353 # We did not find an image. Copy it in the src dir and return the copied
354 # file.
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700355 if board is None:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800356 board = ''
357 base_dir = ('%s/src/build/images/%s' % (chromeos_root_realpath, board))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700358 if not os.path.isdir(base_dir):
359 os.makedirs(base_dir)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800360 temp_dir = tempfile.mkdtemp(prefix='%s/tmp' % base_dir)
361 new_image = '%s/%s' % (temp_dir, os.path.basename(image))
362 l.LogOutput('No matching image found. Copying %s to %s' % (image, new_image))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700363 shutil.copyfile(image, new_image)
364 return [False, new_image]
365
366
Manoj Gupta1d1de432019-04-26 11:30:14 -0700367def GetImageMountCommand(image, rootfs_mp, stateful_mp):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700368 image_dir = os.path.dirname(image)
369 image_file = os.path.basename(image)
Caroline Ticed0f7a732018-03-02 16:31:17 -0800370 mount_command = ('cd ~/trunk/src/scripts &&'
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800371 './mount_gpt_image.sh --from=%s --image=%s'
372 ' --safe --read_only'
373 ' --rootfs_mountpt=%s'
Caroline Ticed0f7a732018-03-02 16:31:17 -0800374 ' --stateful_mountpt=%s' % (image_dir, image_file, rootfs_mp,
375 stateful_mp))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700376 return mount_command
377
378
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800379def MountImage(chromeos_root,
380 image,
381 rootfs_mp,
382 stateful_mp,
383 log_level,
Caroline Ticed0f7a732018-03-02 16:31:17 -0800384 unmount=False,
385 extra_commands=''):
cmtice13909242014-03-11 13:38:07 -0700386 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Manoj Gupta1d1de432019-04-26 11:30:14 -0700387 command = GetImageMountCommand(image, rootfs_mp, stateful_mp)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700388 if unmount:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800389 command = '%s --unmount' % command
Caroline Ticed0f7a732018-03-02 16:31:17 -0800390 if extra_commands:
391 command = '%s ; %s' % (command, extra_commands)
392 ret, out, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
Caroline Tice88272d42016-01-13 09:48:29 -0800393 logger.GetLogger().LogFatalIf(ret, 'Mount/unmount command failed!')
Caroline Ticed0f7a732018-03-02 16:31:17 -0800394 return out
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700395
396
cmtice13909242014-03-11 13:38:07 -0700397def IsImageModdedForTest(chromeos_root, image, log_level):
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800398 if log_level != 'verbose':
399 log_level = 'quiet'
Caroline Ticed0f7a732018-03-02 16:31:17 -0800400 command = 'mktemp -d'
401 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
402 _, rootfs_mp, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
403 _, stateful_mp, _ = cmd_executer.ChrootRunCommandWOutput(
404 chromeos_root, command)
405 rootfs_mp = rootfs_mp.strip()
406 stateful_mp = stateful_mp.strip()
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800407 lsb_release_file = os.path.join(rootfs_mp, 'etc/lsb-release')
Caroline Ticed0f7a732018-03-02 16:31:17 -0800408 extra = (
409 'grep CHROMEOS_RELEASE_DESCRIPTION %s | grep -i test' % lsb_release_file)
410 output = MountImage(
411 chromeos_root,
412 image,
413 rootfs_mp,
414 stateful_mp,
415 log_level,
416 extra_commands=extra)
417 is_test_image = re.search('test', output, re.IGNORECASE)
Caroline Ticef6ef4392017-04-06 17:16:05 -0700418 MountImage(
419 chromeos_root, image, rootfs_mp, stateful_mp, log_level, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700420 return is_test_image
421
422
cmtice13909242014-03-11 13:38:07 -0700423def VerifyChromeChecksum(chromeos_root, image, remote, log_level):
Caroline Ticed0f7a732018-03-02 16:31:17 -0800424 command = 'mktemp -d'
cmtice13909242014-03-11 13:38:07 -0700425 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Caroline Ticed0f7a732018-03-02 16:31:17 -0800426 _, rootfs_mp, _ = cmd_executer.ChrootRunCommandWOutput(chromeos_root, command)
427 _, stateful_mp, _ = cmd_executer.ChrootRunCommandWOutput(
428 chromeos_root, command)
429 rootfs_mp = rootfs_mp.strip()
430 stateful_mp = stateful_mp.strip()
431 chrome_file = '%s/opt/google/chrome/chrome' % rootfs_mp
432 extra = 'md5sum %s' % chrome_file
433 out = MountImage(
434 chromeos_root,
435 image,
436 rootfs_mp,
437 stateful_mp,
438 log_level,
439 extra_commands=extra)
440 image_chrome_checksum = out.strip().split()[0]
Caroline Ticef6ef4392017-04-06 17:16:05 -0700441 MountImage(
442 chromeos_root, image, rootfs_mp, stateful_mp, log_level, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700443
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800444 command = 'md5sum /opt/google/chrome/chrome'
Caroline Ticef6ef4392017-04-06 17:16:05 -0700445 [_, o, _] = cmd_executer.CrosRunCommandWOutput(
446 command, chromeos_root=chromeos_root, machine=remote)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700447 device_chrome_checksum = o.split()[0]
Manoj Gupta1d1de432019-04-26 11:30:14 -0700448 return image_chrome_checksum.strip() == device_chrome_checksum.strip()
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700449
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800450
Luis Lozanof81680c2013-03-15 14:44:13 -0700451# Remount partition as writable.
452# TODO: auto-detect if an image is built using --noenable_rootfs_verification.
cmtice13909242014-03-11 13:38:07 -0700453def TryRemountPartitionAsRW(chromeos_root, remote, log_level):
Luis Lozanof81680c2013-03-15 14:44:13 -0700454 l = logger.GetLogger()
cmtice13909242014-03-11 13:38:07 -0700455 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800456 command = 'sudo mount -o remount,rw /'
Caroline Tice88272d42016-01-13 09:48:29 -0800457 ret = cmd_executer.CrosRunCommand(\
458 command, chromeos_root=chromeos_root, machine=remote,
459 terminated_timeout=10)
460 if ret:
Luis Lozanof81680c2013-03-15 14:44:13 -0700461 ## Safely ignore.
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800462 l.LogWarning('Failed to remount partition as rw, '
463 'probably the image was not built with '
Luis Lozanof81680c2013-03-15 14:44:13 -0700464 "\"--noenable_rootfs_verification\", "
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800465 'you can safely ignore this.')
Luis Lozanof81680c2013-03-15 14:44:13 -0700466 else:
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800467 l.LogOutput('Re-mounted partition as writable.')
Luis Lozanof81680c2013-03-15 14:44:13 -0700468
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700469
cmtice13909242014-03-11 13:38:07 -0700470def EnsureMachineUp(chromeos_root, remote, log_level):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800471 l = logger.GetLogger()
cmtice13909242014-03-11 13:38:07 -0700472 cmd_executer = command_executer.GetCommandExecuter(log_level=log_level)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800473 timeout = 600
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800474 magic = 'abcdefghijklmnopqrstuvwxyz'
475 command = 'echo %s' % magic
Ahmad Sharif4467f002012-12-20 12:09:49 -0800476 start_time = time.time()
477 while True:
478 current_time = time.time()
479 if current_time - start_time > timeout:
Caroline Ticef6ef4392017-04-06 17:16:05 -0700480 l.LogError(
481 'Timeout of %ss reached. Machine still not up. Aborting.' % timeout)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800482 return False
Caroline Ticef6ef4392017-04-06 17:16:05 -0700483 ret = cmd_executer.CrosRunCommand(
484 command, chromeos_root=chromeos_root, machine=remote)
Caroline Tice88272d42016-01-13 09:48:29 -0800485 if not ret:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800486 return True
487
488
Luis Lozanof2a3ef42015-12-15 13:49:30 -0800489if __name__ == '__main__':
cmticee5bc63b2015-05-27 16:59:37 -0700490 retval = DoImage(sys.argv)
491 sys.exit(retval)