def test_create_archive_with_exclude_patterns_calls_borg_with_excludes(): exclude_flags = ('--exclude-from', 'excludes') flexmock(module).should_receive('borgmatic_source_directories').and_return( []) flexmock(module).should_receive('_expand_directories').and_return( ('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return( ('exclude', )) flexmock(module).should_receive('_write_pattern_file').and_return( None).and_return(flexmock(name='/tmp/excludes')) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return( exclude_flags) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create') + exclude_flags + ARCHIVE_WITH_PATHS, output_log_level=logging.INFO) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': ['exclude'], }, storage_config={}, )
def test_create_archive_with_glob_calls_borg_with_expanded_directories(): flexmock(module).should_receive('borgmatic_source_directories').and_return( []) flexmock(module).should_receive('_expand_directories').and_return( ('foo', 'food')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'), output_log_level=logging.INFO, ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo*'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def _run_commands_on_repository(*, args, consistency, json_results, local_path, location, remote_path, retention, storage, unexpanded_repository): # pragma: no cover repository = os.path.expanduser(unexpanded_repository) dry_run_label = ' (dry run; not making any changes)' if args.dry_run else '' if args.prune: logger.info('{}: Pruning archives{}'.format(repository, dry_run_label)) borg_prune.prune_archives( args.dry_run, repository, storage, retention, local_path=local_path, remote_path=remote_path, ) if args.create: logger.info('{}: Creating archive{}'.format(repository, dry_run_label)) borg_create.create_archive( args.dry_run, repository, location, storage, local_path=local_path, remote_path=remote_path, ) if args.check and checks.repository_enabled_for_checks( repository, consistency): logger.info('{}: Running consistency checks'.format(repository)) borg_check.check_archives(repository, storage, consistency, local_path=local_path, remote_path=remote_path) if args.list: logger.info('{}: Listing archives'.format(repository)) output = borg_list.list_archives(repository, storage, local_path=local_path, remote_path=remote_path, json=args.json) if args.json: json_results.append(json.loads(output)) else: sys.stdout.write(output) if args.info: logger.info( '{}: Displaying summary info for archives'.format(repository)) output = borg_info.display_archives_info(repository, storage, local_path=local_path, remote_path=remote_path, json=args.json) if args.json: json_results.append(json.loads(output)) else: sys.stdout.write(output)
def test_create_archive_with_umask_should_call_borg_with_umask_parameters(): flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--umask', '740')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'umask': 740}, )
def test_create_archive_with_verbosity_lots_should_call_borg_with_debug_parameter( ): flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--debug', '--list', '--stats')) module.create_archive( verbosity=VERBOSITY_LOTS, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter( ): flexmock(module).should_receive('_expand_directories').and_return( ('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', '--json') + ARCHIVE_WITH_PATHS, output_log_level=None).and_return('[]') json_output = module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, json=True, stats=True, ) assert json_output == '[]'
def test_create_archive_with_glob_calls_borg_with_expanded_directories(): flexmock(module).should_receive('_expand_directory').and_return(['foo', 'food']) flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo*'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_umask_calls_borg_with_umask_parameters(): flexmock(module).should_receive('_expand_directory').and_return(['foo']).and_return(['bar']) flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--umask', '740')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'umask': 740}, )
def test_create_archive_with_verbosity_lots_calls_borg_with_debug_parameter(): flexmock(module).should_receive('_expand_directory').and_return(['foo']).and_return(['bar']) flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--debug', '--list', '--stats')) module.create_archive( verbosity=VERBOSITY_LOTS, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_glob_calls_borg_with_expanded_directories(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food')) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo*'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--lock-wait', '5')) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'lock_wait': 5}, )
def test_create_archive_with_exclude_patterns_calls_borg_with_excludes(): exclude_flags = ('--exclude-from', 'excludes') flexmock(module).should_receive('_expand_directory').and_return(['foo']).and_return(['bar']) flexmock(module).should_receive('_write_exclude_file').and_return(flexmock(name='/tmp/excludes')) flexmock(module).should_receive('_make_exclude_flags').and_return(exclude_flags) insert_subprocess_mock(CREATE_COMMAND + exclude_flags) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': ['exclude'], }, storage_config={}, )
def main(): # pragma: no cover try: args = parse_arguments(*sys.argv[1:]) config_filenames = tuple( collect.collect_config_filenames(args.config_paths)) convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames) if len(config_filenames) == 0: raise ValueError( 'Error: No configuration files found in: {}'.format(' '.join( args.config_paths))) for config_filename in config_filenames: config = validate.parse_configuration(config_filename, validate.schema_filename()) (location, storage, retention, consistency) = (config.get(section_name, {}) for section_name in ('location', 'storage', 'retention', 'consistency')) remote_path = location.get('remote_path') create.initialize(storage) for repository in location['repositories']: if args.prune: prune.prune_archives(args.verbosity, repository, retention, remote_path=remote_path) if args.create: create.create_archive( args.verbosity, repository, location, storage, ) if args.check: check.check_archives(args.verbosity, repository, consistency, remote_path=remote_path) except (ValueError, OSError, CalledProcessError) as error: print(error, file=sys.stderr) sys.exit(1)
def test_create_archive_with_local_path_calls_borg_via_local_path(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(('borg1',) + CREATE_COMMAND[1:]) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, local_path='borg1', )
def test_create_archive_with_patterns_calls_borg_with_patterns(): pattern_flags = ('--patterns-from', 'patterns') flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(flexmock(name='/tmp/patterns')).and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(pattern_flags) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + pattern_flags) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'patterns': ['pattern'], }, storage_config={}, )
def test_create_archive_with_archive_name_format_accepts_borg_placeholders(): flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock( ('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={ 'archive_name_format': 'Documents_{hostname}-{now}', }, )
def test_create_archive_with_archive_name_format_accepts_borg_placeholders(): flexmock(module).should_receive('_expand_directory').and_return(['foo']).and_return(['bar']) flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={ 'archive_name_format': 'Documents_{hostname}-{now}', }, )
def test_create_archive_with_log_debug_calls_borg_with_debug_parameter(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME','--stats', '--debug', '--show-rc')) insert_logging_mock(logging.DEBUG) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_exclude_patterns_should_call_borg_with_excludes(): exclude_flags = ('--exclude-from', 'excludes') flexmock(module).should_receive('_write_exclude_file').and_return( flexmock(name='/tmp/excludes')) flexmock(module).should_receive('_make_exclude_flags').and_return( exclude_flags) insert_subprocess_mock(CREATE_COMMAND + exclude_flags) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': ['exclude'], }, storage_config={}, )
def test_create_archive_with_remote_rate_limit_calls_borg_with_remote_ratelimit_parameters( ): flexmock(module).should_receive('_expand_directory').and_return( ['foo']).and_return(['bar']) flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--remote-ratelimit', '100')) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'remote_rate_limit': 100}, )
def test_create_archive_with_bsd_flags_true_calls_borg_without_nobsdflags_parameter(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND) module.create_archive( verbosity=None, dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'bsd_flags': True, 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_dry_run_and_verbosity_some_calls_borg_without_stats_parameter(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--info', '--dry-run')) module.create_archive( verbosity=VERBOSITY_SOME, dry_run=True, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_non_matching_source_directories_glob_passes_through( ): flexmock(module).should_receive('_write_exclude_file').and_return(None) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock( ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo*')) flexmock(module.glob).should_receive('glob').with_args('foo*').and_return( []) module.create_archive( verbosity=None, repository='repo', location_config={ 'source_directories': ['foo*'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_archive_name_format_calls_borg_with_archive_name(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar')) module.create_archive( verbosity=None, dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={ 'archive_name_format': 'ARCHIVE_NAME', }, )
def test_create_archive_with_archive_name_format_calls_borg_with_archive_name(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar'), output_log_level=logging.INFO ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'archive_name_format': 'ARCHIVE_NAME'}, )
def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( CREATE_COMMAND + ('--lock-wait', '5'), output_log_level=logging.INFO ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'lock_wait': 5}, )
def test_create_archive_with_dry_run_and_log_debug_calls_borg_without_stats_parameter(): """ --dry-run and --stats are mutually exclusive, see: https://borgbackup.readthedocs.io/en/stable/usage/create.html#description """ flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME', '--debug', '--show-rc', '--dry-run')) insert_logging_mock(logging.DEBUG) module.create_archive( dry_run=True, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_archive_name_format_accepts_borg_placeholders(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar'), output_log_level=logging.INFO, ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'archive_name_format': 'Documents_{hostname}-{now}'}, )
def test_create_archive_with_option_false_calls_borg_with_corresponding_parameter(option_name): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( CREATE_COMMAND + ('--no' + option_name.replace('_', ''),), output_log_level=logging.INFO ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], option_name: False, 'exclude_patterns': None, }, storage_config={}, )
def test_create_archive_with_umask_calls_borg_with_umask_parameters(): flexmock(module).should_receive('_expand_directories').and_return( ('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', '--umask', '740') + ARCHIVE_WITH_PATHS, output_log_level=logging.INFO) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={'umask': 740}, )
def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output(): flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( CREATE_COMMAND + ('--json',), output_log_level=None ) insert_logging_mock(logging.DEBUG) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, json=True, )
def run_configuration(config_filename, args): # pragma: no cover ''' Parse a single configuration file, and execute its defined pruning, backups, and/or consistency checks. ''' logger.info('{}: Parsing configuration file'.format(config_filename)) config = validate.parse_configuration(config_filename, validate.schema_filename()) (location, storage, retention, consistency, hooks) = ( config.get(section_name, {}) for section_name in ('location', 'storage', 'retention', 'consistency', 'hooks') ) try: remote_path = location.get('remote_path') create.initialize_environment(storage) hook.execute_hook(hooks.get('before_backup'), config_filename, 'pre-backup') for unexpanded_repository in location['repositories']: repository = os.path.expanduser(unexpanded_repository) if args.prune: logger.info('{}: Pruning archives'.format(repository)) prune.prune_archives(args.verbosity, repository, retention, remote_path=remote_path) if args.create: logger.info('{}: Creating archive'.format(repository)) create.create_archive( args.verbosity, repository, location, storage, ) if args.check: logger.info('{}: Running consistency checks'.format(repository)) check.check_archives(args.verbosity, repository, consistency, remote_path=remote_path) hook.execute_hook(hooks.get('after_backup'), config_filename, 'post-backup') except (OSError, CalledProcessError): hook.execute_hook(hooks.get('on_error'), config_filename, 'on-error') raise
def test_create_archive_with_patterns_calls_borg_with_patterns(): pattern_flags = ('--patterns-from', 'patterns') flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return( flexmock(name='/tmp/patterns') ).and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(pattern_flags) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( CREATE_COMMAND + pattern_flags, output_log_level=logging.INFO ) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'patterns': ['pattern'], }, storage_config={}, )
def test_create_archive_with_log_debug_calls_borg_with_debug_parameter(): flexmock(module).should_receive('_expand_directories').and_return( ('foo', 'bar')) flexmock(module).should_receive('_expand_home_directories').and_return(()) flexmock(module).should_receive('_write_pattern_file').and_return(None) flexmock(module).should_receive('_make_pattern_flags').and_return(()) flexmock(module).should_receive('_make_exclude_flags').and_return(()) flexmock(module).should_receive('execute_command').with_args( ('borg', 'create', '--list', '--filter', 'AME-', '--stats', '--debug', '--show-rc') + ARCHIVE_WITH_PATHS, output_log_level=logging.INFO, ) insert_logging_mock(logging.DEBUG) module.create_archive( dry_run=False, repository='repo', location_config={ 'source_directories': ['foo', 'bar'], 'repositories': ['repo'], 'exclude_patterns': None, }, storage_config={}, )
def run_actions(*, arguments, location, storage, retention, consistency, local_path, remote_path, repository_path): # pragma: no cover ''' Given parsed command-line arguments as an argparse.ArgumentParser instance, several different configuration dicts, local and remote paths to Borg, and a repository name, run all actions from the command-line arguments on the given repository. Yield JSON output strings from executing any actions that produce JSON. ''' repository = os.path.expanduser(repository_path) global_arguments = arguments['global'] dry_run_label = ' (dry run; not making any changes)' if global_arguments.dry_run else '' if 'init' in arguments: logger.info('{}: Initializing repository'.format(repository)) borg_init.initialize_repository( repository, arguments['init'].encryption_mode, arguments['init'].append_only, arguments['init'].storage_quota, local_path=local_path, remote_path=remote_path, ) if 'prune' in arguments: logger.info('{}: Pruning archives{}'.format(repository, dry_run_label)) borg_prune.prune_archives( global_arguments.dry_run, repository, storage, retention, local_path=local_path, remote_path=remote_path, stats=arguments['prune'].stats, ) if 'create' in arguments: logger.info('{}: Creating archive{}'.format(repository, dry_run_label)) json_output = borg_create.create_archive( global_arguments.dry_run, repository, location, storage, local_path=local_path, remote_path=remote_path, progress=arguments['create'].progress, stats=arguments['create'].stats, json=arguments['create'].json, ) if json_output: yield json.loads(json_output) if 'check' in arguments and checks.repository_enabled_for_checks( repository, consistency): logger.info('{}: Running consistency checks'.format(repository)) borg_check.check_archives( repository, storage, consistency, local_path=local_path, remote_path=remote_path, only_checks=arguments['check'].only, ) if 'extract' in arguments: if arguments['extract'].repository is None or repository == arguments[ 'extract'].repository: logger.info('{}: Extracting archive {}'.format( repository, arguments['extract'].archive)) borg_extract.extract_archive( global_arguments.dry_run, repository, arguments['extract'].archive, arguments['extract'].restore_paths, location, storage, local_path=local_path, remote_path=remote_path, progress=arguments['extract'].progress, ) if 'list' in arguments: if arguments['list'].repository is None or repository == arguments[ 'list'].repository: logger.info('{}: Listing archives'.format(repository)) json_output = borg_list.list_archives( repository, storage, list_arguments=arguments['list'], local_path=local_path, remote_path=remote_path, ) if json_output: yield json.loads(json_output) if 'info' in arguments: if arguments['info'].repository is None or repository == arguments[ 'info'].repository: logger.info( '{}: Displaying summary info for archives'.format(repository)) json_output = borg_info.display_archives_info( repository, storage, info_arguments=arguments['info'], local_path=local_path, remote_path=remote_path, ) if json_output: yield json.loads(json_output)
def run_actions( *, args, location, storage, retention, consistency, local_path, remote_path, repository_path ): # pragma: no cover ''' Given parsed command-line arguments as an argparse.ArgumentParser instance, several different configuration dicts, local and remote paths to Borg, and a repository name, run all actions from the command-line arguments on the given repository. Yield JSON output strings from executing any actions that produce JSON. ''' repository = os.path.expanduser(repository_path) dry_run_label = ' (dry run; not making any changes)' if args.dry_run else '' if args.init: logger.info('{}: Initializing repository'.format(repository)) borg_init.initialize_repository( repository, args.encryption_mode, args.append_only, args.storage_quota, local_path=local_path, remote_path=remote_path, ) if args.prune: logger.info('{}: Pruning archives{}'.format(repository, dry_run_label)) borg_prune.prune_archives( args.dry_run, repository, storage, retention, local_path=local_path, remote_path=remote_path, stats=args.stats, ) if args.create: logger.info('{}: Creating archive{}'.format(repository, dry_run_label)) json_output = borg_create.create_archive( args.dry_run, repository, location, storage, local_path=local_path, remote_path=remote_path, progress=args.progress, stats=args.stats, json=args.json, ) if json_output: yield json.loads(json_output) if args.check and checks.repository_enabled_for_checks(repository, consistency): logger.info('{}: Running consistency checks'.format(repository)) borg_check.check_archives( repository, storage, consistency, local_path=local_path, remote_path=remote_path ) if args.extract: if args.repository is None or repository == args.repository: logger.info('{}: Extracting archive {}'.format(repository, args.archive)) borg_extract.extract_archive( args.dry_run, repository, args.archive, args.restore_paths, location, storage, local_path=local_path, remote_path=remote_path, progress=args.progress, ) if args.list: if args.repository is None or repository == args.repository: logger.info('{}: Listing archives'.format(repository)) json_output = borg_list.list_archives( repository, storage, args.archive, local_path=local_path, remote_path=remote_path, json=args.json, ) if json_output: yield json.loads(json_output) if args.info: logger.info('{}: Displaying summary info for archives'.format(repository)) json_output = borg_info.display_archives_info( repository, storage, local_path=local_path, remote_path=remote_path, json=args.json ) if json_output: yield json.loads(json_output)
def run_configuration(config_filename, args): # pragma: no cover ''' Parse a single configuration file, and execute its defined pruning, backups, and/or consistency checks. ''' logger.info('{}: Parsing configuration file'.format(config_filename)) config = validate.parse_configuration(config_filename, validate.schema_filename()) (location, storage, retention, consistency, hooks) = (config.get(section_name, {}) for section_name in ('location', 'storage', 'retention', 'consistency', 'hooks')) try: local_path = location.get('local_path', 'borg') remote_path = location.get('remote_path') borg_create.initialize_environment(storage) hook.execute_hook(hooks.get('before_backup'), config_filename, 'pre-backup') for unexpanded_repository in location['repositories']: repository = os.path.expanduser(unexpanded_repository) dry_run_label = ' (dry run; not making any changes)' if args.dry_run else '' if args.prune: logger.info('{}: Pruning archives{}'.format( repository, dry_run_label)) borg_prune.prune_archives( args.verbosity, args.dry_run, repository, storage, retention, local_path=local_path, remote_path=remote_path, ) if args.create: logger.info('{}: Creating archive{}'.format( repository, dry_run_label)) borg_create.create_archive( args.verbosity, args.dry_run, repository, location, storage, local_path=local_path, remote_path=remote_path, ) if args.check: logger.info( '{}: Running consistency checks'.format(repository)) borg_check.check_archives( args.verbosity, repository, storage, consistency, local_path=local_path, remote_path=remote_path, ) if args.list: logger.info('{}: Listing archives'.format(repository)) borg_list.list_archives( args.verbosity, repository, storage, local_path=local_path, remote_path=remote_path, ) if args.info: logger.info('{}: Displaying summary info for archives'.format( repository)) borg_info.display_archives_info( args.verbosity, repository, storage, local_path=local_path, remote_path=remote_path, ) hook.execute_hook(hooks.get('after_backup'), config_filename, 'post-backup') except (OSError, CalledProcessError): hook.execute_hook(hooks.get('on_error'), config_filename, 'on-error') raise