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