mirror of
https://projects.torsion.org/witten/borgmatic.git
synced 2025-03-15 20:54:56 +00:00
Make the "configuration" command hook support "error" hooks and also pinging monitoring on failure (#790).
This commit is contained in:
parent
f5c9bc4fa9
commit
6b6e1e0336
9 changed files with 670 additions and 379 deletions
|
@ -67,6 +67,113 @@ def get_skip_actions(config, arguments):
|
||||||
return skip_actions
|
return skip_actions
|
||||||
|
|
||||||
|
|
||||||
|
class Monitoring_hooks:
|
||||||
|
'''
|
||||||
|
A Python context manager for pinging monitoring hooks for the start state before the wrapped
|
||||||
|
code and log and finish (or failure) after the wrapped code. Also responsible for
|
||||||
|
initializing/destroying the monitoring hooks.
|
||||||
|
|
||||||
|
Example use as a context manager:
|
||||||
|
|
||||||
|
with Monitoring_hooks(config_filename, config, arguments, global_arguments):
|
||||||
|
do_stuff()
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, config_filename, config, arguments, global_arguments):
|
||||||
|
'''
|
||||||
|
Given a configuration filename, a configuration dict, command-line arguments as an
|
||||||
|
argparse.Namespace, and global arguments as an argparse.Namespace, save relevant data points
|
||||||
|
for use below.
|
||||||
|
'''
|
||||||
|
using_primary_action = {'create', 'prune', 'compact', 'check'}.intersection(arguments)
|
||||||
|
self.config_filename = config_filename
|
||||||
|
self.config = config
|
||||||
|
self.dry_run = global_arguments.dry_run
|
||||||
|
self.monitoring_log_level = verbosity_to_log_level(global_arguments.monitoring_verbosity)
|
||||||
|
self.monitoring_hooks_are_activated = (
|
||||||
|
using_primary_action and self.monitoring_log_level != DISABLED
|
||||||
|
)
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
'''
|
||||||
|
If monitoring hooks are enabled and a primary action is in use, initialize monitoring hooks
|
||||||
|
and ping them for the "start" state.
|
||||||
|
'''
|
||||||
|
if not self.monitoring_hooks_are_activated:
|
||||||
|
return
|
||||||
|
|
||||||
|
dispatch.call_hooks(
|
||||||
|
'initialize_monitor',
|
||||||
|
self.config,
|
||||||
|
dispatch.Hook_type.MONITORING,
|
||||||
|
self.config_filename,
|
||||||
|
self.monitoring_log_level,
|
||||||
|
self.dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dispatch.call_hooks(
|
||||||
|
'ping_monitor',
|
||||||
|
self.config,
|
||||||
|
dispatch.Hook_type.MONITORING,
|
||||||
|
self.config_filename,
|
||||||
|
monitor.State.START,
|
||||||
|
self.monitoring_log_level,
|
||||||
|
self.dry_run,
|
||||||
|
)
|
||||||
|
except (OSError, CalledProcessError) as error:
|
||||||
|
raise ValueError(f'Error pinging monitor: {error}')
|
||||||
|
|
||||||
|
def __exit__(self, exception_type, exception, traceback):
|
||||||
|
'''
|
||||||
|
If monitoring hooks are enabled and a primary action is in use, ping monitoring hooks for
|
||||||
|
the "log" state and also the "finish" or "fail" states (depending on whether there's an
|
||||||
|
exception). Lastly, destroy monitoring hooks.
|
||||||
|
'''
|
||||||
|
if not self.monitoring_hooks_are_activated:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Send logs irrespective of error.
|
||||||
|
try:
|
||||||
|
dispatch.call_hooks(
|
||||||
|
'ping_monitor',
|
||||||
|
self.config,
|
||||||
|
dispatch.Hook_type.MONITORING,
|
||||||
|
self.config_filename,
|
||||||
|
monitor.State.LOG,
|
||||||
|
self.monitoring_log_level,
|
||||||
|
self.dry_run,
|
||||||
|
)
|
||||||
|
except (OSError, CalledProcessError) as error:
|
||||||
|
raise ValueError(f'Error pinging monitor: {error}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
dispatch.call_hooks(
|
||||||
|
'ping_monitor',
|
||||||
|
self.config,
|
||||||
|
dispatch.Hook_type.MONITORING,
|
||||||
|
self.config_filename,
|
||||||
|
monitor.State.FAIL if exception else monitor.State.FINISH,
|
||||||
|
self.monitoring_log_level,
|
||||||
|
self.dry_run,
|
||||||
|
)
|
||||||
|
except (OSError, CalledProcessError) as error:
|
||||||
|
# If the wrapped code errored, prefer raising that exception, as it's probably more
|
||||||
|
# important than a monitor failing to ping.
|
||||||
|
if exception:
|
||||||
|
return
|
||||||
|
|
||||||
|
raise ValueError(f'Error pinging monitor: {error}')
|
||||||
|
|
||||||
|
dispatch.call_hooks(
|
||||||
|
'destroy_monitor',
|
||||||
|
self.config,
|
||||||
|
dispatch.Hook_type.MONITORING,
|
||||||
|
self.monitoring_log_level,
|
||||||
|
self.dry_run,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_configuration(config_filename, config, config_paths, arguments):
|
def run_configuration(config_filename, config, config_paths, arguments):
|
||||||
'''
|
'''
|
||||||
Given a config filename, the corresponding parsed config dict, a sequence of loaded
|
Given a config filename, the corresponding parsed config dict, a sequence of loaded
|
||||||
|
@ -84,11 +191,9 @@ def run_configuration(config_filename, config, config_paths, arguments):
|
||||||
remote_path = config.get('remote_path')
|
remote_path = config.get('remote_path')
|
||||||
retries = config.get('retries', 0)
|
retries = config.get('retries', 0)
|
||||||
retry_wait = config.get('retry_wait', 0)
|
retry_wait = config.get('retry_wait', 0)
|
||||||
|
repo_queue = Queue()
|
||||||
encountered_error = None
|
encountered_error = None
|
||||||
error_repository = None
|
error_repository = None
|
||||||
using_primary_action = {'create', 'prune', 'compact', 'check'}.intersection(arguments)
|
|
||||||
monitoring_log_level = verbosity_to_log_level(global_arguments.monitoring_verbosity)
|
|
||||||
monitoring_hooks_are_activated = using_primary_action and monitoring_log_level != DISABLED
|
|
||||||
skip_actions = get_skip_actions(config, arguments)
|
skip_actions = get_skip_actions(config, arguments)
|
||||||
|
|
||||||
if skip_actions:
|
if skip_actions:
|
||||||
|
@ -96,187 +201,104 @@ def run_configuration(config_filename, config, config_paths, arguments):
|
||||||
f"Skipping {'/'.join(skip_actions)} action{'s' if len(skip_actions) > 1 else ''} due to configured skip_actions"
|
f"Skipping {'/'.join(skip_actions)} action{'s' if len(skip_actions) > 1 else ''} due to configured skip_actions"
|
||||||
)
|
)
|
||||||
|
|
||||||
with borgmatic.hooks.command.Before_after_hooks(
|
try:
|
||||||
command_hooks=config.get('commands'),
|
with Monitoring_hooks(config_filename, config, arguments, global_arguments):
|
||||||
before_after='configuration',
|
with borgmatic.hooks.command.Before_after_hooks(
|
||||||
umask=config.get('umask'),
|
command_hooks=config.get('commands'),
|
||||||
dry_run=global_arguments.dry_run,
|
before_after='configuration',
|
||||||
action_names=arguments.keys(),
|
umask=config.get('umask'),
|
||||||
configuration_filename=config_filename,
|
dry_run=global_arguments.dry_run,
|
||||||
log_file=arguments['global'].log_file or '',
|
action_names=arguments.keys(),
|
||||||
):
|
|
||||||
try:
|
|
||||||
local_borg_version = borg_version.local_borg_version(config, local_path)
|
|
||||||
logger.debug(f'Borg {local_borg_version}')
|
|
||||||
except (OSError, CalledProcessError, ValueError) as error:
|
|
||||||
yield from log_error_records(
|
|
||||||
f'{config_filename}: Error getting local Borg version', error
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
if monitoring_hooks_are_activated:
|
|
||||||
dispatch.call_hooks(
|
|
||||||
'initialize_monitor',
|
|
||||||
config,
|
|
||||||
dispatch.Hook_type.MONITORING,
|
|
||||||
config_filename,
|
|
||||||
monitoring_log_level,
|
|
||||||
global_arguments.dry_run,
|
|
||||||
)
|
|
||||||
|
|
||||||
dispatch.call_hooks(
|
|
||||||
'ping_monitor',
|
|
||||||
config,
|
|
||||||
dispatch.Hook_type.MONITORING,
|
|
||||||
config_filename,
|
|
||||||
monitor.State.START,
|
|
||||||
monitoring_log_level,
|
|
||||||
global_arguments.dry_run,
|
|
||||||
)
|
|
||||||
except (OSError, CalledProcessError) as error:
|
|
||||||
if command.considered_soft_failure(error):
|
|
||||||
return
|
|
||||||
|
|
||||||
encountered_error = error
|
|
||||||
yield from log_error_records(f'{config_filename}: Error pinging monitor', error)
|
|
||||||
|
|
||||||
if not encountered_error:
|
|
||||||
repo_queue = Queue()
|
|
||||||
for repo in config['repositories']:
|
|
||||||
repo_queue.put(
|
|
||||||
(repo, 0),
|
|
||||||
)
|
|
||||||
|
|
||||||
while not repo_queue.empty():
|
|
||||||
repository, retry_num = repo_queue.get()
|
|
||||||
|
|
||||||
with Log_prefix(repository.get('label', repository['path'])):
|
|
||||||
logger.debug('Running actions for repository')
|
|
||||||
timeout = retry_num * retry_wait
|
|
||||||
if timeout:
|
|
||||||
logger.warning(f'Sleeping {timeout}s before next retry')
|
|
||||||
time.sleep(timeout)
|
|
||||||
try:
|
|
||||||
yield from run_actions(
|
|
||||||
arguments=arguments,
|
|
||||||
config_filename=config_filename,
|
|
||||||
config=config,
|
|
||||||
config_paths=config_paths,
|
|
||||||
local_path=local_path,
|
|
||||||
remote_path=remote_path,
|
|
||||||
local_borg_version=local_borg_version,
|
|
||||||
repository=repository,
|
|
||||||
)
|
|
||||||
except (OSError, CalledProcessError, ValueError) as error:
|
|
||||||
if retry_num < retries:
|
|
||||||
repo_queue.put(
|
|
||||||
(repository, retry_num + 1),
|
|
||||||
)
|
|
||||||
tuple( # Consume the generator so as to trigger logging.
|
|
||||||
log_error_records(
|
|
||||||
'Error running actions for repository',
|
|
||||||
error,
|
|
||||||
levelno=logging.WARNING,
|
|
||||||
log_command_error_output=True,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
logger.warning(f'Retrying... attempt {retry_num + 1}/{retries}')
|
|
||||||
continue
|
|
||||||
|
|
||||||
if command.considered_soft_failure(error):
|
|
||||||
continue
|
|
||||||
|
|
||||||
yield from log_error_records(
|
|
||||||
'Error running actions for repository',
|
|
||||||
error,
|
|
||||||
)
|
|
||||||
encountered_error = error
|
|
||||||
error_repository = repository
|
|
||||||
|
|
||||||
try:
|
|
||||||
if monitoring_hooks_are_activated:
|
|
||||||
# Send logs irrespective of error.
|
|
||||||
dispatch.call_hooks(
|
|
||||||
'ping_monitor',
|
|
||||||
config,
|
|
||||||
dispatch.Hook_type.MONITORING,
|
|
||||||
config_filename,
|
|
||||||
monitor.State.LOG,
|
|
||||||
monitoring_log_level,
|
|
||||||
global_arguments.dry_run,
|
|
||||||
)
|
|
||||||
except (OSError, CalledProcessError) as error:
|
|
||||||
encountered_error = error
|
|
||||||
yield from log_error_records('Error pinging monitor', error)
|
|
||||||
|
|
||||||
if not encountered_error:
|
|
||||||
try:
|
|
||||||
if monitoring_hooks_are_activated:
|
|
||||||
dispatch.call_hooks(
|
|
||||||
'ping_monitor',
|
|
||||||
config,
|
|
||||||
dispatch.Hook_type.MONITORING,
|
|
||||||
config_filename,
|
|
||||||
monitor.State.FINISH,
|
|
||||||
monitoring_log_level,
|
|
||||||
global_arguments.dry_run,
|
|
||||||
)
|
|
||||||
dispatch.call_hooks(
|
|
||||||
'destroy_monitor',
|
|
||||||
config,
|
|
||||||
dispatch.Hook_type.MONITORING,
|
|
||||||
monitoring_log_level,
|
|
||||||
global_arguments.dry_run,
|
|
||||||
)
|
|
||||||
except (OSError, CalledProcessError) as error:
|
|
||||||
encountered_error = error
|
|
||||||
yield from log_error_records(f'{config_filename}: Error pinging monitor', error)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
command.execute_hooks(
|
|
||||||
command.filter_hooks(
|
|
||||||
config.get('commands'), after='error', action_names=arguments.keys()
|
|
||||||
),
|
|
||||||
config.get('umask'),
|
|
||||||
global_arguments.dry_run,
|
|
||||||
configuration_filename=config_filename,
|
configuration_filename=config_filename,
|
||||||
log_file=arguments['global'].log_file or '',
|
log_file=arguments['global'].log_file or '',
|
||||||
repository=error_repository.get('path', '') if error_repository else '',
|
):
|
||||||
repository_label=error_repository.get('label', '') if error_repository else '',
|
try:
|
||||||
error=encountered_error,
|
local_borg_version = borg_version.local_borg_version(config, local_path)
|
||||||
output=getattr(encountered_error, 'output', ''),
|
logger.debug(f'Borg {local_borg_version}')
|
||||||
)
|
except (OSError, CalledProcessError, ValueError) as error:
|
||||||
except (OSError, CalledProcessError) as error:
|
yield from log_error_records(
|
||||||
if command.considered_soft_failure(error):
|
f'{config_filename}: Error getting local Borg version', error
|
||||||
return
|
)
|
||||||
|
return
|
||||||
|
|
||||||
yield from log_error_records(
|
for repo in config['repositories']:
|
||||||
f'{config_filename}: Error running after error hook', error
|
repo_queue.put(
|
||||||
)
|
(repo, 0),
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
while not repo_queue.empty():
|
||||||
if monitoring_hooks_are_activated:
|
repository, retry_num = repo_queue.get()
|
||||||
dispatch.call_hooks(
|
|
||||||
'ping_monitor',
|
with Log_prefix(repository.get('label', repository['path'])):
|
||||||
config,
|
logger.debug('Running actions for repository')
|
||||||
dispatch.Hook_type.MONITORING,
|
timeout = retry_num * retry_wait
|
||||||
config_filename,
|
if timeout:
|
||||||
monitor.State.FAIL,
|
logger.warning(f'Sleeping {timeout}s before next retry')
|
||||||
monitoring_log_level,
|
time.sleep(timeout)
|
||||||
global_arguments.dry_run,
|
try:
|
||||||
)
|
yield from run_actions(
|
||||||
dispatch.call_hooks(
|
arguments=arguments,
|
||||||
'destroy_monitor',
|
config_filename=config_filename,
|
||||||
config,
|
config=config,
|
||||||
dispatch.Hook_type.MONITORING,
|
config_paths=config_paths,
|
||||||
monitoring_log_level,
|
local_path=local_path,
|
||||||
global_arguments.dry_run,
|
remote_path=remote_path,
|
||||||
)
|
local_borg_version=local_borg_version,
|
||||||
except (OSError, CalledProcessError) as error:
|
repository=repository,
|
||||||
yield from log_error_records(f'{config_filename}: Error pinging monitor', error)
|
)
|
||||||
|
except (OSError, CalledProcessError, ValueError) as error:
|
||||||
|
if retry_num < retries:
|
||||||
|
repo_queue.put(
|
||||||
|
(repository, retry_num + 1),
|
||||||
|
)
|
||||||
|
tuple( # Consume the generator so as to trigger logging.
|
||||||
|
log_error_records(
|
||||||
|
'Error running actions for repository',
|
||||||
|
error,
|
||||||
|
levelno=logging.WARNING,
|
||||||
|
log_command_error_output=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
logger.warning(f'Retrying... attempt {retry_num + 1}/{retries}')
|
||||||
|
continue
|
||||||
|
|
||||||
|
if command.considered_soft_failure(error):
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield from log_error_records(
|
||||||
|
'Error running actions for repository',
|
||||||
|
error,
|
||||||
|
)
|
||||||
|
encountered_error = error
|
||||||
|
error_repository = repository
|
||||||
|
|
||||||
|
except (OSError, CalledProcessError, ValueError) as error:
|
||||||
|
yield from log_error_records('Error running configuration', error)
|
||||||
|
|
||||||
|
encountered_error = error
|
||||||
|
|
||||||
|
if not encountered_error:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
command.execute_hooks(
|
||||||
|
command.filter_hooks(
|
||||||
|
config.get('commands'), after='error', action_names=arguments.keys()
|
||||||
|
),
|
||||||
|
config.get('umask'),
|
||||||
|
global_arguments.dry_run,
|
||||||
|
configuration_filename=config_filename,
|
||||||
|
log_file=arguments['global'].log_file or '',
|
||||||
|
repository=error_repository.get('path', '') if error_repository else '',
|
||||||
|
repository_label=error_repository.get('label', '') if error_repository else '',
|
||||||
|
error=encountered_error,
|
||||||
|
output=getattr(encountered_error, 'output', ''),
|
||||||
|
)
|
||||||
|
except (OSError, CalledProcessError) as error:
|
||||||
|
if command.considered_soft_failure(error):
|
||||||
|
return
|
||||||
|
|
||||||
|
yield from log_error_records(f'{config_filename}: Error running after error hook', error)
|
||||||
|
|
||||||
|
|
||||||
def run_actions(
|
def run_actions(
|
||||||
|
@ -845,33 +867,25 @@ def collect_configuration_run_summary_logs(configs, config_paths, arguments):
|
||||||
|
|
||||||
for config_filename, config in configs.items():
|
for config_filename, config in configs.items():
|
||||||
with Log_prefix(config_filename):
|
with Log_prefix(config_filename):
|
||||||
try:
|
results = list(run_configuration(config_filename, config, config_paths, arguments))
|
||||||
results = list(run_configuration(config_filename, config, config_paths, arguments))
|
|
||||||
except (OSError, CalledProcessError, ValueError) as error:
|
|
||||||
yield from log_error_records(
|
|
||||||
'Error running configuration file',
|
|
||||||
error,
|
|
||||||
levelno=logging.CRITICAL,
|
|
||||||
log_command_error_output=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
error_logs = tuple(
|
|
||||||
result for result in results if isinstance(result, logging.LogRecord)
|
|
||||||
)
|
|
||||||
|
|
||||||
if error_logs:
|
error_logs = tuple(
|
||||||
yield from log_error_records('An error occurred')
|
result for result in results if isinstance(result, logging.LogRecord)
|
||||||
yield from error_logs
|
)
|
||||||
else:
|
|
||||||
yield logging.makeLogRecord(
|
if error_logs:
|
||||||
dict(
|
yield from log_error_records('An error occurred')
|
||||||
levelno=logging.INFO,
|
yield from error_logs
|
||||||
levelname='INFO',
|
else:
|
||||||
msg='Successfully ran configuration file',
|
yield logging.makeLogRecord(
|
||||||
)
|
dict(
|
||||||
|
levelno=logging.INFO,
|
||||||
|
levelname='INFO',
|
||||||
|
msg='Successfully ran configuration file',
|
||||||
)
|
)
|
||||||
if results:
|
)
|
||||||
json_results.extend(results)
|
if results:
|
||||||
|
json_results.extend(results)
|
||||||
|
|
||||||
if 'umount' in arguments:
|
if 'umount' in arguments:
|
||||||
logger.info(f"Unmounting mount point {arguments['umount'].mount_point}")
|
logger.info(f"Unmounting mount point {arguments['umount'].mount_point}")
|
||||||
|
|
|
@ -134,7 +134,7 @@ class Runtime_directory:
|
||||||
'''
|
'''
|
||||||
return self.runtime_path
|
return self.runtime_path
|
||||||
|
|
||||||
def __exit__(self, exception, value, traceback):
|
def __exit__(self, exception_type, exception, traceback):
|
||||||
'''
|
'''
|
||||||
Delete any temporary directory that was created as part of initialization.
|
Delete any temporary directory that was created as part of initialization.
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -195,7 +195,7 @@ class Before_after_hooks:
|
||||||
|
|
||||||
raise ValueError(f'Error running before {self.before_after} hook: {error}')
|
raise ValueError(f'Error running before {self.before_after} hook: {error}')
|
||||||
|
|
||||||
def __exit__(self, exception, value, traceback):
|
def __exit__(self, exception_type, exception, traceback):
|
||||||
'''
|
'''
|
||||||
Run the configured "after" command hooks that match the initialized data points.
|
Run the configured "after" command hooks that match the initialized data points.
|
||||||
'''
|
'''
|
||||||
|
@ -215,7 +215,7 @@ class Before_after_hooks:
|
||||||
if considered_soft_failure(error):
|
if considered_soft_failure(error):
|
||||||
return
|
return
|
||||||
|
|
||||||
raise ValueError(f'Error running before {self.before_after} hook: {error}')
|
raise ValueError(f'Error running after {self.before_after} hook: {error}')
|
||||||
|
|
||||||
|
|
||||||
def considered_soft_failure(error):
|
def considered_soft_failure(error):
|
||||||
|
|
|
@ -28,7 +28,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||||
filename in any log entries. If this is a dry run, then don't actually ping anything.
|
filename in any log entries. If this is a dry run, then don't actually ping anything.
|
||||||
'''
|
'''
|
||||||
if state not in MONITOR_STATE_TO_CRONHUB:
|
if state not in MONITOR_STATE_TO_CRONHUB:
|
||||||
logger.debug(f'Ignoring unsupported monitoring {state.name.lower()} in Cronhub hook')
|
logger.debug(f'Ignoring unsupported monitoring state {state.name.lower()} in Cronhub hook')
|
||||||
return
|
return
|
||||||
|
|
||||||
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
|
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
|
||||||
|
|
|
@ -28,7 +28,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||||
filename in any log entries. If this is a dry run, then don't actually ping anything.
|
filename in any log entries. If this is a dry run, then don't actually ping anything.
|
||||||
'''
|
'''
|
||||||
if state not in MONITOR_STATE_TO_CRONITOR:
|
if state not in MONITOR_STATE_TO_CRONITOR:
|
||||||
logger.debug(f'Ignoring unsupported monitoring {state.name.lower()} in Cronitor hook')
|
logger.debug(f'Ignoring unsupported monitoring state {state.name.lower()} in Cronitor hook')
|
||||||
return
|
return
|
||||||
|
|
||||||
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
|
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
|
||||||
|
|
|
@ -46,7 +46,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
|
||||||
'''
|
'''
|
||||||
if state != monitor.State.FAIL:
|
if state != monitor.State.FAIL:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'Ignoring unsupported monitoring {state.name.lower()} in PagerDuty hook',
|
f'Ignoring unsupported monitoring state {state.name.lower()} in PagerDuty hook',
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,7 @@ class Log_prefix:
|
||||||
self.original_prefix = get_log_prefix()
|
self.original_prefix = get_log_prefix()
|
||||||
set_log_prefix(self.prefix)
|
set_log_prefix(self.prefix)
|
||||||
|
|
||||||
def __exit__(self, exception, value, traceback):
|
def __exit__(self, exception_type, exception, traceback):
|
||||||
'''
|
'''
|
||||||
Restore any original prefix.
|
Restore any original prefix.
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -61,14 +61,11 @@ Each command in the `commands:` list has the following options:
|
||||||
* `action` runs before each action for each repository. This replaces the deprecated `before_create`, `after_prune`, etc.
|
* `action` runs before each action for each repository. This replaces the deprecated `before_create`, `after_prune`, etc.
|
||||||
* `repository` runs before or after all actions for each repository. This replaces the deprecated `before_actions` and `after_actions`.
|
* `repository` runs before or after all actions for each repository. This replaces the deprecated `before_actions` and `after_actions`.
|
||||||
* `configuration` runs before or after all actions and repositories in the current configuration file.
|
* `configuration` runs before or after all actions and repositories in the current configuration file.
|
||||||
* `everything` runs before or after all configuration files. This replaces the deprecated `before_everything` and `after_everything`.
|
* `everything` runs before or after all configuration files. Errors here do not trigger `error` hooks or the `fail` state in monitoring hooks. This replaces the deprecated `before_everything` and `after_everything`.
|
||||||
* `error` runs after an error occurs—and it's only available for `after`. This replaces the deprecated `on_error` hook.
|
* `error` runs after an error occurs—and it's only available for `after`. This replaces the deprecated `on_error` hook.
|
||||||
* `when`: Only trigger the hook when borgmatic is run with particular actions (`create`, `prune`, etc.) listed here. Defaults to running for all actions.
|
* `when`: Only trigger the hook when borgmatic is run with particular actions (`create`, `prune`, etc.) listed here. Defaults to running for all actions.
|
||||||
* `run`: List of one or more shell commands or scripts to run when this command hook is triggered.
|
* `run`: List of one or more shell commands or scripts to run when this command hook is triggered.
|
||||||
|
|
||||||
borgmatic does not run `error` hooks if an error occurs within an `everything`
|
|
||||||
hook.
|
|
||||||
|
|
||||||
There's also another command hook that works a little differently:
|
There's also another command hook that works a little differently:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
|
@ -27,9 +27,392 @@ def test_get_skip_actions_uses_config_and_arguments(config, arguments, expected_
|
||||||
assert module.get_skip_actions(config, arguments) == expected_actions
|
assert module.get_skip_actions(config, arguments) == expected_actions
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_with_monioring_disabled_bails():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(module.DISABLED)
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').never()
|
||||||
|
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_with_non_primary_action_bails():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').never()
|
||||||
|
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'extract': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_pings_monitors():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FAIL,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_with_start_ping_error_raises():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).and_raise(OSError).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
assert False # This should never get called.
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_with_log_ping_error_raises():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).and_raise(OSError).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_hooks_with_finish_ping_error_raises():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).and_raise(OSError).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_with_wrapped_code_error_pings_fail():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FAIL,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
|
||||||
|
with pytest.raises(OSError):
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
raise OSError()
|
||||||
|
|
||||||
|
|
||||||
|
def test_monitoring_with_fail_ping_error_raise_original_error():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(flexmock())
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'initialize_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.START,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.LOG,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FINISH,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'ping_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
module.monitor.State.FAIL,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).and_raise(OSError).once()
|
||||||
|
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
||||||
|
'destroy_monitor',
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
object,
|
||||||
|
).never()
|
||||||
|
|
||||||
|
with pytest.raises(OSError):
|
||||||
|
with module.Monitoring_hooks(
|
||||||
|
config_filename='test.yaml',
|
||||||
|
config={},
|
||||||
|
arguments={'create': flexmock()},
|
||||||
|
global_arguments=flexmock(monitoring_verbosity=99, dry_run=False),
|
||||||
|
):
|
||||||
|
raise OSError()
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_runs_actions_for_each_repository():
|
def test_run_configuration_runs_actions_for_each_repository():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
expected_results = [flexmock(), flexmock()]
|
expected_results = [flexmock(), flexmock()]
|
||||||
|
@ -48,6 +431,7 @@ def test_run_configuration_runs_actions_for_each_repository():
|
||||||
def test_run_configuration_with_skip_actions_does_not_raise():
|
def test_run_configuration_with_skip_actions_does_not_raise():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return(['compact'])
|
flexmock(module).should_receive('get_skip_actions').and_return(['compact'])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -61,9 +445,9 @@ def test_run_configuration_with_skip_actions_does_not_raise():
|
||||||
def test_run_configuration_with_invalid_borg_version_errors():
|
def test_run_configuration_with_invalid_borg_version_errors():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_raise(ValueError)
|
flexmock(module.borg_version).should_receive('local_borg_version').and_raise(ValueError)
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').never()
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
flexmock(module).should_receive('run_actions').never()
|
flexmock(module).should_receive('run_actions').never()
|
||||||
config = {'repositories': [{'path': 'foo'}]}
|
config = {'repositories': [{'path': 'foo'}]}
|
||||||
|
@ -75,58 +459,12 @@ def test_run_configuration_with_invalid_borg_version_errors():
|
||||||
list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_monitor_start_error():
|
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').and_raise(OSError).and_return(
|
|
||||||
None
|
|
||||||
).and_return(None).and_return(None)
|
|
||||||
expected_results = [flexmock()]
|
|
||||||
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_actions').never()
|
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
|
||||||
flexmock(module.command).should_receive('execute_hooks')
|
|
||||||
config = {'repositories': [{'path': 'foo'}]}
|
|
||||||
arguments = {
|
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
|
||||||
'create': flexmock(),
|
|
||||||
}
|
|
||||||
|
|
||||||
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
|
||||||
|
|
||||||
assert results == expected_results
|
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_bails_for_monitor_start_soft_failure():
|
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
|
||||||
error = subprocess.CalledProcessError(borgmatic.hooks.command.SOFT_FAIL_EXIT_CODE, 'try again')
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').and_raise(error).and_return(None)
|
|
||||||
flexmock(module).should_receive('log_error_records').never()
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_actions').never()
|
|
||||||
config = {'repositories': [{'path': 'foo'}, {'path': 'bar'}]}
|
|
||||||
arguments = {
|
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
|
||||||
'create': flexmock(),
|
|
||||||
}
|
|
||||||
|
|
||||||
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
|
||||||
|
|
||||||
assert results == []
|
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_actions_error():
|
def test_run_configuration_logs_actions_error():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module.dispatch).should_receive('call_hooks')
|
|
||||||
expected_results = [flexmock()]
|
expected_results = [flexmock()]
|
||||||
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -144,9 +482,9 @@ def test_run_configuration_logs_actions_error():
|
||||||
def test_run_configuration_skips_remaining_actions_for_actions_soft_failure_but_still_runs_next_repository_actions():
|
def test_run_configuration_skips_remaining_actions_for_actions_soft_failure_but_still_runs_next_repository_actions():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').times(5)
|
|
||||||
error = subprocess.CalledProcessError(borgmatic.hooks.command.SOFT_FAIL_EXIT_CODE, 'try again')
|
error = subprocess.CalledProcessError(borgmatic.hooks.command.SOFT_FAIL_EXIT_CODE, 'try again')
|
||||||
log = flexmock()
|
log = flexmock()
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -164,106 +502,13 @@ def test_run_configuration_skips_remaining_actions_for_actions_soft_failure_but_
|
||||||
assert results == [log]
|
assert results == [log]
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_monitor_log_error():
|
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').and_return(None).and_return(
|
|
||||||
None
|
|
||||||
).and_raise(OSError)
|
|
||||||
expected_results = [flexmock()]
|
|
||||||
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
|
||||||
flexmock(module.command).should_receive('execute_hooks')
|
|
||||||
config = {'repositories': [{'path': 'foo'}]}
|
|
||||||
arguments = {
|
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
|
||||||
'create': flexmock(),
|
|
||||||
}
|
|
||||||
|
|
||||||
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
|
||||||
|
|
||||||
assert results == expected_results
|
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_monitor_finish_error():
|
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').and_return(None).and_return(
|
|
||||||
None
|
|
||||||
).and_return(None).and_raise(OSError)
|
|
||||||
expected_results = [flexmock()]
|
|
||||||
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
|
||||||
flexmock(module.command).should_receive('execute_hooks')
|
|
||||||
config = {'repositories': [{'path': 'foo'}]}
|
|
||||||
arguments = {
|
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
|
||||||
'create': flexmock(),
|
|
||||||
}
|
|
||||||
|
|
||||||
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
|
||||||
|
|
||||||
assert results == expected_results
|
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_logs_monitor_fail_error():
|
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks')
|
|
||||||
|
|
||||||
# Trigger an error in the monitor finish so that the monitor fail also gets triggered.
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
|
||||||
'ping_monitor',
|
|
||||||
object,
|
|
||||||
module.dispatch.Hook_type.MONITORING,
|
|
||||||
object,
|
|
||||||
module.monitor.State.FINISH,
|
|
||||||
object,
|
|
||||||
object,
|
|
||||||
).and_raise(OSError)
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').with_args(
|
|
||||||
'ping_monitor',
|
|
||||||
object,
|
|
||||||
module.dispatch.Hook_type.MONITORING,
|
|
||||||
object,
|
|
||||||
module.monitor.State.FAIL,
|
|
||||||
object,
|
|
||||||
object,
|
|
||||||
).and_raise(OSError).once()
|
|
||||||
expected_results = [flexmock()]
|
|
||||||
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_actions').and_return([])
|
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
|
||||||
flexmock(module.command).should_receive('execute_hooks')
|
|
||||||
config = {'repositories': [{'path': 'foo'}]}
|
|
||||||
arguments = {
|
|
||||||
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
|
||||||
'create': flexmock(),
|
|
||||||
}
|
|
||||||
|
|
||||||
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
|
||||||
|
|
||||||
assert results == expected_results + expected_results
|
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_does_not_call_monitoring_hooks_if_monitoring_hooks_are_disabled():
|
def test_run_configuration_does_not_call_monitoring_hooks_if_monitoring_hooks_are_disabled():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(module.DISABLED)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(module.DISABLED)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
|
|
||||||
flexmock(module.dispatch).should_receive('call_hooks').never()
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
flexmock(module).should_receive('run_actions').and_return([])
|
flexmock(module).should_receive('run_actions').and_return([])
|
||||||
|
|
||||||
|
@ -279,6 +524,7 @@ def test_run_configuration_does_not_call_monitoring_hooks_if_monitoring_hooks_ar
|
||||||
def test_run_configuration_logs_on_error_hook_error():
|
def test_run_configuration_logs_on_error_hook_error():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
flexmock(module.command).should_receive('filter_hooks')
|
||||||
|
@ -300,9 +546,56 @@ def test_run_configuration_logs_on_error_hook_error():
|
||||||
assert results == expected_results
|
assert results == expected_results
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_configuration_logs_on_before_command_hook_error():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
|
flexmock(module.command).should_receive('Before_after_hooks').and_raise(OSError)
|
||||||
|
flexmock(module.borg_version).should_receive('local_borg_version').never()
|
||||||
|
flexmock(module.command).should_receive('filter_hooks')
|
||||||
|
flexmock(module.command).should_receive('execute_hooks')
|
||||||
|
expected_results = [flexmock()]
|
||||||
|
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
||||||
|
flexmock(module).should_receive('Log_prefix').never()
|
||||||
|
flexmock(module).should_receive('run_actions').never()
|
||||||
|
config = {'repositories': [{'path': 'foo'}]}
|
||||||
|
arguments = {
|
||||||
|
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
||||||
|
'create': flexmock(),
|
||||||
|
}
|
||||||
|
|
||||||
|
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
||||||
|
|
||||||
|
assert results == expected_results
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_configuration_logs_on_monitoring_hook_error():
|
||||||
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_raise(OSError)
|
||||||
|
flexmock(module.command).should_receive('Before_after_hooks').never()
|
||||||
|
flexmock(module.borg_version).should_receive('local_borg_version').never()
|
||||||
|
flexmock(module.command).should_receive('filter_hooks')
|
||||||
|
flexmock(module.command).should_receive('execute_hooks')
|
||||||
|
expected_results = [flexmock()]
|
||||||
|
flexmock(module).should_receive('log_error_records').and_return(expected_results)
|
||||||
|
flexmock(module).should_receive('Log_prefix').never()
|
||||||
|
flexmock(module).should_receive('run_actions').never()
|
||||||
|
config = {'repositories': [{'path': 'foo'}]}
|
||||||
|
arguments = {
|
||||||
|
'global': flexmock(monitoring_verbosity=1, dry_run=False, log_file=flexmock()),
|
||||||
|
'create': flexmock(),
|
||||||
|
}
|
||||||
|
|
||||||
|
results = list(module.run_configuration('test.yaml', config, ['/tmp/test.yaml'], arguments))
|
||||||
|
|
||||||
|
assert results == expected_results
|
||||||
|
|
||||||
|
|
||||||
def test_run_configuration_bails_for_on_error_hook_soft_failure():
|
def test_run_configuration_bails_for_on_error_hook_soft_failure():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
error = subprocess.CalledProcessError(borgmatic.hooks.command.SOFT_FAIL_EXIT_CODE, 'try again')
|
error = subprocess.CalledProcessError(borgmatic.hooks.command.SOFT_FAIL_EXIT_CODE, 'try again')
|
||||||
|
@ -327,6 +620,7 @@ def test_run_configuration_retries_soft_error():
|
||||||
# Run action first fails, second passes.
|
# Run action first fails, second passes.
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -349,6 +643,7 @@ def test_run_configuration_retries_hard_error():
|
||||||
# Run action fails twice.
|
# Run action fails twice.
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -380,6 +675,7 @@ def test_run_configuration_retries_hard_error():
|
||||||
def test_run_configuration_retries_repositories_in_order():
|
def test_run_configuration_retries_repositories_in_order():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -407,6 +703,7 @@ def test_run_configuration_retries_repositories_in_order():
|
||||||
def test_run_configuration_retries_round_robin():
|
def test_run_configuration_retries_round_robin():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -450,6 +747,7 @@ def test_run_configuration_retries_round_robin():
|
||||||
def test_run_configuration_with_one_retry():
|
def test_run_configuration_with_one_retry():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -491,6 +789,7 @@ def test_run_configuration_with_one_retry():
|
||||||
def test_run_configuration_with_retry_wait_does_backoff_after_each_retry():
|
def test_run_configuration_with_retry_wait_does_backoff_after_each_retry():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -543,6 +842,7 @@ def test_run_configuration_with_retry_wait_does_backoff_after_each_retry():
|
||||||
def test_run_configuration_with_multiple_repositories_retries_with_timeout():
|
def test_run_configuration_with_multiple_repositories_retries_with_timeout():
|
||||||
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
flexmock(module).should_receive('verbosity_to_log_level').and_return(logging.INFO)
|
||||||
flexmock(module).should_receive('get_skip_actions').and_return([])
|
flexmock(module).should_receive('get_skip_actions').and_return([])
|
||||||
|
flexmock(module).should_receive('Monitoring_hooks').and_return(flexmock())
|
||||||
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
flexmock(module.command).should_receive('Before_after_hooks').and_return(flexmock())
|
||||||
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
flexmock(module.borg_version).should_receive('local_borg_version').and_return(flexmock())
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
||||||
|
@ -1715,26 +2015,6 @@ def test_collect_configuration_run_summary_logs_run_configuration_error_logs():
|
||||||
assert {log.levelno for log in logs} == {logging.CRITICAL}
|
assert {log.levelno for log in logs} == {logging.CRITICAL}
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_run_configuration_exception():
|
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
|
||||||
flexmock(module.command).should_receive('execute_hooks')
|
|
||||||
flexmock(module).should_receive('Log_prefix').and_return(flexmock())
|
|
||||||
flexmock(module).should_receive('run_configuration').and_raise(ValueError)
|
|
||||||
flexmock(module).should_receive('log_error_records').and_return(
|
|
||||||
[flexmock(levelno=logging.CRITICAL)]
|
|
||||||
)
|
|
||||||
arguments = {'global': flexmock(dry_run=False, log_file=flexmock())}
|
|
||||||
|
|
||||||
logs = tuple(
|
|
||||||
module.collect_configuration_run_summary_logs(
|
|
||||||
{'test.yaml': {}}, config_paths=['/tmp/test.yaml'], arguments=arguments
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
assert {log.levelno for log in logs} == {logging.CRITICAL}
|
|
||||||
|
|
||||||
|
|
||||||
def test_collect_configuration_run_summary_logs_run_umount_error():
|
def test_collect_configuration_run_summary_logs_run_umount_error():
|
||||||
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
flexmock(module.validate).should_receive('guard_configuration_contains_repository')
|
||||||
flexmock(module.command).should_receive('filter_hooks')
|
flexmock(module.command).should_receive('filter_hooks')
|
||||||
|
|
Loading…
Reference in a new issue