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

Commit b9ce53e

Browse files
jaywinkbabolivier
andauthored
Fix synapse.config module "read" command (#11145)
`synapse.config.__main__` has the possibility to read a config item. This can be used to conveniently also validate the config is valid before trying to start Synapse. The "read" command broke in #10916 as it now requires passing in "server.server_name" for example. Also made the read command optional so one can just call this with just the confirm file reference and get a "Config parses OK" if things are ok. Signed-off-by: Jason Robinson <jasonr@matrix.org> Co-authored-by: Brendan Abolivier <babolivier@matrix.org>
1 parent b0f03ae commit b9ce53e

File tree

5 files changed

+138
-68
lines changed

5 files changed

+138
-68
lines changed

changelog.d/11145.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a bug introduced in Synapse v1.45.0 breaking the configuration file parsing script.

synapse/config/__main__.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright 2015, 2016 OpenMarket Ltd
2+
# Copyright 2021 The Matrix.org Foundation C.I.C.
23
#
34
# Licensed under the Apache License, Version 2.0 (the "License");
45
# you may not use this file except in compliance with the License.
@@ -11,25 +12,44 @@
1112
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1213
# See the License for the specific language governing permissions and
1314
# limitations under the License.
15+
import sys
16+
1417
from synapse.config._base import ConfigError
18+
from synapse.config.homeserver import HomeServerConfig
1519

16-
if __name__ == "__main__":
17-
import sys
1820

19-
from synapse.config.homeserver import HomeServerConfig
21+
def main(args):
22+
action = args[1] if len(args) > 1 and args[1] == "read" else None
23+
# If we're reading a key in the config file, then `args[1]` will be `read` and `args[2]`
24+
# will be the key to read.
25+
# We'll want to rework this code if we want to support more actions than just `read`.
26+
load_config_args = args[3:] if action else args[1:]
2027

21-
action = sys.argv[1]
28+
try:
29+
config = HomeServerConfig.load_config("", load_config_args)
30+
except ConfigError as e:
31+
sys.stderr.write("\n" + str(e) + "\n")
32+
sys.exit(1)
33+
34+
print("Config parses OK!")
2235

2336
if action == "read":
24-
key = sys.argv[2]
37+
key = args[2]
38+
key_parts = key.split(".")
39+
40+
value = config
2541
try:
26-
config = HomeServerConfig.load_config("", sys.argv[3:])
27-
except ConfigError as e:
28-
sys.stderr.write("\n" + str(e) + "\n")
42+
while len(key_parts):
43+
value = getattr(value, key_parts[0])
44+
key_parts.pop(0)
45+
46+
print(f"\n{key}: {value}")
47+
except AttributeError:
48+
print(
49+
f"\nNo '{key}' key could be found in the provided configuration file."
50+
)
2951
sys.exit(1)
3052

31-
print(getattr(config, key))
32-
sys.exit(0)
33-
else:
34-
sys.stderr.write("Unknown command %r\n" % (action,))
35-
sys.exit(1)
53+
54+
if __name__ == "__main__":
55+
main(sys.argv)

tests/config/test___main__.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright 2021 The Matrix.org Foundation C.I.C.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from synapse.config.__main__ import main
15+
16+
from tests.config.utils import ConfigFileTestCase
17+
18+
19+
class ConfigMainFileTestCase(ConfigFileTestCase):
20+
def test_executes_without_an_action(self):
21+
self.generate_config()
22+
main(["", "-c", self.config_file])
23+
24+
def test_read__error_if_key_not_found(self):
25+
self.generate_config()
26+
with self.assertRaises(SystemExit):
27+
main(["", "read", "foo.bar.hello", "-c", self.config_file])
28+
29+
def test_read__passes_if_key_found(self):
30+
self.generate_config()
31+
main(["", "read", "server.server_name", "-c", self.config_file])

tests/config/test_load.py

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Copyright 2016 OpenMarket Ltd
2+
# Copyright 2021 The Matrix.org Foundation C.I.C.
23
#
34
# Licensed under the Apache License, Version 2.0 (the "License");
45
# you may not use this file except in compliance with the License.
@@ -11,43 +12,30 @@
1112
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1213
# See the License for the specific language governing permissions and
1314
# limitations under the License.
14-
import os.path
15-
import shutil
16-
import tempfile
17-
from contextlib import redirect_stdout
18-
from io import StringIO
19-
2015
import yaml
2116

2217
from synapse.config import ConfigError
2318
from synapse.config.homeserver import HomeServerConfig
2419

25-
from tests import unittest
26-
27-
28-
class ConfigLoadingTestCase(unittest.TestCase):
29-
def setUp(self):
30-
self.dir = tempfile.mkdtemp()
31-
self.file = os.path.join(self.dir, "homeserver.yaml")
20+
from tests.config.utils import ConfigFileTestCase
3221

33-
def tearDown(self):
34-
shutil.rmtree(self.dir)
3522

23+
class ConfigLoadingFileTestCase(ConfigFileTestCase):
3624
def test_load_fails_if_server_name_missing(self):
3725
self.generate_config_and_remove_lines_containing("server_name")
3826
with self.assertRaises(ConfigError):
39-
HomeServerConfig.load_config("", ["-c", self.file])
27+
HomeServerConfig.load_config("", ["-c", self.config_file])
4028
with self.assertRaises(ConfigError):
41-
HomeServerConfig.load_or_generate_config("", ["-c", self.file])
29+
HomeServerConfig.load_or_generate_config("", ["-c", self.config_file])
4230

4331
def test_generates_and_loads_macaroon_secret_key(self):
4432
self.generate_config()
4533

46-
with open(self.file) as f:
34+
with open(self.config_file) as f:
4735
raw = yaml.safe_load(f)
4836
self.assertIn("macaroon_secret_key", raw)
4937

50-
config = HomeServerConfig.load_config("", ["-c", self.file])
38+
config = HomeServerConfig.load_config("", ["-c", self.config_file])
5139
self.assertTrue(
5240
hasattr(config.key, "macaroon_secret_key"),
5341
"Want config to have attr macaroon_secret_key",
@@ -58,7 +46,7 @@ def test_generates_and_loads_macaroon_secret_key(self):
5846
"was: %r" % (config.key.macaroon_secret_key,)
5947
)
6048

61-
config = HomeServerConfig.load_or_generate_config("", ["-c", self.file])
49+
config = HomeServerConfig.load_or_generate_config("", ["-c", self.config_file])
6250
self.assertTrue(
6351
hasattr(config.key, "macaroon_secret_key"),
6452
"Want config to have attr macaroon_secret_key",
@@ -71,9 +59,9 @@ def test_generates_and_loads_macaroon_secret_key(self):
7159

7260
def test_load_succeeds_if_macaroon_secret_key_missing(self):
7361
self.generate_config_and_remove_lines_containing("macaroon")
74-
config1 = HomeServerConfig.load_config("", ["-c", self.file])
75-
config2 = HomeServerConfig.load_config("", ["-c", self.file])
76-
config3 = HomeServerConfig.load_or_generate_config("", ["-c", self.file])
62+
config1 = HomeServerConfig.load_config("", ["-c", self.config_file])
63+
config2 = HomeServerConfig.load_config("", ["-c", self.config_file])
64+
config3 = HomeServerConfig.load_or_generate_config("", ["-c", self.config_file])
7765
self.assertEqual(
7866
config1.key.macaroon_secret_key, config2.key.macaroon_secret_key
7967
)
@@ -87,15 +75,15 @@ def test_disable_registration(self):
8775
["enable_registration: true", "disable_registration: true"]
8876
)
8977
# Check that disable_registration clobbers enable_registration.
90-
config = HomeServerConfig.load_config("", ["-c", self.file])
78+
config = HomeServerConfig.load_config("", ["-c", self.config_file])
9179
self.assertFalse(config.registration.enable_registration)
9280

93-
config = HomeServerConfig.load_or_generate_config("", ["-c", self.file])
81+
config = HomeServerConfig.load_or_generate_config("", ["-c", self.config_file])
9482
self.assertFalse(config.registration.enable_registration)
9583

9684
# Check that either config value is clobbered by the command line.
9785
config = HomeServerConfig.load_or_generate_config(
98-
"", ["-c", self.file, "--enable-registration"]
86+
"", ["-c", self.config_file, "--enable-registration"]
9987
)
10088
self.assertTrue(config.registration.enable_registration)
10189

@@ -104,33 +92,5 @@ def test_stats_enabled(self):
10492
self.add_lines_to_config(["enable_metrics: true"])
10593

10694
# The default Metrics Flags are off by default.
107-
config = HomeServerConfig.load_config("", ["-c", self.file])
95+
config = HomeServerConfig.load_config("", ["-c", self.config_file])
10896
self.assertFalse(config.metrics.metrics_flags.known_servers)
109-
110-
def generate_config(self):
111-
with redirect_stdout(StringIO()):
112-
HomeServerConfig.load_or_generate_config(
113-
"",
114-
[
115-
"--generate-config",
116-
"-c",
117-
self.file,
118-
"--report-stats=yes",
119-
"-H",
120-
"lemurs.win",
121-
],
122-
)
123-
124-
def generate_config_and_remove_lines_containing(self, needle):
125-
self.generate_config()
126-
127-
with open(self.file) as f:
128-
contents = f.readlines()
129-
contents = [line for line in contents if needle not in line]
130-
with open(self.file, "w") as f:
131-
f.write("".join(contents))
132-
133-
def add_lines_to_config(self, lines):
134-
with open(self.file, "a") as f:
135-
for line in lines:
136-
f.write(line + "\n")

tests/config/utils.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Copyright 2021 The Matrix.org Foundation C.I.C.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import os
15+
import shutil
16+
import tempfile
17+
import unittest
18+
from contextlib import redirect_stdout
19+
from io import StringIO
20+
21+
from synapse.config.homeserver import HomeServerConfig
22+
23+
24+
class ConfigFileTestCase(unittest.TestCase):
25+
def setUp(self):
26+
self.dir = tempfile.mkdtemp()
27+
self.config_file = os.path.join(self.dir, "homeserver.yaml")
28+
29+
def tearDown(self):
30+
shutil.rmtree(self.dir)
31+
32+
def generate_config(self):
33+
with redirect_stdout(StringIO()):
34+
HomeServerConfig.load_or_generate_config(
35+
"",
36+
[
37+
"--generate-config",
38+
"-c",
39+
self.config_file,
40+
"--report-stats=yes",
41+
"-H",
42+
"lemurs.win",
43+
],
44+
)
45+
46+
def generate_config_and_remove_lines_containing(self, needle):
47+
self.generate_config()
48+
49+
with open(self.config_file) as f:
50+
contents = f.readlines()
51+
contents = [line for line in contents if needle not in line]
52+
with open(self.config_file, "w") as f:
53+
f.write("".join(contents))
54+
55+
def add_lines_to_config(self, lines):
56+
with open(self.config_file, "a") as f:
57+
for line in lines:
58+
f.write(line + "\n")

0 commit comments

Comments
 (0)