support command line args for hostname port username password

This commit is contained in:
Divyansh Singh 2023-06-14 00:11:19 +05:30
parent 8e8e64d920
commit 230cf6adc4
3 changed files with 51 additions and 11 deletions

View File

@ -68,15 +68,21 @@ def restore_single_database(
archive_name, archive_name,
hook_name, hook_name,
database, database,
connection_params,
): # pragma: no cover ): # pragma: no cover
''' '''
Given (among other things) an archive name, a database hook name, and a configured database Given (among other things) an archive name, a database hook name, the hostname,
port, username and password as connection params, and a configured database
configuration dict, restore that database from the archive. configuration dict, restore that database from the archive.
''' '''
logger.info( logger.info(
f'{repository.get("label", repository["path"])}: Restoring database {database["name"]}' f'{repository.get("label", repository["path"])}: Restoring database {database["name"]}'
) )
logger.info(
f'hostname port username password for database {database["name"]}'
)
dump_pattern = borgmatic.hooks.dispatch.call_hooks( dump_pattern = borgmatic.hooks.dispatch.call_hooks(
'make_database_dump_pattern', 'make_database_dump_pattern',
hooks, hooks,
@ -113,6 +119,7 @@ def restore_single_database(
location, location,
global_arguments.dry_run, global_arguments.dry_run,
extract_process, extract_process,
connection_params,
) )
@ -308,6 +315,13 @@ def run_restore(
hooks, archive_database_names, hook_name, database_name hooks, archive_database_names, hook_name, database_name
) )
connection_params = {
'hostname': restore_arguments.hostname,
'port': restore_arguments.port,
'username': restore_arguments.username,
'password': restore_arguments.password,
}
if not found_database: if not found_database:
remaining_restore_names.setdefault(found_hook_name or hook_name, []).append( remaining_restore_names.setdefault(found_hook_name or hook_name, []).append(
database_name database_name
@ -327,6 +341,7 @@ def run_restore(
archive_name, archive_name,
found_hook_name or hook_name, found_hook_name or hook_name,
dict(found_database, **{'schemas': restore_arguments.schemas}), dict(found_database, **{'schemas': restore_arguments.schemas}),
connection_params,
) )
# For any database that weren't found via exact matches in the hooks configuration, try to # For any database that weren't found via exact matches in the hooks configuration, try to

View File

@ -720,6 +720,21 @@ def make_parsers():
dest='schemas', dest='schemas',
help='Names of schemas to restore from the database, defaults to all schemas. Schemas are only supported for PostgreSQL and MongoDB databases', help='Names of schemas to restore from the database, defaults to all schemas. Schemas are only supported for PostgreSQL and MongoDB databases',
) )
restore_group.add_argument(
'--hostname',
help='Database hostname to restore to. Defaults to the "restore_hostname" option in borgmatic\'s configuration',
)
restore_group.add_argument(
'--port', help='Port to restore to. Defaults to the "restore_port" 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',
)
restore_group.add_argument(
'--password',
help='Password with which to connect to the restore database. Defaults to the "restore_password" option in borgmatic\'s configuration',
)
restore_group.add_argument( restore_group.add_argument(
'-h', '--help', action='help', help='Show this help message and exit' '-h', '--help', action='help', help='Show this help message and exit'
) )

View File

