def run(self): log.info("starting on port {}".format(port)) plugin = WebSocketPlugin(cherrypy.engine) plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() p.events.on("switch", self.dispatch_device, priority=True) p.events.on("coil", self.dispatch_device, priority=True) p.events.on("lamp", self.dispatch_device, priority=True) p.events.on("flasher", self.dispatch_device, priority=True) p.events.on("gi", self.dispatch_device, priority=True) p.events.on("notice", self.dispatch_notice, priority=True) cherrypy.quickstart(Root(), "/", config={ "/": { "tools.staticdir.on": True, "tools.staticdir.root": os.path.abspath(os.path.join( os.path.dirname(__file__), "..", "..", "web")), "tools.staticdir.index": "index.html", "tools.staticdir.dir": "" }, "/console": { "tools.staticdir.on": True, "tools.staticdir.dir": "console" }, "/ws": { "tools.websocket.on": True, "tools.websocket.handler_cls": WebSocketHandler } }) self.done(plugin)
def _configure_server(restarting=False): global websocket_plugin # Configure server error log cherrypy.config.update({'log.error_file': 'cherrypy.error.log'}) # Configure server url cherrypy.config.update({'server.socket_host': utils.s2n(autosubliminal.WEBSERVERIP), 'server.socket_port': int(autosubliminal.WEBSERVERPORT) }) # Disable engine plugins (no need for autoreload plugin) cherrypy.config.update({'engine.autoreload.on': False}) # Configure authentication in if a username and password is set by the user if autosubliminal.USERNAME and autosubliminal.PASSWORD: users = {utils.s2n(autosubliminal.USERNAME): utils.s2n(autosubliminal.PASSWORD)} cherrypy.config.update({'tools.auth_digest.on': True, 'tools.auth_digest.realm': 'Auto-Subliminal website', 'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(users), 'tools.auth_digest.key': 'yek.tsegid_htua.lanimilbuS-otuA' # Can be any random string }) if not restarting: # Enable websocket plugin websocket_plugin = WebSocketPlugin(cherrypy.engine) websocket_plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() else: # When restarting we need to create a new websocket manager thread (you cannot start the same thread twice!) websocket_plugin.manager = WebSocketManager() # When restarting we need to clear the httpserver to force the creation of a new one (needed for ip/port change) cherrypy.server.httpserver = None
def extend_server_configuration(cls, engine, config): """Extend the server configuration.""" cp_plugin = WebSocketPlugin(engine) cp_plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() for handler in cls.handlers: config.update({ handler.ws_point: { 'tools.websocket.on': True, 'tools.websocket.handler_cls': handler, }, })
def _configure_server(restarting=False): global websocket_plugin # Configure server error log cherrypy.config.update({'log.error_file': 'cherrypy.error.log'}) # Configure server url cherrypy.config.update({ 'server.socket_host': s2n(autosubliminal.WEBSERVERIP), 'server.socket_port': int(autosubliminal.WEBSERVERPORT) }) # Disable engine plugins (no need for autoreload plugin) cherrypy.config.update({'engine.autoreload.on': False}) # Read and store cherrypy server version (if not set, it returns CherryPy/Unknown because it's not installed) server_header = 'CherryPy/%s' % get_library_version('cherrypy') cherrypy.config.update({'response.headers.server': server_header}) # Configure authentication in if a username and password is set by the user if autosubliminal.USERNAME and autosubliminal.PASSWORD: users = {s2n(autosubliminal.USERNAME): s2n(autosubliminal.PASSWORD)} cherrypy.config.update({ 'tools.auth_digest.on': True, 'tools.auth_digest.realm': 'Auto-Subliminal website', 'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(users), 'tools.auth_digest.key': 'yek.tsegid_htua.lanimilbuS-otuA' # Can be any random string }) # Configure our custom json_out_handler (Uncomment if it should be used for any @cherrypy.tools.json_out()) # cherrypy.config.update({'tools.json_out.handler': json_out_handler}) if not restarting: # Enable websocket plugin websocket_plugin = WebSocketPlugin(cherrypy.engine) websocket_plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() else: # When restarting we need to create a new websocket manager thread (you cannot start the same thread twice!) websocket_plugin.manager = WebSocketManager() # When restarting we need to clear the httpserver to force the creation of a new one (needed for ip/port change) cherrypy.server.httpserver = None
def start_cherrypy_debug_server(htdocs_path, http_host, http_port, mpd_host, mpd_port=6600, mpd_password=None): # set cherrypy configuration. cherrypy.config.update({'server.socket_port': http_port}) cherrypy.config.update({'server.socket_host': http_host}) if (not os.path.isdir(htdocs_path)): print("=" * 80 + """ The ympd htdocs dir is not available: perhaps the git submodule is missing? """ + "=" * 80) sys.exit(1) # Add the websocket requirements. a = WebSocketPlugin(cherrypy.engine) a.manager = WebSocketManager() a.subscribe() cherrypy.tools.websocket = WebSocketTool() web_root = Root() # get a function to instantiate the websocket with the correct settings. ympd_websocket = ympdWebSocket_wrap(mpd_host, mpd_port, mpd_password) # Run a no-websocket alternative at http://hostname:port/nows/ nowebsocket = ympdNoWebSocket_wrap(mpd_host, mpd_port, mpd_password) web_root.nows = nowebsocket(htdocs_path) # this implementation uses POST requests communicate. # Takes a little bit longer for the UI to update, but it should get through # firewalls and proxies where the websocket cannot. cherrypy.quickstart(web_root, '/', config={ '/ws': {'tools.websocket.on': True, 'tools.websocket.handler_cls': ympd_websocket}, '/': {'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(htdocs_path), "tools.staticdir.index": "index.html"}, } )
def _configure_server(restarting=False): global websocket_plugin # Configure server error log cherrypy.config.update({'log.error_file': 'cherrypy.error.log'}) # Configure server url cherrypy.config.update({'server.socket_host': s2n(autosubliminal.WEBSERVERIP), 'server.socket_port': int(autosubliminal.WEBSERVERPORT) }) # Disable engine plugins (no need for autoreload plugin) cherrypy.config.update({'engine.autoreload.on': False}) # Read and store cherrypy server version (if not set, it returns CherryPy/Unknown because it's not installed) server_header = 'CherryPy/%s' % get_library_version('cherrypy') cherrypy.config.update({'response.headers.server': server_header}) # Configure authentication in if a username and password is set by the user if autosubliminal.USERNAME and autosubliminal.PASSWORD: users = {s2n(autosubliminal.USERNAME): s2n(autosubliminal.PASSWORD)} cherrypy.config.update({'tools.auth_digest.on': True, 'tools.auth_digest.realm': 'Auto-Subliminal website', 'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(users), 'tools.auth_digest.key': 'yek.tsegid_htua.lanimilbuS-otuA' # Can be any random string }) # Configure our custom json_out_handler (Uncomment if it should be used for any @cherrypy.tools.json_out()) # cherrypy.config.update({'tools.json_out.handler': json_out_handler}) if not restarting: # Enable websocket plugin websocket_plugin = WebSocketPlugin(cherrypy.engine) websocket_plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() else: # When restarting we need to create a new websocket manager thread (you cannot start the same thread twice!) websocket_plugin.manager = WebSocketManager() # When restarting we need to clear the httpserver to force the creation of a new one (needed for ip/port change) cherrypy.server.httpserver = None
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()
self.stream_mux.active_in = json['stream_source'] class RobotWebApp: @cherrypy.expose def index(self): raise cherrypy.InternalRedirect('/static/index.html') @cherrypy.expose def ws(self): pass cherrypy.tools.websocket = WebSocketTool() websocket_plugin = WebSocketPlugin(cherrypy.engine) websocket_plugin.subscribe() class StreamBroadcaster(Thread): def __init__(self, stream, websockets): super().__init__(daemon=True, name="StreamBroadcaster") self.stream = stream self.websockets = websockets def run(self): try: while True: buf = self.stream.read1(32768) self.websockets.broadcast(buf, binary=True) except ValueError: pass
def start_broker(): """ Starts the broker; Loads settings, connects to database, registers process and starts the web server. """ global process_id, database_access, address, web_socket_plugin, repository_parent_folder, \ web_config, schema_tools, namespaces, log_to_database_severity, plugins, settings process_id = str(ObjectId()) of.common.logging.callback = log_locally write_srvc_dbg("=====Starting broker=============================") try: _cfg_filename = resolve_config_path() settings = JSONXPath(_cfg_filename) except Exception as e: if os.name == "nt": write_to_log(_data="Error loading settings from " + _cfg_filename, _category=EC_SERVICE, _severity=SEV_FATAL) raise Exception("Error loading settings:" + str(e)) if os.name != "nt": x_logger = logging.FileHandler("/var/log/of.log") of.common.logging.severity = of.common.logging.severity_identifiers.index( settings.get("broker/logging/severityLevel", _default="warning")) log_to_database_severity = of.common.logging.severity_identifiers.index( settings.get("broker/logging/databaseLevel", _default="warning")) write_srvc_dbg("Loaded settings from " + _cfg_filename) # An address is completely neccessary. address = settings.get("broker/address", _default=None) if not address or address == "": write_to_log(_data="Broker cannot start, missing [broker] address setting in configuration file.", _category=EC_SERVICE, _severity=SEV_FATAL) raise Exception("Broker cannot start, missing address.") # TODO: Reorganize. It is likely that almost everything but external database credentials should be stored in the db PROD-105 # Initialize schema tools (of_uri_handler is later replaced by the general one) schema_tools = SchemaTools(_json_schema_folders=[os.path.join(script_dir, "../schemas/namespaces/")], _uri_handlers={"ref": of_uri_handler}) namespaces = CumulativeDict(_default={"schemas": []}) write_srvc_dbg("Load plugin data") # Find the plugin directory _plugins_folder = settings.get_path("broker/pluginsFolder", _default="plugins") # Load all plugin data plugins = CherryPyPlugins(_plugins_folder=_plugins_folder, _schema_tools=schema_tools, _namespaces=namespaces, _process_id=process_id, _no_package_name_override=settings.get("broker/packageNameOverride")) # Plugins may want to load settings or add globals plugins.call_hook("init_broker_scope", _broker_scope=globals(), _settings=settings) write_srvc_dbg("===Register signal handlers===") register_signals(stop_broker) plugins.call_hook("before_db_connect", _broker_scope=globals()) # Connect to the database _host = settings.get("broker/database/host", _default="127.0.0.1") _user = settings.get("broker/database/username", _default=None) _password = settings.get("broker/database/password", _default=None) if _user: write_srvc_dbg("===Connecting to remote MongoDB backend " + _host + "===") # http://api.mongodb.org/python/current/examples/authentication.html _client = MongoClient("mongodb://" + _user + ":" + _password + "@" + _host) else: write_srvc_dbg("===Connecting to local MongoDB backend===") _client = MongoClient() _database_name = settings.get("broker/database/databaseName", _default="optimalframework") write_srvc_dbg("Using database name :" + _database_name) _database = _client[_database_name] database_access = DatabaseAccess(_database=_database, _schema_tools=schema_tools) of.common.logging.callback = log_to_database database_access.save(store_process_system_document(_process_id=process_id, _name="Broker instance(" + address + ")"), _user=None, _allow_save_id=True) plugins.call_hook("after_db_connect", _broker_scope=globals()) # TODO: It is possible that one would like to initialize, or at least read the plugins *before* trying to connect to the database # Must have a valid CherryPy version if hasattr(cherrypy.engine, "subscribe"): # CherryPy >= 3.1 pass else: write_to_log(_data="This application requires CherryPy >= 3.1 or higher.", _category=EC_SERVICE, _severity=SEV_FATAL) raise Exception("Broker init: This application requires CherryPy >= 3.1 or higher.") # cherrypy.engine.on_stop_engine_list.append(_save_data) def ssl_path(): # Figure out the path to the ssl-certificates # TODO: Load from database instead. Or not? (PROD-19) return os.path.dirname(_cfg_filename) # Initialize CherryPy:s global configuration; note that this could be moved into a configuration file cherrypy.config.update({ "tools.encode.on": True, "tools.encode.encoding": "utf-8", "tools.decode.on": True, "tools.trailing_slash.on": True, "tools.staticdir.root": os.path.abspath(os.path.dirname(__file__)), "server.ssl_module": "builtin", # TODO: Remove this when this bug is fixed: # https://bitbucket.org/cherrypy/cherrypy/issue/1341/autoreloader-also-fails-if-six-is-present "engine.autoreload.on": False, 'server.socket_host': '0.0.0.0', "server.ssl_certificate": os.path.join(ssl_path(), "optimalframework_test_cert.pem"), "server.ssl_private_key": os.path.join(ssl_path(), "optimalframework_test_privkey.pem"), "error_page.default": error_message_default }) write_srvc_dbg("Starting CherryPy, ssl at " + os.path.join(ssl_path(), "optimalframework_test_privkey.pem")) web_config = { # The UI root "/": { "tools.staticdir.on": True, "tools.staticdir.dir": "ui", "tools.trailing_slash.on": True, "tools.staticdir.index": "index.html", }, # Note that the web socket handling is put under /socket. "/socket": { "tools.websocket.on": True, "tools.websocket.handler_cls": BrokerWebSocket } } global web_root cherrypy._global_conf_alias.update(web_config) web_socket_plugin = WebSocketPlugin(cherrypy.engine) web_socket_plugin.subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.engine.signals.bus.signal_handler.handlers = {'SIGUSR1': cherrypy.engine.signals.bus.graceful} # Initialize the decorator-based authentication framework init_authentication(MongoDBAuthBackend(database_access)) # Initialize root UI web_root = CherryPyBroker(_process_id=process_id, _address=address, _database_access=database_access) # Initialize messaging of.common.messaging.websocket.monitor = Monitor(_handler=BrokerWebSocketHandler(process_id, _peers=web_root.peers, _database_access=database_access, _schema_tools=database_access.schema_tools, _address=address)) web_root.plugins = plugins # Generate the static content, initialisation plugins.call_hook("init_web", _broker_scope = globals()) _web_config_debug = "Broker configured. Starting web server. Web config:\n" for _curr_key, _curr_config in web_config.items(): if "tools.staticdir.dir" in _curr_config: _web_config_debug += "Path: " + _curr_key + " directory: " + _curr_config["tools.staticdir.dir"] else: _web_config_debug += "Path: " + _curr_key + " - no static dir" write_to_log(_web_config_debug, _category=EC_SERVICE, _severity=SEV_INFO) plugins.call_hook("pre_webserver_start", web_config=web_config, globals=globals()) cherrypy.quickstart(web_root, "/", web_config)
@cherrypy.expose def default(self): pass class WebSocketChecker(WebSocketTool): def __init__(self): cherrypy.Tool.__init__(self, "before_handler", self.upgrade) def upgrade(self, **kwargs): try: kwargs["handler_cls"].check_authentication() except: raise cherrypy.HTTPError(401, "You must be logged in to establish a websocket connection.") else: return WebSocketTool.upgrade(self, **kwargs) cherrypy.tools.websockets = WebSocketChecker() websocket_plugin = WebSocketPlugin(cherrypy.engine) websocket_plugin.subscribe() broadcaster = Caller(WebSocketDispatcher.broadcast) responder = Caller(WebSocketDispatcher.handle_message, threads=config['ws_thread_pool']) cherrypy.engine.subscribe("stop", WebSocketDispatcher.close_all) for _task in [broadcaster, responder]: cherrypy.engine.subscribe("start", _task.start, priority=99) cherrypy.engine.subscribe("stop", _task.stop)
class SpyDashServer(object): """ Server class for the SpyDash This class encapsulates all the functionality for the SpyDash server. It loads available modules and handles communication over Websockets """ def __init__(self): """ Find and load modules in the modules package """ self.wsplugin = None self.worker = set() pluginmanager.load_configs() def start(self): """ Start the server. This blocks """ # Setting up plugins pluginmanager.load_models() pluginmanager.load_plugin_roots(self) create_tables() self.wsplugin = WebSocketPlugin(cherrypy.engine) self.wsplugin.subscribe() cherrypy.tools.websocket = WebSocketTool() # cherrypy.config.update({"log.access_file": "access.log", # "log.error_file": "error.log"}) cherrypy.engine.subscribe("receive", self.receive) self.start_updater() config = {"/ws": {"tools.websocket.on": True, "tools.websocket.handler_cls": WebSocketHandler}} cherrypy.quickstart(self, "/", config=config) def broadcast(self, data, module): """ Broadcast a message to all connected clients :param data: Data to broadcast :param module: reference to the calling module """ try: label = pluginmanager.get_containing_pluginconfig(module).label except AttributeError: return msg = {"module": label, "data": data} try: msg = json.dumps(msg, ensure_ascii=False) except TypeError: return self.wsplugin.broadcast(msg) def start_updater(self): def predicate(x): try: return x.updater except (TypeError, AttributeError): return False for plugin in pluginmanager.get_instances(): try: for name, method in inspect.getmembers(plugin, predicate): worker = BackgroundTask(method.interval, method) self.worker.add(worker) worker.start() except (TypeError, AttributeError, StopIteration): pass def cancel_updater(self, functions): """ Cancel given updater functions or function :param functions: The updater functions to cancel, this can either be a set of functions to cancel or a singel function """ try: workers = [worker for worker in self.worker if worker.function in functions] except TypeError: workers = [worker for worker in self.worker if worker.function == functions] for worker in workers: worker.cancel() def receive(self, client, message): try: payload = json.loads(str(message)) plugin_name = payload["module"] command = payload["command"] if plugin_name == "system": attribute = getattr(self, command) else: plugin = pluginmanager.get_plugin_for_label(plugin_name) attribute = getattr(plugin, command) if attribute.socketexposed is True: try: answer = attribute(**payload["data"]) except (KeyError, TypeError): answer = attribute() if answer is not None: msg = json.dumps({"module": plugin_name, "data": answer}, ensure_ascii=False) client.send(msg) except (json.JSONDecodeError, TypeError, AttributeError, KeyError): return @socketexpose def get_modules(self): response = [name for name in pluginmanager.get_labels()] return response def _cp_dispatch(self, vpath): path = deque(vpath) modulename = path.popleft() module = pluginmanager.get_plugin_for_label(modulename) if module is not None: return module else: return vpath @cherrypy.expose def index(self): return "HI" @cherrypy.expose def ws(self): pass
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, 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
' - %(message)s') ch.setFormatter(formatter) interface_logger.addHandler(ch) # create the preset folder if it does not exist: preset_dir = os.path.abspath(args.presetdir) if (not os.path.isdir(preset_dir)): print("Preset folder {} did not exist, creating.".format(preset_dir)) os.makedirs(preset_dir) # Add the websocket requirements. cherrypy.tools.websocket = WebSocketTool() a = WebSocketPlugin(cherrypy.engine) a.manager = WebSocketManager() a.subscribe() stack_interface = interface.StackInterface() stack_interface.daemon = True stack_interface.start() server_tree = FocusStackRoot(stack_interface, preset_dir=preset_dir) # create a broadcast function which relays messages received over the # serial port to the websockets via the websocketmanager. def broadcaster(): m = stack_interface.get_message() if m: payload = dict(m) payload["msg_type"] = message.msg_type_name[payload["msg_type"]] msg = ["serial", payload] a.manager.broadcast(json.dumps(msg))