Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Generate missing configuration files at startup (#13615)
Browse files Browse the repository at this point in the history
If things like the signing key file are missing, let's just try to generate
them on startup.

Again, this is useful for k8s-like deployments where we just want to generate
keys on the first run.
  • Loading branch information
richvdh committed Aug 26, 2022
1 parent 998e211 commit 5e5c815
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 12 deletions.
1 change: 1 addition & 0 deletions changelog.d/13615.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change the default startup behaviour so that any missing "additional" configuration files (signing key, etc) are generated automatically.
8 changes: 7 additions & 1 deletion docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2139,6 +2139,9 @@ allows the shared secret to be specified in an external file.

The file should be a plain text file, containing only the shared secret.

If this file does not exist, Synapse will create a new signing
key on startup and store it in this file.

Example configuration:
```yaml
registration_shared_secret_file: /path/to/secrets/file
Expand Down Expand Up @@ -2555,7 +2558,10 @@ Config options relating to signing keys
---
### `signing_key_path`

Path to the signing key to sign messages with.
Path to the signing key to sign events and federation requests with.

*New in Synapse 1.67*: If this file does not exist, Synapse will create a new signing
key on startup and store it in this file.

Example configuration:
```yaml
Expand Down
59 changes: 48 additions & 11 deletions synapse/config/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import os
import re
from collections import OrderedDict
from enum import Enum, auto
from hashlib import sha256
from textwrap import dedent
from typing import (
Expand Down Expand Up @@ -603,18 +604,44 @@ def load_or_generate_config(
" may specify directories containing *.yaml files.",
)

generate_group = parser.add_argument_group("Config generation")
generate_group.add_argument(
# we nest the mutually-exclusive group inside another group so that the help
# text shows them in their own group.
generate_mode_group = parser.add_argument_group(
"Config generation mode",
)
generate_mode_exclusive = generate_mode_group.add_mutually_exclusive_group()
generate_mode_exclusive.add_argument(
# hidden option to make the type and default work
"--generate-mode",
help=argparse.SUPPRESS,
type=_ConfigGenerateMode,
default=_ConfigGenerateMode.GENERATE_MISSING_AND_RUN,
)
generate_mode_exclusive.add_argument(
"--generate-config",
action="store_true",
help="Generate a config file, then exit.",
action="store_const",
const=_ConfigGenerateMode.GENERATE_EVERYTHING_AND_EXIT,
dest="generate_mode",
)
generate_group.add_argument(
generate_mode_exclusive.add_argument(
"--generate-missing-configs",
"--generate-keys",
action="store_true",
help="Generate any missing additional config files, then exit.",
action="store_const",
const=_ConfigGenerateMode.GENERATE_MISSING_AND_EXIT,
dest="generate_mode",
)
generate_mode_exclusive.add_argument(
"--generate-missing-and-run",
help="Generate any missing additional config files, then run. This is the "
"default behaviour.",
action="store_const",
const=_ConfigGenerateMode.GENERATE_MISSING_AND_RUN,
dest="generate_mode",
)

generate_group = parser.add_argument_group("Details for --generate-config")
generate_group.add_argument(
"-H", "--server-name", help="The server name to generate a config file for."
)
Expand Down Expand Up @@ -670,11 +697,12 @@ def load_or_generate_config(
config_dir_path = os.path.abspath(config_dir_path)
data_dir_path = os.getcwd()

generate_missing_configs = config_args.generate_missing_configs

obj = cls(config_files)

if config_args.generate_config:
if (
config_args.generate_mode
== _ConfigGenerateMode.GENERATE_EVERYTHING_AND_EXIT
):
if config_args.report_stats is None:
parser.error(
"Please specify either --report-stats=yes or --report-stats=no\n\n"
Expand Down Expand Up @@ -732,11 +760,14 @@ def load_or_generate_config(
)
% (config_path,)
)
generate_missing_configs = True

config_dict = read_config_files(config_files)
if generate_missing_configs:
obj.generate_missing_files(config_dict, config_dir_path)
obj.generate_missing_files(config_dict, config_dir_path)

if config_args.generate_mode in (
_ConfigGenerateMode.GENERATE_EVERYTHING_AND_EXIT,
_ConfigGenerateMode.GENERATE_MISSING_AND_EXIT,
):
return None

obj.parse_config_dict(
Expand Down Expand Up @@ -965,6 +996,12 @@ def read_file(file_path: Any, config_path: Iterable[str]) -> str:
raise ConfigError("Error accessing file %r" % (file_path,), config_path) from e


class _ConfigGenerateMode(Enum):
GENERATE_MISSING_AND_RUN = auto()
GENERATE_MISSING_AND_EXIT = auto()
GENERATE_EVERYTHING_AND_EXIT = auto()


__all__ = [
"Config",
"RootConfig",
Expand Down

0 comments on commit 5e5c815

Please sign in to comment.