def test_set_inheritable(self): sockfile = self._get_tmp_filename() sock = CircusSocket('somename', path=sockfile, umask=0) try: sock.bind_and_listen() self.assertTrue(sock.get_inheritable()) finally: sock.close()
def test_socket(self): if TRAVIS: return sock = CircusSocket('somename', 'localhost', 0) try: sock.bind_and_listen() finally: sock.close()
def test_unix_socket(self): sockfile = self._get_tmp_filename() sock = CircusSocket('somename', path=sockfile, umask=0) try: sock.bind_and_listen() self.assertTrue(os.path.exists(sockfile)) permissions = oct(os.stat(sockfile).st_mode)[-3:] self.assertEqual(permissions, '777') finally: sock.close()
def test_unix_socket(self): fd, sockfile = tempfile.mkstemp() os.close(fd) os.remove(sockfile) sock = CircusSocket('somename', path=sockfile) try: sock.bind_and_listen() self.assertTrue(os.path.exists(sockfile)) finally: sock.close() os.remove(sockfile)
def test_unix_socket(self): fd, sockfile = tempfile.mkstemp() os.close(fd) os.remove(sockfile) sock = CircusSocket('somename', path=sockfile, umask=0) try: sock.bind_and_listen() self.assertTrue(os.path.exists(sockfile)) permissions = oct(os.stat(sockfile).st_mode)[-3:] self.assertEqual(permissions, '777') finally: sock.close()
def test_stdin_socket(self): cmd = 'circus.tests.test_stdin_socket.run_process' stream = QueueStream() stdout_stream = {'stream': stream} sk = CircusSocket(name='test', host='localhost', port=0) yield self.start_arbiter(cmd=cmd, stdout_stream=stdout_stream, arbiter_kw={'sockets': [sk]}, stdin_socket='test', use_sockets=True) # check same socket in child fd 0 addr_string_actual = yield read_from_stream(stream) addr_string_expected = "%s %s" % (sk.host, sk.port) self.assertEqual(addr_string_actual, addr_string_expected) yield self.stop_arbiter()
def __init__(self, watchers, endpoint, pubsub_endpoint, check_delay=1.0, prereload_fn=None, context=None, loop=None, statsd=False, stats_endpoint=None, statsd_close_outputs=False, multicast_endpoint=None, plugins=None, sockets=None, warmup_delay=0, httpd=False, httpd_host='localhost', httpd_port=8080, httpd_close_outputs=False, debug=False, debug_gc=False, ssh_server=None, proc_name='circusd', pidfile=None, loglevel=None, logoutput=None, fqdn_prefix=None, umask=None, endpoint_owner=None): self.watchers = watchers self.endpoint = endpoint self.check_delay = check_delay self.prereload_fn = prereload_fn self.pubsub_endpoint = pubsub_endpoint self.multicast_endpoint = multicast_endpoint self.proc_name = proc_name self.ssh_server = ssh_server self.evpub_socket = None self.pidfile = pidfile self.loglevel = loglevel self.logoutput = logoutput self.umask = umask self.endpoint_owner = endpoint_owner try: # getfqdn appears to fail in Python3.3 in the unittest # framework so fall back to gethostname socket_fqdn = socket.getfqdn() except KeyError: socket_fqdn = socket.gethostname() if fqdn_prefix is None: fqdn = socket_fqdn else: fqdn = '{}@{}'.format(fqdn_prefix, socket_fqdn) self.fqdn = fqdn self.ctrl = self.loop = None self._provided_loop = False self.socket_event = False if loop is not None: self._provided_loop = True self.loop = loop # initialize zmq context self._init_context(context) self.pid = os.getpid() self._watchers_names = {} self._stopping = False self._restarting = False self.debug = debug self._exclusive_running_command = None if self.debug: self.stdout_stream = self.stderr_stream = {'class': 'StdoutStream'} else: self.stdout_stream = self.stderr_stream = None self.debug_gc = debug_gc if debug_gc: gc.set_debug(gc.DEBUG_LEAK) # initializing circusd-stats as a watcher when configured self.statsd = statsd self.stats_endpoint = stats_endpoint if self.statsd: cmd = "%s -c 'from circus import stats; stats.main()'" % \ sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --pubsub %s' % self.pubsub_endpoint cmd += ' --statspoint %s' % self.stats_endpoint if ssh_server is not None: cmd += ' --ssh %s' % ssh_server if debug: cmd += ' --log-level DEBUG' stats_watcher = Watcher('circusd-stats', cmd, use_sockets=True, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=statsd_close_outputs, close_child_stdout=statsd_close_outputs) self.watchers.append(stats_watcher) # adding the httpd if httpd: # adding the socket httpd_socket = CircusSocket(name='circushttpd', host=httpd_host, port=httpd_port) if sockets is None: sockets = [httpd_socket] else: sockets.append(httpd_socket) cmd = ("%s -c 'from circusweb import circushttpd; " "circushttpd.main()'") % sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --fd $(circus.sockets.circushttpd)' if ssh_server is not None: cmd += ' --ssh %s' % ssh_server # Adding the watcher httpd_watcher = Watcher('circushttpd', cmd, use_sockets=True, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=httpd_close_outputs, close_child_stdout=httpd_close_outputs) self.watchers.append(httpd_watcher) # adding each plugin as a watcher ch_stderr = self.stderr_stream is None ch_stdout = self.stdout_stream is None if plugins is not None: for plugin in plugins: fqn = plugin['use'] cmd = get_plugin_cmd(plugin, self.endpoint, self.pubsub_endpoint, self.check_delay, ssh_server, debug=self.debug) plugin_cfg = dict(cmd=cmd, priority=1, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=ch_stderr, close_child_stdout=ch_stdout) plugin_cfg.update(plugin) if 'name' not in plugin_cfg: plugin_cfg['name'] = fqn plugin_watcher = Watcher.load_from_config(plugin_cfg) self.watchers.append(plugin_watcher) self.sockets = CircusSockets(sockets) self.warmup_delay = warmup_delay
def main(): #configure_logger(logger, 'DEBUG') config_mod = 'circus_settings' if len(sys.argv) > 1: config_mod = sys.argv[1] config = import_module(config_mod) for p in config.PATHS: ap = os.path.abspath(p) if ap not in os.sys.path: os.sys.path.append(ap) watchers = [] sockets = [] for s in config.SERVERS: w = Watcher(gc(s, SERVER_NAME), gc(s, SERVER_PROGRAM), gc(s, SERVER_ARGS), numprocesses=gc(s, SERVER_WORKERS, 1), working_dir=gc(s, SERVER_WORKING_DIR, './'), env=gc(s, SERVER_ENV, dict()), copy_env=True, copy_path=True, use_sockets=True) watchers.append(w) sock_port = gc(s, SERVER_PORT) if sock_port is not None: sock_name = gc(s, SERVER_NAME) sock_host = gc(s, SERVER_HOST, '127.0.0.1') sock = CircusSocket(sock_name, host=sock_host, port=sock_port) sockets.append(sock) for sock in sockets: print '>> %s'%(sock,) try: WANT_WEB = getattr(config, 'WANT_WEB') except Exception: WANT_WEB = True if HAS_WEB and WANT_WEB: arbiter = Arbiter(watchers, DEFAULT_ENDPOINT_DEALER, DEFAULT_ENDPOINT_SUB, sockets=sockets, stats_endpoint=DEFAULT_ENDPOINT_STATS, multicast_endpoint=DEFAULT_ENDPOINT_MULTICAST, statsd=True, httpd=True, httpd_port=9999) else: arbiter = Arbiter(watchers, DEFAULT_ENDPOINT_DEALER, DEFAULT_ENDPOINT_SUB, sockets=sockets, stats_endpoint=DEFAULT_ENDPOINT_STATS, multicast_endpoint=DEFAULT_ENDPOINT_MULTICAST) arbiter.start()
def __init__(self, watchers, endpoint, pubsub_endpoint, check_delay=.5, prereload_fn=None, context=None, loop=None, stats_endpoint=None, plugins=None, sockets=None, warmup_delay=0, httpd=False, httpd_host='localhost', httpd_port=8080, debug=False, ssh_server=None, proc_name='circusd'): self.watchers = watchers self.endpoint = endpoint self.check_delay = check_delay self.prereload_fn = prereload_fn self.pubsub_endpoint = pubsub_endpoint self.proc_name = proc_name self.ctrl = self.loop = None self.socket_event = False # initialize zmq context self.context = context or zmq.Context.instance() self.pid = os.getpid() self._watchers_names = {} self.alive = True self._lock = RLock() self.debug = debug if self.debug: stdout_stream = stderr_stream = {'class': 'StdoutStream'} else: stdout_stream = stderr_stream = None # initializing circusd-stats as a watcher when configured self.stats_endpoint = stats_endpoint if self.stats_endpoint is not None: cmd = "%s -c 'from circus import stats; stats.main()'" % \ sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --pubsub %s' % self.pubsub_endpoint cmd += ' --statspoint %s' % self.stats_endpoint if ssh_server is not None: cmd += ' --ssh %s' % ssh_server if debug: cmd += ' --log-level DEBUG' stats_watcher = Watcher('circusd-stats', cmd, use_sockets=True, singleton=True, stdout_stream=stdout_stream, stderr_stream=stderr_stream, copy_env=True, copy_path=True) self.watchers.append(stats_watcher) # adding the httpd if httpd: cmd = ("%s -c 'from circusweb import circushttpd; " "circushttpd.main()'") % sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --fd $(circus.sockets.circushttpd)' if ssh_server is not None: cmd += ' --ssh %s' % ssh_server httpd_watcher = Watcher('circushttpd', cmd, use_sockets=True, singleton=True, stdout_stream=stdout_stream, stderr_stream=stderr_stream, copy_env=True, copy_path=True) self.watchers.append(httpd_watcher) httpd_socket = CircusSocket(name='circushttpd', host=httpd_host, port=httpd_port) # adding the socket if sockets is None: sockets = [httpd_socket] else: sockets.append(httpd_socket) # adding each plugin as a watcher if plugins is not None: for plugin in plugins: fqnd = plugin['use'] name = 'plugin:%s' % fqnd.replace('.', '-') cmd = get_plugin_cmd(plugin, self.endpoint, self.pubsub_endpoint, self.check_delay, ssh_server, debug=self.debug) plugin_watcher = Watcher(name, cmd, priority=1, singleton=True, stdout_stream=stdout_stream, stderr_stream=stderr_stream, copy_env=True, copy_path=True) self.watchers.append(plugin_watcher) self.sockets = CircusSockets(sockets) self.warmup_delay = warmup_delay self.loop = ioloop.IOLoop.instance() self.ctrl = Controller(self.endpoint, self.context, self.loop, self, self.check_delay)
def __init__(self, watchers, endpoint, pubsub_endpoint, check_delay=.5, prereload_fn=None, context=None, loop=None, statsd=False, stats_endpoint=None, statsd_close_outputs=False, multicast_endpoint=None, plugins=None, sockets=None, warmup_delay=0, httpd=False, httpd_host='localhost', httpd_port=8080, httpd_close_outputs=False, debug=False, ssh_server=None, proc_name='circusd', pidfile=None, loglevel=None, logoutput=None, fqdn_prefix=None): self.watchers = watchers self.endpoint = endpoint self.check_delay = check_delay self.prereload_fn = prereload_fn self.pubsub_endpoint = pubsub_endpoint self.multicast_endpoint = multicast_endpoint self.proc_name = proc_name self.ssh_server = ssh_server self.pidfile = pidfile self.loglevel = loglevel self.logoutput = logoutput socket_fqdn = socket.getfqdn() if fqdn_prefix is None: fqdn = socket_fqdn else: fqdn = '{}@{}'.format(fqdn_prefix, socket_fqdn) self.fqdn = fqdn self.ctrl = self.loop = None self.socket_event = False # initialize zmq context self._init_context(context) self.pid = os.getpid() self._watchers_names = {} self.alive = True self._lock = RLock() self.debug = debug if self.debug: self.stdout_stream = self.stderr_stream = {'class': 'StdoutStream'} else: self.stdout_stream = self.stderr_stream = None # initializing circusd-stats as a watcher when configured self.statsd = statsd self.stats_endpoint = stats_endpoint if self.statsd: cmd = "%s -c 'from circus import stats; stats.main()'" % \ sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --pubsub %s' % self.pubsub_endpoint cmd += ' --statspoint %s' % self.stats_endpoint if ssh_server is not None: cmd += ' --ssh %s' % ssh_server if debug: cmd += ' --log-level DEBUG' stats_watcher = Watcher('circusd-stats', cmd, use_sockets=True, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=statsd_close_outputs, close_child_stdout=statsd_close_outputs) self.watchers.append(stats_watcher) # adding the httpd if httpd: cmd = ("%s -c 'from circusweb import circushttpd; " "circushttpd.main()'") % sys.executable cmd += ' --endpoint %s' % self.endpoint cmd += ' --fd $(circus.sockets.circushttpd)' if ssh_server is not None: cmd += ' --ssh %s' % ssh_server httpd_watcher = Watcher('circushttpd', cmd, use_sockets=True, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=httpd_close_outputs, close_child_stdout=httpd_close_outputs) self.watchers.append(httpd_watcher) httpd_socket = CircusSocket(name='circushttpd', host=httpd_host, port=httpd_port) # adding the socket if sockets is None: sockets = [httpd_socket] else: sockets.append(httpd_socket) # adding each plugin as a watcher ch_stderr = self.stderr_stream is None ch_stdout = self.stdout_stream is None if plugins is not None: for plugin in plugins: fqn = plugin['use'] cmd = get_plugin_cmd(plugin, self.endpoint, self.pubsub_endpoint, self.check_delay, ssh_server, debug=self.debug) plugin_cfg = dict(cmd=cmd, priority=1, singleton=True, stdout_stream=self.stdout_stream, stderr_stream=self.stderr_stream, copy_env=True, copy_path=True, close_child_stderr=ch_stderr, close_child_stdout=ch_stdout) plugin_cfg.update(plugin) if 'name' not in plugin_cfg: plugin_cfg['name'] = fqn plugin_watcher = Watcher.load_from_config(plugin_cfg) self.watchers.append(plugin_watcher) self.sockets = CircusSockets(sockets) self.warmup_delay = warmup_delay
def serve_development( bento_identifier: str, working_dir: str, port: int = Provide[DeploymentContainer.api_server_config.port], host: str = Provide[DeploymentContainer.api_server_config.host], backlog: int = Provide[DeploymentContainer.api_server_config.backlog], with_ngrok: bool = False, reload: bool = False, reload_delay: float = 0.25, ) -> None: working_dir = os.path.realpath(os.path.expanduser(working_dir)) from circus.sockets import CircusSocket # type: ignore from circus.watcher import Watcher # type: ignore watchers: t.List[Watcher] = [] if with_ngrok: watchers.append( Watcher( name="ngrok", cmd=sys.executable, args=[ "-m", SCRIPT_NGROK, ], copy_env=True, numprocesses=1, stop_children=True, working_dir=working_dir, )) circus_socket_map: t.Dict[str, CircusSocket] = {} circus_socket_map["_bento_api_server"] = CircusSocket( name="_bento_api_server", host=host, port=port, backlog=backlog, ) watchers.append( Watcher( name="dev_api_server", cmd=sys.executable, args=[ "-m", SCRIPT_DEV_API_SERVER, bento_identifier, "fd://$(circus.sockets._bento_api_server)", "--working-dir", working_dir, ] + (["--reload", "--reload-delay", f"{reload_delay}"] if reload else []), copy_env=True, numprocesses=1, stop_children=True, use_sockets=True, working_dir=working_dir, )) arbiter = create_standalone_arbiter( watchers, sockets=list(circus_socket_map.values()), ) _ensure_prometheus_dir() arbiter.start( cb=lambda _: logger.info( # type: ignore f'Starting development BentoServer from "{bento_identifier}" ' f"running on http://{host}:{port} (Press CTRL+C to quit)"), )
def serve_production( bento_identifier: str, working_dir: str, port: int = Provide[DeploymentContainer.api_server_config.port], host: str = Provide[DeploymentContainer.api_server_config.host], backlog: int = Provide[DeploymentContainer.api_server_config.backlog], app_workers: t.Optional[int] = None, ) -> None: working_dir = os.path.realpath(os.path.expanduser(working_dir)) svc = load(bento_identifier, working_dir=working_dir, change_global_cwd=True) from circus.sockets import CircusSocket # type: ignore from circus.watcher import Watcher # type: ignore watchers: t.List[Watcher] = [] circus_socket_map: t.Dict[str, CircusSocket] = {} runner_bind_map: t.Dict[str, str] = {} uds_path = None if psutil.POSIX: # use AF_UNIX sockets for Circus uds_path = tempfile.mkdtemp() for runner_name, runner in svc.runners.items(): sockets_path = os.path.join(uds_path, f"{id(runner)}.sock") assert len(sockets_path) < MAX_AF_UNIX_PATH_LENGTH runner_bind_map[runner_name] = path_to_uri(sockets_path) circus_socket_map[runner_name] = CircusSocket( name=runner_name, path=sockets_path, backlog=backlog, ) watchers.append( Watcher( name=f"runner_{runner_name}", cmd=sys.executable, args=[ "-m", SCRIPT_RUNNER, bento_identifier, runner_name, f"fd://$(circus.sockets.{runner_name})", "--working-dir", working_dir, ], copy_env=True, stop_children=True, working_dir=working_dir, use_sockets=True, numprocesses=runner.num_replica, )) elif psutil.WINDOWS: # Windows doesn't (fully) support AF_UNIX sockets with contextlib.ExitStack() as port_stack: for runner_name, runner in svc.runners.items(): runner_port = port_stack.enter_context(reserve_free_port()) runner_host = "127.0.0.1" runner_bind_map[ runner_name] = f"tcp://{runner_host}:{runner_port}" circus_socket_map[runner_name] = CircusSocket( name=runner_name, host=runner_host, port=runner_port, backlog=backlog, ) watchers.append( Watcher( name=f"runner_{runner_name}", cmd=sys.executable, args=[ "-m", SCRIPT_RUNNER, bento_identifier, runner_name, f"fd://$(circus.sockets.{runner_name})", "--working-dir", working_dir, ], copy_env=True, stop_children=True, use_sockets=True, working_dir=working_dir, numprocesses=runner.num_replica, )) port_stack.enter_context( reserve_free_port()) # reserve one more to avoid conflicts else: raise NotImplementedError("Unsupported platform: {}".format( sys.platform)) logger.debug("Runner map: %s", runner_bind_map) circus_socket_map["_bento_api_server"] = CircusSocket( name="_bento_api_server", host=host, port=port, backlog=backlog, ) watchers.append( Watcher( name="api_server", cmd=sys.executable, args=[ "-m", SCRIPT_API_SERVER, bento_identifier, "fd://$(circus.sockets._bento_api_server)", "--runner-map", json.dumps(runner_bind_map), "--working-dir", working_dir, "--backlog", f"{backlog}", ], copy_env=True, numprocesses=app_workers or 1, stop_children=True, use_sockets=True, working_dir=working_dir, )) arbiter = create_standalone_arbiter( watchers=watchers, sockets=list(circus_socket_map.values()), ) _ensure_prometheus_dir() try: arbiter.start( cb=lambda _: logger.info( # type: ignore f'Starting production BentoServer from "bento_identifier" ' f"running on http://{host}:{port} (Press CTRL+C to quit)"), ) finally: if uds_path is not None: shutil.rmtree(uds_path)