OLD | NEW |
1 # Copyright (c) 2009-2010 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 import autoupdate |
| 6 import buildutil |
5 import optparse | 7 import optparse |
6 import os | 8 import os |
7 import sys | 9 import sys |
8 import web | 10 import web |
9 | 11 |
10 import autoupdate | |
11 import buildutil | |
12 | |
13 # Sets up global to share between classes. | |
14 global updater | 12 global updater |
15 updater = None | 13 updater = None |
16 | 14 |
17 | 15 |
18 class index: | 16 class index: |
19 def GET(self): | 17 def GET(self): |
20 return render.index(None) | 18 return render.index(None) |
21 | 19 |
22 | |
23 class update: | 20 class update: |
24 """ | 21 """ |
25 Processes updates from the client machine. If an update is found, the url | 22 Processes updates from the client machine. If an update is found, the url |
26 references a static link that can be served automagically from web.py. | 23 references a static link that can be served automagically from web.py. |
27 """ | 24 """ |
28 def POST(self, args=None): | 25 def POST(self, args=None): |
29 return updater.HandleUpdatePing(web.data(), args) | 26 return updater.HandleUpdatePing(web.data(), args) |
30 | 27 |
31 | |
32 class build: | 28 class build: |
33 """ | 29 """ |
34 builds the package specified by the pkg parameter and returns the name | 30 builds the package specified by the pkg parameter and returns the name |
35 of the output file. | 31 of the output file. |
36 """ | 32 """ |
37 def POST(self): | 33 def POST(self): |
38 input = web.input() | 34 input = web.input() |
39 web.debug('emerging %s ' % input.pkg) | 35 web.debug('emerging %s ' % input.pkg) |
40 emerge_command = 'emerge-%s %s' % (input.board, input.pkg) | 36 emerge_command = 'emerge-%s %s' % (input.board, input.pkg) |
41 err = os.system(emerge_command) | 37 err = os.system(emerge_command) |
42 if err != 0: | 38 if err != 0: |
43 raise Exception('failed to execute %s' % emerge_command) | 39 raise Exception('failed to execute %s' % emerge_command) |
44 eclean_command = 'eclean-%s -d packages' % input.board | 40 eclean_command = 'eclean-%s -d packages' % input.board |
45 err = os.system(eclean_command) | 41 err = os.system(eclean_command) |
46 if err != 0: | 42 if err != 0: |
47 raise Exception('failed to execute %s' % emerge_command) | 43 raise Exception('failed to execute %s' % emerge_command) |
48 | 44 |
49 | |
50 def OverrideWSGIServer(server_address, wsgi_app): | 45 def OverrideWSGIServer(server_address, wsgi_app): |
51 """Creates a CherryPyWSGIServer instance. | 46 """Creates a CherryPyWSGIServer instance. |
52 | 47 |
53 Overrides web.py's WSGIServer routine (web.httpserver.WSGIServer) to | 48 Overrides web.py's WSGIServer routine (web.httpserver.WSGIServer) to |
54 increase the accepted connection socket timeout from the default 10 | 49 increase the accepted connection socket timeout from the default 10 |
55 seconds to 10 minutes. The extra time is necessary to serve delta | 50 seconds to 10 minutes. The extra time is necessary to serve delta |
56 updates as well as update requests from a low priority update_engine | 51 updates as well as update requests from a low priority update_engine |
57 process running on a heavily loaded Chrome OS device. | 52 process running on a heavily loaded Chrome OS device. |
58 """ | 53 """ |
59 web.debug('using local OverrideWSGIServer routine') | 54 web.debug('using local OverrideWSGIServer routine') |
60 from web.wsgiserver import CherryPyWSGIServer | 55 from web.wsgiserver import CherryPyWSGIServer |
61 return CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost", | 56 return CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost", |
62 timeout=600) | 57 timeout=600) |
63 | 58 |
64 def _PrepareToServeUpdatesOnly(image_dir): | |
65 """Sets up symlink to image_dir for serving purposes.""" | |
66 assert os.path.exists(image_dir), '%s must exist.' % image_dir | |
67 # If we're serving out of an archived build dir (e.g. a | |
68 # buildbot), prepare this webserver's magic 'static/' dir with a | |
69 # link to the build archive. | |
70 web.debug('Preparing autoupdate for "serve updates only" mode.') | |
71 if os.path.exists('static/archive'): | |
72 if image_dir != os.readlink('static/archive'): | |
73 web.debug('removing stale symlink to %s' % image_dir) | |
74 os.unlink('static/archive') | |
75 os.symlink(image_dir, 'static/archive') | |
76 else: | |
77 os.symlink(image_dir, 'static/archive') | |
78 web.debug('archive dir: %s ready to be used to serve images.' % image_dir) | |
79 | |
80 | |
81 if __name__ == '__main__': | 59 if __name__ == '__main__': |
82 usage = 'usage: %prog [options]' | 60 usage = 'usage: %prog [options]' |
83 parser = optparse.OptionParser(usage) | 61 parser = optparse.OptionParser(usage) |
84 parser.add_option('--archive_dir', dest='archive_dir', | 62 parser.add_option('--archive_dir', dest='archive_dir', |
85 help='serve archived builds only.') | 63 help='serve archived builds only.') |
86 parser.add_option('--client_prefix', dest='client_prefix', | 64 parser.add_option('--client_prefix', dest='client_prefix', |
87 help='Required prefix for client software version.', | 65 help='Required prefix for client software version.', |
88 default='MementoSoftwareUpdate') | 66 default='MementoSoftwareUpdate') |
89 parser.add_option('--factory_config', dest='factory_config', | 67 parser.add_option('--factory_config', dest='factory_config', |
90 help='Config file for serving images from factory floor.') | 68 help='Config file for serving images from factory floor.') |
91 parser.add_option('--image', dest='image', | |
92 help='Force update using this image.') | |
93 parser.add_option('-t', action='store_true', dest='test_image') | 69 parser.add_option('-t', action='store_true', dest='test_image') |
94 parser.add_option('-u', '--urlbase', dest='urlbase', | 70 parser.add_option('-u', '--urlbase', dest='urlbase', |
95 help='base URL, other than devserver, for update images.') | 71 help='base URL, other than devserver, for update images.') |
96 parser.add_option('--validate_factory_config', action="store_true", | 72 parser.add_option('--validate_factory_config', action="store_true", |
97 dest='validate_factory_config', | 73 dest='validate_factory_config', |
98 help='Validate factory config file, then exit.') | 74 help='Validate factory config file, then exit.') |
99 # Clean up the args, due to httpserver's hardcoded use of sys.argv. | 75 options, args = parser.parse_args() |
100 options, sys.argv = parser.parse_args(sys.argv) | 76 # clean up the args, due to httpserver's hardcoded use of sys.argv |
| 77 if options.archive_dir: |
| 78 sys.argv.remove('--archive_dir') |
| 79 sys.argv.remove(options.archive_dir) |
| 80 if '--client_prefix' in sys.argv: |
| 81 sys.argv.remove('--client_prefix') |
| 82 sys.argv.remove(options.client_prefix) |
| 83 if options.factory_config: |
| 84 sys.argv.remove('--factory_config') |
| 85 sys.argv.remove(options.factory_config) |
| 86 if options.test_image: |
| 87 sys.argv.remove('-t') |
| 88 if options.urlbase: |
| 89 sys.argv.remove('-u') |
| 90 sys.argv.remove(options.urlbase) |
| 91 if options.validate_factory_config: |
| 92 sys.argv.remove('--validate_factory_config') |
101 | 93 |
102 root_dir = os.path.realpath('%s/../..' % | 94 root_dir = os.path.realpath('%s/../..' % |
103 os.path.dirname(os.path.abspath(sys.argv[0]))) | 95 os.path.dirname(os.path.abspath(sys.argv[0]))) |
104 | |
105 serve_only = False | |
106 | |
107 if options.archive_dir: | 96 if options.archive_dir: |
108 static_dir = os.path.realpath(options.archive_dir) | 97 static_dir = os.path.realpath(options.archive_dir) |
109 _PrepareToServeUpdatesOnly(static_dir) | 98 assert os.path.exists(static_dir), '%s must exist.' % options.archive_dir |
110 serve_only = True | 99 web.debug('using archive dir: %s' % static_dir) |
111 else: | 100 else: |
112 static_dir = os.path.realpath('%s/static' % | 101 static_dir = os.path.realpath('%s/static' % |
113 os.path.dirname(os.path.abspath(sys.argv[0]))) | 102 os.path.dirname(os.path.abspath(sys.argv[0]))) |
114 web.debug('dev root is %s' % root_dir) | 103 web.debug('dev root is %s' % root_dir) |
115 os.system('mkdir -p %s' % static_dir) | 104 os.system('mkdir -p %s' % static_dir) |
116 | 105 web.debug('Serving images from %s' % static_dir) |
117 web.debug('Serving from %s' % static_dir) | |
118 | 106 |
119 updater = autoupdate.Autoupdate( | 107 updater = autoupdate.Autoupdate( |
120 root_dir=root_dir, | 108 root_dir=root_dir, |
121 static_dir=static_dir, | 109 static_dir=static_dir, |
122 serve_only=serve_only, | 110 serve_only=options.archive_dir, |
123 urlbase=options.urlbase, | 111 urlbase=options.urlbase, |
124 test_image=options.test_image, | 112 test_image=options.test_image, |
125 factory_config_path=options.factory_config, | 113 factory_config_path=options.factory_config, |
126 client_prefix=options.client_prefix, | 114 validate_factory_config=options.validate_factory_config, |
127 forced_image=options.image) | 115 client_prefix=options.client_prefix) |
| 116 if options.validate_factory_config: |
| 117 sys.exit(0) |
| 118 urls = ('/', 'index', |
| 119 '/update', 'update', |
| 120 '/update/(.+)', 'update', |
| 121 '/build', 'build') |
128 | 122 |
129 if options.factory_config: | 123 # Overrides the default WSGIServer routine -- see OverrideWSGIServer. |
130 updater.ImportFactoryConfigFile(factory_config_path, | 124 web.httpserver.WSGIServer = OverrideWSGIServer |
131 validate_factory_config) | 125 app = web.application(urls, globals(), autoreload=True) |
132 | 126 render = web.template.render('templates/') |
133 if not options.validate_factory_config: | 127 app.run() |
134 # We do not need to run the dev server for validating the factory config. | |
135 # TODO(nsanders): Write unit test to validate. | |
136 urls = ('/', 'index', | |
137 '/update', 'update', | |
138 '/update/(.+)', 'update', | |
139 '/build', 'build') | |
140 | |
141 # Overrides the default WSGIServer routine -- see OverrideWSGIServer. | |
142 web.httpserver.WSGIServer = OverrideWSGIServer | |
143 app = web.application(urls, globals(), autoreload=True) | |
144 render = web.template.render('templates/') | |
145 app.run() | |
OLD | NEW |