Add a script to generate a clean config file
Ultimately I want to make this part of the debian packaging process, to stop the debian config getting out of sync.pull/4315/head
							parent
							
								
									fc9cdbabe7
								
							
						
					
					
						commit
						59f93bbd5c
					
				|  | @ -0,0 +1 @@ | |||
| Add a script to generate a clean config file | ||||
|  | @ -0,0 +1,67 @@ | |||
| #!/usr/bin/env python | ||||
| 
 | ||||
| import argparse | ||||
| import sys | ||||
| 
 | ||||
| from synapse.config.homeserver import HomeServerConfig | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument( | ||||
|         "--config-dir", | ||||
|         default="CONFDIR", | ||||
| 
 | ||||
|         help="The path where the config files are kept. Used to create filenames for " | ||||
|              "things like the log config and the signing key. Default: %(default)s", | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument( | ||||
|         "--data-dir", | ||||
|         default="DATADIR", | ||||
|         help="The path where the data files are kept. Used to create filenames for " | ||||
|              "things like the database and media store. Default: %(default)s", | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument( | ||||
|         "--server-name", | ||||
|         default="SERVERNAME", | ||||
|         help="The server name. Used to initialise the server_name config param, but also " | ||||
|              "used in the names of some of the config files. Default: %(default)s", | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument( | ||||
|         "--report-stats", | ||||
|         action="store", | ||||
|         help="Whether the generated config reports anonymized usage statistics", | ||||
|         choices=["yes", "no"], | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument( | ||||
|         "--generate-secrets", | ||||
|         action="store_true", | ||||
|         help="Enable generation of new secrets for things like the macaroon_secret_key." | ||||
|              "By default, these parameters will be left unset." | ||||
|     ) | ||||
| 
 | ||||
|     parser.add_argument( | ||||
|         "-o", "--output-file", | ||||
|         type=argparse.FileType('w'), | ||||
|         default=sys.stdout, | ||||
|         help="File to write the configuration to. Default: stdout", | ||||
|     ) | ||||
| 
 | ||||
|     args = parser.parse_args() | ||||
| 
 | ||||
|     report_stats = args.report_stats | ||||
|     if report_stats is not None: | ||||
|         report_stats = report_stats == "yes" | ||||
| 
 | ||||
|     conf = HomeServerConfig().generate_config( | ||||
|         config_dir_path=args.config_dir, | ||||
|         data_dir_path=args.data_dir, | ||||
|         server_name=args.server_name, | ||||
|         generate_secrets=args.generate_secrets, | ||||
|         report_stats=report_stats, | ||||
|     ) | ||||
| 
 | ||||
|     args.output_file.write(conf) | ||||
|  | @ -134,10 +134,6 @@ class Config(object): | |||
|         with open(file_path) as file_stream: | ||||
|             return file_stream.read() | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def default_path(name): | ||||
|         return os.path.abspath(os.path.join(os.path.curdir, name)) | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def read_config_file(file_path): | ||||
|         with open(file_path) as file_stream: | ||||
|  | @ -151,8 +147,39 @@ class Config(object): | |||
|         return results | ||||
| 
 | ||||
|     def generate_config( | ||||
|         self, config_dir_path, server_name, is_generating_file, report_stats=None | ||||
|         self, | ||||
|         config_dir_path, | ||||
|         data_dir_path, | ||||
|         server_name, | ||||
|         generate_secrets=False, | ||||
|         report_stats=None, | ||||
|     ): | ||||
|         """Build a default configuration file | ||||
| 
 | ||||
|         This is used both when the user explicitly asks us to generate a config file | ||||
|         (eg with --generate_config), and before loading the config at runtime (to give | ||||
|         a base which the config files override) | ||||
| 
 | ||||
|         Args: | ||||
|             config_dir_path (str): The path where the config files are kept. Used to | ||||
|                 create filenames for things like the log config and the signing key. | ||||
| 
 | ||||
|             data_dir_path (str): The path where the data files are kept. Used to create | ||||
|                 filenames for things like the database and media store. | ||||
| 
 | ||||
|             server_name (str): The server name. Used to initialise the server_name | ||||
|                 config param, but also used in the names of some of the config files. | ||||
| 
 | ||||
|             generate_secrets (bool): True if we should generate new secrets for things | ||||
|                 like the macaroon_secret_key. If False, these parameters will be left | ||||
|                 unset. | ||||
| 
 | ||||
|             report_stats (bool|None): Initial setting for the report_stats setting. | ||||
|                 If None, report_stats will be left unset. | ||||
| 
 | ||||
|         Returns: | ||||
|             str: the yaml config file | ||||
|         """ | ||||
|         default_config = "# vim:ft=yaml\n" | ||||
| 
 | ||||
|         default_config += "\n\n".join( | ||||
|  | @ -160,15 +187,14 @@ class Config(object): | |||
|             for conf in self.invoke_all( | ||||
|                 "default_config", | ||||
|                 config_dir_path=config_dir_path, | ||||
|                 data_dir_path=data_dir_path, | ||||
|                 server_name=server_name, | ||||
|                 is_generating_file=is_generating_file, | ||||
|                 generate_secrets=generate_secrets, | ||||
|                 report_stats=report_stats, | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|         config = yaml.load(default_config) | ||||
| 
 | ||||
|         return default_config, config | ||||
|         return default_config | ||||
| 
 | ||||
|     @classmethod | ||||
|     def load_config(cls, description, argv): | ||||
|  | @ -274,12 +300,14 @@ class Config(object): | |||
|                 if not cls.path_exists(config_dir_path): | ||||
|                     os.makedirs(config_dir_path) | ||||
|                 with open(config_path, "w") as config_file: | ||||
|                     config_str, config = obj.generate_config( | ||||
|                     config_str = obj.generate_config( | ||||
|                         config_dir_path=config_dir_path, | ||||
|                         data_dir_path=os.getcwd(), | ||||
|                         server_name=server_name, | ||||
|                         report_stats=(config_args.report_stats == "yes"), | ||||
|                         is_generating_file=True, | ||||
|                         generate_secrets=True, | ||||
|                     ) | ||||
|                     config = yaml.load(config_str) | ||||
|                     obj.invoke_all("generate_files", config) | ||||
|                     config_file.write(config_str) | ||||
|                 print( | ||||
|  | @ -350,11 +378,13 @@ class Config(object): | |||
|             raise ConfigError(MISSING_SERVER_NAME) | ||||
| 
 | ||||
|         server_name = specified_config["server_name"] | ||||
|         _, config = self.generate_config( | ||||
|         config_string = self.generate_config( | ||||
|             config_dir_path=config_dir_path, | ||||
|             data_dir_path=os.getcwd(), | ||||
|             server_name=server_name, | ||||
|             is_generating_file=False, | ||||
|             generate_secrets=False, | ||||
|         ) | ||||
|         config = yaml.load(config_string) | ||||
|         config.pop("log_config") | ||||
|         config.update(specified_config) | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| # 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. | ||||
| import os | ||||
| 
 | ||||
| from ._base import Config | ||||
| 
 | ||||
|  | @ -45,8 +46,8 @@ class DatabaseConfig(Config): | |||
| 
 | ||||
|         self.set_databasepath(config.get("database_path")) | ||||
| 
 | ||||
|     def default_config(self, **kwargs): | ||||
|         database_path = self.abspath("homeserver.db") | ||||
|     def default_config(self, data_dir_path, **kwargs): | ||||
|         database_path = os.path.join(data_dir_path, "homeserver.db") | ||||
|         return """\ | ||||
|         # Database configuration | ||||
|         database: | ||||
|  |  | |||
|  | @ -53,10 +53,3 @@ class HomeServerConfig(TlsConfig, ServerConfig, DatabaseConfig, LoggingConfig, | |||
|                        ServerNoticesConfig, RoomDirectoryConfig, | ||||
|                        ): | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     import sys | ||||
|     sys.stdout.write( | ||||
|         HomeServerConfig().generate_config(sys.argv[1], sys.argv[2], True)[0] | ||||
|     ) | ||||
|  |  | |||
|  | @ -66,26 +66,35 @@ class KeyConfig(Config): | |||
|         # falsification of values | ||||
|         self.form_secret = config.get("form_secret", None) | ||||
| 
 | ||||
|     def default_config(self, config_dir_path, server_name, is_generating_file=False, | ||||
|     def default_config(self, config_dir_path, server_name, generate_secrets=False, | ||||
|                        **kwargs): | ||||
|         base_key_name = os.path.join(config_dir_path, server_name) | ||||
| 
 | ||||
|         if is_generating_file: | ||||
|             macaroon_secret_key = random_string_with_symbols(50) | ||||
|             form_secret = '"%s"' % random_string_with_symbols(50) | ||||
|         if generate_secrets: | ||||
|             macaroon_secret_key = 'macaroon_secret_key: "%s"' % ( | ||||
|                 random_string_with_symbols(50), | ||||
|             ) | ||||
|             form_secret = 'form_secret: "%s"' % random_string_with_symbols(50) | ||||
|         else: | ||||
|             macaroon_secret_key = None | ||||
|             form_secret = 'null' | ||||
|             macaroon_secret_key = "# macaroon_secret_key: <PRIVATE STRING>" | ||||
|             form_secret = "# form_secret: <PRIVATE STRING>" | ||||
| 
 | ||||
|         return """\ | ||||
|         macaroon_secret_key: "%(macaroon_secret_key)s" | ||||
|         # a secret which is used to sign access tokens. If none is specified, | ||||
|         # the registration_shared_secret is used, if one is given; otherwise, | ||||
|         # a secret key is derived from the signing key. | ||||
|         # | ||||
|         # Note that changing this will invalidate any active access tokens, so | ||||
|         # all clients will have to log back in. | ||||
|         %(macaroon_secret_key)s | ||||
| 
 | ||||
|         # Used to enable access token expiration. | ||||
|         expire_access_token: False | ||||
| 
 | ||||
|         # a secret which is used to calculate HMACs for form values, to stop | ||||
|         # falsification of values | ||||
|         form_secret: %(form_secret)s | ||||
|         # falsification of values. Must be specified for the User Consent | ||||
|         # forms to work. | ||||
|         %(form_secret)s | ||||
| 
 | ||||
|         ## Signing Keys ## | ||||
| 
 | ||||
|  |  | |||
|  | @ -80,9 +80,7 @@ class LoggingConfig(Config): | |||
|         self.log_file = self.abspath(config.get("log_file")) | ||||
| 
 | ||||
|     def default_config(self, config_dir_path, server_name, **kwargs): | ||||
|         log_config = self.abspath( | ||||
|             os.path.join(config_dir_path, server_name + ".log.config") | ||||
|         ) | ||||
|         log_config = os.path.join(config_dir_path, server_name + ".log.config") | ||||
|         return """ | ||||
|         # A yaml python logging config file | ||||
|         log_config: "%(log_config)s" | ||||
|  |  | |||
|  | @ -24,10 +24,16 @@ class MetricsConfig(Config): | |||
|         self.metrics_bind_host = config.get("metrics_bind_host", "127.0.0.1") | ||||
| 
 | ||||
|     def default_config(self, report_stats=None, **kwargs): | ||||
|         suffix = "" if report_stats is None else "report_stats: %(report_stats)s\n" | ||||
|         return ("""\ | ||||
|         res = """\ | ||||
|         ## Metrics ### | ||||
| 
 | ||||
|         # Enable collection and rendering of performance metrics | ||||
|         enable_metrics: False | ||||
|         """ + suffix) % locals() | ||||
|         """ | ||||
| 
 | ||||
|         if report_stats is None: | ||||
|             res += "# report_stats: true|false\n" | ||||
|         else: | ||||
|             res += "report_stats: %s\n" % ('true' if report_stats else 'false') | ||||
| 
 | ||||
|         return res | ||||
|  |  | |||
|  | @ -50,8 +50,13 @@ class RegistrationConfig(Config): | |||
|                 raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias,)) | ||||
|         self.autocreate_auto_join_rooms = config.get("autocreate_auto_join_rooms", True) | ||||
| 
 | ||||
|     def default_config(self, **kwargs): | ||||
|         registration_shared_secret = random_string_with_symbols(50) | ||||
|     def default_config(self, generate_secrets=False, **kwargs): | ||||
|         if generate_secrets: | ||||
|             registration_shared_secret = 'registration_shared_secret: "%s"' % ( | ||||
|                 random_string_with_symbols(50), | ||||
|             ) | ||||
|         else: | ||||
|             registration_shared_secret = '# registration_shared_secret: <PRIVATE STRING>' | ||||
| 
 | ||||
|         return """\ | ||||
|         ## Registration ## | ||||
|  | @ -78,7 +83,7 @@ class RegistrationConfig(Config): | |||
| 
 | ||||
|         # If set, allows registration by anyone who also has the shared | ||||
|         # secret, even if registration is otherwise disabled. | ||||
|         registration_shared_secret: "%(registration_shared_secret)s" | ||||
|         %(registration_shared_secret)s | ||||
| 
 | ||||
|         # Set the number of bcrypt rounds used to generate password hash. | ||||
|         # Larger numbers increase the work factor needed to generate the hash. | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| # 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. | ||||
| 
 | ||||
| import os | ||||
| from collections import namedtuple | ||||
| 
 | ||||
| from synapse.util.module_loader import load_module | ||||
|  | @ -175,9 +175,9 @@ class ContentRepositoryConfig(Config): | |||
|                 "url_preview_url_blacklist", () | ||||
|             ) | ||||
| 
 | ||||
|     def default_config(self, **kwargs): | ||||
|         media_store = self.default_path("media_store") | ||||
|         uploads_path = self.default_path("uploads") | ||||
|     def default_config(self, data_dir_path, **kwargs): | ||||
|         media_store = os.path.join(data_dir_path, "media_store") | ||||
|         uploads_path = os.path.join(data_dir_path, "uploads") | ||||
|         return r""" | ||||
|         # Directory where uploaded images and attachments are stored. | ||||
|         media_store_path: "%(media_store)s" | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| # limitations under the License. | ||||
| 
 | ||||
| import logging | ||||
| import os.path | ||||
| 
 | ||||
| from synapse.http.endpoint import parse_and_validate_server_name | ||||
| 
 | ||||
|  | @ -203,7 +204,7 @@ class ServerConfig(Config): | |||
|                 ] | ||||
|             }) | ||||
| 
 | ||||
|     def default_config(self, server_name, **kwargs): | ||||
|     def default_config(self, server_name, data_dir_path, **kwargs): | ||||
|         _, bind_port = parse_and_validate_server_name(server_name) | ||||
|         if bind_port is not None: | ||||
|             unsecure_port = bind_port - 400 | ||||
|  | @ -211,7 +212,7 @@ class ServerConfig(Config): | |||
|             bind_port = 8448 | ||||
|             unsecure_port = 8008 | ||||
| 
 | ||||
|         pid_file = self.abspath("homeserver.pid") | ||||
|         pid_file = os.path.join(data_dir_path, "homeserver.pid") | ||||
|         return """\ | ||||
|         ## Server ## | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Richard van der Hoff
						Richard van der Hoff