OLD | NEW |
---|---|
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 cherrypy |
9 import os | 9 import os |
10 import shutil | 10 import shutil |
11 import subprocess | 11 import subprocess |
12 import time | 12 import time |
13 | 13 |
14 | 14 |
15 def _LogMessage(message): | 15 def _LogMessage(message): |
16 cherrypy.log(message, 'UPDATE') | 16 cherrypy.log(message, 'UPDATE') |
17 | 17 |
18 UPDATE_FILE='update.gz' | 18 UPDATE_FILE='update.gz' |
19 STATEFUL_FILE='stateful.tgz' | 19 STATEFUL_FILE='stateful.tgz' |
20 | 20 |
21 class Autoupdate(BuildObject): | 21 class Autoupdate(BuildObject): |
22 """Class that contains functionality that handles Chrome OS update pings. | 22 """Class that contains functionality that handles Chrome OS update pings. |
23 | 23 |
24 Members: | 24 Members: |
25 serve_only: Serve images from a pre-built image.zip file. static_dir | 25 serve_only: Serve only pre-built updates. static_dir must contain update.gz |
26 must be set to the location of the image.zip. | 26 and stateful.tgz. |
27 factory_config: Path to the factory config file if handling factory | 27 factory_config: Path to the factory config file if handling factory |
28 requests. | 28 requests. |
29 use_test_image: Use chromiumos_test_image.bin rather than the standard. | 29 use_test_image: Use chromiumos_test_image.bin rather than the standard. |
30 static_url_base: base URL, other than devserver, for update images. | 30 static_url_base: base URL, other than devserver, for update images. |
31 client_prefix: The prefix for the update engine client. | 31 client_prefix: The prefix for the update engine client. |
32 forced_image: Path to an image to use for all updates. | 32 forced_image: Path to an image to use for all updates. |
33 """ | 33 """ |
34 | 34 |
35 def __init__(self, serve_only=None, test_image=False, urlbase=None, | 35 def __init__(self, serve_only=None, test_image=False, urlbase=None, |
36 factory_config_path=None, client_prefix=None, | 36 factory_config_path=None, client_prefix=None, |
37 forced_image=None, forced_payload=None, | 37 forced_image=None, forced_payload=None, |
38 port=8080, src_image='', vm=False, board=None, | 38 port=8080, src_image='', vm=False, board=None, |
39 *args, **kwargs): | 39 *args, **kwargs): |
40 super(Autoupdate, self).__init__(*args, **kwargs) | 40 super(Autoupdate, self).__init__(*args, **kwargs) |
41 self.serve_only = serve_only | 41 self.serve_only = serve_only |
42 self.factory_config = factory_config_path | 42 self.factory_config = factory_config_path |
43 self.use_test_image = test_image | 43 self.use_test_image = test_image |
44 if urlbase: | 44 if urlbase: |
45 self.urlbase = urlbase | 45 self.urlbase = urlbase |
46 else: | 46 else: |
47 self.urlbase = None | 47 self.urlbase = None |
48 | 48 |
49 self.client_prefix = client_prefix | 49 self.client_prefix = client_prefix |
50 self.forced_image = forced_image | 50 self.forced_image = forced_image |
51 self.forced_payload = forced_payload | 51 self.forced_payload = forced_payload |
52 self.src_image = src_image | 52 self.src_image = src_image |
53 self.vm = vm | 53 self.vm = vm |
54 self.board = board | 54 self.board = board |
55 | 55 |
56 # Caching is enabled if we are not doing serve_only | 56 # Caching is enabled if we are not doing serve_only |
sosa
2010/11/30 19:38:48
Remove part of this comment
DaleCurtis
2010/11/30 21:44:19
Done.
| |
57 # aka if --archive_dir was not passed in. | 57 # aka if --archive_dir was not passed in. |
58 self.caching_enabled = not self.serve_only | 58 self.caching_enabled = not self.serve_only |
59 | 59 |
60 # Track update pregeneration, so we don't recopy if not needed. | 60 # Track update pregeneration, so we don't recopy if not needed. |
61 self.pregenerated = False | 61 self.pregenerated = False |
62 | 62 |
63 def _GetSecondsSinceMidnight(self): | 63 def _GetSecondsSinceMidnight(self): |
64 """Returns the seconds since midnight as a decimal value.""" | 64 """Returns the seconds since midnight as a decimal value.""" |
65 now = time.localtime() | 65 now = time.localtime() |
66 return now[3] * 3600 + now[4] * 60 + now[5] | 66 return now[3] * 3600 + now[4] * 60 + now[5] |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
391 | 391 |
392 # Check to see whether or not we should update. | 392 # Check to see whether or not we should update. |
393 if client_version != 'ForcedUpdate' and not self._CanUpdate( | 393 if client_version != 'ForcedUpdate' and not self._CanUpdate( |
394 client_version, latest_version): | 394 client_version, latest_version): |
395 _LogMessage('no update') | 395 _LogMessage('no update') |
396 return None | 396 return None |
397 | 397 |
398 return self.GenerateUpdateImageWithCache(latest_image_path, | 398 return self.GenerateUpdateImageWithCache(latest_image_path, |
399 static_image_dir=static_image_dir) | 399 static_image_dir=static_image_dir) |
400 | 400 |
401 def GenerateImageFromZip(self, static_image_dir): | |
402 """Generates an update from an image zip file. | |
403 | |
404 This method assumes you have an image.zip in directory you are serving | |
405 from. If this file is newer than a previously cached file, it will unzip | |
406 this file, create a payload and serve it. | |
407 | |
408 Args: | |
409 static_image_dir: Directory where the zip file exists. | |
410 Returns: | |
411 Name of the update payload relative to static_image_dir if successful. | |
412 """ | |
413 _LogMessage('Preparing to generate update from zip in %s.' % | |
414 static_image_dir) | |
415 image_path = os.path.join(static_image_dir, self._GetImageName()) | |
416 zip_file_path = os.path.join(static_image_dir, 'image.zip') | |
417 | |
418 # TODO(dgarrett): Either work caching into this path before | |
419 # we unpack, or remove zip support (sosa is considering). | |
420 # It does currently cache, but after the unpack. | |
421 | |
422 if not self._UnpackZip(static_image_dir): | |
423 _LogMessage('unzip image.zip failed.') | |
424 return None | |
425 | |
426 return self.GenerateUpdateImageWithCache(image_path, | |
427 static_image_dir=static_image_dir) | |
428 | |
429 def ImportFactoryConfigFile(self, filename, validate_checksums=False): | 401 def ImportFactoryConfigFile(self, filename, validate_checksums=False): |
430 """Imports a factory-floor server configuration file. The file should | 402 """Imports a factory-floor server configuration file. The file should |
431 be in this format: | 403 be in this format: |
432 config = [ | 404 config = [ |
433 { | 405 { |
434 'qual_ids': set([1, 2, 3, "x86-generic"]), | 406 'qual_ids': set([1, 2, 3, "x86-generic"]), |
435 'factory_image': 'generic-factory.gz', | 407 'factory_image': 'generic-factory.gz', |
436 'factory_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=', | 408 'factory_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=', |
437 'release_image': 'generic-release.gz', | 409 'release_image': 'generic-release.gz', |
438 'release_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=', | 410 'release_checksum': 'AtiI8B64agHVN+yeBAyiNMX3+HM=', |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 # setting sha-256 to an empty string. | 491 # setting sha-256 to an empty string. |
520 return self.GetUpdatePayload(checksum, '', size, url, is_delta_format) | 492 return self.GetUpdatePayload(checksum, '', size, url, is_delta_format) |
521 | 493 |
522 def GenerateUpdatePayloadForNonFactory(self, board_id, client_version, | 494 def GenerateUpdatePayloadForNonFactory(self, board_id, client_version, |
523 static_image_dir): | 495 static_image_dir): |
524 """Generates an update for non-factory image. | 496 """Generates an update for non-factory image. |
525 | 497 |
526 Returns: | 498 Returns: |
527 file name relative to static_image_dir on success. | 499 file name relative to static_image_dir on success. |
528 """ | 500 """ |
501 dest_path = os.path.join(static_image_dir, UPDATE_FILE) | |
502 dest_stateful = os.path.join(static_image_dir, STATEFUL_FILE) | |
503 | |
529 if self.forced_payload: | 504 if self.forced_payload: |
530 # If the forced payload is not already in our static_image_dir, | 505 # If the forced payload is not already in our static_image_dir, |
531 # copy it there. | 506 # copy it there. |
532 src_path = os.path.abspath(self.forced_payload) | 507 src_path = os.path.abspath(self.forced_payload) |
533 dest_path = os.path.join(static_image_dir, UPDATE_FILE) | |
534 | 508 |
535 src_stateful = os.path.join(os.path.dirname(src_path), | 509 src_stateful = os.path.join(os.path.dirname(src_path), |
536 STATEFUL_FILE) | 510 STATEFUL_FILE) |
537 dest_stateful = os.path.join(static_image_dir, | |
538 STATEFUL_FILE) | |
539 | 511 |
540 # Only copy the files if the source directory is different from dest. | 512 # Only copy the files if the source directory is different from dest. |
541 if os.path.dirname(src_path) != os.path.abspath(static_image_dir): | 513 if os.path.dirname(src_path) != os.path.abspath(static_image_dir): |
542 self._Copy(src_path, dest_path) | 514 self._Copy(src_path, dest_path) |
543 | 515 |
544 # The stateful payload is optional. | 516 # The stateful payload is optional. |
545 if os.path.exists(src_stateful): | 517 if os.path.exists(src_stateful): |
546 self._Copy(src_stateful, dest_stateful) | 518 self._Copy(src_stateful, dest_stateful) |
547 else: | 519 else: |
548 _LogMessage('WARN: %s not found. Expected for dev and test builds.' % | 520 _LogMessage('WARN: %s not found. Expected for dev and test builds.' % |
549 STATEFUL_FILE) | 521 STATEFUL_FILE) |
550 if os.path.exists(dest_stateful): | 522 if os.path.exists(dest_stateful): |
551 os.remove(dest_stateful) | 523 os.remove(dest_stateful) |
552 | 524 |
553 return UPDATE_FILE | 525 return UPDATE_FILE |
554 elif self.forced_image: | 526 elif self.forced_image: |
555 return self.GenerateUpdateImageWithCache( | 527 return self.GenerateUpdateImageWithCache( |
556 self.forced_image, | 528 self.forced_image, |
557 static_image_dir=static_image_dir) | 529 static_image_dir=static_image_dir) |
558 elif self.serve_only: | 530 elif self.serve_only: |
559 return self.GenerateImageFromZip(static_image_dir) | 531 # Warn if update or stateful files can't be found. |
532 if not os.path.exists(dest_path): | |
533 _LogMessage('WARN: %s not found. Expected for dev and test builds.' % | |
534 UPDATE_FILE) | |
535 | |
536 if not os.path.exists(dest_stateful): | |
537 _LogMessage('WARN: %s not found. Expected for dev and test builds.' % | |
538 STATEFUL_FILE) | |
539 | |
540 return UPDATE_FILE | |
560 else: | 541 else: |
561 if board_id: | 542 if board_id: |
562 return self.GenerateLatestUpdateImage(board_id, | 543 return self.GenerateLatestUpdateImage(board_id, |
563 client_version, | 544 client_version, |
564 static_image_dir) | 545 static_image_dir) |
565 | 546 |
566 _LogMessage('You must set --board for pre-generating latest update.') | 547 _LogMessage('You must set --board for pre-generating latest update.') |
567 return None | 548 return None |
568 | 549 |
569 def PreGenerateUpdate(self): | 550 def PreGenerateUpdate(self): |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
648 is_delta_format = self._IsDeltaFormatFile(filename) | 629 is_delta_format = self._IsDeltaFormatFile(filename) |
649 if label: | 630 if label: |
650 url = '%s/%s/%s' % (static_urlbase, label, payload_path) | 631 url = '%s/%s/%s' % (static_urlbase, label, payload_path) |
651 else: | 632 else: |
652 url = '%s/%s' % (static_urlbase, payload_path) | 633 url = '%s/%s' % (static_urlbase, payload_path) |
653 | 634 |
654 _LogMessage('Responding to client to use url %s to get image.' % url) | 635 _LogMessage('Responding to client to use url %s to get image.' % url) |
655 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format) | 636 return self.GetUpdatePayload(hash, sha256, size, url, is_delta_format) |
656 else: | 637 else: |
657 return self.GetNoUpdatePayload() | 638 return self.GetNoUpdatePayload() |
OLD | NEW |