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

Don't default to an invalid sqlite config if no database configuration is provided #6573

Merged
merged 6 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/6573.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Don't attempt to use an invalid sqlite config if no database configuration is provided. Contributed by @nekatak.
69 changes: 47 additions & 22 deletions synapse/config/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

logger = logging.getLogger(__name__)

NON_SQLITE_DATABASE_PATH_WARNING = """\
Ignoring 'database_path' setting: not using a sqlite3 database.
--------------------------------------------------------------------------------
"""

DEFAULT_CONFIG = """\
## Database ##

Expand Down Expand Up @@ -105,6 +110,11 @@ def __init__(self, name: str, db_config: dict):
class DatabaseConfig(Config):
section = "database"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

self.databases = []

def read_config(self, config, **kwargs):
self.event_cache_size = self.parse_size(config.get("event_cache_size", "10K"))

Expand All @@ -125,54 +135,69 @@ def read_config(self, config, **kwargs):

multi_database_config = config.get("databases")
database_config = config.get("database")
database_path = config.get("database_path")

if multi_database_config and database_config:
raise ConfigError("Can't specify both 'database' and 'datbases' in config")

if multi_database_config:
if config.get("database_path"):
if database_path:
raise ConfigError("Can't specify 'database_path' with 'databases'")

self.databases = [
DatabaseConnectionConfig(name, db_conf)
for name, db_conf in multi_database_config.items()
]

else:
if database_config is None:
database_config = {"name": "sqlite3", "args": {}}

if database_config:
self.databases = [DatabaseConnectionConfig("master", database_config)]

self.set_databasepath(config.get("database_path"))
if database_path:
if self.databases and self.databases[0].name != "sqlite3":
logger.warning(NON_SQLITE_DATABASE_PATH_WARNING)
return

database_config = {"name": "sqlite3", "args": {}}
self.databases = [DatabaseConnectionConfig("master", database_config)]
self.set_databasepath(database_path)
nekatak marked this conversation as resolved.
Show resolved Hide resolved

def generate_config_section(self, data_dir_path, **kwargs):
return DEFAULT_CONFIG % {
"database_path": os.path.join(data_dir_path, "homeserver.db")
}

def read_arguments(self, args):
self.set_databasepath(args.database_path)
"""
Cases for the cli input:
- If no databases are configured and no database_path is set, raise.
- No databases and only database_path available ==> sqlite3 db.
- If there are multiple databases and a database_path raise an error.
- If the database set in the config file is sqlite then
overwrite with the command line argument.
"""

def set_databasepath(self, database_path):
if database_path is None:
if args.database_path is None:
if not self.databases:
raise ConfigError("No database config provided")
return

if database_path != ":memory:":
database_path = self.abspath(database_path)
if len(self.databases) == 0:
database_config = {"name": "sqlite3", "args": {}}
self.databases = [DatabaseConnectionConfig("master", database_config)]
self.set_databasepath(args.database_path)
return

if self.get_single_database().name == "sqlite3":
self.set_databasepath(args.database_path)
else:
logger.warning(NON_SQLITE_DATABASE_PATH_WARNING)

# We only support setting a database path if we have a single sqlite3
# database.
if len(self.databases) != 1:
raise ConfigError("Cannot specify 'database_path' with multiple databases")
def set_databasepath(self, database_path):

database = self.get_single_database()
if database.config["name"] != "sqlite3":
# We don't raise here as we haven't done so before for this case.
logger.warn("Ignoring 'database_path' for non-sqlite3 database")
return
if database_path != ":memory:":
database_path = self.abspath(database_path)

database.config["args"]["database"] = database_path
self.databases[0].config["args"]["database"] = database_path

@staticmethod
def add_arguments(parser):
Expand All @@ -187,7 +212,7 @@ def add_arguments(parser):
def get_single_database(self) -> DatabaseConnectionConfig:
"""Returns the database if there is only one, useful for e.g. tests
"""
if len(self.databases) != 1:
if not self.databases:
raise Exception("More than one database exists")

return self.databases[0]