blob: a346a7709a3e4aee64cd29a094add123c0d06f96 [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
19import tc_enter_chroot
20from utils import command_executer
21from utils import logger
22from utils import utils
23
24checksum_file = "/home/chronos/osimage_checksum_file"
25
26
27def Usage(parser, message):
28 print "ERROR: " + message
29 parser.print_help()
30 sys.exit(0)
31
32def Main(argv):
33 """Build ChromeOS."""
34 # Common initializations
35 cmd_executer = command_executer.GetCommandExecuter()
36 l = logger.GetLogger()
37
38 parser = optparse.OptionParser()
39 parser.add_option("-c", "--chromeos_root", dest="chromeos_root",
40 help="Target directory for ChromeOS installation.")
41 parser.add_option("-r", "--remote", dest="remote",
42 help="Target device.")
43 parser.add_option("-i", "--image", dest="image",
44 help="Image binary file.")
45 parser.add_option("-b", "--board", dest="board",
46 help="Target board override.")
47 parser.add_option("-f", "--force", dest="force",
48 action="store_true",
49 default=False,
50 help="Force an image even if it is non-test.")
51
52 options = parser.parse_args(argv[1:])[0]
53
54 if options.chromeos_root is None:
55 Usage(parser, "--chromeos_root must be set")
56
57 if options.remote is None:
58 Usage(parser, "--remote must be set")
59
60 options.chromeos_root = os.path.expanduser(options.chromeos_root)
61
62 if options.board is None:
63 board = cmd_executer.CrosLearnBoard(options.chromeos_root, options.remote)
64 else:
65 board = options.board
66
67 if options.image is None:
68 image = (options.chromeos_root +
69 "/src/build/images/" + board +
70 "/latest/" +
71 "/chromiumos_image.bin")
72 else:
73 image = options.image
74 image = os.path.expanduser(image)
75
76 image = os.path.realpath(image)
77
78 if not os.path.exists(image):
79 Usage(parser, "Image file: " + image + " does not exist!")
80
81 image_checksum = utils.Md5File(image)
82
83 command = "cat " + checksum_file
84 retval, device_checksum, err = cmd_executer.CrosRunCommand(command,
85 return_output=True,
86 chromeos_root=options.chromeos_root,
87 machine=options.remote)
88
89 device_checksum = device_checksum.strip()
90 image_checksum = str(image_checksum)
91
92 l.LogOutput("Image checksum: " + image_checksum)
93 l.LogOutput("Device checksum: " + device_checksum)
94
95 if image_checksum != device_checksum:
96 [found, located_image] = LocateOrCopyImage(options.chromeos_root,
97 image,
98 board=board)
99
100 l.LogOutput("Checksums do not match. Re-imaging...")
101
102 is_test_image = IsImageModdedForTest(options.chromeos_root,
103 located_image)
104
105 if not is_test_image and not options.force:
106 logger.GetLogger().LogFatal("Have to pass --force to image a non-test "
107 "image!")
108
109 # If the device has /tmp mounted as noexec, image_to_live.sh can fail.
110 command = "mount -o remount,rw,exec /tmp"
111 cmd_executer.CrosRunCommand(command,
112 chromeos_root=options.chromeos_root,
113 machine=options.remote)
114
115 command = (options.chromeos_root +
116 "/src/scripts/image_to_live.sh --remote=" +
117 options.remote +
118 " --image=" + located_image)
119
120 retval = cmd_executer.RunCommand(command)
121
122 if found == False:
123 temp_dir = os.path.dirname(located_image)
124 l.LogOutput("Deleting temp image dir: %s" % temp_dir)
125 shutil.rmtree(temp_dir)
126
127 logger.GetLogger().LogFatalIf(retval, "Image command failed")
128 command = "'echo " + image_checksum + " > " + checksum_file
129 command += "&& chmod -w " + checksum_file + "'"
130 retval = cmd_executer.CrosRunCommand(command,
131 chromeos_root=options.chromeos_root,
132 machine=options.remote)
133 logger.GetLogger().LogFatalIf(retval, "Writing checksum failed.")
134
135 successfully_imaged = VerifyChromeChecksum(options.chromeos_root,
136 image,
137 options.remote)
138 logger.GetLogger().LogFatalIf(not successfully_imaged,
139 "Image verification failed!")
140 else:
141 l.LogOutput("Checksums match. Skipping reimage")
142
143 return retval
144
145
146def LocateOrCopyImage(chromeos_root, image, board=None):
147 l = logger.GetLogger()
148 if board is None:
149 board_glob = "*"
150 else:
151 board_glob = board
152
153 chromeos_root_realpath = os.path.realpath(chromeos_root)
154 image = os.path.realpath(image)
155
156 if image.startswith("%s/" % chromeos_root_realpath):
157 return [True, image]
158
159 # First search within the existing build dirs for any matching files.
160 images_glob = ("%s/src/build/images/%s/*/*.bin" %
161 (chromeos_root_realpath,
162 board_glob))
163 images_list = glob.glob(images_glob)
164 for potential_image in images_list:
165 if filecmp.cmp(potential_image, image):
166 l.LogOutput("Found matching image %s in chromeos_root." % potential_image)
167 return [True, potential_image]
168 # We did not find an image. Copy it in the src dir and return the copied file.
169 if board is None:
170 board = ""
171 base_dir = ("%s/src/build/images/%s" %
172 (chromeos_root_realpath,
173 board))
174 if not os.path.isdir(base_dir):
175 os.makedirs(base_dir)
176 temp_dir = tempfile.mkdtemp(prefix="%s/tmp" % base_dir)
177 new_image = "%s/%s" % (temp_dir, os.path.basename(image))
178 l.LogOutput("No matching image found. Copying %s to %s" %
179 (image, new_image))
180 shutil.copyfile(image, new_image)
181 return [False, new_image]
182
183
184def GetImageMountCommand(chromeos_root, image, mount_point):
185 image_dir = os.path.dirname(image)
186 image_file = os.path.basename(image)
187 mount_command = ("cd %s/src/scripts &&"
188 "./mount_gpt_image.sh --from=%s --image=%s"
189 " --safe --read_only"
190 " --rootfs_mountpt=%s" %
191 (chromeos_root, image_dir, image_file, mount_point))
192 return mount_command
193
194
195def MountImage(chromeos_root, image, mount_point, unmount=False):
196 cmd_executer = command_executer.GetCommandExecuter()
197 command = GetImageMountCommand(chromeos_root, image, mount_point)
198 if unmount:
199 command = "%s --unmount" % command
200 retval = cmd_executer.RunCommand(command)
201 logger.GetLogger().LogFatalIf(retval, "Mount/unmount command failed!")
202 return retval
203
204
205def IsImageModdedForTest(chromeos_root, image):
206 mount_point = tempfile.mkdtemp()
207 MountImage(chromeos_root, image, mount_point)
208 signature_file = "/usr/local/lib/python2.6/test/autotest.py"
209 is_test_image = os.path.isfile("%s/%s" % (mount_point, signature_file))
210 MountImage(chromeos_root, image, mount_point, unmount=True)
211 return is_test_image
212
213
214def VerifyChromeChecksum(chromeos_root, image, remote):
215 cmd_executer = command_executer.GetCommandExecuter()
216 mount_point = tempfile.mkdtemp()
217 MountImage(chromeos_root, image, mount_point)
218 image_chrome_checksum = utils.Md5File("%s/opt/google/chrome/chrome" %
219 mount_point)
220 MountImage(chromeos_root, image, mount_point, unmount=True)
221
222 command = "md5sum /opt/google/chrome/chrome"
223 [r, o, e] = cmd_executer.CrosRunCommand(command,
224 return_output=True,
225 chromeos_root=chromeos_root,
226 machine=remote)
227 device_chrome_checksum = o.split()[0]
228 if image_chrome_checksum.strip() == device_chrome_checksum.strip():
229 return True
230 else:
231 return False
232
233
234if __name__ == "__main__":
235 retval = Main(sys.argv)
236 sys.exit(retval)