| 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 |