cleanup database option resolving.

This commit is contained in:
Florian Apolloner
2025-09-15 20:02:31 +02:00
parent 133a11c647
commit e058df6b7e
6 changed files with 75 additions and 84 deletions
+4
View File
@@ -1475,6 +1475,10 @@ def make_parsers(schema, unparsed_arguments): # noqa: PLR0915
'--port',
help='Database port to restore to. Defaults to the "restore_port" option in borgmatic\'s configuration',
)
restore_group.add_argument(
'--container',
help='Container to restore to. Defaults to the "restore_container" option in borgmatic\'s configuration',
)
restore_group.add_argument(
'--username',
help='Username with which to connect to the database. Defaults to the "restore_username" option in borgmatic\'s configuration',
+8 -17
View File
@@ -122,7 +122,7 @@ def database_names_to_dump(database, config, username, password, environment, dr
)
extra_options, defaults_extra_filename = parse_extra_options(database.get('list_options'))
password_transport = database.get('password_transport', 'pipe')
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
show_command = (
mariadb_show_command
+ (
@@ -194,7 +194,7 @@ def execute_dump_command(
)
extra_options, defaults_extra_filename = parse_extra_options(database.get('options'))
password_transport = database.get('password_transport', 'pipe')
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
dump_command = (
mariadb_dump_command
+ (
@@ -417,26 +417,17 @@ def restore_data_source_dump(
subprocess.Popen) to produce output to consume.
'''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
hostname = connection_params['hostname'] or data_source.get(
'restore_hostname',
utils.get_hostname_from_config(data_source),
hostname = utils.resolve_database_option(
'hostname', data_source, connection_params, restore=True
)
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', '')),
)
tls = data_source.get('restore_tls', data_source.get('tls'))
port = utils.resolve_database_option('port', data_source, connection_params, restore=True)
tls = utils.resolve_database_option('tls', data_source, restore=True)
username = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
),
utils.resolve_database_option('username', data_source, connection_params, restore=True),
config,
)
password = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['password']
or data_source.get('restore_password', data_source.get('password'))
),
utils.resolve_database_option('password', data_source, connection_params, restore=True),
config,
)
+10 -16
View File
@@ -139,7 +139,7 @@ def build_dump_command(database, config, dump_filename, dump_format):
dump_command = tuple(
shlex.quote(part) for part in shlex.split(database.get('mongodump_command') or 'mongodump')
)
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
return (
dump_command
+ (('--out', shlex.quote(dump_filename)) if dump_format == 'directory' else ())
@@ -160,7 +160,10 @@ def build_dump_command(database, config, dump_filename, dump_format):
)
+ (('--config', make_password_config_file(password)) if password else ())
+ (
('--authenticationDatabase', shlex.quote(database['authentication_database']))
(
'--authenticationDatabase',
shlex.quote(database['authentication_database']),
)
if 'authentication_database' in database
else ()
)
@@ -251,7 +254,7 @@ def restore_data_source_dump(
connection_params,
)
logger.debug(f"Restoring MongoDB database {data_source['name']}{dry_run_label}")
logger.debug(f'Restoring MongoDB database {data_source["name"]}{dry_run_label}')
if dry_run:
return
@@ -269,23 +272,14 @@ def build_restore_command(extract_process, database, config, dump_filename, conn
'''
Return the custom mongorestore_command from a single database configuration.
'''
hostname = connection_params['hostname'] or database.get(
'restore_hostname',
utils.get_hostname_from_config(database),
)
port = str(connection_params['port'] or database.get('restore_port', database.get('port', '')))
hostname = utils.resolve_database_option('hostname', database, connection_params, restore=True)
port = utils.resolve_database_option('port', database, connection_params, restore=True)
username = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['username']
or database.get('restore_username', database.get('username'))
),
utils.resolve_database_option('username', database, connection_params, restore=True),
config,
)
password = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['password']
or database.get('restore_password', database.get('password'))
),
utils.resolve_database_option('password', database, connection_params, restore=True),
config,
)
+8 -17
View File
@@ -47,7 +47,7 @@ def database_names_to_dump(database, config, username, password, environment, dr
borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('list_options'))
)
password_transport = database.get('password_transport', 'pipe')
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
show_command = (
mysql_show_command
+ (
@@ -121,7 +121,7 @@ def execute_dump_command(
borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('options'))
)
password_transport = database.get('password_transport', 'pipe')
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
dump_command = (
mysql_dump_command
+ (
@@ -348,26 +348,17 @@ def restore_data_source_dump(
subprocess.Popen) to produce output to consume.
'''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
hostname = connection_params['hostname'] or data_source.get(
'restore_hostname',
utils.get_hostname_from_config(data_source),
hostname = utils.resolve_database_option(
'hostname', data_source, connection_params, restore=True
)
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', '')),
)
tls = data_source.get('restore_tls', data_source.get('tls'))
port = utils.resolve_database_option('port', data_source, connection_params, restore=True)
tls = utils.resolve_database_option('tls', data_source, restore=True)
username = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
),
utils.resolve_database_option('username', data_source, connection_params, restore=True),
config,
)
password = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['password']
or data_source.get('restore_password', data_source.get('password'))
),
utils.resolve_database_option('password', data_source, connection_params, restore=True),
config,
)
+17 -30
View File
@@ -32,22 +32,15 @@ def make_environment(database, config, restore_connection_params=None):
'''
environment = dict(os.environ)
try:
if restore_connection_params:
environment['PGPASSWORD'] = borgmatic.hooks.credential.parse.resolve_credential(
(
restore_connection_params.get('password')
or database.get('restore_password', database['password'])
),
config,
)
else:
environment['PGPASSWORD'] = borgmatic.hooks.credential.parse.resolve_credential(
database['password'],
config,
)
except (AttributeError, KeyError):
pass
password = utils.resolve_database_option(
'password', database, restore_connection_params, restore=restore_connection_params
)
if password:
environment['PGPASSWORD'] = borgmatic.hooks.credential.parse.resolve_credential(
password,
config,
)
if 'ssl_mode' in database:
environment['PGSSLMODE'] = database['ssl_mode']
@@ -91,7 +84,7 @@ def database_names_to_dump(database, config, environment, dry_run):
psql_command = tuple(
shlex.quote(part) for part in shlex.split(database.get('psql_command') or 'psql')
)
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
list_command = (
psql_command
+ ('--list', '--no-password', '--no-psqlrc', '--csv', '--tuples-only')
@@ -196,7 +189,7 @@ def dump_data_sources(
)
continue
hostname = utils.get_hostname_from_config(database)
hostname = utils.resolve_database_option('hostname', database)
command = (
dump_command
+ (
@@ -342,18 +335,12 @@ def restore_data_source_dump(
hostname, port, username, and password.
'''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
hostname = connection_params['hostname'] or data_source.get(
'restore_hostname',
utils.get_hostname_from_config(data_source),
)
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', '')),
hostname = utils.resolve_database_option(
'hostname', data_source, connection_params, restore=True
)
port = utils.resolve_database_option('port', data_source, connection_params, restore=True)
username = borgmatic.hooks.credential.parse.resolve_credential(
(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
),
utils.resolve_database_option('username', data_source, connection_params, restore=True),
config,
)
@@ -372,7 +359,7 @@ def restore_data_source_dump(
psql_command
+ ('--no-password', '--no-psqlrc', '--quiet')
+ (('--host', hostname) if hostname else ())
+ (('--port', port) if port else ())
+ (('--port', str(port)) if port else ())
+ (('--username', username) if username else ())
+ (('--dbname', data_source['name']) if not all_databases else ())
+ (
@@ -393,7 +380,7 @@ def restore_data_source_dump(
+ (('--no-psqlrc',) if use_psql_command else ('--if-exists', '--exit-on-error', '--clean'))
+ (('--dbname', data_source['name']) if not all_databases else ())
+ (('--host', hostname) if hostname else ())
+ (('--port', port) if port else ())
+ (('--port', str(port)) if port else ())
+ (('--username', username) if username else ())
+ (('--no-owner',) if data_source.get('no_owner', False) else ())
+ (
+28 -4
View File
@@ -7,10 +7,34 @@ from borgmatic.execute import execute_command_and_capture_output
IS_A_HOOK = False
def get_hostname_from_config(database):
if 'container' in database:
return get_ip_from_container(database['container'])
return database.get('hostname', '')
def resolve_database_option(option, data_source, connection_params=None, restore=False):
# Special case `hostname` since it overlaps with `container`
if option == 'hostname':
return _get_hostname_from_config(data_source, connection_params, restore)
if connection_params and (value := connection_params.get(option)):
return value
if restore and f'restore_{option}' in data_source:
return data_source[f'restore_{option}']
return data_source.get(option)
def _get_hostname_from_config(data_source, connection_params=None, restore=False):
# connection params win, full stop
if connection_params:
if container := connection_params.get('container'):
return container
if hostname := connection_params.get('hostname'):
return hostname
# ... then try the restore config
if restore:
if 'restore_container' in data_source:
return get_ip_from_container(data_source['restore_container'])
if 'restore_hostname' in data_source:
return data_source['restore_hostname']
# ... and finally fall back to the normal options
if 'container' in data_source:
return get_ip_from_container(data_source['container'])
return data_source.get('hostname', '')
def get_ip_from_container(container):