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