blob: 17812d4def5950ded55d3bce3d5dd7b7b3a725a5 [file] [log] [blame]
Ahmad Sharif70de27b2011-06-15 17:51:24 -07001#!/usr/bin/python2.6
2#
3# Copyright 2011 Google Inc. All Rights Reserved.
4
5"""Script to image a ChromeOS device.
6
7This script images a remote ChromeOS device with a specific image."
8"""
9
10__author__ = "asharif@google.com (Ahmad Sharif)"
11
12import filecmp
13import glob
14import optparse
15import os
16import shutil
17import sys
18import tempfile
Ahmad Sharif70de27b2011-06-15 17:51:24 -070019from utils import command_executer
20from utils import logger
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080021from utils.file_utils import FileUtils
Ahmad Sharif70de27b2011-06-15 17:51:24 -070022
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080023checksum_file = "/usr/local/osimage_checksum_file"
Ahmad Sharif70de27b2011-06-15 17:51:24 -070024
25
26def Usage(parser, message):
27 print "ERROR: " + message
28 parser.print_help()
29 sys.exit(0)
30
31def Main(argv):
32 """Build ChromeOS."""
33 # Common initializations
34 cmd_executer = command_executer.GetCommandExecuter()
35 l = logger.GetLogger()
36
37 parser = optparse.OptionParser()
38 parser.add_option("-c", "--chromeos_root", dest="chromeos_root",
39 help="Target directory for ChromeOS installation.")
40 parser.add_option("-r", "--remote", dest="remote",
41 help="Target device.")
42 parser.add_option("-i", "--image", dest="image",
43 help="Image binary file.")
44 parser.add_option("-b", "--board", dest="board",
45 help="Target board override.")
46 parser.add_option("-f", "--force", dest="force",
47 action="store_true",
48 default=False,
49 help="Force an image even if it is non-test.")
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080050 parser.add_option("-a",
51 "--image_to_live_args",
52 dest="image_to_live_args")
53
Ahmad Sharif70de27b2011-06-15 17:51:24 -070054
55 options = parser.parse_args(argv[1:])[0]
56
57 if options.chromeos_root is None:
58 Usage(parser, "--chromeos_root must be set")
59
60 if options.remote is None:
61 Usage(parser, "--remote must be set")
62
63 options.chromeos_root = os.path.expanduser(options.chromeos_root)
64
65 if options.board is None:
66 board = cmd_executer.CrosLearnBoard(options.chromeos_root, options.remote)
67 else:
68 board = options.board
69
70 if options.image is None:
71 image = (options.chromeos_root +
72 "/src/build/images/" + board +
73 "/latest/" +
74 "/chromiumos_image.bin")
75 else:
76 image = options.image
77 image = os.path.expanduser(image)
78
79 image = os.path.realpath(image)
80
81 if not os.path.exists(image):
82 Usage(parser, "Image file: " + image + " does not exist!")
83
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080084 image_checksum = FileUtils().Md5File(image)
Ahmad Sharif70de27b2011-06-15 17:51:24 -070085
86 command = "cat " + checksum_file
87 retval, device_checksum, err = cmd_executer.CrosRunCommand(command,
88 return_output=True,
89 chromeos_root=options.chromeos_root,
90 machine=options.remote)
91
92 device_checksum = device_checksum.strip()
93 image_checksum = str(image_checksum)
94
95 l.LogOutput("Image checksum: " + image_checksum)
96 l.LogOutput("Device checksum: " + device_checksum)
97
98 if image_checksum != device_checksum:
99 [found, located_image] = LocateOrCopyImage(options.chromeos_root,
100 image,
101 board=board)
102
103 l.LogOutput("Checksums do not match. Re-imaging...")
104
105 is_test_image = IsImageModdedForTest(options.chromeos_root,
106 located_image)
107
108 if not is_test_image and not options.force:
109 logger.GetLogger().LogFatal("Have to pass --force to image a non-test "
110 "image!")
111
112 # If the device has /tmp mounted as noexec, image_to_live.sh can fail.
113 command = "mount -o remount,rw,exec /tmp"
114 cmd_executer.CrosRunCommand(command,
115 chromeos_root=options.chromeos_root,
116 machine=options.remote)
117
118 command = (options.chromeos_root +
119 "/src/scripts/image_to_live.sh --remote=" +
120 options.remote +
121 " --image=" + located_image)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800122 if options.image_to_live_args:
123 command += " %s" % options.image_to_live_args
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700124
125 retval = cmd_executer.RunCommand(command)
126
127 if found == False:
128 temp_dir = os.path.dirname(located_image)
129 l.LogOutput("Deleting temp image dir: %s" % temp_dir)
130 shutil.rmtree(temp_dir)
131
132 logger.GetLogger().LogFatalIf(retval, "Image command failed")
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800133 command = "echo %s > %s && chmod -w %s" % (image_checksum, checksum_file,
134 checksum_file)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700135 retval = cmd_executer.CrosRunCommand(command,
136 chromeos_root=options.chromeos_root,
137 machine=options.remote)
138 logger.GetLogger().LogFatalIf(retval, "Writing checksum failed.")
139
140 successfully_imaged = VerifyChromeChecksum(options.chromeos_root,
141 image,
142 options.remote)
143 logger.GetLogger().LogFatalIf(not successfully_imaged,
144 "Image verification failed!")
145 else:
146 l.LogOutput("Checksums match. Skipping reimage")
147
148 return retval
149
150
151def LocateOrCopyImage(chromeos_root, image, board=None):
152 l = logger.GetLogger()
153 if board is None:
154 board_glob = "*"
155 else:
156 board_glob = board
157
158 chromeos_root_realpath = os.path.realpath(chromeos_root)
159 image = os.path.realpath(image)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800160
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700161 if image.startswith("%s/" % chromeos_root_realpath):
162 return [True, image]
163
164 # First search within the existing build dirs for any matching files.
165 images_glob = ("%s/src/build/images/%s/*/*.bin" %
166 (chromeos_root_realpath,
167 board_glob))
168 images_list = glob.glob(images_glob)
169 for potential_image in images_list:
170 if filecmp.cmp(potential_image, image):
171 l.LogOutput("Found matching image %s in chromeos_root." % potential_image)
172 return [True, potential_image]
173 # We did not find an image. Copy it in the src dir and return the copied file.
174 if board is None:
175 board = ""
176 base_dir = ("%s/src/build/images/%s" %
177 (chromeos_root_realpath,
178 board))
179 if not os.path.isdir(base_dir):
180 os.makedirs(base_dir)
181 temp_dir = tempfile.mkdtemp(prefix="%s/tmp" % base_dir)
182 new_image = "%s/%s" % (temp_dir, os.path.basename(image))
183 l.LogOutput("No matching image found. Copying %s to %s" %
184 (image, new_image))
185 shutil.copyfile(image, new_image)
186 return [False, new_image]
187
188
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800189def GetImageMountCommand(chromeos_root, image, rootfs_mp, stateful_mp):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700190 image_dir = os.path.dirname(image)
191 image_file = os.path.basename(image)
192 mount_command = ("cd %s/src/scripts &&"
193 "./mount_gpt_image.sh --from=%s --image=%s"
194 " --safe --read_only"
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800195 " --rootfs_mountpt=%s"
196 " --stateful_mountpt=%s" %
197 (chromeos_root, image_dir, image_file, rootfs_mp,
198 stateful_mp))
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700199 return mount_command
200
201
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800202def MountImage(chromeos_root, image, rootfs_mp, stateful_mp, unmount=False):
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700203 cmd_executer = command_executer.GetCommandExecuter()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800204 command = GetImageMountCommand(chromeos_root, image, rootfs_mp, stateful_mp)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700205 if unmount:
206 command = "%s --unmount" % command
207 retval = cmd_executer.RunCommand(command)
208 logger.GetLogger().LogFatalIf(retval, "Mount/unmount command failed!")
209 return retval
210
211
212def IsImageModdedForTest(chromeos_root, image):
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800213 rootfs_mp = tempfile.mkdtemp()
214 stateful_mp = tempfile.mkdtemp()
215 MountImage(chromeos_root, image, rootfs_mp, stateful_mp)
216 lsb_release_file = os.path.join(rootfs_mp, "etc/lsb-release")
217 is_test_image = "Test Build" in open(lsb_release_file).read()
218 MountImage(chromeos_root, image, rootfs_mp, stateful_mp, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700219 return is_test_image
220
221
222def VerifyChromeChecksum(chromeos_root, image, remote):
223 cmd_executer = command_executer.GetCommandExecuter()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800224 rootfs_mp = tempfile.mkdtemp()
225 stateful_mp = tempfile.mkdtemp()
226 MountImage(chromeos_root, image, rootfs_mp, stateful_mp)
227 image_chrome_checksum = FileUtils().Md5File("%s/opt/google/chrome/chrome" %
228 rootfs_mp)
229 MountImage(chromeos_root, image, rootfs_mp, stateful_mp, unmount=True)
Ahmad Sharif70de27b2011-06-15 17:51:24 -0700230
231 command = "md5sum /opt/google/chrome/chrome"
232 [r, o, e] = cmd_executer.CrosRunCommand(command,
233 return_output=True,
234 chromeos_root=chromeos_root,
235 machine=remote)
236 device_chrome_checksum = o.split()[0]
237 if image_chrome_checksum.strip() == device_chrome_checksum.strip():
238 return True
239 else:
240 return False
241
242
243if __name__ == "__main__":
244 retval = Main(sys.argv)
245 sys.exit(retval)