mirror of
https://github.com/element-hq/synapse.git
synced 2024-12-14 11:57:44 +00:00
Add a script to generate a clean config file (#4315)
This commit is contained in:
parent
f3561f8d86
commit
9c2af7b2c5
11 changed files with 157 additions and 46 deletions
1
changelog.d/4315.feature
Normal file
1
changelog.d/4315.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Add a script to generate a clean config file
|
67
scripts/generate_config
Executable file
67
scripts/generate_config
Executable 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 a new issue