Skip to content

Commit

Permalink
Manually generate the default config yaml, remove most of the command…
Browse files Browse the repository at this point in the history
…line arguments for synapse anticipating that people will use the yaml instead. Simpify implementing config options by not requiring the classes to hit the super class
  • Loading branch information
Mark Haines committed Apr 30, 2015
1 parent 109c8aa commit d624e2a
Show file tree
Hide file tree
Showing 17 changed files with 457 additions and 478 deletions.
27 changes: 13 additions & 14 deletions demo/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,29 @@ if [ $# -eq 1 ]; then
fi
fi

export PYTHONPATH=$(readlink -f $(pwd))


echo $PYTHONPATH

for port in 8080 8081 8082; do
echo "Starting server on port $port... "

https_port=$((port + 400))
mkdir -p demo/$port
pushd demo/$port

rm $DIR/etc/$port.config
python -m synapse.app.homeserver \
--generate-config \
--config-path "demo/etc/$port.config" \
-p "$https_port" \
--unsecure-port "$port" \
-H "localhost:$https_port" \
-f "$DIR/$port.log" \
-d "$DIR/$port.db" \
-D --pid-file "$DIR/$port.pid" \
--manhole $((port + 1000)) \
--tls-dh-params-path "demo/demo.tls.dh" \
--media-store-path "demo/media_store.$port" \
$PARAMS $SYNAPSE_PARAMS \
--enable-registration
--generate-config "localhost:$https_port" \
--config-path "$DIR/etc/$port.config" \

python -m synapse.app.homeserver \
--config-path "demo/etc/$port.config" \
--config-path "$DIR/etc/$port.config" \
-D \
-vv \

popd
done

cd "$CWD"
6 changes: 2 additions & 4 deletions synapse/app/homeserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,6 @@ def setup(config_options):
config.server_name,
domain_with_port=domain_with_port,
upload_dir=os.path.abspath("uploads"),
db_name=config.database_path,
db_config=config.database_config,
tls_context_factory=tls_context_factory,
config=config,
Expand All @@ -407,9 +406,8 @@ def setup(config_options):
redirect_root_to_web_client=True,
)

db_name = hs.get_db_name()

logger.info("Preparing database: %s...", db_name)
logger.info("Preparing database: %r...", config.database_config)

try:
db_conn = database_engine.module.connect(
Expand All @@ -431,7 +429,7 @@ def setup(config_options):
)
sys.exit(1)

logger.info("Database prepared in %s.", db_name)
logger.info("Database prepared in %r.", config.database_config)

if config.manhole:
f = twisted.manhole.telnet.ShellFactory()
Expand Down
141 changes: 76 additions & 65 deletions synapse/config/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@
# limitations under the License.

import argparse
import sys
import os
import yaml
import sys
from textwrap import dedent


class ConfigError(Exception):
pass


class Config(object):
def __init__(self, args):
pass

@staticmethod
def parse_size(string):
Expand All @@ -37,6 +36,22 @@ def parse_size(string):
size = sizes[suffix]
return int(string) * size

@staticmethod
def parse_duration(string):
second = 1000
hour = 60 * 60 * second
day = 24 * hour
week = 7 * day
year = 365 * day

sizes = {"s": second, "h": hour, "d": day, "w": week, "y": year}
size = 1
suffix = string[-1]
if suffix in sizes:
string = string[:-1]
size = sizes[suffix]
return int(string) * size

@staticmethod
def abspath(file_path):
return os.path.abspath(file_path) if file_path else file_path
Expand Down Expand Up @@ -77,17 +92,6 @@ def read_file(cls, file_path, config_name):
with open(file_path) as file_stream:
return file_stream.read()

@classmethod
def read_yaml_file(cls, file_path, config_name):
cls.check_file(file_path, config_name)
with open(file_path) as file_stream:
try:
return yaml.load(file_stream)
except:
raise ConfigError(
"Error parsing yaml in file %r" % (file_path,)
)

@staticmethod
def default_path(name):
return os.path.abspath(os.path.join(os.path.curdir, name))
Expand All @@ -97,16 +101,33 @@ def read_config_file(file_path):
with open(file_path) as file_stream:
return yaml.load(file_stream)

@classmethod
def add_arguments(cls, parser):
pass
def invoke_all(self, name, *args, **kargs):
results = []
for cls in type(self).mro():
if name in cls.__dict__:
results.append(getattr(cls, name)(self, *args, **kargs))
return results

@classmethod
def generate_config(cls, args, config_dir_path):
pass
def generate_config(self, config_dir_path, server_name):
default_config = "# vim:ft=yaml\n"

default_config += "\n\n".join(dedent(conf) for conf in self.invoke_all(
"default_config", config_dir_path, server_name
))

config = yaml.load(default_config)

if not os.path.exists(config_dir_path):
os.makedirs(config_dir_path)

self.invoke_all("generate_keys", config)

return default_config

@classmethod
def load_config(cls, description, argv, generate_section=None):
result = cls()

config_parser = argparse.ArgumentParser(add_help=False)
config_parser.add_argument(
"-c", "--config-path",
Expand All @@ -115,66 +136,56 @@ def load_config(cls, description, argv, generate_section=None):
)
config_parser.add_argument(
"--generate-config",
action="store_true",
help="Generate config file"
metavar="SERVER_NAME",
help="Generate a config file for the server name"
)
config_args, remaining_args = config_parser.parse_known_args(argv)

if config_args.generate_config:
if not config_args.config_path:
config_parser.error(
"Must specify where to generate the config file"
)
config_dir_path = os.path.dirname(config_args.config_path)
if os.path.exists(config_args.config_path):
defaults = cls.read_config_file(config_args.config_path)
else:
defaults = {}
else:
if config_args.config_path:
defaults = cls.read_config_file(config_args.config_path)
else:
defaults = {}

