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

Side by Side Diff: autoupdate.py

Issue 3708004: Move dev server to use cherrypy. (Closed) Base URL: http://git.chromium.org/git/dev-util.git
Patch Set: last Created 10 years, 2 months 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') | no next file with comments »
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
8 import cherrypy
8 import os 9 import os
9 import shutil 10 import shutil
11 import socket
10 import time 12 import time
11 import web 13
14 def _LogMessage(message):
15 cherrypy.log(message, 'UPDATE')
12 16
13 17
14 class Autoupdate(BuildObject): 18 class Autoupdate(BuildObject):
15 """Class that contains functionality that handles Chrome OS update pings. 19 """Class that contains functionality that handles Chrome OS update pings.
16 20
17 Members: 21 Members:
18 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
19 must be set to the location of the image.zip. 23 must be set to the location of the image.zip.
20 factory_config: Path to the factory config file if handling factory 24 factory_config: Path to the factory config file if handling factory
21 requests. 25 requests.
22 use_test_image: Use chromiumos_test_image.bin rather than the standard. 26 use_test_image: Use chromiumos_test_image.bin rather than the standard.
23 static_url_base: base URL, other than devserver, for update images. 27 static_url_base: base URL, other than devserver, for update images.
24 client_prefix: The prefix for the update engine client. 28 client_prefix: The prefix for the update engine client.
25 forced_image: Path to an image to use for all updates. 29 forced_image: Path to an image to use for all updates.
26 """ 30 """
27 31
28 def __init__(self, serve_only=None, test_image=False, urlbase=None, 32 def __init__(self, serve_only=None, test_image=False, urlbase=None,
29 factory_config_path=None, client_prefix=None, forced_image=None, 33 factory_config_path=None, client_prefix=None, forced_image=None,
30 use_cached=False, *args, **kwargs): 34 use_cached=False, port=8080, *args, **kwargs):
31 super(Autoupdate, self).__init__(*args, **kwargs) 35 super(Autoupdate, self).__init__(*args, **kwargs)
32 self.serve_only = serve_only 36 self.serve_only = serve_only
33 self.factory_config = factory_config_path 37 self.factory_config = factory_config_path
34 self.use_test_image = test_image 38 self.use_test_image = test_image
39 self.hostname = '%s:%s' % (socket.gethostname(), port)
35 if urlbase: 40 if urlbase:
36 self.static_urlbase = urlbase 41 self.static_urlbase = urlbase
37 elif self.serve_only: 42 elif self.serve_only:
38 self.static_urlbase = 'http://%(host)s/static/archive' 43 self.static_urlbase = 'http://%s/static/archive' % self.hostname
39 else: 44 else:
40 self.static_urlbase = 'http://%(host)s/static' 45 self.static_urlbase = 'http://%s/static' % self.hostname
41 46
42 self.client_prefix = client_prefix 47 self.client_prefix = client_prefix
43 self.forced_image = forced_image 48 self.forced_image = forced_image
44 self.use_cached = use_cached 49 self.use_cached = use_cached
45 50
46 def _GetSecondsSinceMidnight(self): 51 def _GetSecondsSinceMidnight(self):
47 """Returns the seconds since midnight as a decimal value.""" 52 """Returns the seconds since midnight as a decimal value."""
48 now = time.localtime() 53 now = time.localtime()
49 return now[3] * 3600 + now[4] * 60 + now[5] 54 return now[3] * 3600 + now[4] * 60 + now[5]
50 55
(...skipping 12 matching lines...) Expand all
63 68
64 def _GetVersionFromDir(self, image_dir): 69 def _GetVersionFromDir(self, image_dir):
65 """Returns the version of the image based on the name of the directory.""" 70 """Returns the version of the image based on the name of the directory."""
66 latest_version = os.path.basename(image_dir) 71 latest_version = os.path.basename(image_dir)
67 return latest_version.split('-')[0] 72 return latest_version.split('-')[0]
68 73
69 def _CanUpdate(self, client_version, latest_version): 74 def _CanUpdate(self, client_version, latest_version):
70 """Returns true if the latest_version is greater than the client_version.""" 75 """Returns true if the latest_version is greater than the client_version."""
71 client_tokens = client_version.replace('_', '').split('.') 76 client_tokens = client_version.replace('_', '').split('.')
72 latest_tokens = latest_version.replace('_', '').split('.') 77 latest_tokens = latest_version.replace('_', '').split('.')
73 web.debug('client version %s latest version %s' 78 _LogMessage('client version %s latest version %s'
74 % (client_version, latest_version)) 79 % (client_version, latest_version))
75 for i in range(4): 80 for i in range(4):
76 if int(latest_tokens[i]) == int(client_tokens[i]): 81 if int(latest_tokens[i]) == int(client_tokens[i]):
77 continue 82 continue
78 return int(latest_tokens[i]) > int(client_tokens[i]) 83 return int(latest_tokens[i]) > int(client_tokens[i])
79 return False 84 return False
80 85
81 def _UnpackStatefulPartition(self, image_path, stateful_file): 86 def _UnpackStatefulPartition(self, image_path, stateful_file):
82 """Given an image, unpacks its stateful partition to stateful_file.""" 87 """Given an image, unpacks its stateful partition to stateful_file."""
83 image_dir = os.path.dirname(image_path) 88 image_dir = os.path.dirname(image_path)
84 image_file = os.path.basename(image_path) 89 image_file = os.path.basename(image_path)
85 90
86 get_offset = '$(cgpt show -b -i 1 %s)' % image_file 91 get_offset = '$(cgpt show -b -i 1 %s)' % image_file
87 get_size = '$(cgpt show -s -i 1 %s)' % image_file 92 get_size = '$(cgpt show -s -i 1 %s)' % image_file
88 unpack_command = ( 93 unpack_command = (
89 'cd %s && ' 94 'cd %s && '
90 'dd if=%s of=%s bs=512 skip=%s count=%s' % (image_dir, image_file, 95 'dd if=%s of=%s bs=512 skip=%s count=%s' % (image_dir, image_file,
91 stateful_file, get_offset, 96 stateful_file, get_offset,
92 get_size)) 97 get_size))
93 web.debug(unpack_command) 98 _LogMessage(unpack_command)
94 return os.system(unpack_command) == 0 99 return os.system(unpack_command) == 0
95 100
96 def _UnpackZip(self, image_dir): 101 def _UnpackZip(self, image_dir):
97 """Unpacks an image.zip into a given directory.""" 102 """Unpacks an image.zip into a given directory."""
98 image = os.path.join(image_dir, self._GetImageName()) 103 image = os.path.join(image_dir, self._GetImageName())
99 if os.path.exists(image): 104 if os.path.exists(image):
100 return True 105 return True
101 else: 106 else:
102 # -n, never clobber an existing file, in case we get invoked 107 # -n, never clobber an existing file, in case we get invoked
103 # simultaneously by multiple request handlers. This means that 108 # simultaneously by multiple request handlers. This means that
104 # we're assuming each image.zip file lives in a versioned 109 # we're assuming each image.zip file lives in a versioned
105 # directory (a la Buildbot). 110 # directory (a la Buildbot).
106 return os.system('cd %s && unzip -n image.zip' % image_dir) == 0 111 return os.system('cd %s && unzip -n image.zip' % image_dir) == 0
107 112
108 def _GetImageName(self): 113 def _GetImageName(self):
109 """Returns the name of the image that should be used.""" 114 """Returns the name of the image that should be used."""
110 if self.use_test_image: 115 if self.use_test_image:
111 image_name = 'chromiumos_test_image.bin' 116 image_name = 'chromiumos_test_image.bin'
112 else: 117 else:
113 image_name = 'chromiumos_image.bin' 118 image_name = 'chromiumos_image.bin'
114 return image_name 119 return image_name
115 120
116 def _IsImageNewerThanCached(self, image_path, cached_file_path): 121 def _IsImageNewerThanCached(self, image_path, cached_file_path):
117 """Returns true if the image is newer than the cached image.""" 122 """Returns true if the image is newer than the cached image."""
118 if os.path.exists(cached_file_path) and os.path.exists(image_path): 123 if os.path.exists(cached_file_path) and os.path.exists(image_path):
119 web.debug('Usable cached image found at %s.' % cached_file_path) 124 _LogMessage('Usable cached image found at %s.' % cached_file_path)
120 return os.path.getmtime(image_path) > os.path.getmtime(cached_file_path) 125 return os.path.getmtime(image_path) > os.path.getmtime(cached_file_path)
121 elif not os.path.exists(cached_file_path) and not os.path.exists(image_path) : 126 elif not os.path.exists(cached_file_path) and not os.path.exists(image_path) :
122 raise Exception('Image does not exist and cached image missing') 127 raise Exception('Image does not exist and cached image missing')
123 else: 128 else:
124 # Only one is missing, figure out which one. 129 # Only one is missing, figure out which one.
125 if os.path.exists(image_path): 130 if os.path.exists(image_path):
126 web.debug('No cached image found - image generation required.') 131 _LogMessage('No cached image found - image generation required.')
127 return True 132 return True
128 else: 133 else:
129 web.debug('Cached image found to serve at %s.' % cached_file_path) 134 _LogMessage('Cached image found to serve at %s.' % cached_file_path)
130 return False 135 return False
131 136
132 def _GetSize(self, update_path): 137 def _GetSize(self, update_path):
133 """Returns the size of the file given.""" 138 """Returns the size of the file given."""
134 return os.path.getsize(update_path) 139 return os.path.getsize(update_path)
135 140
136 def _GetHash(self, update_path): 141 def _GetHash(self, update_path):
137 """Returns the sha1 of the file given.""" 142 """Returns the sha1 of the file given."""
138 cmd = ('cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';' 143 cmd = ('cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';'
139 % update_path) 144 % update_path)
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 def GenerateUpdateFile(self, image_path): 200 def GenerateUpdateFile(self, image_path):
196 """Generates an update gz given a full path to an image. 201 """Generates an update gz given a full path to an image.
197 202
198 Args: 203 Args:
199 image_path: Full path to image. 204 image_path: Full path to image.
200 Returns: 205 Returns:
201 Path to created update_payload or None on error. 206 Path to created update_payload or None on error.
202 """ 207 """
203 image_dir = os.path.dirname(image_path) 208 image_dir = os.path.dirname(image_path)
204 update_path = os.path.join(image_dir, 'update.gz') 209 update_path = os.path.join(image_dir, 'update.gz')
205 web.debug('Generating update image %s' % update_path) 210 _LogMessage('Generating update image %s' % update_path)
206 211
207 mkupdate_command = ( 212 mkupdate_command = (
208 '%s/cros_generate_update_payload --image=%s --output=%s ' 213 '%s/cros_generate_update_payload --image=%s --output=%s '
209 '--patch_kernel' % (self.scripts_dir, image_path, update_path)) 214 '--patch_kernel' % (self.scripts_dir, image_path, update_path))
210 if os.system(mkupdate_command) != 0: 215 if os.system(mkupdate_command) != 0:
211 web.debug('Failed to create base update file') 216 _LogMessage('Failed to create base update file')
212 return None 217 return None
213 218
214 return update_path 219 return update_path
215 220
216 def GenerateStatefulFile(self, image_path): 221 def GenerateStatefulFile(self, image_path):
217 """Generates a stateful update gz given a full path to an image. 222 """Generates a stateful update gz given a full path to an image.
218 223
219 Args: 224 Args:
220 image_path: Full path to image. 225 image_path: Full path to image.
221 Returns: 226 Returns:
222 Path to created stateful update_payload or None on error. 227 Path to created stateful update_payload or None on error.
223 """ 228 """
224 stateful_partition_path = '%s/stateful.image' % os.path.dirname(image_path) 229 stateful_partition_path = '%s/stateful.image' % os.path.dirname(image_path)
225 230
226 # Unpack to get stateful partition. 231 # Unpack to get stateful partition.
227 if self._UnpackStatefulPartition(image_path, stateful_partition_path): 232 if self._UnpackStatefulPartition(image_path, stateful_partition_path):
228 mkstatefulupdate_command = 'gzip -f %s' % stateful_partition_path 233 mkstatefulupdate_command = 'gzip -f %s' % stateful_partition_path
229 if os.system(mkstatefulupdate_command) == 0: 234 if os.system(mkstatefulupdate_command) == 0:
230 web.debug('Successfully generated %s.gz' % stateful_partition_path) 235 _LogMessage('Successfully generated %s.gz' % stateful_partition_path)
231 return '%s.gz' % stateful_partition_path 236 return '%s.gz' % stateful_partition_path
232 237
233 web.debug('Failed to create stateful update file') 238 _LogMessage('Failed to create stateful update file')
234 return None 239 return None
235 240
236 def MoveImagesToStaticDir(self, update_path, stateful_update_path, 241 def MoveImagesToStaticDir(self, update_path, stateful_update_path,
237 static_image_dir): 242 static_image_dir):
238 """Moves gz files from their directories to serving directories. 243 """Moves gz files from their directories to serving directories.
239 244
240 Args: 245 Args:
241 update_path: full path to main update gz. 246 update_path: full path to main update gz.
242 stateful_update_path: full path to stateful partition gz. 247 stateful_update_path: full path to stateful partition gz.
243 static_image_dir: where to put files. 248 static_image_dir: where to put files.
244 Returns: 249 Returns:
245 Returns True if the files were moved over successfully. 250 Returns True if the files were moved over successfully.
246 """ 251 """
247 try: 252 try:
248 shutil.copy(update_path, static_image_dir) 253 shutil.copy(update_path, static_image_dir)
249 shutil.copy(stateful_update_path, static_image_dir) 254 shutil.copy(stateful_update_path, static_image_dir)
250 os.remove(update_path) 255 os.remove(update_path)
251 os.remove(stateful_update_path) 256 os.remove(stateful_update_path)
252 except Exception: 257 except Exception:
253 web.debug('Failed to move %s and %s to %s' % (update_path, 258 _LogMessage('Failed to move %s and %s to %s' % (update_path,
254 stateful_update_path, 259 stateful_update_path,
255 static_image_dir)) 260 static_image_dir))
256 return False 261 return False
257 262
258 return True 263 return True
259 264
260 def GenerateUpdateImage(self, image_path, move_to_static_dir=False, 265 def GenerateUpdateImage(self, image_path, move_to_static_dir=False,
261 static_image_dir=None): 266 static_image_dir=None):
262 """Force generates an update payload based on the given image_path. 267 """Force generates an update payload based on the given image_path.
263 268
264 Args: 269 Args:
265 image_path: full path to the image. 270 image_path: full path to the image.
266 move_to_static_dir: Moves the files from their dir to the static dir. 271 move_to_static_dir: Moves the files from their dir to the static dir.
267 static_image_dir: the directory to move images to after generating. 272 static_image_dir: the directory to move images to after generating.
268 Returns: 273 Returns:
269 True if the update payload was created successfully. 274 True if the update payload was created successfully.
270 """ 275 """
271 web.debug('Generating update for image %s' % image_path) 276 _LogMessage('Generating update for image %s' % image_path)
272 update_path = self.GenerateUpdateFile(image_path) 277 update_path = self.GenerateUpdateFile(image_path)
273 stateful_update_path = self.GenerateStatefulFile(image_path) 278 stateful_update_path = self.GenerateStatefulFile(image_path)
274 if not update_path or not stateful_update_path: 279 if not update_path or not stateful_update_path:
275 web.debug('Failed to generate update') 280 _LogMessage('Failed to generate update')
276 return False 281 return False
277 282
278 if move_to_static_dir: 283 if move_to_static_dir:
279 return self.MoveImagesToStaticDir(update_path, stateful_update_path, 284 return self.MoveImagesToStaticDir(update_path, stateful_update_path,
280 static_image_dir) 285 static_image_dir)
281 else: 286 else:
282 return True 287 return True
283 288
284 def GenerateLatestUpdateImage(self, board_id, client_version, 289 def GenerateLatestUpdateImage(self, board_id, client_version,
285 static_image_dir=None): 290 static_image_dir=None):
286 """Generates an update using the latest image that has been built. 291 """Generates an update using the latest image that has been built.
287 292
288 This will only generate an update if the newest update is newer than that 293 This will only generate an update if the newest update is newer than that
289 on the client or client_version is 'ForcedUpdate'. 294 on the client or client_version is 'ForcedUpdate'.
290 295
291 Args: 296 Args:
292 board_id: Name of the board. 297 board_id: Name of the board.
293 client_version: Current version of the client or 'ForcedUpdate' 298 client_version: Current version of the client or 'ForcedUpdate'
294 static_image_dir: the directory to move images to after generating. 299 static_image_dir: the directory to move images to after generating.
295 Returns: 300 Returns:
296 True if the update payload was created successfully. 301 True if the update payload was created successfully.
297 """ 302 """
298 latest_image_dir = self._GetLatestImageDir(board_id) 303 latest_image_dir = self._GetLatestImageDir(board_id)
299 latest_version = self._GetVersionFromDir(latest_image_dir) 304 latest_version = self._GetVersionFromDir(latest_image_dir)
300 latest_image_path = os.path.join(latest_image_dir, self._GetImageName()) 305 latest_image_path = os.path.join(latest_image_dir, self._GetImageName())
301 306
302 web.debug('Preparing to generate update from latest built image %s.' % 307 _LogMessage('Preparing to generate update from latest built image %s.' %
303 latest_image_path) 308 latest_image_path)
304 309
305 # Check to see whether or not we should update. 310 # Check to see whether or not we should update.
306 if client_version != 'ForcedUpdate' and not self._CanUpdate( 311 if client_version != 'ForcedUpdate' and not self._CanUpdate(
307 client_version, latest_version): 312 client_version, latest_version):
308 web.debug('no update') 313 _LogMessage('no update')
309 return False 314 return False
310 315
311 cached_file_path = os.path.join(static_image_dir, 'update.gz') 316 cached_file_path = os.path.join(static_image_dir, 'update.gz')
312 if (os.path.exists(cached_file_path) and 317 if (os.path.exists(cached_file_path) and
313 not self._IsImageNewerThanCached(latest_image_path, cached_file_path)): 318 not self._IsImageNewerThanCached(latest_image_path, cached_file_path)):
314 return True 319 return True
315 320
316 return self.GenerateUpdateImage(latest_image_path, move_to_static_dir=True, 321 return self.GenerateUpdateImage(latest_image_path, move_to_static_dir=True,
317 static_image_dir=static_image_dir) 322 static_image_dir=static_image_dir)
318 323
319 def GenerateImageFromZip(self, static_image_dir): 324 def GenerateImageFromZip(self, static_image_dir):
320 """Generates an update from an image zip file. 325 """Generates an update from an image zip file.
321 326
322 This method assumes you have an image.zip in directory you are serving 327 This method assumes you have an image.zip in directory you are serving
323 from. If this file is newer than a previously cached file, it will unzip 328 from. If this file is newer than a previously cached file, it will unzip
324 this file, create a payload and serve it. 329 this file, create a payload and serve it.
325 330
326 Args: 331 Args:
327 static_image_dir: Directory where the zip file exists. 332 static_image_dir: Directory where the zip file exists.
328 Returns: 333 Returns:
329 True if the update payload was created successfully. 334 True if the update payload was created successfully.
330 """ 335 """
331 web.debug('Preparing to generate update from zip in %s.' % static_image_dir) 336 _LogMessage('Preparing to generate update from zip in %s.' % static_image_di r)
332 image_path = os.path.join(static_image_dir, self._GetImageName()) 337 image_path = os.path.join(static_image_dir, self._GetImageName())
333 cached_file_path = os.path.join(static_image_dir, 'update.gz') 338 cached_file_path = os.path.join(static_image_dir, 'update.gz')
334 zip_file_path = os.path.join(static_image_dir, 'image.zip') 339 zip_file_path = os.path.join(static_image_dir, 'image.zip')
335 if not self._IsImageNewerThanCached(zip_file_path, cached_file_path): 340 if not self._IsImageNewerThanCached(zip_file_path, cached_file_path):
336 return True 341 return True
337 342
338 if not self._UnpackZip(static_image_dir): 343 if not self._UnpackZip(static_image_dir):
339 web.debug('unzip image.zip failed.') 344 _LogMessage('unzip image.zip failed.')
340 return False 345 return False
341 346
342 return self.GenerateUpdateImage(image_path, move_to_static_dir=False, 347 return self.GenerateUpdateImage(image_path, move_to_static_dir=False,
343 static_image_dir=None) 348 static_image_dir=None)
344 349
345 def ImportFactoryConfigFile(self, filename, validate_checksums=False): 350 def ImportFactoryConfigFile(self, filename, validate_checksums=False):
346 """Imports a factory-floor server configuration file. The file should 351 """Imports a factory-floor server configuration file. The file should
347 be in this format: 352 be in this format:
348 config = [ 353 config = [
349 { 354 {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 for stanza in self.factory_config: 421 for stanza in self.factory_config:
417 if board_id not in stanza['qual_ids']: 422 if board_id not in stanza['qual_ids']:
418 continue 423 continue
419 if kind + '_image' not in stanza: 424 if kind + '_image' not in stanza:
420 break 425 break
421 return (stanza[kind + '_image'], 426 return (stanza[kind + '_image'],
422 stanza[kind + '_checksum'], 427 stanza[kind + '_checksum'],
423 stanza[kind + '_size']) 428 stanza[kind + '_size'])
424 return (None, None, None) 429 return (None, None, None)
425 430
426 def HandleFactoryRequest(self, hostname, board_id, channel): 431 def HandleFactoryRequest(self, board_id, channel):
427 (filename, checksum, size) = self.GetFactoryImage(board_id, channel) 432 (filename, checksum, size) = self.GetFactoryImage(board_id, channel)
428 if filename is None: 433 if filename is None:
429 web.debug('unable to find image for board %s' % board_id) 434 _LogMessage('unable to find image for board %s' % board_id)
430 return self.GetNoUpdatePayload() 435 return self.GetNoUpdatePayload()
431 url = 'http://%s/static/%s' % (hostname, filename) 436 url = 'http://%s/static/%s' % (self.hostname, filename)
432 web.debug('returning update payload ' + url) 437 _LogMessage('returning update payload ' + url)
433 # Factory install is using memento updater which is using the sha-1 hash so 438 # Factory install is using memento updater which is using the sha-1 hash so
434 # setting sha-256 to an empty string. 439 # setting sha-256 to an empty string.
435 return self.GetUpdatePayload(checksum, '', size, url) 440 return self.GetUpdatePayload(checksum, '', size, url)
436 441
437 def HandleUpdatePing(self, data, label=None): 442 def HandleUpdatePing(self, data, label=None):
438 """Handles an update ping from an update client. 443 """Handles an update ping from an update client.
439 444
440 Args: 445 Args:
441 data: xml blob from client. 446 data: xml blob from client.
442 label: optional label for the update. 447 label: optional label for the update.
443 Returns: 448 Returns:
444 Update payload message for client. 449 Update payload message for client.
445 """ 450 """
446 web.debug('handling update ping: %s' % data) 451 _LogMessage('handling update ping: %s' % data)
447 update_dom = minidom.parseString(data) 452 update_dom = minidom.parseString(data)
448 root = update_dom.firstChild 453 root = update_dom.firstChild
449 454
450 # Parse host if not done yet.
451 if '%(host)' in self.static_urlbase:
452 self.static_urlbase = self.static_urlbase % {'host' : web.ctx.host}
453
454 # Check the client prefix to make sure you can support this type of update. 455 # Check the client prefix to make sure you can support this type of update.
455 if (root.hasAttribute('updaterversion') and 456 if (root.hasAttribute('updaterversion') and
456 not root.getAttribute('updaterversion').startswith(self.client_prefix)): 457 not root.getAttribute('updaterversion').startswith(self.client_prefix)):
457 web.debug('Got update from unsupported updater:' + 458 _LogMessage('Got update from unsupported updater:' +
458 root.getAttribute('updaterversion')) 459 root.getAttribute('updaterversion'))
459 return self.GetNoUpdatePayload() 460 return self.GetNoUpdatePayload()
460 461
461 # We only generate update payloads for updatecheck requests. 462 # We only generate update payloads for updatecheck requests.
462 update_check = root.getElementsByTagName('o:updatecheck') 463 update_check = root.getElementsByTagName('o:updatecheck')
463 if not update_check: 464 if not update_check:
464 web.debug('Non-update check received. Returning blank payload.') 465 _LogMessage('Non-update check received. Returning blank payload.')
465 # TODO(sosa): Generate correct non-updatecheck payload to better test 466 # TODO(sosa): Generate correct non-updatecheck payload to better test
466 # update clients. 467 # update clients.
467 return self.GetNoUpdatePayload() 468 return self.GetNoUpdatePayload()
468 469
469 # Since this is an updatecheck, get information about the requester. 470 # Since this is an updatecheck, get information about the requester.
470 hostname = web.ctx.host
471 query = root.getElementsByTagName('o:app')[0] 471 query = root.getElementsByTagName('o:app')[0]
472 client_version = query.getAttribute('version') 472 client_version = query.getAttribute('version')
473 channel = query.getAttribute('track') 473 channel = query.getAttribute('track')
474 board_id = (query.hasAttribute('board') and query.getAttribute('board') 474 board_id = (query.hasAttribute('board') and query.getAttribute('board')
475 or self._GetDefaultBoardID()) 475 or self._GetDefaultBoardID())
476 476
477 # Separate logic as Factory requests have static url's that override 477 # Separate logic as Factory requests have static url's that override
478 # other options. 478 # other options.
479 if self.factory_config: 479 if self.factory_config:
480 return self.HandleFactoryRequest(hostname, board_id, channel) 480 return self.HandleFactoryRequest(board_id, channel)
481 else: 481 else:
482 static_image_dir = self.static_dir 482 static_image_dir = self.static_dir
483 if label: 483 if label:
484 static_image_dir = os.path.join(static_image_dir, label) 484 static_image_dir = os.path.join(static_image_dir, label)
485 485
486 # Prefer cached image if it exists. 486 # Prefer cached image if it exists.
487 if self.use_cached and os.path.exists(os.path.join(static_image_dir, 487 if self.use_cached and os.path.exists(os.path.join(static_image_dir,
488 'update.gz')): 488 'update.gz')):
489 web.debug('Using cached image regardless of timestamps.') 489 _LogMessage('Using cached image regardless of timestamps.')
490 has_built_image = True 490 has_built_image = True
491 else: 491 else:
492 if self.forced_image: 492 if self.forced_image:
493 has_built_image = self.GenerateUpdateImage( 493 has_built_image = self.GenerateUpdateImage(
494 self.forced_image, move_to_static_dir=True, 494 self.forced_image, move_to_static_dir=True,
495 static_image_dir=static_image_dir) 495 static_image_dir=static_image_dir)
496 # Now that we've generated it, clear out so that other pings of same 496 # Now that we've generated it, clear out so that other pings of same
497 # devserver instance do not generate new images. 497 # devserver instance do not generate new images.
498 self.forced_image = None 498 self.forced_image = None
499 elif self.serve_only: 499 elif self.serve_only:
500 has_built_image = self.GenerateImageFromZip(static_image_dir) 500 has_built_image = self.GenerateImageFromZip(static_image_dir)
501 else: 501 else:
502 has_built_image = self.GenerateLatestUpdateImage(board_id, 502 has_built_image = self.GenerateLatestUpdateImage(board_id,
503 client_version, 503 client_version,
504 static_image_dir) 504 static_image_dir)
505 505
506 if has_built_image: 506 if has_built_image:
507 hash = self._GetHash(os.path.join(static_image_dir, 'update.gz')) 507 hash = self._GetHash(os.path.join(static_image_dir, 'update.gz'))
508 sha256 = self._GetSHA256(os.path.join(static_image_dir, 'update.gz')) 508 sha256 = self._GetSHA256(os.path.join(static_image_dir, 'update.gz'))
509 size = self._GetSize(os.path.join(static_image_dir, 'update.gz')) 509 size = self._GetSize(os.path.join(static_image_dir, 'update.gz'))
510 if label: 510 if label:
511 url = '%s/%s/update.gz' % (self.static_urlbase, label) 511 url = '%s/%s/update.gz' % (self.static_urlbase, label)
512 else: 512 else:
513 url = '%s/update.gz' % self.static_urlbase 513 url = '%s/update.gz' % self.static_urlbase
514 514
515 web.debug('Responding to client to use url %s to get image.' % url) 515 _LogMessage('Responding to client to use url %s to get image.' % url)
516 return self.GetUpdatePayload(hash, sha256, size, url) 516 return self.GetUpdatePayload(hash, sha256, size, url)
517 else: 517 else:
518 return self.GetNoUpdatePayload() 518 return self.GetNoUpdatePayload()
OLDNEW
« no previous file with comments | « no previous file | autoupdate_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698