OLD | NEW |
1 # Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2009 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 os | 8 import os |
9 import shutil | 9 import shutil |
10 import web | 10 import web |
11 | 11 |
12 class Autoupdate(BuildObject): | 12 class Autoupdate(BuildObject): |
13 # Basic functionality of handling ChromeOS autoupdate pings | 13 # Basic functionality of handling ChromeOS autoupdate pings |
14 # and building/serving update images. | 14 # and building/serving update images. |
15 # TODO(rtc): Clean this code up and write some tests. | 15 # TODO(rtc): Clean this code up and write some tests. |
16 | 16 |
17 def __init__(self, serve_only=None, test_image=False, *args, **kwargs): | 17 def __init__(self, serve_only=None, test_image=False, urlbase=None, |
| 18 *args, **kwargs): |
| 19 super(Autoupdate, self).__init__(*args, **kwargs) |
18 self.serve_only = serve_only | 20 self.serve_only = serve_only |
| 21 self.test_image=test_image |
| 22 self.static_urlbase = urlbase |
19 if serve_only: | 23 if serve_only: |
| 24 # If we're serving out of an archived build dir (e.g. a |
| 25 # buildbot), prepare this webserver's magic 'static/' dir with a |
| 26 # link to the build archive. |
20 web.debug('Autoupdate in "serve update images only" mode.') | 27 web.debug('Autoupdate in "serve update images only" mode.') |
21 self.test_image=test_image | 28 if os.path.exists('static/archive'): |
22 super(Autoupdate, self).__init__(*args, **kwargs) | 29 archive_symlink = os.readlink('static/archive') |
| 30 if archive_symlink != self.static_dir: |
| 31 web.debug('removing stale symlink to %s' % self.static_dir) |
| 32 os.unlink('static/archive') |
| 33 else: |
| 34 os.symlink(self.static_dir, 'static/archive') |
23 | 35 |
24 def GetUpdatePayload(self, hash, size, url): | 36 def GetUpdatePayload(self, hash, size, url): |
25 payload = """<?xml version="1.0" encoding="UTF-8"?> | 37 payload = """<?xml version="1.0" encoding="UTF-8"?> |
26 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0"> | 38 <gupdate xmlns="http://www.google.com/update2/response" protocol="2.0"> |
27 <app appid="{%s}" status="ok"> | 39 <app appid="{%s}" status="ok"> |
28 <ping status="ok"/> | 40 <ping status="ok"/> |
29 <updatecheck | 41 <updatecheck |
30 codebase="%s" | 42 codebase="%s" |
31 hash="%s" | 43 hash="%s" |
32 needsadmin="false" | 44 needsadmin="false" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 return int(latest_tokens[i]) > int(client_tokens[i]) | 85 return int(latest_tokens[i]) > int(client_tokens[i]) |
74 return False | 86 return False |
75 | 87 |
76 def UnpackRootfs(self, image_path, rootfs_file): | 88 def UnpackRootfs(self, image_path, rootfs_file): |
77 if os.path.exists(rootfs_file): | 89 if os.path.exists(rootfs_file): |
78 return True | 90 return True |
79 if self.test_image: | 91 if self.test_image: |
80 image_file = 'chromiumos_test_image.bin' | 92 image_file = 'chromiumos_test_image.bin' |
81 else: | 93 else: |
82 image_file = 'chromiumos_image.bin' | 94 image_file = 'chromiumos_image.bin' |
| 95 if self.serve_only: |
| 96 os.system('cd %s && unzip -o image.zip unpack_partitions.sh %s' % |
| 97 (image_path, image_file)) |
83 os.system('rm -f %s/part_*' % image_path) | 98 os.system('rm -f %s/part_*' % image_path) |
84 os.system('cd %s && ./unpack_partitions.sh %s' % (image_path, image_file)) | 99 os.system('cd %s && ./unpack_partitions.sh %s' % (image_path, image_file)) |
85 shutil.move(os.path.join(image_path, 'part_3'), rootfs_file) | 100 shutil.move(os.path.join(image_path, 'part_3'), rootfs_file) |
86 os.system('rm -f %s/part_*' % image_path) | 101 os.system('rm -f %s/part_*' % image_path) |
87 return True | 102 return True |
88 | 103 |
89 def BuildUpdateImage(self, image_path): | 104 def BuildUpdateImage(self, image_path): |
90 if self.test_image: | 105 if self.test_image: |
91 image_file = '%s/rootfs_test.image' % image_path | 106 image_file = '%s/rootfs_test.image' % image_path |
92 else: | 107 else: |
93 image_file = '%s/rootfs.image' % image_path | 108 image_file = '%s/rootfs.image' % image_path |
94 | 109 |
95 if not self.UnpackRootfs(image_path, image_file): | 110 if not self.UnpackRootfs(image_path, image_file): |
96 web.debug('failed to unpack rootfs.') | 111 web.debug('failed to unpack rootfs.') |
97 return False | 112 return False |
98 | 113 |
99 update_file = '%s/update.gz' % image_path | 114 update_file = '%s/update.gz' % image_path |
100 if (os.path.exists(update_file) and | 115 if (os.path.exists(update_file) and |
101 os.path.getmtime(update_file) >= os.path.getmtime(image_file)): | 116 os.path.getmtime(update_file) >= os.path.getmtime(image_file)): |
102 web.debug('Found cached update image %s/update.gz' % image_path) | 117 web.debug('Found cached update image %s/update.gz' % image_path) |
103 else: | 118 else: |
104 web.debug('generating update image %s/update.gz' % image_path) | 119 web.debug('generating update image %s' % update_file) |
105 mkupdate = '%s/mk_memento_images.sh %s' % (self.scripts_dir, image_file) | 120 mkupdate = '%s/mk_memento_images.sh %s' % (self.scripts_dir, image_file) |
106 web.debug(mkupdate) | 121 web.debug(mkupdate) |
107 err = os.system(mkupdate) | 122 err = os.system(mkupdate) |
108 if err != 0: | 123 if err != 0: |
109 web.debug('failed to create update image') | 124 web.debug('failed to create update image') |
110 return False | 125 return False |
111 if not self.serve_only: | 126 if not self.serve_only: |
112 web.debug('Found an image, copying it to static') | 127 web.debug('Found an image, copying it to static') |
113 try: | 128 try: |
114 shutil.copy('%s/update.gz' % image_path, self.static_dir) | 129 shutil.copy(update_file, self.static_dir) |
115 except Exception, e: | 130 except Exception, e: |
116 web.debug('Unable to copy update.gz from %s to %s' \ | 131 web.debug('Unable to copy %s to %s' % (update_file, self.static_dir)) |
117 % (image_path, self.static_dir)) | |
118 return False | 132 return False |
119 return True | 133 return True |
120 | 134 |
121 def GetSize(self, update_path): | 135 def GetSize(self, update_path): |
122 return os.path.getsize(update_path) | 136 return os.path.getsize(update_path) |
123 | 137 |
124 def GetHash(self, update_path): | 138 def GetHash(self, update_path): |
125 cmd = "cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';" \ | 139 cmd = "cat %s | openssl sha1 -binary | openssl base64 | tr \'\\n\' \' \';" \ |
126 % update_path | 140 % update_path |
127 web.debug(cmd) | 141 web.debug(cmd) |
(...skipping 22 matching lines...) Expand all Loading... |
150 web.debug('%s not found.' % image_path) | 164 web.debug('%s not found.' % image_path) |
151 return self.GetNoUpdatePayload() | 165 return self.GetNoUpdatePayload() |
152 # Construct a response | 166 # Construct a response |
153 ok = self.BuildUpdateImage(image_path) | 167 ok = self.BuildUpdateImage(image_path) |
154 if ok != True: | 168 if ok != True: |
155 web.debug('Failed to build an update image') | 169 web.debug('Failed to build an update image') |
156 return self.GetNoUpdatePayload() | 170 return self.GetNoUpdatePayload() |
157 web.debug('serving update: ') | 171 web.debug('serving update: ') |
158 hash = self.GetHash('%s/%s/update.gz' % (self.static_dir, label)) | 172 hash = self.GetHash('%s/%s/update.gz' % (self.static_dir, label)) |
159 size = self.GetSize('%s/%s/update.gz' % (self.static_dir, label)) | 173 size = self.GetSize('%s/%s/update.gz' % (self.static_dir, label)) |
160 url = 'http://%s/static/archive/%s/update.gz' % (hostname, label) | 174 # In case we configured images to be hosted elsewhere |
| 175 # (e.g. buildbot's httpd), use that. Otherwise, serve it |
| 176 # ourselves using web.py's static resource handler. |
| 177 if self.static_urlbase: |
| 178 urlbase = self.static_urlbase |
| 179 else: |
| 180 urlbase = 'http://%s/static/archive/' % hostname |
| 181 |
| 182 url = '%s/%s/update.gz' % (urlbase, label) |
161 return self.GetUpdatePayload(hash, size, url) | 183 return self.GetUpdatePayload(hash, size, url) |
162 web.debug( 'DONE') | 184 web.debug( 'DONE') |
163 else: | 185 else: |
164 web.debug('update found %s ' % latest_version) | 186 web.debug('update found %s ' % latest_version) |
165 ok = self.BuildUpdateImage(latest_image_path) | 187 ok = self.BuildUpdateImage(latest_image_path) |
166 if ok != True: | 188 if ok != True: |
167 web.debug('Failed to build an update image') | 189 web.debug('Failed to build an update image') |
168 return self.GetNoUpdatePayload() | 190 return self.GetNoUpdatePayload() |
169 | 191 |
170 hash = self.GetHash('%s/update.gz' % self.static_dir) | 192 hash = self.GetHash('%s/update.gz' % self.static_dir) |
171 size = self.GetSize('%s/update.gz' % self.static_dir) | 193 size = self.GetSize('%s/update.gz' % self.static_dir) |
172 | 194 |
173 url = 'http://%s/static/update.gz' % hostname | 195 url = 'http://%s/static/update.gz' % hostname |
174 return self.GetUpdatePayload(hash, size, url) | 196 return self.GetUpdatePayload(hash, size, url) |
OLD | NEW |