parser = argparse.ArgumentParser(
parents=[config_parser],
description=description,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
cls.add_arguments(parser)
parser.set_defaults(**defaults)

args = parser.parse_args(remaining_args)
if not config_args.config_path:
config_parser.error(
"Must supply a config file.\nA config file can be automatically"
" generated using \"--generate-config SERVER_NAME"
" -c CONFIG-FILE\""
)

if config_args.generate_config:
server_name = config_args.generate_config
config_path = config_args.config_path
if os.path.exists(config_path):
print "Config file %r already exists. Not overwriting" % (
config_args.config_path
)
sys.exit(0)
config_dir_path = os.path.dirname(config_args.config_path)
config_dir_path = os.path.abspath(config_dir_path)
if not os.path.exists(config_dir_path):
os.makedirs(config_dir_path)
cls.generate_config(args, config_dir_path)
config = {}
for key, value in vars(args).items():
if (key not in set(["config_path", "generate_config"])
and value is not None):
config[key] = value
with open(config_args.config_path, "w") as config_file:
# TODO(mark/paul) We might want to output emacs-style mode
# markers as well as vim-style mode markers into the file,
# to further hint to people this is a YAML file.
config_file.write("# vim:ft=yaml\n")
yaml.dump(config, config_file, default_flow_style=False)
with open(config_path, "wb") as config_file:
config_file.write(
result.generate_config(config_dir_path, server_name)
)
print (
"A config file has been generated in %s for server name"
" '%s' with corresponding SSL keys and self-signed"
" certificates. Please review this file and customise it to"
" your needs."
) % (
config_args.config_path, config['server_name']
)
) % (config_path, server_name)
print (
"If this server name is incorrect, you will need to regenerate"
" the SSL certificates"
)
sys.exit(0)

return cls(args)
config = cls.read_config_file(config_args.config_path)
result.invoke_all("read_config", config)

parser = argparse.ArgumentParser(
parents=[config_parser],
description=description,
formatter_class=argparse.RawDescriptionHelpFormatter,
)

result.invoke_all("add_arguments", parser)
args = parser.parse_args(remaining_args)

result.invoke_all("read_arguments", args)

return result
18 changes: 7 additions & 11 deletions synapse/config/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,11 @@

class AppServiceConfig(Config):

def __init__(self, args):
super(AppServiceConfig, self).__init__(args)
self.app_service_config_files = args.app_service_config_files
def read_config(self, config):
self.app_service_config_files = config.get("app_service_config_files", [])

@classmethod
def add_arguments(cls, parser):
super(AppServiceConfig, cls).add_arguments(parser)
group = parser.add_argument_group("appservice")
group.add_argument(
"--app-service-config-files", type=str, nargs='+',
help="A list of application service config files to use."
)
def default_config(cls, config_dir_path, server_name):
return """\
# A list of application service config file to use
app_service_config_files: []
"""
64 changes: 29 additions & 35 deletions synapse/config/captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,34 @@

class CaptchaConfig(Config):

def __init__(self, args):
super(CaptchaConfig, self).__init__(args)
self.recaptcha_private_key = args.recaptcha_private_key
self.recaptcha_public_key = args.recaptcha_public_key
self.enable_registration_captcha = args.enable_registration_captcha
def read_config(self, config):
self.recaptcha_private_key = config["recaptcha_private_key"]
self.recaptcha_public_key = config["recaptcha_public_key"]
self.enable_registration_captcha = config["enable_registration_captcha"]
self.captcha_ip_origin_is_x_forwarded = (
args.captcha_ip_origin_is_x_forwarded
)
self.captcha_bypass_secret = args.captcha_bypass_secret

@classmethod
def add_arguments(cls, parser):
super(CaptchaConfig, cls).add_arguments(parser)
group = parser.add_argument_group("recaptcha")
group.add_argument(
"--recaptcha-public-key", type=str, default="YOUR_PUBLIC_KEY",
help="This Home Server's ReCAPTCHA public key."
)
group.add_argument(
"--recaptcha-private-key", type=str, default="YOUR_PRIVATE_KEY",
help="This Home Server's ReCAPTCHA private key."
)
group.add_argument(
"--enable-registration-captcha", type=bool, default=False,
help="Enables ReCaptcha checks when registering, preventing signup"
+ " unless a captcha is answered. Requires a valid ReCaptcha "
+ "public/private key."
)
group.add_argument(
"--captcha_ip_origin_is_x_forwarded", type=bool, default=False,
help="When checking captchas, use the X-Forwarded-For (XFF) header"
+ " as the client IP and not the actual client IP."
)
group.add_argument(
"--captcha_bypass_secret", type=str,
help="A secret key used to bypass the captcha test entirely."
config["captcha_ip_origin_is_x_forwarded"]
)
self.captcha_bypass_secret = config.get("captcha_bypass_secret")

def default_config(self, config_dir_path, server_name):
return """\
## Captcha ##
# This Home Server's ReCAPTCHA public key.
recaptcha_private_key: "YOUR_PUBLIC_KEY"
# This Home Server's ReCAPTCHA private key.
recaptcha_public_key: "YOUR_PRIVATE_KEY"
# Enables ReCaptcha checks when registering, preventing signup
# unless a captcha is answered. Requires a valid ReCaptcha
# public/private key.
enable_registration_captcha: False
# When checking captchas, use the X-Forwarded-For (XFF) header
# as the client IP and not the actual client IP.
captcha_ip_origin_is_x_forwarded: False
# A secret key used to bypass the captcha test entirely.
captcha_bypass_secret: ~
"""
Loading

0 comments on commit d624e2a

Please sign in to comment.