Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: autoupdate.py

Issue 4906001: Reworked devserver so that update images generated are cached in directories named after (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/dev-util.git@master
Patch Set: Removed workaround for bug chromium-os:9073. Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | autoupdate_unittest.py » ('j') | devserver.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from buildutil import BuildObject 5 from buildutil import BuildObject
6 from xml.dom import minidom 6 from xml.dom import minidom
7
7 import cherrypy 8 import cherrypy
8 import os 9 import os
9 import shutil 10 import shutil
10 import subprocess 11 import socket
11 import tempfile
12 import time 12 import time
13 13
14
15 def _LogMessage(message): 14 def _LogMessage(message):
16 cherrypy.log(message, 'UPDATE') 15 cherrypy.log(message, 'UPDATE')
17 16
18 17
19 class Autoupdate(BuildObject): 18 class Autoupdate(BuildObject):
20 """Class that contains functionality that handles Chrome OS update pings. 19 """Class that contains functionality that handles Chrome OS update pings.
21 20
22 Members: 21 Members:
23 serve_only: Serve images from a pre-built image.zip file. static_dir 22 serve_only: Serve images from a pre-built image.zip file. static_dir
24 must be set to the location of the image.zip. 23 must be set to the location of the image.zip.
(...skipping 17 matching lines...) Expand all
42 self.urlbase = urlbase 41 self.urlbase = urlbase
43 else: 42 else:
44 self.urlbase = None 43 self.urlbase = None
45 44
46 self.client_prefix = client_prefix 45 self.client_prefix = client_prefix
47 self.forced_image = forced_image 46 self.forced_image = forced_image
48 self.use_cached = use_cached 47 self.use_cached = use_cached
49 self.src_image = src_image 48 self.src_image = src_image
50 self.vm = vm 49 self.vm = vm
51 self.board = board 50 self.board = board
52 self.crosutils = os.path.join(os.path.dirname(__file__), '../../scripts')
53 51
54 def _GetSecondsSinceMidnight(self): 52 def _GetSecondsSinceMidnight(self):
55 """Returns the seconds since midnight as a decimal value.""" 53 """Returns the seconds since midnight as a decimal value."""
56 now = time.localtime() 54 now = time.localtime()
57 return now[3] * 3600 + now[4] * 60 + now[5] 55 return now[3] * 3600 + now[4] * 60 + now[5]
58 56
59 def _GetDefaultBoardID(self): 57 def _GetDefaultBoardID(self):
60 """Returns the default board id stored in .default_board.""" 58 """Returns the default board id stored in .default_board."""
61 board_file = '%s/.default_board' % (self.scripts_dir) 59 board_file = '%s/.default_board' % (self.scripts_dir)
62 try: 60 try:
(...skipping 16 matching lines...) Expand all
79 client_tokens = client_version.replace('_', '').split('.') 77 client_tokens = client_version.replace('_', '').split('.')
80 latest_tokens = latest_version.replace('_', '').split('.') 78 latest_tokens = latest_version.replace('_', '').split('.')
81 _LogMessage('client version %s latest version %s' 79 _LogMessage('client version %s latest version %s'
82 % (client_version, latest_version)) 80 % (client_version, latest_version))
83 for i in range(4): 81 for i in range(4):
84 if int(latest_tokens[i]) == int(client_tokens[i]): 82 if int(latest_tokens[i]) == int(client_tokens[i]):
85 continue 83 continue
86 return int(latest_tokens[i]) > int(client_tokens[i]) 84 return int(latest_tokens[i]) > int(client_tokens[i])
87 return False 85 return False
88 86
87 def _UnpackStatefulPartition(self, image_path, stateful_file):
88 """Given an image, unpacks its stateful partition to stateful_file."""
89 image_dir = os.path.dirname(image_path)
90 image_file = os.path.basename(image_path)
91
92 get_offset = '$(cgpt show -b -i 1 %s)' % image_file
93 get_size = '$(cgpt show -s -i 1 %s)' % image_file
94 unpack_command = (
95 'cd %s && '
96 'dd if=%s of=%s bs=512 skip=%s count=%s' % (image_dir, image_file,
97 stateful_file, get_offset,
98 get_size))
99 _LogMessage(unpack_command)
100 return os.system(unpack_command) == 0
101
89 def _UnpackZip(self, image_dir): 102 def _UnpackZip(self, image_dir):
90 """Unpacks an image.zip into a given directory.""" 103 """Unpacks an image.zip into a given directory."""
91 image = os.path.join(image_dir, self._GetImageName()) 104 image = os.path.join(image_dir, self._GetImageName())
92 if os.path.exists(image): 105 if os.path.exists(image):
93 return True 106 return True
94 else: 107 else:
95 # -n, never clobber an existing file, in case we get invoked 108 # -n, never clobber an existing file, in case we get invoked
96 # simultaneously by multiple request handlers. This means that 109 # simultaneously by multiple request handlers. This means that
97 # we're assuming each image.zip file lives in a versioned 110 # we're assuming each image.zip file lives in a versioned
98 # directory (a la Buildbot). 111 # directory (a la Buildbot).
99 return os.system('cd %s && unzip -n image.zip' % image_dir) == 0 112 return os.system('cd %s && unzip -n image.zip' % image_dir) == 0
100 113
101 def _GetImageName(self): 114 def _GetImageName(self):
102 """Returns the name of the image that should be used.""" 115 """Returns the name of the image that should be used."""
103 if self.use_test_image: 116 if self.use_test_image:
104 image_name = 'chromiumos_test_image.bin' 117 image_name = 'chromiumos_test_image.bin'
105 else: 118 else:
106 image_name = 'chromiumos_image.bin' 119 image_name = 'chromiumos_image.bin'
107 return image_name 120 return image_name
108 121
109 def _IsImageNewerThanCached(self, image_path, cached_file_path):
110 """Returns true if the image is newer than the cached image."""
111 if os.path.exists(cached_file_path) and os.path.exists(image_path):
112 _LogMessage('Usable cached image found at %s.' % cached_file_path)
113 return os.path.getmtime(image_path) > os.path.getmtime(cached_file_path)
114 elif not os.path.exists(cached_file_path) and not os.path.exists(image_path) :
115 raise Exception('Image does not exist and cached image missing')
116 else:
117 # Only one is missing, figure out which one.
118 if os.path.exists(image_path):
119 _LogMessage('No cached image found - image generation required.')
120 return True
121 else:
122 _LogMessage('Cached image found to serve at %s.' % cached_file_path)
123 return False
124
125 def _GetSize(self, update_path): 122 def _GetSize(self, update_path):
126 """Returns the size of the file given.""" 123 """Returns the size of the file given."""
127 return os.path.getsize(update_path) 124 return os.path.getsize(update_path)
128 125
129 def _GetHash(self, update_path): 126 def _GetHash(self, update_path):
130 """Returns the sha1 of the file given.""" 127 """Returns the sha1 of the file given."""
131 cmd = ('cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';' 128 cmd = ('cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';'
132 % update_path) 129 % update_path)
133 return os.popen(cmd).read().rstrip() 130 return os.popen(cmd).read().rstrip()
134 131
(...skipping 10 matching lines...) Expand all
145 # it takes advantage of reduced I/O and multiple processors. Something like: 142 # it takes advantage of reduced I/O and multiple processors. Something like:
146 # % tee < FILE > /dev/null \ 143 # % tee < FILE > /dev/null \
147 # >( openssl dgst -sha256 -binary | openssl base64 ) \ 144 # >( openssl dgst -sha256 -binary | openssl base64 ) \
148 # >( openssl sha1 -binary | openssl base64 ) 145 # >( openssl sha1 -binary | openssl base64 )
149 def _GetSHA256(self, update_path): 146 def _GetSHA256(self, update_path):
150 """Returns the sha256 of the file given.""" 147 """Returns the sha256 of the file given."""
151 cmd = ('cat %s | openssl dgst -sha256 -binary | openssl base64' % 148 cmd = ('cat %s | openssl dgst -sha256 -binary | openssl base64' %
152 update_path) 149 update_path)
153 return os.popen(cmd).read().rstrip() 150 return os.popen(cmd).read().rstrip()
154 151
152 def _GetMd5(self, update_path):
153 """Returns the md5 checksum of the file given."""
154 cmd = ("md5sum %s | awk '{print $1}'" % update_path)
155 return os.popen(cmd).read().rstrip()
156
155 def GetUpdatePayload(self, hash, sha256, size, url, is_delta_format): 157 def GetUpdatePayload(self, hash, sha256, size, url, is_delta_format):
156 """Returns a payload to the client corresponding to a new update. 158 """Returns a payload to the client corresponding to a new update.
157 159
158 Args: 160 Args:
159 hash: hash of update blob 161 hash: hash of update blob
160 sha256: SHA-256 hash of update blob 162 sha256: SHA-256 hash of update blob
161 size: size of update blob 163 size: size of update blob
162 url: where to find update blob 164 url: where to find update blob
163 Returns: 165 Returns:
164 Xml string to be passed back to client. 166 Xml string to be passed back to client.
(...skipping 26 matching lines...) Expand all
191 < gupdate xmlns = "http://www.google.com/update2/response" protocol = "2.0 " > 193 < gupdate xmlns = "http://www.google.com/update2/response" protocol = "2.0 " >
192 < daystart elapsed_seconds = "%s" /> 194 < daystart elapsed_seconds = "%s" />
193 < app appid = "{%s}" status = "ok" > 195 < app appid = "{%s}" status = "ok" >
194 < ping status = "ok" /> 196 < ping status = "ok" />
195 < updatecheck status = "noupdate" /> 197 < updatecheck status = "noupdate" />
196 </ app > 198 </ app >
197 </ gupdate > 199 </ gupdate >
198 """ 200 """
199 return payload % (self._GetSecondsSinceMidnight(), self.app_id) 201 return payload % (self._GetSecondsSinceMidnight(), self.app_id)
200 202
201 def GenerateUpdateFile(self, image_path): 203 def GenerateUpdateFile(self, src_image, image_path, static_image_dir):
202 """Generates an update gz given a full path to an image. 204 """Generates an update gz given a full path to an image.
203 205
204 Args: 206 Args:
205 image_path: Full path to image. 207 image_path: Full path to image.
206 Returns: 208 Returns:
207 Path to created update_payload or None on error. 209 Path to created update_payload or None on error.
208 """ 210 """
209 image_dir = os.path.dirname(image_path) 211 image_dir = os.path.dirname(image_path)
210 update_path = os.path.join(image_dir, 'update.gz') 212 update_path = os.path.join(static_image_dir, 'update.gz')
petkov 2010/11/13 00:55:18 Since you're updating this stuff, maybe we should
dgarrett 2010/11/15 21:50:33 This sounds good to me, but I'm not certain what e
211 patch_kernel_flag = '--patch_kernel' 213 patch_kernel_flag = '--patch_kernel'
212 _LogMessage('Generating update image %s' % update_path) 214 _LogMessage('Generating update image %s' % update_path)
213 215
214 # Don't patch the kernel for vm images as they don't need the patch. 216 # Don't patch the kernel for vm images as they don't need the patch.
215 if self.vm: 217 if self.vm:
216 patch_kernel_flag = '' 218 patch_kernel_flag = ''
217 219
218 mkupdate_command = ( 220 mkupdate_command = (
219 '%s/cros_generate_update_payload --image="%s" --output="%s" ' 221 '%s/cros_generate_update_payload --image="%s" --output="%s" '
220 '%s --noold_style --src_image="%s"' % ( 222 '%s --noold_style --src_image="%s"' % (
221 self.scripts_dir, image_path, update_path, patch_kernel_flag, 223 self.scripts_dir, image_path, update_path, patch_kernel_flag,
222 self.src_image)) 224 src_image))
223 _LogMessage(mkupdate_command) 225 _LogMessage(mkupdate_command)
224 if os.system(mkupdate_command) != 0: 226 if os.system(mkupdate_command) != 0:
225 _LogMessage('Failed to create base update file') 227 _LogMessage('Failed to create base update file')
226 return None 228 return None
227 229
228 return update_path 230 return update_path
229 231
230 def GenerateStatefulFile(self, image_path): 232 def GenerateStatefulFile(self, image_path, static_image_dir):
petkov 2010/11/13 00:55:18 Why are you not calling ./cros_generate_stateful_u
dgarrett 2010/11/15 21:50:33 Because I was reading the wrong side of a merge as
231 """Generates a stateful update given a full path to an image. 233 """Generates a stateful update gz given a full path to an image.
232 234
233 Args: 235 Args:
234 image_path: Full path to image. 236 image_path: Full path to image.
235 Returns: 237 Returns:
236 Path to created stateful update_payload. 238 Path to created stateful update_payload or None on error.
237 Raises:
238 A subprocess exception if the update generator fails to generate a
239 stateful payload.
240 """ 239 """
241 work_dir = os.path.dirname(image_path) 240 stateful_partition_path = os.path.join(os.path.dirname(image_path),
242 output_gz = os.path.join(work_dir, 'stateful.tgz') 241 'stateful.image')
243 subprocess.check_call(
244 ['%s/cros_generate_stateful_update_payload' % self.crosutils,
245 '--image=%s' % image_path,
246 '--output_dir=%s' % work_dir,
247 ])
248 return output_gz
249 242
250 def MoveImagesToStaticDir(self, update_path, stateful_update_path, 243 output_file = os.path.join(static_image_dir,
251 static_image_dir): 244 'stateful.image.gz')
252 """Moves gz files from their directories to serving directories.
253 245
254 Args: 246 # Unpack to get stateful partition.
255 update_path: full path to main update gz. 247 if self._UnpackStatefulPartition(image_path, stateful_partition_path):
256 stateful_update_path: full path to stateful partition gz. 248 cmd = 'gzip --stdout %s > %s' % (stateful_partition_path, output_file)
257 static_image_dir: where to put files. 249 if os.system(cmd) == 0:
258 Returns: 250 _LogMessage('Successfully generated %s' % output_file)
259 Returns True if the files were moved over successfully. 251 return output_file
260 """
261 try:
262 shutil.copy(update_path, static_image_dir)
263 shutil.copy(stateful_update_path, static_image_dir)
264 os.remove(update_path)
265 os.remove(stateful_update_path)
266 except Exception:
267 _LogMessage('Failed to move %s and %s to %s' % (update_path,
268 stateful_update_path,
269 static_image_dir))
270 return False
271 252
272 return True 253 _LogMessage('Failed to create stateful update file')
254 return None
273 255
274 def GenerateUpdateImage(self, image_path, move_to_static_dir=False, 256 def FindCachedUpdateImageSubDir(self, src_image, dest_image):
275 static_image_dir=None): 257 """Given one, or two images for an update, this finds which
petkov 2010/11/13 00:55:18 I think Python style is one summary line. Then fol
276 """Generates an update payload based on the given image_path. 258 cache directory should hold the udpate files, even if they don't exist ye t.
petkov 2010/11/13 00:55:18 80 chars
259 The directory will be inside static_image_dir, and of the form:
260
261 Non-delta updates:
262 cache/12345678
263
264 Delta updates:
265 cache/12345678_12345678
266 """
267
268 # If there is no src, we only have an image file, check image for changes
269 if not src_image:
270 return os.path.join('cache', self._GetMd5(dest_image))
271
272 # If we have src and dest, we are a delta, and check both for changes
273 return os.path.join('cache',
274 "%s_%s" % (self._GetMd5(src_image),
275 self._GetMd5(dest_image)))
276
277 def GenerateUpdateImage(self, src_image, image_path, static_image_dir):
278 """Force generates an update payload based on the given image_path.
277 279
278 Args: 280 Args:
279 image_path: full path to the image. 281 image_path: full path to the image.
280 move_to_static_dir: Moves the files from their dir to the static dir. 282 move_to_static_dir: Moves the files from their dir to the static dir.
281 static_image_dir: the directory to move images to after generating. 283 static_image_dir: the directory to move images to after generating.
282 Returns: 284 Returns:
283 True if the update payload was created successfully. 285 update filename (not directory) on success, or None
284 """ 286 """
287
288 update_file = None
289 stateful_update_file = None
290
291 # Actually do the generation
285 _LogMessage('Generating update for image %s' % image_path) 292 _LogMessage('Generating update for image %s' % image_path)
286 update_path = self.GenerateUpdateFile(image_path) 293 update_file = self.GenerateUpdateFile(src_image,
287 if update_path: 294 image_path,
288 stateful_update_path = self.GenerateStatefulFile(image_path)
289 if move_to_static_dir:
290 return self.MoveImagesToStaticDir(update_path, stateful_update_path,
291 static_image_dir) 295 static_image_dir)
292 return True 296
297 if update_file:
298 stateful_update_file = self.GenerateStatefulFile(image_path,
299 static_image_dir)
300
301 if update_file and stateful_update_file:
302 return os.path.basename(update_file)
293 303
294 _LogMessage('Failed to generate update') 304 _LogMessage('Failed to generate update')
295 return False 305
306 # Cleanup incomplete files, if they exist
307 if update_file and os.path.exists(update_file):
308 os.remove(update_file)
309
310 if stateful_update_file and os.path.exists(stateful_update_file):
311 os.remove(stateful_update_file)
312
313 return None
314
315 def GenerateUpdateImageWithCache(self, image_path, static_image_dir):
316 """Force generates an update payload based on the given image_path.
317
318 Args:
319 image_path: full path to the image.
320 move_to_static_dir: Moves the files from their dir to the static dir.
321 static_image_dir: the directory to move images to after generating.
322 Returns:
323 update filename (not directory) relative to static_image_dir on success,
324 or None
325 """
326
327 _LogMessage('Generating update for src %s image %s' % (self.src_image,
328 image_path))
329
330 # Which sub_dir of static_image_dir should hold our cached update image
331 cache_sub_dir = self.FindCachedUpdateImageSubDir(self.src_image, image_path)
332 _LogMessage('Caching in sub_dir "%s"' % cache_sub_dir)
333
334 # Check for a cached image to use
335 if os.path.exists(os.path.join(static_image_dir, cache_sub_dir, 'update.gz') ):
petkov 2010/11/13 00:55:18 80 chars
336 return os.path.join(cache_sub_dir, 'update.gz')
337
338 full_cache_dir = os.path.join(static_image_dir, cache_sub_dir)
339 src_image = ""
340 dest_image = os.path.join(full_cache_dir, 'dest_image.bin')
341
342 # Create the directory for the cache values
343 if not os.path.exists(full_cache_dir):
344 os.makedirs(full_cache_dir)
345
346 gen_image = self.GenerateUpdateImage(self.src_image,
347 image_path,
348 full_cache_dir)
349
350 # If the generation worked
351 if gen_image:
352 return os.path.join(cache_sub_dir, gen_image)
353 else:
354 return None
355
296 356
297 def GenerateLatestUpdateImage(self, board_id, client_version, 357 def GenerateLatestUpdateImage(self, board_id, client_version,
298 static_image_dir=None): 358 static_image_dir):
299 """Generates an update using the latest image that has been built. 359 """Generates an update using the latest image that has been built.
300 360
301 This will only generate an update if the newest update is newer than that 361 This will only generate an update if the newest update is newer than that
302 on the client or client_version is 'ForcedUpdate'. 362 on the client or client_version is 'ForcedUpdate'.
303 363
304 Args: 364 Args:
305 board_id: Name of the board. 365 board_id: Name of the board.
306 client_version: Current version of the client or 'ForcedUpdate' 366 client_version: Current version of the client or 'ForcedUpdate'
307 static_image_dir: the directory to move images to after generating. 367 static_image_dir: the directory to move images to after generating.
308 Returns: 368 Returns:
309 True if the update payload was created successfully. 369 Name of the update image relative to static_image_dir or None
310 """ 370 """
311 latest_image_dir = self._GetLatestImageDir(board_id) 371 latest_image_dir = self._GetLatestImageDir(board_id)
312 latest_version = self._GetVersionFromDir(latest_image_dir) 372 latest_version = self._GetVersionFromDir(latest_image_dir)
313 latest_image_path = os.path.join(latest_image_dir, self._GetImageName()) 373 latest_image_path = os.path.join(latest_image_dir, self._GetImageName())
314 374
315 _LogMessage('Preparing to generate update from latest built image %s.' % 375 _LogMessage('Preparing to generate update from latest built image %s.' %
316 latest_image_path) 376 latest_image_path)
317 377
318 # Check to see whether or not we should update. 378 # Check to see whether or not we should update.
319 if client_version != 'ForcedUpdate' and not self._CanUpdate( 379 if client_version != 'ForcedUpdate' and not self._CanUpdate(
320 client_version, latest_version): 380 client_version, latest_version):
321 _LogMessage('no update') 381 _LogMessage('no update')
322 return False 382 return None
323 383
324 cached_file_path = os.path.join(static_image_dir, 'update.gz') 384 return self.GenerateUpdateImageWithCache(latest_image_path,
325 if (os.path.exists(cached_file_path) and 385 static_image_dir=static_image_dir)
326 not self._IsImageNewerThanCached(latest_image_path, cached_file_path)):
327 return True
328
329 return self.GenerateUpdateImage(latest_image_path, move_to_static_dir=True,
330 static_image_dir=static_image_dir)
331 386
332 def GenerateImageFromZip(self, static_image_dir): 387 def GenerateImageFromZip(self, static_image_dir):
333 """Generates an update from an image zip file. 388 """Generates an update from an image zip file.
334 389
335 This method assumes you have an image.zip in directory you are serving 390 This method assumes you have an image.zip in directory you are serving
336 from. If this file is newer than a previously cached file, it will unzip 391 from. If this file is newer than a previously cached file, it will unzip
337 this file, create a payload and serve it. 392 this file, create a payload and serve it.
338 393
339 Args: 394 Args:
340 static_image_dir: Directory where the zip file exists. 395 static_image_dir: Directory where the zip file exists.
341 Returns: 396 Returns:
342 True if the update payload was created successfully. 397 Name of the update payload relative to static_image_dir if successful.
343 """ 398 """
344 _LogMessage('Preparing to generate update from zip in %s.' % static_image_di r) 399 _LogMessage('Preparing to generate update from zip in %s.' % static_image_di r)
345 image_path = os.path.join(static_image_dir, self._GetImageName()) 400 image_path = os.path.join(static_image_dir, self._GetImageName())
346 cached_file_path = os.path.join(static_image_dir, 'update.gz')
347 zip_file_path = os.path.join(static_image_dir, 'image.zip') 401 zip_file_path = os.path.join(static_image_dir, 'image.zip')
348 if not self._IsImageNewerThanCached(zip_file_path, cached_file_path): 402
349 return True 403 # XXX Work this into new path
petkov 2010/11/13 00:55:18 Remove this comment along with the commented code?
404 #cached_file_path = os.path.join(static_image_dir, 'update.gz')
405 #if not self._IsImageNewerThanCached(zip_file_path, cached_file_path):
406 # return 'update.gz'
350 407
351 if not self._UnpackZip(static_image_dir): 408 if not self._UnpackZip(static_image_dir):
352 _LogMessage('unzip image.zip failed.') 409 _LogMessage('unzip image.zip failed.')
353 return False 410 return None
354 411
355 return self.GenerateUpdateImage(image_path, move_to_static_dir=False, 412 return self.GenerateUpdateImageWithCache(image_path,
356 static_image_dir=None) 413 static_image_dir=static_image_dir)
357 414
358 def ImportFactoryConfigFile(self, filename, validate_checksums=False): 415 def ImportFactoryConfigFile(self, filename, validate_checksums=False):
359 """Imports a factory-floor server configuration file. The file should 416 """Imports a factory-floor server configuration file. The file should
360 be in this format: 417 be in this format:
361 config = [ 418 config = [
362 { 419 {
363 'qual_ids': set([1, 2, 3, "x86-generic"]), 420 'qual_ids': set([1, 2, 3, "x86-generic"]),
364 'factory_image': 'generic-factory.gz', 421 'factory_image': 'generic-factory.gz',
365 'factory_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=', 422 'factory_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=',
366 'release_image': 'generic-release.gz', 423 'release_image': 'generic-release.gz',
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 return self.GetNoUpdatePayload() 500 return self.GetNoUpdatePayload()
444 url = '%s/static/%s' % (self.hostname, filename) 501 url = '%s/static/%s' % (self.hostname, filename)
445 is_delta_format = self._IsDeltaFormatFile(filename) 502 is_delta_format = self._IsDeltaFormatFile(filename)
446 _LogMessage('returning update payload ' + url) 503 _LogMessage('returning update payload ' + url)
447 # Factory install is using memento updater which is using the sha-1 hash so 504 # Factory install is using memento updater which is using the sha-1 hash so
448 # setting sha-256 to an empty string. 505 # setting sha-256 to an empty string.
449 return self.GetUpdatePayload(checksum, '', size, url, is_delta_format) 506 return self.GetUpdatePayload(checksum, '', size, url, is_delta_format)
450 507
451 def GenerateUpdatePayloadForNonFactory(self, board_id, client_version, 508 def GenerateUpdatePayloadForNonFactory(self, board_id, client_version,
452 static_image_dir): 509 static_image_dir):
453 """Generates an update for non-factory and returns True on success.""" 510 """Generates an update for non-factory and returns file name relative to
petkov 2010/11/13 00:55:18 One line summary. Then description.
454 if self.use_cached and os.path.exists(os.path.join(static_image_dir, 511 static_image_dir on success.
455 'update.gz')): 512
456 _LogMessage('Using cached image regardless of timestamps.') 513 Returns the update file relative to the static_image_dir on success."""
457 return True 514
515 if self.forced_image:
516 return self.GenerateUpdateImageWithCache(
517 self.forced_image,
518 static_image_dir=static_image_dir)
519 elif self.serve_only:
520 return self.GenerateImageFromZip(static_image_dir)
458 else: 521 else:
459 if self.forced_image: 522 if board_id:
460 has_built_image = self.GenerateUpdateImage( 523 return self.GenerateLatestUpdateImage(board_id,
461 self.forced_image, move_to_static_dir=True, 524 client_version,
462 static_image_dir=static_image_dir) 525 static_image_dir)
463 return has_built_image
464 elif self.serve_only:
465 return self.GenerateImageFromZip(static_image_dir)
466 else:
467 if board_id:
468 return self.GenerateLatestUpdateImage(board_id,
469 client_version,
470 static_image_dir)
471 526
472 _LogMessage('You must set --board for pre-generating latest update.') 527 _LogMessage('You must set --board for pre-generating latest update.')
473 return False 528 return None
474 529
475 def PreGenerateUpdate(self): 530 def PreGenerateUpdate(self):
476 """Pre-generates an update. Returns True on success.""" 531 """Pre-generates an update. Returns True on success."""
477 # Does not work with factory config. 532 # Does not work with factory config.
478 assert(not self.factory_config) 533 assert(not self.factory_config)
479 _LogMessage('Pre-generating the update payload.') 534 _LogMessage('Pre-generating the update payload.')
480 # Does not work with labels so just use static dir. 535 # Does not work with labels so just use static dir.
481 if self.GenerateUpdatePayloadForNonFactory(self.board, '0.0.0.0', 536 if self.GenerateUpdatePayloadForNonFactory(self.board, '0.0.0.0',
482 self.static_dir): 537 self.static_dir):
483 # Force the devserver to use the pre-generated payload.
484 self.use_cached = True
485 _LogMessage('Pre-generated update successfully.') 538 _LogMessage('Pre-generated update successfully.')
486 return True 539 return True
487 else: 540 else:
488 _LogMessage('Failed to pre-generate update.') 541 _LogMessage('Failed to pre-generate update.')
489 return False 542 return False
490 543
491 def HandleUpdatePing(self, data, label=None): 544 def HandleUpdatePing(self, data, label=None):
492 """Handles an update ping from an update client. 545 """Handles an update ping from an update client.
493 546
494 Args: 547 Args:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 589
537 # Separate logic as Factory requests have static url's that override 590 # Separate logic as Factory requests have static url's that override
538 # other options. 591 # other options.
539 if self.factory_config: 592 if self.factory_config:
540 return self.HandleFactoryRequest(board_id, channel) 593 return self.HandleFactoryRequest(board_id, channel)
541 else: 594 else:
542 static_image_dir = self.static_dir 595 static_image_dir = self.static_dir
543 if label: 596 if label:
544 static_image_dir = os.path.join(static_image_dir, label) 597 static_image_dir = os.path.join(static_image_dir, label)
545 598
546 if self.GenerateUpdatePayloadForNonFactory(board_id, client_version, 599 update_name = self.GenerateUpdatePayloadForNonFactory(board_id,
547 static_image_dir): 600 client_version,
548 filename = os.path.join(static_image_dir, 'update.gz') 601 static_image_dir)
602 if update_name:
603 filename = os.path.join(static_image_dir, update_name)
549 hash = self._GetHash(filename) 604 hash = self._GetHash(filename)
550 sha256 = self._GetSHA256(filename) 605 sha256 = self._GetSHA256(filename)
551 size = self._GetSize(filename) 606 size = self._GetSize(filename)
552 is_delta_format = self._IsDeltaFormatFile(filename) 607 is_delta_format = self._IsDeltaFormatFile(filename)
553 if label: 608 if label:
554 url = '%s/%s/update.gz' % (static_urlbase, label) 609 url = '%s/%s/%s' % (static_urlbase, label, update_name)
555 else: 610 else:
556 url = '%s/update.gz' % static_urlbase 611 url = '%s/%s' % (static_urlbase, update_name)
557 612
558 _LogMessage('Responding to client to use url %s to get image.' % url) 613 _LogMessage('Responding to client to use url %s to get image.' % url)
559 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format) 614 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format)
560 else: 615 else:
561 return self.GetNoUpdatePayload() 616 return self.GetNoUpdatePayload()
OLDNEW
« no previous file with comments | « no previous file | autoupdate_unittest.py » ('j') | devserver.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698