@ -22,8 +22,7 @@ def make_dump_path(location_config): # pragma: no cover
location_config.get('borgmatic_source_directory'), 'postgresql_databases' location_config.get('borgmatic_source_directory'), 'postgresql_databases'
) )
def make_extra_environment(database, restore=False, connection_params=None):
def make_extra_environment(database, restore=False):
''' '''
Make the extra_environment dict from the given database configuration. Make the extra_environment dict from the given database configuration.
''' '''
@ -32,6 +31,8 @@ def make_extra_environment(database, restore=False):
extra['PGPASSWORD'] = database['password'] extra['PGPASSWORD'] = database['password']
if restore and 'restore_password' in database: if restore and 'restore_password' in database:
extra['PGPASSWORD'] = database['restore_password'] extra['PGPASSWORD'] = database['restore_password']
if connection_params is not None and connection_params.get('password'):
extra['PGPASSWORD'] = connection_params['password']
extra['PGSSLMODE'] = database.get('ssl_mode', 'disable') extra['PGSSLMODE'] = database.get('ssl_mode', 'disable')
if 'ssl_cert' in database: if 'ssl_cert' in database:
extra['PGSSLCERT'] = database['ssl_cert'] extra['PGSSLCERT'] = database['ssl_cert']
@ -195,7 +196,7 @@ def make_database_dump_pattern(
return dump.make_database_dump_filename(make_dump_path(location_config), name, hostname='*') return dump.make_database_dump_filename(make_dump_path(location_config), name, hostname='*')
def restore_database_dump(database_config, log_prefix, location_config, dry_run, extract_process): def restore_database_dump(database_config, log_prefix, location_config, dry_run, extract_process, connection_params):
''' '''
Restore the given PostgreSQL database from an extract stream. The database is supplied as a Restore the given PostgreSQL database from an extract stream. The database is supplied as a
one-element sequence containing a dict describing the database, as per the configuration schema. one-element sequence containing a dict describing the database, as per the configuration schema.
@ -205,6 +206,9 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
If the extract process is None, then restore the dump from the filesystem rather than from an If the extract process is None, then restore the dump from the filesystem rather than from an
extract stream. extract stream.
Use the given connection parameters to connect to the database. The connection parameters are
hostname, port, username, and password.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
@ -212,6 +216,12 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
raise ValueError('The database configuration value is invalid') raise ValueError('The database configuration value is invalid')
database = database_config[0] database = database_config[0]
hostname = connection_params['hostname'] or database.get('restore_hostname', database.get('hostname'))
port = str(connection_params['port'] or database.get('restore_port', database.get('port')))
username = connection_params['username'] or database.get('restore_username', database.get('username'))
password = connection_params['password'] or database.get('restore_password', database.get('password'))
all_databases = bool(database['name'] == 'all') all_databases = bool(database['name'] == 'all')
dump_filename = dump.make_database_dump_filename( dump_filename = dump.make_database_dump_filename(
make_dump_path(location_config), database['name'], database.get('hostname') make_dump_path(location_config), database['name'], database.get('hostname')
@ -220,9 +230,9 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
analyze_command = ( analyze_command = (
tuple(psql_command) tuple(psql_command)
+ ('--no-password', '--no-psqlrc', '--quiet') + ('--no-password', '--no-psqlrc', '--quiet')
+ (('--host', database.get('restore_hostname', database.get('hostname'))) if 'hostname' in database else ()) + (('--host', hostname) if 'hostname' in database or 'restore_hostname' in database or 'hostname' in connection_params else ())
+ (('--port', str(database.get('restore_port', database.get('port')))) if 'port' in database else ()) + (('--port', port) if 'port' in database or 'restore_port' in database or 'port' in connection_params else ())
+ (('--username', database.get('restore_username', database.get('username'))) if 'username' in database else ()) + (('--username', username) if 'username' in database or 'restore_username' in database or 'username' in connection_params else ())
+ (('--dbname', database['name']) if not all_databases else ()) + (('--dbname', database['name']) if not all_databases else ())
+ (tuple(database['analyze_options'].split(' ')) if 'analyze_options' in database else ()) + (tuple(database['analyze_options'].split(' ')) if 'analyze_options' in database else ())
+ ('--command', 'ANALYZE') + ('--command', 'ANALYZE')
@ -234,9 +244,9 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
+ ('--no-password',) + ('--no-password',)
+ (('--no-psqlrc',) if use_psql_command else ('--if-exists', '--exit-on-error', '--clean')) + (('--no-psqlrc',) if use_psql_command else ('--if-exists', '--exit-on-error', '--clean'))
+ (('--dbname', database['name']) if not all_databases else ()) + (('--dbname', database['name']) if not all_databases else ())
+ (('--host', database.get('restore_hostname', database.get('hostname'))) if 'hostname' in database or 'restore_hostname' in database else ()) + (('--host', hostname) if 'hostname' in database or 'restore_hostname' in database or 'hostname' in connection_params else ())
+ (('--port', str(database.get('restore_port', database.get('port')))) if 'port' in database or 'restore_port' in database else ()) + (('--port', port) if 'port' in database or 'restore_port' in database or 'port' in connection_params else ())
+ (('--username', database.get('restore_username', database.get('username'))) if 'username' in database or 'restore_username' in database else ()) + (('--username', username) if 'username' in database or 'restore_username' in database or 'username' in connection_params else ())
+ (('--no-owner',) if database['no_owner'] else ()) + (('--no-owner',) if database['no_owner'] else ())
+ (tuple(database['restore_options'].split(' ')) if 'restore_options' in database else ()) + (tuple(database['restore_options'].split(' ')) if 'restore_options' in database else ())
+ (() if extract_process else (dump_filename,)) + (() if extract_process else (dump_filename,))
@ -247,7 +257,7 @@ def restore_database_dump(database_config, log_prefix, location_config, dry_run,
) )
) )
extra_environment = make_extra_environment(database, restore=True) extra_environment = make_extra_environment(database, restore=True, connection_params=connection_params)
logger.debug(f"{log_prefix}: Restoring PostgreSQL database {database['name']}{dry_run_label}") logger.debug(f"{log_prefix}: Restoring PostgreSQL database {database['name']}{dry_run_label}")
if dry_run: if dry_run: