def test_load_fails_if_server_name_missing(self): self.generate_config_and_remove_lines_containing("server_name") with self.assertRaises(ConfigError): HomeServerConfig.load_config("", ["-c", self.config_file]) with self.assertRaises(ConfigError): HomeServerConfig.load_or_generate_config("", ["-c", self.config_file])
def generate_config(self): HomeServerConfig.load_config("", [ "--generate-config", "-c", self.file, "--report-stats=yes", "-H", "lemurs.win" ])
def test_load_succeeds_if_macaroon_secret_key_missing(self): self.generate_config_and_remove_lines_containing("macaroon") config1 = HomeServerConfig.load_config("", ["-c", self.file]) config2 = HomeServerConfig.load_config("", ["-c", self.file]) config3 = HomeServerConfig.load_or_generate_config("", ["-c", self.file]) self.assertEqual(config1.macaroon_secret_key, config2.macaroon_secret_key) self.assertEqual(config1.macaroon_secret_key, config3.macaroon_secret_key)
def test_depreciated_identity_server_flag_throws_error(self): self.generate_config() # Needed to ensure that actual key/value pair added below don't end up on a line with a comment self.add_lines_to_config([" "]) # Check that presence of "trust_identity_server_for_password" throws config error self.add_lines_to_config( ["trust_identity_server_for_password_resets: true"]) with self.assertRaises(ConfigError): HomeServerConfig.load_config("", ["-c", self.config_file])
def test_disable_registration(self): self.generate_config() self.add_lines_to_config([ "enable_registration: true", "disable_registration: true", ]) # Check that disable_registration clobbers enable_registration. config = HomeServerConfig.load_config("", ["-c", self.file]) self.assertFalse(config.enable_registration) # Check that either config value is clobbered by the command line. config = HomeServerConfig.load_config( "", ["-c", self.file, "--enable-registration"]) self.assertTrue(config.enable_registration)
def test_disable_registration(self): self.generate_config() self.add_lines_to_config([ "enable_registration: true", "disable_registration: true", ]) # Check that disable_registration clobbers enable_registration. config = HomeServerConfig.load_config("", ["-c", self.file]) self.assertFalse(config.enable_registration) # Check that either config value is clobbered by the command line. config = HomeServerConfig.load_config("", [ "-c", self.file, "--enable-registration" ]) self.assertTrue(config.enable_registration)
def test_generate_config_generates_files(self): HomeServerConfig.load_config("", [ "--generate-config", "-c", self.file, "--report-stats=yes", "-H", "lemurs.win" ]) self.assertSetEqual( set([ "homeserver.yaml", "lemurs.win.log.config", "lemurs.win.signing.key", "lemurs.win.tls.crt", "lemurs.win.tls.dh", "lemurs.win.tls.key", ]), set(os.listdir(self.dir)))
def test_generates_and_loads_macaroon_secret_key(self): self.generate_config() with open(self.config_file) as f: raw = yaml.safe_load(f) self.assertIn("macaroon_secret_key", raw) config = HomeServerConfig.load_config("", ["-c", self.config_file]) self.assertTrue( hasattr(config.key, "macaroon_secret_key"), "Want config to have attr macaroon_secret_key", ) if len(config.key.macaroon_secret_key) < 5: self.fail( "Want macaroon secret key to be string of at least length 5," "was: %r" % (config.key.macaroon_secret_key, )) config2 = HomeServerConfig.load_or_generate_config( "", ["-c", self.config_file]) assert config2 is not None self.assertTrue( hasattr(config2.key, "macaroon_secret_key"), "Want config to have attr macaroon_secret_key", ) if len(config2.key.macaroon_secret_key) < 5: self.fail( "Want macaroon secret key to be string of at least length 5," "was: %r" % (config2.key.macaroon_secret_key, ))
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse synchrotron", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-synchrotron", config)
def main(args): action = args[1] if len(args) > 1 and args[1] == "read" else None # If we're reading a key in the config file, then `args[1]` will be `read` and `args[2]` # will be the key to read. # We'll want to rework this code if we want to support more actions than just `read`. load_config_args = args[3:] if action else args[1:] try: config = HomeServerConfig.load_config("", load_config_args) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) print("Config parses OK!") if action == "read": key = args[2] key_parts = key.split(".") value = config try: while len(key_parts): value = getattr(value, key_parts[0]) key_parts.pop(0) print(f"\n{key}: {value}") except AttributeError: print( f"\nNo '{key}' key could be found in the provided configuration file." ) sys.exit(1)
def test_stats_enabled(self): self.generate_config_and_remove_lines_containing("enable_metrics") self.add_lines_to_config(["enable_metrics: true"]) # The default Metrics Flags are off by default. config = HomeServerConfig.load_config("", ["-c", self.config_file]) self.assertFalse(config.metrics.metrics_flags.known_servers)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse event creator", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.event_creator" assert config.worker_replication_http_port is not None # This should only be done on the user directory worker or the master config.update_user_directory = False events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = EventCreatorServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-event-creator", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse client reader", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-client-reader", config)
def test_generates_and_loads_macaroon_secret_key(self): self.generate_config() with open(self.file, "r") as f: raw = yaml.load(f) self.assertIn("macaroon_secret_key", raw) config = HomeServerConfig.load_config("", ["-c", self.file]) self.assertTrue( hasattr(config, "macaroon_secret_key"), "Want config to have attr macaroon_secret_key", ) if len(config.macaroon_secret_key) < 5: self.fail( "Want macaroon secret key to be string of at least length 5," "was: %r" % (config.macaroon_secret_key,) ) config = HomeServerConfig.load_or_generate_config("", ["-c", self.file]) self.assertTrue( hasattr(config, "macaroon_secret_key"), "Want config to have attr macaroon_secret_key", ) if len(config.macaroon_secret_key) < 5: self.fail( "Want macaroon secret key to be string of at least length 5," "was: %r" % (config.macaroon_secret_key,) )
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts ss = SynchrotronServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), application_service_handler=SynchrotronApplicationService(), ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-synchrotron", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-synchrotron", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse frontend proxy", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-frontend-proxy", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n") events.USE_FROZEN_DICTS = config.use_frozen_dicts ss = MediaRepositoryServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse client reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-client-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse frontend proxy", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.addSystemEventTrigger("before", "startup", _base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-frontend-proxy", config)
def setup(): config = HomeServerConfig.load_config( "Synapse Homeserver", sys.argv[1:], generate_section="Homeserver" ) config.setup_logging() logger.info("Server hostname: %s", config.server_name) if re.search(":[0-9]+$", config.server_name): domain_with_port = config.server_name else: domain_with_port = "%s:%s" % (config.server_name, config.bind_port) tls_context_factory = context_factory.ServerContextFactory(config) hs = SynapseHomeServer( config.server_name, domain_with_port=domain_with_port, upload_dir=os.path.abspath("uploads"), db_name=config.database_path, tls_context_factory=tls_context_factory, config=config, content_addr=config.content_addr, ) hs.register_servlets() hs.create_resource_tree( web_client=config.webclient, redirect_root_to_web_client=True, ) hs.start_listening(config.bind_port, config.unsecure_port) hs.get_db_pool() if config.manhole: f = twisted.manhole.telnet.ShellFactory() f.username = "******" f.password = "******" f.namespace['hs'] = hs reactor.listenTCP(config.manhole, f, interface='127.0.0.1') if config.daemonize: print config.pid_file daemon = Daemonize( app="synapse-homeserver", pid=config.pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config, use_worker_options=True) synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def run(): # make sure that we run the reactor with the sentinel log context, # otherwise other PreserveLoggingContext instances will get confused # and complain when they see the logcontext arbitrarily swapping # between the sentinel and `run` logcontexts. with PreserveLoggingContext(): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_datastore().start_profiling() ss.replicate() ss.get_state_handler().start_caching() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-synchrotron", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config("Synapse client reader", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.client_reader" setup_logging(config.worker_log_config, config.worker_log_file) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = ClientReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() ss.replicate() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-client-reader", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config.worker_log_config, config.worker_log_file) database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() ss.replicate() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-federation-reader", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def test_generate_config_generates_files(self): HomeServerConfig.load_config("", [ "--generate-config", "-c", self.file, "--report-stats=yes", "-H", "lemurs.win" ]) self.assertSetEqual( set([ "homeserver.yaml", "lemurs.win.log.config", "lemurs.win.signing.key", "lemurs.win.tls.crt", "lemurs.win.tls.dh", "lemurs.win.tls.key", ]), set(os.listdir(self.dir)) )
def start(config_options): try: config = HomeServerConfig.load_config("Synapse synchrotron", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.synchrotron" setup_logging(config.worker_log_config, config.worker_log_file) database_engine = create_engine(config.database_config) ss = SynchrotronServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, application_service_handler=SynchrotronApplicationService(), ) ss.setup() ss.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ss.get_datastore().start_profiling() ss.replicate() ss.get_state_handler().start_caching() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-synchrotron", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
def start(config_options: List[str]) -> None: try: config = HomeServerConfig.load_config("Synapse worker", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) # For backwards compatibility let any of the old app names. assert config.worker.worker_app in ( "synapse.app.appservice", "synapse.app.client_reader", "synapse.app.event_creator", "synapse.app.federation_reader", "synapse.app.federation_sender", "synapse.app.frontend_proxy", "synapse.app.generic_worker", "synapse.app.media_repository", "synapse.app.pusher", "synapse.app.synchrotron", "synapse.app.user_dir", ) synapse.events.USE_FROZEN_DICTS = config.server.use_frozen_dicts synapse.util.caches.TRACK_MEMORY_USAGE = config.caches.track_memory_usage if config.server.gc_seconds: synapse.metrics.MIN_TIME_BETWEEN_GCS = config.server.gc_seconds hs = GenericWorkerServer( config.server.server_name, config=config, version_string="Synapse/" + get_distribution_version_string("matrix-synapse"), ) setup_logging(hs, config, use_worker_options=True) try: hs.setup() # Ensure the replication streamer is always started in case we write to any # streams. Will no-op if no streams can be written to by this worker. hs.get_replication_streamer() except Exception as e: handle_startup_exception(e) register_start(_base.start, hs) # redirect stdio to the logs, if configured. if not hs.config.logging.no_redirect_stdio: redirect_stdio_to_logs() _base.start_worker_reactor("synapse-generic-worker", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse user directory", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ps = UserDirectoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-user-dir", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse user directory", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ps = UserDirectoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-user-dir", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation sender", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True tls_server_context_factory = context_factory.ServerContextFactory(config) ps = FederationSenderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-sender", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_pusherpool().start() ps.get_datastore().start_profiling() ps.get_state_handler().start_caching() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-pusher", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse federation sender", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True ss = FederationSenderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() def start(): ss.config.read_certificate_from_disk() ss.tls_server_context_factory = context_factory.ServerContextFactory( config) ss.tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss.start_listening(config.worker_listeners) ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-sender", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def start(): ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-pusher", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n") setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse media repository", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" if config.enable_media_repo: _base.quit_with_error( "enable_media_repo must be disabled in the main synapse process\n" "before the media repo can be run in a separate worker.\n" "Please add ``enable_media_repo: false`` to the main config\n" ) setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse event creator", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.event_creator" assert config.worker_replication_http_port is not None setup_logging(config, use_worker_options=True) # This should only be done on the user directory worker or the master config.update_user_directory = False events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = EventCreatorServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-event-creator", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation sender", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_sender" events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.send_federation = True ss = FederationSenderServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) setup_logging(ss, config, use_worker_options=True) ss.setup() reactor.addSystemEventTrigger( "before", "startup", _base.start, ss, config.worker_listeners ) _base.start_worker_reactor("synapse-federation-sender", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse frontend proxy", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-frontend-proxy", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse frontend proxy", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.frontend_proxy" assert config.worker_main_http_uri is not None setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = FrontendProxyServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-frontend-proxy", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse pusher", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" events.USE_FROZEN_DICTS = config.use_frozen_dicts if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True ps = PusherServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) setup_logging(ps, config, use_worker_options=True) ps.setup() def start(): _base.start(ps, config.worker_listeners) ps.get_pusherpool().start() reactor.addSystemEventTrigger("before", "startup", start) _base.start_worker_reactor("synapse-pusher", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse user directory", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.user_dir" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) if config.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.update_user_directory = True ss = UserDirectoryServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() reactor.callWhenRunning(_base.start, ss, config.worker_listeners) _base.start_worker_reactor("synapse-user-dir", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse federation reader", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory( config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse federation reader", config_options ) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) assert config.worker_app == "synapse.app.federation_reader" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) tls_client_options_factory = context_factory.ClientTLSOptionsFactory(config) ss = FederationReaderServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, tls_client_options_factory=tls_client_options_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.start_listening(config.worker_listeners) def start(): ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-federation-reader", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse media repository", config_options) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.media_repository" setup_logging(config, use_worker_options=True) events.USE_FROZEN_DICTS = config.use_frozen_dicts database_engine = create_engine(config.database_config) tls_server_context_factory = context_factory.ServerContextFactory(config) ss = MediaRepositoryServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ss.setup() ss.get_handlers() ss.start_listening(config.worker_listeners) def start(): ss.get_state_handler().start_caching() ss.get_datastore().start_profiling() reactor.callWhenRunning(start) _base.start_worker_reactor("synapse-media-repository", config)
def start(config_options): try: config = HomeServerConfig.load_config("Synapse worker", config_options) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) # For backwards compatibility let any of the old app names. assert config.worker_app in ( "synapse.app.appservice", "synapse.app.client_reader", "synapse.app.event_creator", "synapse.app.federation_reader", "synapse.app.federation_sender", "synapse.app.frontend_proxy", "synapse.app.generic_worker", "synapse.app.media_repository", "synapse.app.pusher", "synapse.app.synchrotron", "synapse.app.user_dir", ) if config.worker_app == "synapse.app.appservice": if config.appservice.notify_appservices: sys.stderr.write( "\nThe appservices must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``notify_appservices: false`` to the main config" "\n") sys.exit(1) # Force the appservice to start since they will be disabled in the main config config.appservice.notify_appservices = True else: # For other worker types we force this to off. config.appservice.notify_appservices = False if config.worker_app == "synapse.app.pusher": if config.server.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.server.start_pushers = True else: # For other worker types we force this to off. config.server.start_pushers = False if config.worker_app == "synapse.app.user_dir": if config.server.update_user_directory: sys.stderr.write( "\nThe update_user_directory must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``update_user_directory: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.server.update_user_directory = True else: # For other worker types we force this to off. config.server.update_user_directory = False if config.worker_app == "synapse.app.federation_sender": if config.worker.send_federation: sys.stderr.write( "\nThe send_federation must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``send_federation: false`` to the main config" "\n") sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.worker.send_federation = True else: # For other worker types we force this to off. config.worker.send_federation = False synapse.events.USE_FROZEN_DICTS = config.use_frozen_dicts hs = GenericWorkerServer( config.server_name, config=config, version_string="Synapse/" + get_version_string(synapse), ) setup_logging(hs, config, use_worker_options=True) hs.setup() # Ensure the replication streamer is always started in case we write to any # streams. Will no-op if no streams can be written to by this worker. hs.get_replication_streamer() register_start(_base.start, hs, config.worker_listeners) _base.start_worker_reactor("synapse-generic-worker", config)
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. Returns: HomeServer """ try: config = HomeServerConfig.load_config( "Synapse Homeserver", config_options, generate_section="Homeserver" ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) if not config: # If a config isn't returned, and an exception isn't raised, we're just # generating config files and shouldn't try to continue. sys.exit(0) config.setup_logging() # check any extra requirements we have now we have a config check_requirements(config) version_string = get_version_string("Synapse", synapse) logger.info("Server hostname: %s", config.server_name) logger.info("Server version: %s", version_string) events.USE_FROZEN_DICTS = config.use_frozen_dicts tls_server_context_factory = context_factory.ServerContextFactory(config) database_engine = create_engine(config.database_config) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, db_config=config.database_config, tls_server_context_factory=tls_server_context_factory, config=config, content_addr=config.content_addr, version_string=version_string, database_engine=database_engine, ) logger.info("Preparing database: %s...", config.database_config['name']) try: db_conn = hs.get_db_conn(run_new_connection=False) prepare_database(db_conn, database_engine, config=config) database_engine.on_new_connection(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %s.", config.database_config['name']) hs.setup() hs.start_listening() def start(): hs.get_pusherpool().start() hs.get_state_handler().start_caching() hs.get_datastore().start_profiling() hs.get_datastore().start_doing_background_updates() hs.get_replication_layer().start_get_pdu_cache() reactor.callWhenRunning(start) return hs
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. should_run (bool): Whether to start the reactor. Returns: HomeServer """ config = HomeServerConfig.load_config( "Synapse Homeserver", config_options, generate_section="Homeserver" ) config.setup_logging() # check any extra requirements we have now we have a config check_requirements(config) version_string = get_version_string() logger.info("Server hostname: %s", config.server_name) logger.info("Server version: %s", version_string) events.USE_FROZEN_DICTS = config.use_frozen_dicts tls_context_factory = context_factory.ServerContextFactory(config) database_engine = create_engine(config.database_config["name"]) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, db_config=config.database_config, tls_context_factory=tls_context_factory, config=config, content_addr=config.content_addr, version_string=version_string, database_engine=database_engine, ) logger.info("Preparing database: %r...", config.database_config) try: db_conn = database_engine.module.connect( **{ k: v for k, v in config.database_config.get("args", {}).items() if not k.startswith("cp_") } ) database_engine.prepare_database(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %r.", config.database_config) hs.start_listening() hs.get_pusherpool().start() hs.get_state_handler().start_caching() hs.get_datastore().start_profiling() hs.get_replication_layer().start_get_pdu_cache() return hs
def test_load_fails_if_server_name_missing(self): self.generate_config_and_remove_lines_containing("server_name") with self.assertRaises(Exception): HomeServerConfig.load_config("", ["-c", self.file]) with self.assertRaises(Exception): HomeServerConfig.load_or_generate_config("", ["-c", self.file])
def setup(config_options): """ Args: config_options_options: The options passed to Synapse. Usually `sys.argv[1:]`. should_run (bool): Whether to start the reactor. Returns: HomeServer """ config = HomeServerConfig.load_config( "Synapse Homeserver", config_options, generate_section="Homeserver" ) config.setup_logging() # check any extra requirements we have now we have a config check_requirements(config) version_string = get_version_string() logger.info("Server hostname: %s", config.server_name) logger.info("Server version: %s", version_string) if re.search(":[0-9]+$", config.server_name): domain_with_port = config.server_name else: domain_with_port = "%s:%s" % (config.server_name, config.bind_port) tls_context_factory = context_factory.ServerContextFactory(config) database_engine = create_engine(config.database_config["name"]) config.database_config["args"]["cp_openfun"] = database_engine.on_new_connection hs = SynapseHomeServer( config.server_name, domain_with_port=domain_with_port, upload_dir=os.path.abspath("uploads"), db_config=config.database_config, tls_context_factory=tls_context_factory, config=config, content_addr=config.content_addr, version_string=version_string, database_engine=database_engine, ) hs.create_resource_tree( redirect_root_to_web_client=True, ) logger.info("Preparing database: %r...", config.database_config) try: db_conn = database_engine.module.connect( **{ k: v for k, v in config.database_config.get("args", {}).items() if not k.startswith("cp_") } ) database_engine.prepare_database(db_conn) hs.run_startup_checks(db_conn, database_engine) db_conn.commit() except UpgradeDatabaseException: sys.stderr.write( "\nFailed to upgrade database.\n" "Have you checked for version specific instructions in" " UPGRADES.rst?\n" ) sys.exit(1) logger.info("Database prepared in %r.", config.database_config) if config.manhole: f = twisted.manhole.telnet.ShellFactory() f.username = "******" f.password = "******" f.namespace['hs'] = hs reactor.listenTCP(config.manhole, f, interface='127.0.0.1') hs.start_listening() hs.get_pusherpool().start() hs.get_state_handler().start_caching() hs.get_datastore().start_profiling() hs.get_replication_layer().start_get_pdu_cache() return hs
def start(config_options): try: config = HomeServerConfig.load_config( "Synapse pusher", config_options ) except ConfigError as e: sys.stderr.write("\n" + e.message + "\n") sys.exit(1) assert config.worker_app == "synapse.app.pusher" setup_logging(config.worker_log_config, config.worker_log_file) if config.start_pushers: sys.stderr.write( "\nThe pushers must be disabled in the main synapse process" "\nbefore they can be run in a separate worker." "\nPlease add ``start_pushers: false`` to the main config" "\n" ) sys.exit(1) # Force the pushers to start since they will be disabled in the main config config.start_pushers = True database_engine = create_engine(config.database_config) ps = PusherServer( config.server_name, db_config=config.database_config, config=config, version_string="Synapse/" + get_version_string(synapse), database_engine=database_engine, ) ps.setup() ps.start_listening(config.worker_listeners) def run(): with LoggingContext("run"): logger.info("Running") change_resource_limit(config.soft_file_limit) if config.gc_thresholds: gc.set_threshold(*config.gc_thresholds) reactor.run() def start(): ps.replicate() ps.get_pusherpool().start() ps.get_datastore().start_profiling() reactor.callWhenRunning(start) if config.worker_daemonize: daemon = Daemonize( app="synapse-pusher", pid=config.worker_pid_file, action=run, auto_close_fds=False, verbose=True, logger=logger, ) daemon.start() else: run()
# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from synapse.config._base import ConfigError if __name__ == "__main__": import sys from synapse.config.homeserver import HomeServerConfig action = sys.argv[1] if action == "read": key = sys.argv[2] try: config = HomeServerConfig.load_config("", sys.argv[3:]) except ConfigError as e: sys.stderr.write("\n" + str(e) + "\n") sys.exit(1) print(getattr(config, key)) sys.exit(0) else: sys.stderr.write("Unknown command %r\n" % (action,)) sys.exit(1)