mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-08-03 07:03:00 +02:00
Send MariaDB and MySQL passwords via anonymous pipe instead of environment variable (#1009).
Reviewed-on: https://projects.torsion.org/borgmatic-collective/borgmatic/pulls/1011
This commit is contained in:
@@ -74,7 +74,7 @@ def make_environment(config):
|
||||
os.write(write_file_descriptor, passphrase.encode('utf-8'))
|
||||
os.close(write_file_descriptor)
|
||||
|
||||
# This, plus subprocess.Popen(..., close_fds=False) in execute.py, is necessary for the Borg
|
||||
# This plus subprocess.Popen(..., close_fds=False) in execute.py is necessary for the Borg
|
||||
# child process to inherit the file descriptor.
|
||||
os.set_inheritable(read_file_descriptor, True)
|
||||
environment['BORG_PASSPHRASE_FD'] = str(read_file_descriptor)
|
||||
|
||||
+19
-16
@@ -266,8 +266,8 @@ def log_command(full_command, input_file=None, output_file=None, environment=Non
|
||||
width=MAX_LOGGED_COMMAND_LENGTH,
|
||||
placeholder=' ...',
|
||||
)
|
||||
+ (f" < {getattr(input_file, 'name', '')}" if input_file else '')
|
||||
+ (f" > {getattr(output_file, 'name', '')}" if output_file else '')
|
||||
+ (f" < {getattr(input_file, 'name', input_file)}" if input_file else '')
|
||||
+ (f" > {getattr(output_file, 'name', output_file)}" if output_file else '')
|
||||
)
|
||||
|
||||
|
||||
@@ -315,8 +315,8 @@ def execute_command(
|
||||
shell=shell,
|
||||
env=environment,
|
||||
cwd=working_directory,
|
||||
# Necessary for the passcommand credential hook to work.
|
||||
close_fds=not bool((environment or {}).get('BORG_PASSPHRASE_FD')),
|
||||
# Necessary for passing credentials via anonymous pipe.
|
||||
close_fds=False,
|
||||
)
|
||||
if not run_to_completion:
|
||||
return process
|
||||
@@ -333,6 +333,7 @@ def execute_command(
|
||||
|
||||
def execute_command_and_capture_output(
|
||||
full_command,
|
||||
input_file=None,
|
||||
capture_stderr=False,
|
||||
shell=False,
|
||||
environment=None,
|
||||
@@ -342,28 +343,30 @@ def execute_command_and_capture_output(
|
||||
):
|
||||
'''
|
||||
Execute the given command (a sequence of command/argument strings), capturing and returning its
|
||||
output (stdout). If capture stderr is True, then capture and return stderr in addition to
|
||||
stdout. If shell is True, execute the command within a shell. If an environment variables dict
|
||||
is given, then pass it into the command. If a working directory is given, use that as the
|
||||
present working directory when running the command. If a Borg local path is given, and the
|
||||
command matches it (regardless of arguments), treat exit code 1 as a warning instead of an
|
||||
error. But if Borg exit codes are given as a sequence of exit code configuration dicts, then use
|
||||
that configuration to decide what's an error and what's a warning.
|
||||
output (stdout). If an input file descriptor is given, then pipe it to the command's stdin. If
|
||||
capture stderr is True, then capture and return stderr in addition to stdout. If shell is True,
|
||||
execute the command within a shell. If an environment variables dict is given, then pass it into
|
||||
the command. If a working directory is given, use that as the present working directory when
|
||||
running the command. If a Borg local path is given, and the command matches it (regardless of
|
||||
arguments), treat exit code 1 as a warning instead of an error. But if Borg exit codes are given
|
||||
as a sequence of exit code configuration dicts, then use that configuration to decide what's an
|
||||
error and what's a warning.
|
||||
|
||||
Raise subprocesses.CalledProcessError if an error occurs while running the command.
|
||||
'''
|
||||
log_command(full_command, environment=environment)
|
||||
log_command(full_command, input_file, environment=environment)
|
||||
command = ' '.join(full_command) if shell else full_command
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
command,
|
||||
stdin=input_file,
|
||||
stderr=subprocess.STDOUT if capture_stderr else None,
|
||||
shell=shell,
|
||||
env=environment,
|
||||
cwd=working_directory,
|
||||
# Necessary for the passcommand credential hook to work.
|
||||
close_fds=not bool((environment or {}).get('BORG_PASSPHRASE_FD')),
|
||||
# Necessary for passing credentials via anonymous pipe.
|
||||
close_fds=False,
|
||||
)
|
||||
except subprocess.CalledProcessError as error:
|
||||
if (
|
||||
@@ -422,8 +425,8 @@ def execute_command_with_processes(
|
||||
shell=shell,
|
||||
env=environment,
|
||||
cwd=working_directory,
|
||||
# Necessary for the passcommand credential hook to work.
|
||||
close_fds=not bool((environment or {}).get('BORG_PASSPHRASE_FD')),
|
||||
# Necessary for passing credentials via anonymous pipe.
|
||||
close_fds=False,
|
||||
)
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
# Something has gone wrong. So vent each process' output buffer to prevent it from hanging.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
|
||||
import borgmatic.borg.pattern
|
||||
@@ -23,14 +24,90 @@ def make_dump_path(base_directory): # pragma: no cover
|
||||
return dump.make_data_source_dump_path(base_directory, 'mariadb_databases')
|
||||
|
||||
|
||||
SYSTEM_DATABASE_NAMES = ('information_schema', 'mysql', 'performance_schema', 'sys')
|
||||
DEFAULTS_EXTRA_FILE_FLAG_PATTERN = re.compile('^--defaults-extra-file=(?P<filename>.*)$')
|
||||
|
||||
|
||||
def database_names_to_dump(database, config, environment, dry_run):
|
||||
def parse_extra_options(extra_options):
|
||||
'''
|
||||
Given a requested database config and a configuration dict, return the corresponding sequence of
|
||||
database names to dump. In the case of "all", query for the names of databases on the configured
|
||||
host and return them, excluding any system databases that will cause problems during restore.
|
||||
Given an extra options string, split the options into a tuple and return it. Additionally, if
|
||||
the first option is "--defaults-extra-file=...", then remove it from the options and return the
|
||||
filename.
|
||||
|
||||
So the return value is a tuple of: (parsed options, defaults extra filename).
|
||||
|
||||
The intent is to support downstream merging of multiple "--defaults-extra-file"s, as
|
||||
MariaDB/MySQL only allows one at a time.
|
||||
'''
|
||||
split_extra_options = tuple(shlex.split(extra_options)) if extra_options else ()
|
||||
|
||||
if not split_extra_options:
|
||||
return ((), None)
|
||||
|
||||
match = DEFAULTS_EXTRA_FILE_FLAG_PATTERN.match(split_extra_options[0])
|
||||
|
||||
if not match:
|
||||
return (split_extra_options, None)
|
||||
|
||||
return (split_extra_options[1:], match.group('filename'))
|
||||
|
||||
|
||||
def make_defaults_file_options(username=None, password=None, defaults_extra_filename=None):
|
||||
'''
|
||||
Given a database username and/or password, write it to an anonymous pipe and return the flags
|
||||
for passing that file descriptor to an executed command. The idea is that this is a more secure
|
||||
way to transmit credentials to a database client than using an environment variable.
|
||||
|
||||
If no username or password are given, then return the options for the given defaults extra
|
||||
filename (if any). But if there is a username and/or password and a defaults extra filename is
|
||||
given, then "!include" it from the generated file, effectively allowing multiple defaults extra
|
||||
files.
|
||||
|
||||
Do not use the returned value for multiple different command invocations. That will not work
|
||||
because each pipe is "used up" once read.
|
||||
'''
|
||||
values = '\n'.join(
|
||||
(
|
||||
(f'user={username}' if username is not None else ''),
|
||||
(f'password={password}' if password is not None else ''),
|
||||
)
|
||||
).strip()
|
||||
|
||||
if not values:
|
||||
if defaults_extra_filename:
|
||||
return (f'--defaults-extra-file={defaults_extra_filename}',)
|
||||
|
||||
return ()
|
||||
|
||||
fields_message = ' and '.join(
|
||||
field_name
|
||||
for field_name in (
|
||||
(f'username ({username})' if username is not None else None),
|
||||
('password' if password is not None else None),
|
||||
)
|
||||
if field_name is not None
|
||||
)
|
||||
include_message = f' (including {defaults_extra_filename})' if defaults_extra_filename else ''
|
||||
logger.debug(f'Writing database {fields_message} to defaults extra file pipe{include_message}')
|
||||
|
||||
include = f'!include {defaults_extra_filename}\n' if defaults_extra_filename else ''
|
||||
|
||||
read_file_descriptor, write_file_descriptor = os.pipe()
|
||||
os.write(write_file_descriptor, f'{include}[client]\n{values}'.encode('utf-8'))
|
||||
os.close(write_file_descriptor)
|
||||
|
||||
# This plus subprocess.Popen(..., close_fds=False) in execute.py is necessary for the database
|
||||
# client child process to inherit the file descriptor.
|
||||
os.set_inheritable(read_file_descriptor, True)
|
||||
|
||||
return (f'--defaults-extra-file=/dev/fd/{read_file_descriptor}',)
|
||||
|
||||
|
||||
def database_names_to_dump(database, config, username, password, environment, dry_run):
|
||||
'''
|
||||
Given a requested database config, a configuration dict, a database username and password, an
|
||||
environment dict, and whether this is a dry run, return the corresponding sequence of database
|
||||
names to dump. In the case of "all", query for the names of databases on the configured host and
|
||||
return them, excluding any system databases that will cause problems during restore.
|
||||
'''
|
||||
if database['name'] != 'all':
|
||||
return (database['name'],)
|
||||
@@ -40,24 +117,20 @@ def database_names_to_dump(database, config, environment, dry_run):
|
||||
mariadb_show_command = tuple(
|
||||
shlex.quote(part) for part in shlex.split(database.get('mariadb_command') or 'mariadb')
|
||||
)
|
||||
extra_options, defaults_extra_filename = parse_extra_options(database.get('list_options'))
|
||||
show_command = (
|
||||
mariadb_show_command
|
||||
+ (tuple(database['list_options'].split(' ')) if 'list_options' in database else ())
|
||||
+ make_defaults_file_options(username, password, defaults_extra_filename)
|
||||
+ extra_options
|
||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
|
||||
+ (
|
||||
(
|
||||
'--user',
|
||||
borgmatic.hooks.credential.parse.resolve_credential(database['username'], config),
|
||||
)
|
||||
if 'username' in database
|
||||
else ()
|
||||
)
|
||||
+ ('--skip-column-names', '--batch')
|
||||
+ ('--execute', 'show schemas')
|
||||
)
|
||||
|
||||
logger.debug('Querying for "all" MariaDB databases to dump')
|
||||
|
||||
show_output = execute_command_and_capture_output(show_command, environment=environment)
|
||||
|
||||
return tuple(
|
||||
@@ -67,8 +140,19 @@ def database_names_to_dump(database, config, environment, dry_run):
|
||||
)
|
||||
|
||||
|
||||
SYSTEM_DATABASE_NAMES = ('information_schema', 'mysql', 'performance_schema', 'sys')
|
||||
|
||||
|
||||
def execute_dump_command(
|
||||
database, config, dump_path, database_names, environment, dry_run, dry_run_label
|
||||
database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
database_names,
|
||||
environment,
|
||||
dry_run,
|
||||
dry_run_label,
|
||||
):
|
||||
'''
|
||||
Kick off a dump for the given MariaDB database (provided as a configuration dict) to a named
|
||||
@@ -95,21 +179,15 @@ def execute_dump_command(
|
||||
shlex.quote(part)
|
||||
for part in shlex.split(database.get('mariadb_dump_command') or 'mariadb-dump')
|
||||
)
|
||||
extra_options, defaults_extra_filename = parse_extra_options(database.get('options'))
|
||||
dump_command = (
|
||||
mariadb_dump_command
|
||||
+ (tuple(database['options'].split(' ')) if 'options' in database else ())
|
||||
+ make_defaults_file_options(username, password, defaults_extra_filename)
|
||||
+ extra_options
|
||||
+ (('--add-drop-database',) if database.get('add_drop_database', True) else ())
|
||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
|
||||
+ (
|
||||
(
|
||||
'--user',
|
||||
borgmatic.hooks.credential.parse.resolve_credential(database['username'], config),
|
||||
)
|
||||
if 'username' in database
|
||||
else ()
|
||||
)
|
||||
+ ('--databases',)
|
||||
+ database_names
|
||||
+ ('--result-file', dump_filename)
|
||||
@@ -165,19 +243,16 @@ def dump_data_sources(
|
||||
|
||||
for database in databases:
|
||||
dump_path = make_dump_path(borgmatic_runtime_directory)
|
||||
environment = dict(
|
||||
os.environ,
|
||||
**(
|
||||
{
|
||||
'MYSQL_PWD': borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database['password'], config
|
||||
)
|
||||
}
|
||||
if 'password' in database
|
||||
else {}
|
||||
),
|
||||
username = borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database.get('username'), config
|
||||
)
|
||||
password = borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database.get('password'), config
|
||||
)
|
||||
environment = dict(os.environ)
|
||||
dump_database_names = database_names_to_dump(
|
||||
database, config, username, password, environment, dry_run
|
||||
)
|
||||
dump_database_names = database_names_to_dump(database, config, environment, dry_run)
|
||||
|
||||
if not dump_database_names:
|
||||
if dry_run:
|
||||
@@ -193,6 +268,8 @@ def dump_data_sources(
|
||||
execute_dump_command(
|
||||
renamed_database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
(dump_name,),
|
||||
environment,
|
||||
@@ -205,6 +282,8 @@ def dump_data_sources(
|
||||
execute_dump_command(
|
||||
database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
dump_database_names,
|
||||
environment,
|
||||
@@ -296,20 +375,17 @@ def restore_data_source_dump(
|
||||
mariadb_restore_command = tuple(
|
||||
shlex.quote(part) for part in shlex.split(data_source.get('mariadb_command') or 'mariadb')
|
||||
)
|
||||
extra_options, defaults_extra_filename = parse_extra_options(data_source.get('restore_options'))
|
||||
restore_command = (
|
||||
mariadb_restore_command
|
||||
+ make_defaults_file_options(username, password, defaults_extra_filename)
|
||||
+ extra_options
|
||||
+ ('--batch',)
|
||||
+ (
|
||||
tuple(data_source['restore_options'].split(' '))
|
||||
if 'restore_options' in data_source
|
||||
else ()
|
||||
)
|
||||
+ (('--host', hostname) if hostname else ())
|
||||
+ (('--port', str(port)) if port else ())
|
||||
+ (('--protocol', 'tcp') if hostname or port else ())
|
||||
+ (('--user', username) if username else ())
|
||||
)
|
||||
environment = dict(os.environ, **({'MYSQL_PWD': password} if password else {}))
|
||||
environment = dict(os.environ)
|
||||
|
||||
logger.debug(f"Restoring MariaDB database {data_source['name']}{dry_run_label}")
|
||||
if dry_run:
|
||||
|
||||
@@ -6,6 +6,7 @@ import shlex
|
||||
import borgmatic.borg.pattern
|
||||
import borgmatic.config.paths
|
||||
import borgmatic.hooks.credential.parse
|
||||
import borgmatic.hooks.data_source.mariadb
|
||||
from borgmatic.execute import (
|
||||
execute_command,
|
||||
execute_command_and_capture_output,
|
||||
@@ -26,11 +27,12 @@ def make_dump_path(base_directory): # pragma: no cover
|
||||
SYSTEM_DATABASE_NAMES = ('information_schema', 'mysql', 'performance_schema', 'sys')
|
||||
|
||||
|
||||
def database_names_to_dump(database, config, environment, dry_run):
|
||||
def database_names_to_dump(database, config, username, password, environment, dry_run):
|
||||
'''
|
||||
Given a requested database config and a configuration dict, return the corresponding sequence of
|
||||
database names to dump. In the case of "all", query for the names of databases on the configured
|
||||
host and return them, excluding any system databases that will cause problems during restore.
|
||||
Given a requested database config, a configuration dict, a database username and password, an
|
||||
environment dict, and whether this is a dry run, return the corresponding sequence of database
|
||||
names to dump. In the case of "all", query for the names of databases on the configured host and
|
||||
return them, excluding any system databases that will cause problems during restore.
|
||||
'''
|
||||
if database['name'] != 'all':
|
||||
return (database['name'],)
|
||||
@@ -40,24 +42,24 @@ def database_names_to_dump(database, config, environment, dry_run):
|
||||
mysql_show_command = tuple(
|
||||
shlex.quote(part) for part in shlex.split(database.get('mysql_command') or 'mysql')
|
||||
)
|
||||
extra_options, defaults_extra_filename = (
|
||||
borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('list_options'))
|
||||
)
|
||||
show_command = (
|
||||
mysql_show_command
|
||||
+ (tuple(database['list_options'].split(' ')) if 'list_options' in database else ())
|
||||
+ borgmatic.hooks.data_source.mariadb.make_defaults_file_options(
|
||||
username, password, defaults_extra_filename
|
||||
)
|
||||
+ extra_options
|
||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
|
||||
+ (
|
||||
(
|
||||
'--user',
|
||||
borgmatic.hooks.credential.parse.resolve_credential(database['username'], config),
|
||||
)
|
||||
if 'username' in database
|
||||
else ()
|
||||
)
|
||||
+ ('--skip-column-names', '--batch')
|
||||
+ ('--execute', 'show schemas')
|
||||
)
|
||||
|
||||
logger.debug('Querying for "all" MySQL databases to dump')
|
||||
|
||||
show_output = execute_command_and_capture_output(show_command, environment=environment)
|
||||
|
||||
return tuple(
|
||||
@@ -68,7 +70,15 @@ def database_names_to_dump(database, config, environment, dry_run):
|
||||
|
||||
|
||||
def execute_dump_command(
|
||||
database, config, dump_path, database_names, environment, dry_run, dry_run_label
|
||||
database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
database_names,
|
||||
environment,
|
||||
dry_run,
|
||||
dry_run_label,
|
||||
):
|
||||
'''
|
||||
Kick off a dump for the given MySQL/MariaDB database (provided as a configuration dict) to a
|
||||
@@ -94,21 +104,19 @@ def execute_dump_command(
|
||||
mysql_dump_command = tuple(
|
||||
shlex.quote(part) for part in shlex.split(database.get('mysql_dump_command') or 'mysqldump')
|
||||
)
|
||||
extra_options, defaults_extra_filename = (
|
||||
borgmatic.hooks.data_source.mariadb.parse_extra_options(database.get('options'))
|
||||
)
|
||||
dump_command = (
|
||||
mysql_dump_command
|
||||
+ (tuple(database['options'].split(' ')) if 'options' in database else ())
|
||||
+ borgmatic.hooks.data_source.mariadb.make_defaults_file_options(
|
||||
username, password, defaults_extra_filename
|
||||
)
|
||||
+ extra_options
|
||||
+ (('--add-drop-database',) if database.get('add_drop_database', True) else ())
|
||||
+ (('--host', database['hostname']) if 'hostname' in database else ())
|
||||
+ (('--port', str(database['port'])) if 'port' in database else ())
|
||||
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
|
||||
+ (
|
||||
(
|
||||
'--user',
|
||||
borgmatic.hooks.credential.parse.resolve_credential(database['username'], config),
|
||||
)
|
||||
if 'username' in database
|
||||
else ()
|
||||
)
|
||||
+ ('--databases',)
|
||||
+ database_names
|
||||
+ ('--result-file', dump_filename)
|
||||
@@ -164,19 +172,16 @@ def dump_data_sources(
|
||||
|
||||
for database in databases:
|
||||
dump_path = make_dump_path(borgmatic_runtime_directory)
|
||||
environment = dict(
|
||||
os.environ,
|
||||
**(
|
||||
{
|
||||
'MYSQL_PWD': borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database['password'], config
|
||||
)
|
||||
}
|
||||
if 'password' in database
|
||||
else {}
|
||||
),
|
||||
username = borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database.get('username'), config
|
||||
)
|
||||
password = borgmatic.hooks.credential.parse.resolve_credential(
|
||||
database.get('password'), config
|
||||
)
|
||||
environment = dict(os.environ)
|
||||
dump_database_names = database_names_to_dump(
|
||||
database, config, username, password, environment, dry_run
|
||||
)
|
||||
dump_database_names = database_names_to_dump(database, config, environment, dry_run)
|
||||
|
||||
if not dump_database_names:
|
||||
if dry_run:
|
||||
@@ -192,6 +197,8 @@ def dump_data_sources(
|
||||
execute_dump_command(
|
||||
renamed_database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
(dump_name,),
|
||||
environment,
|
||||
@@ -204,6 +211,8 @@ def dump_data_sources(
|
||||
execute_dump_command(
|
||||
database,
|
||||
config,
|
||||
username,
|
||||
password,
|
||||
dump_path,
|
||||
dump_database_names,
|
||||
environment,
|
||||
@@ -295,20 +304,21 @@ def restore_data_source_dump(
|
||||
mysql_restore_command = tuple(
|
||||
shlex.quote(part) for part in shlex.split(data_source.get('mysql_command') or 'mysql')
|
||||
)
|
||||
extra_options, defaults_extra_filename = (
|
||||
borgmatic.hooks.data_source.mariadb.parse_extra_options(data_source.get('restore_options'))
|
||||
)
|
||||
restore_command = (
|
||||
mysql_restore_command
|
||||
+ ('--batch',)
|
||||
+ (
|
||||
tuple(data_source['restore_options'].split(' '))
|
||||
if 'restore_options' in data_source
|
||||
else ()
|
||||
+ borgmatic.hooks.data_source.mariadb.make_defaults_file_options(
|
||||
username, password, defaults_extra_filename
|
||||
)
|
||||
+ extra_options
|
||||
+ ('--batch',)
|
||||
+ (('--host', hostname) if hostname else ())
|
||||
+ (('--port', str(port)) if port else ())
|
||||
+ (('--protocol', 'tcp') if hostname or port else ())
|
||||
+ (('--user', username) if username else ())
|
||||
)
|
||||
environment = dict(os.environ, **({'MYSQL_PWD': password} if password else {}))
|
||||
environment = dict(os.environ)
|
||||
|
||||
logger.debug(f"Restoring MySQL database {data_source['name']}{dry_run_label}")
|
||||
if dry_run:
|
||||
|
||||
@@ -309,10 +309,8 @@ hooks:
|
||||
### External passwords
|
||||
|
||||
If you don't want to keep your database passwords in your borgmatic
|
||||
configuration file, you can instead pass them in via [environment
|
||||
variables](https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/)
|
||||
or command-line [configuration
|
||||
overrides](https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#configuration-overrides).
|
||||
configuration file, you can instead pass them in [from external credential
|
||||
sources](https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/).
|
||||
|
||||
|
||||
### Configuration backups
|
||||
|
||||
@@ -6,10 +6,108 @@ from flexmock import flexmock
|
||||
from borgmatic.hooks.data_source import mariadb as module
|
||||
|
||||
|
||||
def test_parse_extra_options_passes_through_empty_options():
|
||||
assert module.parse_extra_options('') == ((), None)
|
||||
|
||||
|
||||
def test_parse_extra_options_with_defaults_extra_file_removes_and_and_parses_out_filename():
|
||||
assert module.parse_extra_options('--defaults-extra-file=extra.cnf --skip-ssl') == (
|
||||
('--skip-ssl',),
|
||||
'extra.cnf',
|
||||
)
|
||||
|
||||
|
||||
def test_parse_extra_options_without_defaults_extra_file_passes_through_options():
|
||||
assert module.parse_extra_options('--skip-ssl --and=stuff') == (
|
||||
('--skip-ssl', '--and=stuff'),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
def test_make_defaults_file_pipe_without_username_or_password_bails():
|
||||
flexmock(module.os).should_receive('pipe').never()
|
||||
|
||||
assert module.make_defaults_file_options(username=None, password=None) == ()
|
||||
|
||||
|
||||
def test_make_defaults_file_option_with_username_and_password_writes_them_to_file_descriptor():
|
||||
read_descriptor = 99
|
||||
write_descriptor = flexmock()
|
||||
|
||||
flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
|
||||
flexmock(module.os).should_receive('write').with_args(
|
||||
write_descriptor, b'[client]\nuser=root\npassword=trustsome1'
|
||||
).once()
|
||||
flexmock(module.os).should_receive('close')
|
||||
flexmock(module.os).should_receive('set_inheritable')
|
||||
|
||||
assert module.make_defaults_file_options(username='root', password='trustsome1') == (
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
)
|
||||
|
||||
|
||||
def test_make_defaults_file_pipe_with_only_username_writes_it_to_file_descriptor():
|
||||
read_descriptor = 99
|
||||
write_descriptor = flexmock()
|
||||
|
||||
flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
|
||||
flexmock(module.os).should_receive('write').with_args(
|
||||
write_descriptor, b'[client]\nuser=root'
|
||||
).once()
|
||||
flexmock(module.os).should_receive('close')
|
||||
flexmock(module.os).should_receive('set_inheritable')
|
||||
|
||||
assert module.make_defaults_file_options(username='root', password=None) == (
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
)
|
||||
|
||||
|
||||
def test_make_defaults_file_pipe_with_only_password_writes_it_to_file_descriptor():
|
||||
read_descriptor = 99
|
||||
write_descriptor = flexmock()
|
||||
|
||||
flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
|
||||
flexmock(module.os).should_receive('write').with_args(
|
||||
write_descriptor, b'[client]\npassword=trustsome1'
|
||||
).once()
|
||||
flexmock(module.os).should_receive('close')
|
||||
flexmock(module.os).should_receive('set_inheritable')
|
||||
|
||||
assert module.make_defaults_file_options(username=None, password='trustsome1') == (
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
)
|
||||
|
||||
|
||||
def test_make_defaults_file_option_with_defaults_extra_filename_includes_it_in_file_descriptor():
|
||||
read_descriptor = 99
|
||||
write_descriptor = flexmock()
|
||||
|
||||
flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor)
|
||||
flexmock(module.os).should_receive('write').with_args(
|
||||
write_descriptor, b'!include extra.cnf\n[client]\nuser=root\npassword=trustsome1'
|
||||
).once()
|
||||
flexmock(module.os).should_receive('close')
|
||||
flexmock(module.os).should_receive('set_inheritable')
|
||||
|
||||
assert module.make_defaults_file_options(
|
||||
username='root', password='trustsome1', defaults_extra_filename='extra.cnf'
|
||||
) == ('--defaults-extra-file=/dev/fd/99',)
|
||||
|
||||
|
||||
def test_make_defaults_file_option_with_only_defaults_extra_filename_uses_it_instead_of_file_descriptor():
|
||||
flexmock(module.os).should_receive('pipe').never()
|
||||
|
||||
assert module.make_defaults_file_options(
|
||||
username=None, password=None, defaults_extra_filename='extra.cnf'
|
||||
) == ('--defaults-extra-file=extra.cnf',)
|
||||
|
||||
|
||||
def test_database_names_to_dump_passes_through_name():
|
||||
environment = flexmock()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'foo'}, {}, environment, dry_run=False)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'foo'}, {}, 'root', 'trustsome1', environment, dry_run=False
|
||||
)
|
||||
|
||||
assert names == ('foo',)
|
||||
|
||||
@@ -18,7 +116,9 @@ def test_database_names_to_dump_bails_for_dry_run():
|
||||
environment = flexmock()
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').never()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'all'}, {}, environment, dry_run=True)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=True
|
||||
)
|
||||
|
||||
assert names == ()
|
||||
|
||||
@@ -28,12 +128,25 @@ def test_database_names_to_dump_queries_mariadb_for_database_names():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
('mariadb', '--skip-column-names', '--batch', '--execute', 'show schemas'),
|
||||
(
|
||||
'mariadb',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
'show schemas',
|
||||
),
|
||||
environment=environment,
|
||||
).and_return('foo\nbar\nmysql\n').once()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'all'}, {}, environment, dry_run=False)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=False
|
||||
)
|
||||
|
||||
assert names == ('foo', 'bar')
|
||||
|
||||
@@ -53,6 +166,9 @@ def test_dump_data_sources_dumps_each_database():
|
||||
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
||||
processes = [flexmock(), flexmock()]
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).and_return(None)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
@@ -65,6 +181,8 @@ def test_dump_data_sources_dumps_each_database():
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': name},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=(name,),
|
||||
environment={'USER': 'root'},
|
||||
@@ -89,10 +207,10 @@ def test_dump_data_sources_dumps_with_password():
|
||||
database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
|
||||
process = flexmock()
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
|
||||
('bar',)
|
||||
)
|
||||
@@ -100,9 +218,11 @@ def test_dump_data_sources_dumps_with_password():
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database=database,
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=object,
|
||||
database_names=('foo',),
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
|
||||
environment={'USER': 'root'},
|
||||
dry_run=object,
|
||||
dry_run_label=object,
|
||||
).and_return(process).once()
|
||||
@@ -121,14 +241,16 @@ def test_dump_data_sources_dumps_all_databases_at_once():
|
||||
databases = [{'name': 'all'}]
|
||||
process = flexmock()
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': 'all'},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=('foo', 'bar'),
|
||||
environment={'USER': 'root'},
|
||||
@@ -150,16 +272,18 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
|
||||
databases = [{'name': 'all', 'format': 'sql'}]
|
||||
processes = [flexmock(), flexmock()]
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
).and_return(None)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
|
||||
|
||||
for name, process in zip(('foo', 'bar'), processes):
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': name, 'format': 'sql'},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=(name,),
|
||||
environment={'USER': 'root'},
|
||||
@@ -181,11 +305,18 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
|
||||
|
||||
|
||||
def test_database_names_to_dump_runs_mariadb_with_list_options():
|
||||
database = {'name': 'all', 'list_options': '--defaults-extra-file=mariadb.cnf'}
|
||||
database = {'name': 'all', 'list_options': '--defaults-extra-file=mariadb.cnf --skip-ssl'}
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(
|
||||
('--skip-ssl',), 'mariadb.cnf'
|
||||
)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', 'mariadb.cnf'
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
(
|
||||
'mariadb',
|
||||
'--defaults-extra-file=mariadb.cnf',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-ssl',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
@@ -194,20 +325,30 @@ def test_database_names_to_dump_runs_mariadb_with_list_options():
|
||||
environment=None,
|
||||
).and_return(('foo\nbar')).once()
|
||||
|
||||
assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
|
||||
assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
|
||||
'foo',
|
||||
'bar',
|
||||
)
|
||||
|
||||
|
||||
def test_database_names_to_dump_runs_non_default_mariadb_with_list_options():
|
||||
database = {
|
||||
'name': 'all',
|
||||
'list_options': '--defaults-extra-file=mariadb.cnf',
|
||||
'list_options': '--defaults-extra-file=mariadb.cnf --skip-ssl',
|
||||
'mariadb_command': 'custom_mariadb',
|
||||
}
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(
|
||||
('--skip-ssl',), 'mariadb.cnf'
|
||||
)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', 'mariadb.cnf'
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
environment=None,
|
||||
full_command=(
|
||||
'custom_mariadb', # Custom MariaDB command
|
||||
'--defaults-extra-file=mariadb.cnf',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-ssl',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
@@ -215,7 +356,10 @@ def test_database_names_to_dump_runs_non_default_mariadb_with_list_options():
|
||||
),
|
||||
).and_return(('foo\nbar')).once()
|
||||
|
||||
assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
|
||||
assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
|
||||
'foo',
|
||||
'bar',
|
||||
)
|
||||
|
||||
|
||||
def test_execute_dump_command_runs_mariadb_dump():
|
||||
@@ -225,11 +369,16 @@ def test_execute_dump_command_runs_mariadb_dump():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mariadb-dump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
'foo',
|
||||
@@ -244,6 +393,8 @@ def test_execute_dump_command_runs_mariadb_dump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -261,11 +412,16 @@ def test_execute_dump_command_runs_mariadb_dump_without_add_drop_database():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mariadb-dump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--databases',
|
||||
'foo',
|
||||
'--result-file',
|
||||
@@ -279,6 +435,8 @@ def test_execute_dump_command_runs_mariadb_dump_without_add_drop_database():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'add_drop_database': False},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -296,11 +454,16 @@ def test_execute_dump_command_runs_mariadb_dump_with_hostname_and_port():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mariadb-dump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--host',
|
||||
'database.example.org',
|
||||
@@ -321,6 +484,8 @@ def test_execute_dump_command_runs_mariadb_dump_with_hostname_and_port():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'hostname': 'database.example.org', 'port': 5433},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -338,20 +503,23 @@ def test_execute_dump_command_runs_mariadb_dump_with_username_and_password():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mariadb-dump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--user',
|
||||
'root',
|
||||
'--databases',
|
||||
'foo',
|
||||
'--result-file',
|
||||
'dump',
|
||||
),
|
||||
environment={'MYSQL_PWD': 'trustsome1'},
|
||||
environment={},
|
||||
run_to_completion=False,
|
||||
).and_return(process).once()
|
||||
|
||||
@@ -359,9 +527,11 @@ def test_execute_dump_command_runs_mariadb_dump_with_username_and_password():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'username': 'root', 'password': 'trustsome1'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment={'MYSQL_PWD': 'trustsome1'},
|
||||
environment={},
|
||||
dry_run=False,
|
||||
dry_run_label='',
|
||||
)
|
||||
@@ -376,11 +546,16 @@ def test_execute_dump_command_runs_mariadb_dump_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(('--stuff=such',), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mariadb-dump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--stuff=such',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
@@ -396,6 +571,8 @@ def test_execute_dump_command_runs_mariadb_dump_with_options():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'options': '--stuff=such'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -413,11 +590,16 @@ def test_execute_dump_command_runs_non_default_mariadb_dump_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(('--stuff=such',), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'custom_mariadb_dump', # Custom MariaDB dump command
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--stuff=such',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
@@ -437,6 +619,8 @@ def test_execute_dump_command_runs_non_default_mariadb_dump_with_options():
|
||||
'options': '--stuff=such',
|
||||
}, # Custom MariaDB dump command specified
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -450,6 +634,10 @@ def test_execute_dump_command_runs_non_default_mariadb_dump_with_options():
|
||||
def test_execute_dump_command_with_duplicate_dump_skips_mariadb_dump():
|
||||
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
|
||||
@@ -457,6 +645,8 @@ def test_execute_dump_command_with_duplicate_dump_skips_mariadb_dump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -473,6 +663,10 @@ def test_execute_dump_command_with_dry_run_skips_mariadb_dump():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
@@ -481,6 +675,8 @@ def test_execute_dump_command_with_dry_run_skips_mariadb_dump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -546,6 +742,10 @@ def test_restore_data_source_dump_runs_mariadb_to_restore():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
None, None, None
|
||||
).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mariadb', '--batch'),
|
||||
@@ -578,9 +778,13 @@ def test_restore_data_source_dump_runs_mariadb_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(('--harder',), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
None, None, None
|
||||
).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mariadb', '--batch', '--harder'),
|
||||
('mariadb', '--harder', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
@@ -612,9 +816,13 @@ def test_restore_data_source_dump_runs_non_default_mariadb_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return(('--harder',), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
None, None, None
|
||||
).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('custom_mariadb', '--batch', '--harder'),
|
||||
('custom_mariadb', '--harder', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
@@ -644,6 +852,10 @@ def test_restore_data_source_dump_runs_mariadb_with_hostname_and_port():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
None, None, None
|
||||
).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
@@ -685,13 +897,17 @@ def test_restore_data_source_dump_runs_mariadb_with_username_and_password():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'root', 'trustsome1', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mariadb', '--batch', '--user', 'root'),
|
||||
('mariadb', '--defaults-extra-file=/dev/fd/99', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -727,10 +943,15 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'cliusername', 'clipassword', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
'mariadb',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--batch',
|
||||
'--host',
|
||||
'clihost',
|
||||
@@ -738,13 +959,11 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
|
||||
'cliport',
|
||||
'--protocol',
|
||||
'tcp',
|
||||
'--user',
|
||||
'cliusername',
|
||||
),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'clipassword'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -782,10 +1001,15 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
'restoreuser', 'restorepass', None
|
||||
).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
'mariadb',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--batch',
|
||||
'--host',
|
||||
'restorehost',
|
||||
@@ -793,13 +1017,11 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
|
||||
'restoreport',
|
||||
'--protocol',
|
||||
'tcp',
|
||||
'--user',
|
||||
'restoreuser',
|
||||
),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'restorepass'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -824,6 +1046,10 @@ def test_restore_data_source_dump_with_dry_run_skips_restore():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('parse_extra_options').and_return((), None)
|
||||
flexmock(module).should_receive('make_defaults_file_options').with_args(
|
||||
None, None, None
|
||||
).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').never()
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ from borgmatic.hooks.data_source import mysql as module
|
||||
def test_database_names_to_dump_passes_through_name():
|
||||
environment = flexmock()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'foo'}, {}, environment, dry_run=False)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'foo'}, {}, 'root', 'trustsome1', environment, dry_run=False
|
||||
)
|
||||
|
||||
assert names == ('foo',)
|
||||
|
||||
@@ -21,7 +23,9 @@ def test_database_names_to_dump_bails_for_dry_run():
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').never()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'all'}, {}, environment, dry_run=True)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=True
|
||||
)
|
||||
|
||||
assert names == ()
|
||||
|
||||
@@ -31,12 +35,27 @@ def test_database_names_to_dump_queries_mysql_for_database_names():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
('mysql', '--skip-column-names', '--batch', '--execute', 'show schemas'),
|
||||
(
|
||||
'mysql',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
'show schemas',
|
||||
),
|
||||
environment=environment,
|
||||
).and_return('foo\nbar\nmysql\n').once()
|
||||
|
||||
names = module.database_names_to_dump({'name': 'all'}, {}, environment, dry_run=False)
|
||||
names = module.database_names_to_dump(
|
||||
{'name': 'all'}, {}, 'root', 'trustsome1', environment, dry_run=False
|
||||
)
|
||||
|
||||
assert names == ('foo', 'bar')
|
||||
|
||||
@@ -56,6 +75,9 @@ def test_dump_data_sources_dumps_each_database():
|
||||
databases = [{'name': 'foo'}, {'name': 'bar'}]
|
||||
processes = [flexmock(), flexmock()]
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).and_return(None)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
|
||||
('bar',)
|
||||
@@ -65,6 +87,8 @@ def test_dump_data_sources_dumps_each_database():
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': name},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=(name,),
|
||||
environment={'USER': 'root'},
|
||||
@@ -89,10 +113,10 @@ def test_dump_data_sources_dumps_with_password():
|
||||
database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
|
||||
process = flexmock()
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
|
||||
('bar',)
|
||||
)
|
||||
@@ -100,9 +124,11 @@ def test_dump_data_sources_dumps_with_password():
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database=database,
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=object,
|
||||
database_names=('foo',),
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
|
||||
environment={'USER': 'root'},
|
||||
dry_run=object,
|
||||
dry_run_label=object,
|
||||
).and_return(process).once()
|
||||
@@ -121,11 +147,16 @@ def test_dump_data_sources_dumps_all_databases_at_once():
|
||||
databases = [{'name': 'all'}]
|
||||
process = flexmock()
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).and_return(None)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': 'all'},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=('foo', 'bar'),
|
||||
environment={'USER': 'root'},
|
||||
@@ -147,6 +178,9 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
|
||||
databases = [{'name': 'all', 'format': 'sql'}]
|
||||
processes = [flexmock(), flexmock()]
|
||||
flexmock(module).should_receive('make_dump_path').and_return('')
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).and_return(None)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
|
||||
|
||||
@@ -154,6 +188,8 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
|
||||
flexmock(module).should_receive('execute_dump_command').with_args(
|
||||
database={'name': name, 'format': 'sql'},
|
||||
config={},
|
||||
username=None,
|
||||
password=None,
|
||||
dump_path=object,
|
||||
database_names=(name,),
|
||||
environment={'USER': 'root'},
|
||||
@@ -175,11 +211,18 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
|
||||
|
||||
|
||||
def test_database_names_to_dump_runs_mysql_with_list_options():
|
||||
database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf'}
|
||||
database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf --skip-ssl'}
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return(('--skip-ssl',), 'my.cnf')
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', 'my.cnf').and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
(
|
||||
'mysql',
|
||||
'--defaults-extra-file=my.cnf',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-ssl',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
@@ -188,20 +231,30 @@ def test_database_names_to_dump_runs_mysql_with_list_options():
|
||||
environment=None,
|
||||
).and_return(('foo\nbar')).once()
|
||||
|
||||
assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
|
||||
assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
|
||||
'foo',
|
||||
'bar',
|
||||
)
|
||||
|
||||
|
||||
def test_database_names_to_dump_runs_non_default_mysql_with_list_options():
|
||||
database = {
|
||||
'name': 'all',
|
||||
'list_options': '--defaults-extra-file=my.cnf',
|
||||
'list_options': '--defaults-extra-file=my.cnf --skip-ssl',
|
||||
'mysql_command': 'custom_mysql',
|
||||
}
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return(('--skip-ssl',), 'my.cnf')
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', 'my.cnf').and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
|
||||
environment=None,
|
||||
full_command=(
|
||||
'custom_mysql', # Custom MySQL command
|
||||
'--defaults-extra-file=my.cnf',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--skip-ssl',
|
||||
'--skip-column-names',
|
||||
'--batch',
|
||||
'--execute',
|
||||
@@ -209,7 +262,10 @@ def test_database_names_to_dump_runs_non_default_mysql_with_list_options():
|
||||
),
|
||||
).and_return(('foo\nbar')).once()
|
||||
|
||||
assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
|
||||
assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
|
||||
'foo',
|
||||
'bar',
|
||||
)
|
||||
|
||||
|
||||
def test_execute_dump_command_runs_mysqldump():
|
||||
@@ -219,11 +275,18 @@ def test_execute_dump_command_runs_mysqldump():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mysqldump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
'foo',
|
||||
@@ -238,6 +301,8 @@ def test_execute_dump_command_runs_mysqldump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -255,11 +320,18 @@ def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mysqldump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--databases',
|
||||
'foo',
|
||||
'--result-file',
|
||||
@@ -273,6 +345,8 @@ def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'add_drop_database': False},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -290,11 +364,18 @@ def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mysqldump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--host',
|
||||
'database.example.org',
|
||||
@@ -315,6 +396,8 @@ def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'hostname': 'database.example.org', 'port': 5433},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -332,20 +415,25 @@ def test_execute_dump_command_runs_mysqldump_with_username_and_password():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mysqldump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--user',
|
||||
'root',
|
||||
'--databases',
|
||||
'foo',
|
||||
'--result-file',
|
||||
'dump',
|
||||
),
|
||||
environment={'MYSQL_PWD': 'trustsome1'},
|
||||
environment={},
|
||||
run_to_completion=False,
|
||||
).and_return(process).once()
|
||||
|
||||
@@ -353,9 +441,11 @@ def test_execute_dump_command_runs_mysqldump_with_username_and_password():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'username': 'root', 'password': 'trustsome1'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment={'MYSQL_PWD': 'trustsome1'},
|
||||
environment={},
|
||||
dry_run=False,
|
||||
dry_run_label='',
|
||||
)
|
||||
@@ -370,11 +460,18 @@ def test_execute_dump_command_runs_mysqldump_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return(('--stuff=such',), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'mysqldump',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--stuff=such',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
@@ -390,6 +487,8 @@ def test_execute_dump_command_runs_mysqldump_with_options():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo', 'options': '--stuff=such'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -407,11 +506,18 @@ def test_execute_dump_command_runs_non_default_mysqldump():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
(
|
||||
'custom_mysqldump', # Custom MySQL dump command
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--add-drop-database',
|
||||
'--databases',
|
||||
'foo',
|
||||
@@ -429,6 +535,8 @@ def test_execute_dump_command_runs_non_default_mysqldump():
|
||||
'mysql_dump_command': 'custom_mysqldump',
|
||||
}, # Custom MySQL dump command specified
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -442,6 +550,12 @@ def test_execute_dump_command_runs_non_default_mysqldump():
|
||||
def test_execute_dump_command_with_duplicate_dump_skips_mysqldump():
|
||||
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
|
||||
@@ -449,6 +563,8 @@ def test_execute_dump_command_with_duplicate_dump_skips_mysqldump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -465,6 +581,12 @@ def test_execute_dump_command_with_dry_run_skips_mysqldump():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
|
||||
|
||||
flexmock(module).should_receive('execute_command').never()
|
||||
@@ -473,6 +595,8 @@ def test_execute_dump_command_with_dry_run_skips_mysqldump():
|
||||
module.execute_dump_command(
|
||||
database={'name': 'foo'},
|
||||
config={},
|
||||
username='root',
|
||||
password='trustsome1',
|
||||
dump_path=flexmock(),
|
||||
database_names=('foo',),
|
||||
environment=None,
|
||||
@@ -538,6 +662,12 @@ def test_restore_data_source_dump_runs_mysql_to_restore():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args(None, None, None).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mysql', '--batch'),
|
||||
@@ -570,9 +700,15 @@ def test_restore_data_source_dump_runs_mysql_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return(('--harder',), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args(None, None, None).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mysql', '--batch', '--harder'),
|
||||
('mysql', '--harder', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
@@ -602,9 +738,15 @@ def test_restore_data_source_dump_runs_non_default_mysql_with_options():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return(('--harder',), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args(None, None, None).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('custom_mysql', '--batch', '--harder'),
|
||||
('custom_mysql', '--harder', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
@@ -634,6 +776,12 @@ def test_restore_data_source_dump_runs_mysql_with_hostname_and_port():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args(None, None, None).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
@@ -675,13 +823,19 @@ def test_restore_data_source_dump_runs_mysql_with_username_and_password():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
('mysql', '--batch', '--user', 'root'),
|
||||
('mysql', '--defaults-extra-file=/dev/fd/99', '--batch'),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -717,10 +871,19 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('cliusername', 'clipassword', None).and_return(
|
||||
('--defaults-extra-file=/dev/fd/99',)
|
||||
)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
'mysql',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--batch',
|
||||
'--host',
|
||||
'clihost',
|
||||
@@ -728,13 +891,11 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
|
||||
'cliport',
|
||||
'--protocol',
|
||||
'tcp',
|
||||
'--user',
|
||||
'cliusername',
|
||||
),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'clipassword'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -772,10 +933,19 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args('restoreuser', 'restorepass', None).and_return(
|
||||
('--defaults-extra-file=/dev/fd/99',)
|
||||
)
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').with_args(
|
||||
(
|
||||
'mysql',
|
||||
'--defaults-extra-file=/dev/fd/99',
|
||||
'--batch',
|
||||
'--host',
|
||||
'restorehost',
|
||||
@@ -783,13 +953,11 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
|
||||
'restoreport',
|
||||
'--protocol',
|
||||
'tcp',
|
||||
'--user',
|
||||
'restoreuser',
|
||||
),
|
||||
processes=[extract_process],
|
||||
output_log_level=logging.DEBUG,
|
||||
input_file=extract_process.stdout,
|
||||
environment={'USER': 'root', 'MYSQL_PWD': 'restorepass'},
|
||||
environment={'USER': 'root'},
|
||||
).once()
|
||||
|
||||
module.restore_data_source_dump(
|
||||
@@ -814,6 +982,12 @@ def test_restore_data_source_dump_with_dry_run_skips_restore():
|
||||
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
|
||||
'resolve_credential'
|
||||
).replace_with(lambda value, config: value)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'parse_extra_options'
|
||||
).and_return((), None)
|
||||
flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
|
||||
'make_defaults_file_options'
|
||||
).with_args(None, None, None).and_return(())
|
||||
flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
|
||||
flexmock(module).should_receive('execute_command_with_processes').never()
|
||||
|
||||
|
||||
+31
-93
@@ -191,7 +191,7 @@ def test_execute_command_calls_full_command():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -213,7 +213,7 @@ def test_execute_command_calls_full_command_with_output_file():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stderr=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -234,7 +234,7 @@ def test_execute_command_calls_full_command_without_capturing_output():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(wait=lambda: 0)).once()
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(module.Exit_status.SUCCESS)
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
@@ -257,7 +257,7 @@ def test_execute_command_calls_full_command_with_input_file():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -278,7 +278,7 @@ def test_execute_command_calls_full_command_with_shell():
|
||||
shell=True,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -299,7 +299,7 @@ def test_execute_command_calls_full_command_with_environment():
|
||||
shell=False,
|
||||
env={'a': 'b'},
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -320,33 +320,12 @@ def test_execute_command_calls_full_command_with_working_directory():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd='/working',
|
||||
close_fds=True,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
|
||||
output = module.execute_command(full_command, working_directory='/working')
|
||||
|
||||
assert output is None
|
||||
|
||||
|
||||
def test_execute_command_with_BORG_PASSPHRASE_FD_leaves_file_descriptors_open():
|
||||
full_command = ['foo', 'bar']
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('Popen').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stdout=module.subprocess.PIPE,
|
||||
stderr=module.subprocess.STDOUT,
|
||||
shell=False,
|
||||
env={'BORG_PASSPHRASE_FD': '4'},
|
||||
cwd=None,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
|
||||
output = module.execute_command(full_command, environment={'BORG_PASSPHRASE_FD': '4'})
|
||||
output = module.execute_command(full_command, working_directory='/working')
|
||||
|
||||
assert output is None
|
||||
|
||||
@@ -363,7 +342,7 @@ def test_execute_command_without_run_to_completion_returns_process():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(process).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -377,11 +356,12 @@ def test_execute_command_and_capture_output_returns_stdout():
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(full_command)
|
||||
@@ -395,11 +375,12 @@ def test_execute_command_and_capture_output_with_capture_stderr_returns_stderr()
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=module.subprocess.STDOUT,
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(full_command, capture_stderr=True)
|
||||
@@ -414,11 +395,12 @@ def test_execute_command_and_capture_output_returns_output_when_process_error_is
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_raise(subprocess.CalledProcessError(1, full_command, err_output)).once()
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(
|
||||
module.Exit_status.SUCCESS
|
||||
@@ -435,11 +417,12 @@ def test_execute_command_and_capture_output_raises_when_command_errors():
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_raise(subprocess.CalledProcessError(2, full_command, expected_output)).once()
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(
|
||||
module.Exit_status.ERROR
|
||||
@@ -455,11 +438,12 @@ def test_execute_command_and_capture_output_returns_output_with_shell():
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
'foo bar',
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=True,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(full_command, shell=True)
|
||||
@@ -473,11 +457,12 @@ def test_execute_command_and_capture_output_returns_output_with_environment():
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env={'a': 'b'},
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(
|
||||
@@ -493,37 +478,16 @@ def test_execute_command_and_capture_output_returns_output_with_working_director
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd='/working',
|
||||
close_fds=True,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(
|
||||
full_command, shell=False, working_directory='/working'
|
||||
)
|
||||
|
||||
assert output == expected_output
|
||||
|
||||
|
||||
def test_execute_command_and_capture_output_with_BORG_PASSPHRASE_FD_leaves_file_descriptors_open():
|
||||
full_command = ['foo', 'bar']
|
||||
expected_output = '[]'
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('check_output').with_args(
|
||||
full_command,
|
||||
stderr=None,
|
||||
shell=False,
|
||||
env={'BORG_PASSPHRASE_FD': '4'},
|
||||
cwd=None,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(decode=lambda: expected_output)).once()
|
||||
|
||||
output = module.execute_command_and_capture_output(
|
||||
full_command,
|
||||
shell=False,
|
||||
environment={'BORG_PASSPHRASE_FD': '4'},
|
||||
full_command, shell=False, working_directory='/working'
|
||||
)
|
||||
|
||||
assert output == expected_output
|
||||
@@ -541,7 +505,7 @@ def test_execute_command_with_processes_calls_full_command():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -564,7 +528,7 @@ def test_execute_command_with_processes_returns_output_with_output_log_level_non
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(process).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs').and_return({process: 'out'})
|
||||
@@ -587,7 +551,7 @@ def test_execute_command_with_processes_calls_full_command_with_output_file():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stderr=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -609,7 +573,7 @@ def test_execute_command_with_processes_calls_full_command_without_capturing_out
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(wait=lambda: 0)).once()
|
||||
flexmock(module).should_receive('interpret_exit_code').and_return(module.Exit_status.SUCCESS)
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
@@ -635,7 +599,7 @@ def test_execute_command_with_processes_calls_full_command_with_input_file():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -657,7 +621,7 @@ def test_execute_command_with_processes_calls_full_command_with_shell():
|
||||
shell=True,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -679,7 +643,7 @@ def test_execute_command_with_processes_calls_full_command_with_environment():
|
||||
shell=False,
|
||||
env={'a': 'b'},
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
@@ -701,39 +665,13 @@ def test_execute_command_with_processes_calls_full_command_with_working_director
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd='/working',
|
||||
close_fds=True,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
|
||||
output = module.execute_command_with_processes(
|
||||
full_command, processes, working_directory='/working'
|
||||
)
|
||||
|
||||
assert output is None
|
||||
|
||||
|
||||
def test_execute_command_with_processes_with_BORG_PASSPHRASE_FD_leaves_file_descriptors_open():
|
||||
full_command = ['foo', 'bar']
|
||||
processes = (flexmock(),)
|
||||
flexmock(module).should_receive('log_command')
|
||||
flexmock(module.subprocess).should_receive('Popen').with_args(
|
||||
full_command,
|
||||
stdin=None,
|
||||
stdout=module.subprocess.PIPE,
|
||||
stderr=module.subprocess.STDOUT,
|
||||
shell=False,
|
||||
env={'BORG_PASSPHRASE_FD': '4'},
|
||||
cwd=None,
|
||||
close_fds=False,
|
||||
).and_return(flexmock(stdout=None)).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs')
|
||||
|
||||
output = module.execute_command_with_processes(
|
||||
full_command,
|
||||
processes,
|
||||
environment={'BORG_PASSPHRASE_FD': '4'},
|
||||
full_command, processes, working_directory='/working'
|
||||
)
|
||||
|
||||
assert output is None
|
||||
@@ -754,7 +692,7 @@ def test_execute_command_with_processes_kills_processes_on_error():
|
||||
shell=False,
|
||||
env=None,
|
||||
cwd=None,
|
||||
close_fds=True,
|
||||
close_fds=False,
|
||||
).and_raise(subprocess.CalledProcessError(1, full_command, 'error')).once()
|
||||
flexmock(module.borgmatic.logger).should_receive('Log_prefix').and_return(flexmock())
|
||||
flexmock(module).should_receive('log_outputs').never()
|
||||
|
||||
Reference in New Issue
Block a user