class ZuulWeb(object): log = logging.getLogger("zuul.web.ZuulWeb") def __init__(self, listen_address, listen_port, gear_server, gear_port, ssl_key=None, ssl_cert=None, ssl_ca=None, static_cache_expiry=3600, connections=None, info=None, static_path=None, zk_hosts=None): self.start_time = time.time() self.listen_address = listen_address self.listen_port = listen_port self.event_loop = None self.term = None self.server = None self.static_cache_expiry = static_cache_expiry self.info = info self.static_path = os.path.abspath(static_path or STATIC_DIR) # instanciate handlers self.rpc = zuul.rpcclient.RPCClient(gear_server, gear_port, ssl_key, ssl_cert, ssl_ca) self.zk = zuul.zk.ZooKeeper() if zk_hosts: self.zk.connect(hosts=zk_hosts, read_only=True) self.connections = connections self.stream_manager = StreamManager() route_map = cherrypy.dispatch.RoutesDispatcher() api = ZuulWebAPI(self) route_map.connect('api', '/api', controller=api, action='index') route_map.connect('api', '/api/info', controller=api, action='info') route_map.connect('api', '/api/connections', controller=api, action='connections') route_map.connect('api', '/api/tenants', controller=api, action='tenants') route_map.connect('api', '/api/tenant/{tenant}/info', controller=api, action='tenant_info') route_map.connect('api', '/api/tenant/{tenant}/status', controller=api, action='status') route_map.connect('api', '/api/tenant/{tenant}/status/change/{change}', controller=api, action='status_change') route_map.connect('api', '/api/tenant/{tenant}/jobs', controller=api, action='jobs') route_map.connect('api', '/api/tenant/{tenant}/job/{job_name}', controller=api, action='job') route_map.connect('api', '/api/tenant/{tenant}/projects', controller=api, action='projects') route_map.connect('api', '/api/tenant/{tenant}/project/{project:.*}', controller=api, action='project') route_map.connect( 'api', '/api/tenant/{tenant}/pipeline/{pipeline}' '/project/{project:.*}/branch/{branch:.*}/freeze-jobs', controller=api, action='project_freeze_jobs' ) route_map.connect('api', '/api/tenant/{tenant}/pipelines', controller=api, action='pipelines') route_map.connect('api', '/api/tenant/{tenant}/labels', controller=api, action='labels') route_map.connect('api', '/api/tenant/{tenant}/nodes', controller=api, action='nodes') route_map.connect('api', '/api/tenant/{tenant}/key/{project:.*}.pub', controller=api, action='key') route_map.connect('api', '/api/tenant/{tenant}/' 'project-ssh-key/{project:.*}.pub', controller=api, action='project_ssh_key') route_map.connect('api', '/api/tenant/{tenant}/console-stream', controller=api, action='console_stream') route_map.connect('api', '/api/tenant/{tenant}/builds', controller=api, action='builds') route_map.connect('api', '/api/tenant/{tenant}/build/{uuid}', controller=api, action='build') route_map.connect('api', '/api/tenant/{tenant}/buildsets', controller=api, action='buildsets') route_map.connect('api', '/api/tenant/{tenant}/buildset/{uuid}', controller=api, action='buildset') route_map.connect('api', '/api/tenant/{tenant}/config-errors', controller=api, action='config_errors') for connection in connections.connections.values(): controller = connection.getWebController(self) if controller: cherrypy.tree.mount( controller, '/api/connection/%s' % connection.connection_name) # Add fallthrough routes at the end for the static html/js files route_map.connect( 'root_static', '/{path:.*}', controller=StaticHandler(self.static_path), action='default') conf = { '/': { 'request.dispatch': route_map } } cherrypy.config.update({ 'global': { 'environment': 'production', 'server.socket_host': listen_address, 'server.socket_port': int(listen_port), }, }) cherrypy.tree.mount(api, '/', config=conf) @property def port(self): return cherrypy.server.bound_addr[1] def start(self): self.log.debug("ZuulWeb starting") self.stream_manager.start() self.wsplugin = WebSocketPlugin(cherrypy.engine) self.wsplugin.subscribe() cherrypy.engine.start() def stop(self): self.log.debug("ZuulWeb stopping") self.rpc.shutdown() cherrypy.engine.exit() # Not strictly necessary, but without this, if the server is # started again (e.g., in the unit tests) it will reuse the # same host/port settings. cherrypy.server.httpserver = None self.wsplugin.unsubscribe() self.stream_manager.stop() self.zk.disconnect()
class ZuulWeb(object): log = logging.getLogger("zuul.web.ZuulWeb") def __init__(self, listen_address, listen_port, gear_server, gear_port, ssl_key=None, ssl_cert=None, ssl_ca=None, static_cache_expiry=3600, connections=None, info=None, static_path=None): self.start_time = time.time() self.listen_address = listen_address self.listen_port = listen_port self.event_loop = None self.term = None self.server = None self.static_cache_expiry = static_cache_expiry self.info = info self.static_path = os.path.abspath(static_path or STATIC_DIR) # instanciate handlers self.rpc = zuul.rpcclient.RPCClient(gear_server, gear_port, ssl_key, ssl_cert, ssl_ca) self.connections = connections self.stream_manager = StreamManager() route_map = cherrypy.dispatch.RoutesDispatcher() api = ZuulWebAPI(self) tenant_static = TenantStaticHandler(self.static_path) root_static = RootStaticHandler(self.static_path) route_map.connect('api', '/api/info', controller=api, action='info') route_map.connect('api', '/api/tenants', controller=api, action='tenants') route_map.connect('api', '/api/tenant/{tenant}/info', controller=api, action='tenant_info') route_map.connect('api', '/api/tenant/{tenant}/status', controller=api, action='status') route_map.connect('api', '/api/tenant/{tenant}/status/change/{change}', controller=api, action='status_change') route_map.connect('api', '/api/tenant/{tenant}/jobs', controller=api, action='jobs') route_map.connect('api', '/api/tenant/{tenant}/key/{project:.*}.pub', controller=api, action='key') route_map.connect('api', '/api/tenant/{tenant}/console-stream', controller=api, action='console_stream') route_map.connect('api', '/api/tenant/{tenant}/builds', controller=api, action='builds') route_map.connect('api', '/api/tenant/{tenant}/config-errors', controller=api, action='config_errors') for connection in connections.connections.values(): controller = connection.getWebController(self) if controller: cherrypy.tree.mount( controller, '/api/connection/%s' % connection.connection_name) # Add fallthrough routes at the end for the static html/js files route_map.connect('root_static', '/{path:.*}', controller=root_static, action='default') route_map.connect('tenant_static', '/t/{tenant}/{path:.*}', controller=tenant_static, action='default') conf = { '/': { 'request.dispatch': route_map } } cherrypy.config.update({ 'global': { 'environment': 'production', 'server.socket_host': listen_address, 'server.socket_port': int(listen_port), }, }) cherrypy.tree.mount(api, '/', config=conf) @property def port(self): return cherrypy.server.bound_addr[1] def start(self): self.log.debug("ZuulWeb starting") self.stream_manager.start() self.wsplugin = WebSocketPlugin(cherrypy.engine) self.wsplugin.subscribe() cherrypy.engine.start() def stop(self): self.log.debug("ZuulWeb stopping") self.rpc.shutdown() cherrypy.engine.exit() # Not strictly necessary, but without this, if the server is # started again (e.g., in the unit tests) it will reuse the # same host/port settings. cherrypy.server.httpserver = None self.wsplugin.unsubscribe() self.stream_manager.stop()
class ZuulWeb(object): log = logging.getLogger("zuul.web.ZuulWeb") def __init__( self, listen_address, listen_port, gear_server, gear_port, ssl_key=None, ssl_cert=None, ssl_ca=None, static_cache_expiry=3600, connections=None, info=None, static_path=None, zk_hosts=None, authenticators=None, command_socket=None, ): self.start_time = time.time() self.listen_address = listen_address self.listen_port = listen_port self.event_loop = None self.term = None self.server = None self.static_cache_expiry = static_cache_expiry self.info = info self.static_path = os.path.abspath(static_path or STATIC_DIR) # instanciate handlers self.rpc = zuul.rpcclient.RPCClient(gear_server, gear_port, ssl_key, ssl_cert, ssl_ca) self.zk = zuul.zk.ZooKeeper() if zk_hosts: self.zk.connect(hosts=zk_hosts, read_only=True) self.connections = connections self.authenticators = authenticators self.stream_manager = StreamManager() self.command_socket = commandsocket.CommandSocket(command_socket) self.repl = None self.command_map = { 'stop': self.stop, 'repl': self.start_repl, 'norepl': self.stop_repl, } route_map = cherrypy.dispatch.RoutesDispatcher() api = ZuulWebAPI(self) route_map.connect('api', '/api', controller=api, action='index') route_map.connect('api', '/api/info', controller=api, action='info') route_map.connect('api', '/api/connections', controller=api, action='connections') route_map.connect('api', '/api/tenants', controller=api, action='tenants') route_map.connect('api', '/api/tenant/{tenant}/info', controller=api, action='tenant_info') route_map.connect('api', '/api/tenant/{tenant}/status', controller=api, action='status') route_map.connect('api', '/api/tenant/{tenant}/status/change/{change}', controller=api, action='status_change') route_map.connect('api', '/api/tenant/{tenant}/jobs', controller=api, action='jobs') route_map.connect('api', '/api/tenant/{tenant}/job/{job_name}', controller=api, action='job') # if no auth configured, deactivate admin routes if self.authenticators.authenticators: # route order is important, put project actions before the more # generic tenant/{tenant}/project/{project} route route_map.connect( 'api', '/api/tenant/{tenant}/project/{project:.*}/autohold', controller=api, action='autohold') route_map.connect( 'api', '/api/tenant/{tenant}/project/{project:.*}/enqueue', controller=api, action='enqueue') route_map.connect( 'api', '/api/tenant/{tenant}/project/{project:.*}/dequeue', controller=api, action='dequeue') route_map.connect('api', '/api/tenant/{tenant}/autohold', controller=api, action='autohold_list') route_map.connect('api', '/api/tenant/{tenant}/projects', controller=api, action='projects') route_map.connect('api', '/api/tenant/{tenant}/project/{project:.*}', controller=api, action='project') route_map.connect( 'api', '/api/tenant/{tenant}/pipeline/{pipeline}' '/project/{project:.*}/branch/{branch:.*}/freeze-jobs', controller=api, action='project_freeze_jobs') route_map.connect('api', '/api/tenant/{tenant}/pipelines', controller=api, action='pipelines') route_map.connect('api', '/api/tenant/{tenant}/labels', controller=api, action='labels') route_map.connect('api', '/api/tenant/{tenant}/nodes', controller=api, action='nodes') route_map.connect('api', '/api/tenant/{tenant}/key/{project:.*}.pub', controller=api, action='key') route_map.connect('api', '/api/tenant/{tenant}/' 'project-ssh-key/{project:.*}.pub', controller=api, action='project_ssh_key') route_map.connect('api', '/api/tenant/{tenant}/console-stream', controller=api, action='console_stream') route_map.connect('api', '/api/tenant/{tenant}/builds', controller=api, action='builds') route_map.connect('api', '/api/tenant/{tenant}/build/{uuid}', controller=api, action='build') route_map.connect('api', '/api/tenant/{tenant}/buildsets', controller=api, action='buildsets') route_map.connect('api', '/api/tenant/{tenant}/buildset/{uuid}', controller=api, action='buildset') route_map.connect('api', '/api/tenant/{tenant}/config-errors', controller=api, action='config_errors') for connection in connections.connections.values(): controller = connection.getWebController(self) if controller: cherrypy.tree.mount( controller, '/api/connection/%s' % connection.connection_name) # Add fallthrough routes at the end for the static html/js files route_map.connect('root_static', '/{path:.*}', controller=StaticHandler(self.static_path), action='default') conf = {'/': {'request.dispatch': route_map}} cherrypy.config.update({ 'global': { 'environment': 'production', 'server.socket_host': listen_address, 'server.socket_port': int(listen_port), }, }) cherrypy.tree.mount(api, '/', config=conf) @property def port(self): return cherrypy.server.bound_addr[1] def start(self): self.log.debug("ZuulWeb starting") self.stream_manager.start() self.wsplugin = WebSocketPlugin(cherrypy.engine) self.wsplugin.subscribe() cherrypy.engine.start() self.log.debug("Starting command processor") self._command_running = True self.command_socket.start() self.command_thread = threading.Thread(target=self.runCommand, name='command') self.command_thread.daemon = True self.command_thread.start() def stop(self): self.log.debug("ZuulWeb stopping") self.rpc.shutdown() cherrypy.engine.exit() # Not strictly necessary, but without this, if the server is # started again (e.g., in the unit tests) it will reuse the # same host/port settings. cherrypy.server.httpserver = None self.wsplugin.unsubscribe() self.stream_manager.stop() self.zk.disconnect() self.stop_repl() self._command_running = False self.command_socket.stop() self.command_thread.join() def runCommand(self): while self._command_running: try: command = self.command_socket.get().decode('utf8') if command != '_stop': self.command_map[command]() except Exception: self.log.exception("Exception while processing command") def start_repl(self): if self.repl: return self.repl = zuul.lib.repl.REPLServer(self) self.repl.start() def stop_repl(self): if not self.repl: return self.repl.stop() self.repl = None