示例#1
0
def run_configuration(config_filename, config, args):  # pragma: no cover
    '''
    Given a config filename and the corresponding parsed config dict, execute its defined pruning,
    backups, consistency checks, and/or other actions.
    '''
    (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_environment.initialize(storage)

        if args.create:
            hook.execute_hook(hooks.get('before_backup'), config_filename,
                              'pre-backup')

        _run_commands(
            args=args,
            consistency=consistency,
            local_path=local_path,
            location=location,
            remote_path=remote_path,
            retention=retention,
            storage=storage,
        )

        if args.create:
            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
示例#2
0
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_environment.initialize(storage)

        if args.create:
            hook.execute_hook(hooks.get('before_backup'), config_filename, 'pre-backup')

        _run_commands(
            args=args,
            consistency=consistency,
            local_path=local_path,
            location=location,
            remote_path=remote_path,
            retention=retention,
            storage=storage,
        )

        if args.create:
            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
示例#3
0
def test_initialize_with_passphrase_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'encryption_passphrase': 'pass'})
        assert os.environ.get('BORG_PASSPHRASE') == 'pass'
    finally:
        os.environ = orig_environ
def test_initialize_passes_through_existing_borg_environment_variable():
    orig_environ = os.environ

    try:
        os.environ = {'BORG_PASSPHRASE': 'pass'}
        module.initialize({'ssh_command': 'ssh -C'})
        assert os.environ.get('BORG_PASSPHRASE') == 'pass'
    finally:
        os.environ = orig_environ
示例#5
0
def test_initialize_with_passcommand_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'encryption_passcommand': 'command'})
        assert os.environ.get('BORG_PASSCOMMAND') == 'command'
    finally:
        os.environ = orig_environ
示例#6
0
def test_initialize_with_ssh_command_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'ssh_command': 'ssh -C'})
        assert os.environ.get('BORG_RSH') == 'ssh -C'
    finally:
        os.environ = orig_environ
示例#7
0
def test_initialize_with_ssh_command_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'ssh_command': 'ssh -C'})
        assert os.environ.get('BORG_RSH') == 'ssh -C'
    finally:
        os.environ = orig_environ
示例#8
0
def test_initialize_with_passphrase_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'encryption_passphrase': 'pass'})
        assert os.environ.get('BORG_PASSPHRASE') == 'pass'
    finally:
        os.environ = orig_environ
示例#9
0
def test_initialize_with_passcommand_should_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'encryption_passcommand': 'command'})
        assert os.environ.get('BORG_PASSCOMMAND') == 'command'
    finally:
        os.environ = orig_environ
示例#10
0
def run_configuration(config_filename, config, arguments):  # pragma: no cover
    '''
    Given a config filename, the corresponding parsed config dict, and command-line arguments as a
    dict from subparser name to a namespace of parsed arguments, execute its defined pruning,
    backups, consistency checks, and/or other actions.

    Yield JSON output strings from executing any actions that produce JSON.
    '''
    (location, storage, retention, consistency,
     hooks) = (config.get(section_name, {})
               for section_name in ('location', 'storage', 'retention',
                                    'consistency', 'hooks'))
    global_arguments = arguments['global']

    try:
        local_path = location.get('local_path', 'borg')
        remote_path = location.get('remote_path')
        borg_environment.initialize(storage)

        if 'create' in arguments:
            hook.execute_hook(
                hooks.get('before_backup'),
                hooks.get('umask'),
                config_filename,
                'pre-backup',
                global_arguments.dry_run,
            )

        for repository_path in location['repositories']:
            yield from run_actions(
                arguments=arguments,
                location=location,
                storage=storage,
                retention=retention,
                consistency=consistency,
                local_path=local_path,
                remote_path=remote_path,
                repository_path=repository_path,
            )

        if 'create' in arguments:
            hook.execute_hook(
                hooks.get('after_backup'),
                hooks.get('umask'),
                config_filename,
                'post-backup',
                global_arguments.dry_run,
            )
    except (OSError, CalledProcessError):
        hook.execute_hook(
            hooks.get('on_error'),
            hooks.get('umask'),
            config_filename,
            'on-error',
            global_arguments.dry_run,
        )
        raise
示例#11
0
def test_initialize_with_relocated_repo_access_should_override_default():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({'relocated_repo_access_is_ok': True})
        assert os.environ.get('BORG_RELOCATED_REPO_ACCESS_IS_OK') == 'yes'
    finally:
        os.environ = orig_environ
示例#12
0
def test_initialize_prefers_configuration_option_over_borg_environment_variable(
):
    orig_environ = os.environ

    try:
        os.environ = {'BORG_SSH': 'mosh'}
        module.initialize({'ssh_command': 'ssh -C'})
        assert os.environ.get('BORG_RSH') == 'ssh -C'
    finally:
        os.environ = orig_environ
示例#13
0
def test_initialize_is_not_affected_by_existing_environment():
    orig_environ = os.environ

    try:
        os.environ = {'BORG_PASSPHRASE': 'pass', 'BORG_SSH': 'mosh'}
        module.initialize({'ssh_command': 'ssh -C'})
        assert 'BORG_PASSPHRASE' not in os.environ
        assert os.environ.get('BORG_RSH') == 'ssh -C'
    finally:
        os.environ = orig_environ
示例#14
0
def test_initialize_without_configuration_should_not_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({})

        assert sum(1 for key in os.environ.keys()
                   if key.startswith('BORG_')) == 0
    finally:
        os.environ = orig_environ
示例#15
0
def test_initialize_without_configuration_should_not_set_environment():
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({})
        assert os.environ.get('BORG_PASSCOMMAND') is None
        assert os.environ.get('BORG_PASSPHRASE') is None
        assert os.environ.get('BORG_RSH') is None
    finally:
        os.environ = orig_environ
示例#16
0
def test_initialize_without_configuration_should_only_set_default_environment(
):
    orig_environ = os.environ

    try:
        os.environ = {}
        module.initialize({})

        assert {
            key: value
            for key, value in os.environ.items() if key.startswith('BORG_')
        } == {
            'BORG_RELOCATED_REPO_ACCESS_IS_OK': 'no',
            'BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK': 'no',
        }
    finally:
        os.environ = orig_environ
示例#17
0
def run_configuration(config_filename, config, args):  # pragma: no cover
    '''
    Given a config filename and the corresponding parsed config dict, execute its defined pruning,
    backups, consistency checks, and/or other actions.

    Yield JSON output strings from executing any actions that produce JSON.
    '''
    (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_environment.initialize(storage)

        if args.create:
            hook.execute_hook(
                hooks.get('before_backup'), config_filename, 'pre-backup', args.dry_run
            )

        for repository_path in location['repositories']:
            yield from run_actions(
                args=args,
                location=location,
                storage=storage,
                retention=retention,
                consistency=consistency,
                local_path=local_path,
                remote_path=remote_path,
                repository_path=repository_path,
            )

        if args.create:
            hook.execute_hook(
                hooks.get('after_backup'), config_filename, 'post-backup', args.dry_run
            )
    except (OSError, CalledProcessError):
        hook.execute_hook(hooks.get('on_error'), config_filename, 'on-error', args.dry_run)
        raise
示例#18
0
def run_configuration(config_filename, config, arguments):
    '''
    Given a config filename, the corresponding parsed config dict, and command-line arguments as a
    dict from subparser name to a namespace of parsed arguments, execute its defined pruning,
    backups, consistency checks, and/or other actions.

    Yield a combination of:

      * JSON output strings from successfully executing any actions that produce JSON
      * logging.LogRecord instances containing errors from any actions or backup hooks that fail
    '''
    (location, storage, retention, consistency,
     hooks) = (config.get(section_name, {})
               for section_name in ('location', 'storage', 'retention',
                                    'consistency', 'hooks'))
    global_arguments = arguments['global']

    local_path = location.get('local_path', 'borg')
    remote_path = location.get('remote_path')
    borg_environment.initialize(storage)
    encountered_error = None
    error_repository = ''

    if 'create' in arguments:
        try:
            healthchecks.ping_healthchecks(hooks.get('healthchecks'),
                                           config_filename,
                                           global_arguments.dry_run, 'start')
            command.execute_hook(
                hooks.get('before_backup'),
                hooks.get('umask'),
                config_filename,
                'pre-backup',
                global_arguments.dry_run,
            )
            postgresql.dump_databases(hooks.get('postgresql_databases'),
                                      config_filename,
                                      global_arguments.dry_run)
        except (OSError, CalledProcessError) as error:
            encountered_error = error
            yield from make_error_log_records(
                '{}: Error running pre-backup hook'.format(config_filename),
                error)

    if not encountered_error:
        for repository_path in location['repositories']:
            try:
                yield from run_actions(
                    arguments=arguments,
                    location=location,
                    storage=storage,
                    retention=retention,
                    consistency=consistency,
                    local_path=local_path,
                    remote_path=remote_path,
                    repository_path=repository_path,
                )
            except (OSError, CalledProcessError) as error:
                encountered_error = error
                error_repository = repository_path
                yield from make_error_log_records(
                    '{}: Error running actions for repository'.format(
                        repository_path), error)

    if 'create' in arguments and not encountered_error:
        try:
            postgresql.remove_database_dumps(hooks.get('postgresql_databases'),
                                             config_filename,
                                             global_arguments.dry_run)
            command.execute_hook(
                hooks.get('after_backup'),
                hooks.get('umask'),
                config_filename,
                'post-backup',
                global_arguments.dry_run,
            )
            healthchecks.ping_healthchecks(hooks.get('healthchecks'),
                                           config_filename,
                                           global_arguments.dry_run)
        except (OSError, CalledProcessError) as error:
            encountered_error = error
            yield from make_error_log_records(
                '{}: Error running post-backup hook'.format(config_filename),
                error)

    if encountered_error:
        try:
            command.execute_hook(
                hooks.get('on_error'),
                hooks.get('umask'),
                config_filename,
                'on-error',
                global_arguments.dry_run,
                repository=error_repository,
                error=encountered_error,
                output=getattr(encountered_error, 'output', ''),
            )
            healthchecks.ping_healthchecks(hooks.get('healthchecks'),
                                           config_filename,
                                           global_arguments.dry_run, 'fail')
        except (OSError, CalledProcessError) as error:
            yield from make_error_log_records(
                '{}: Error running on-error hook'.format(config_filename),
                error)
示例#19
0
def run_configuration(config_filename, config, arguments):
    '''
    Given a config filename, the corresponding parsed config dict, and command-line arguments as a
    dict from subparser name to a namespace of parsed arguments, execute its defined pruning,
    backups, consistency checks, and/or other actions.

    Yield a combination of:

      * JSON output strings from successfully executing any actions that produce JSON
      * logging.LogRecord instances containing errors from any actions or backup hooks that fail
    '''
    (location, storage, retention, consistency,
     hooks) = (config.get(section_name, {})
               for section_name in ('location', 'storage', 'retention',
                                    'consistency', 'hooks'))
    global_arguments = arguments['global']

    local_path = location.get('local_path', 'borg')
    remote_path = location.get('remote_path')
    borg_environment.initialize(storage)
    encountered_error = None
    error_repository = ''
    prune_create_or_check = {'prune', 'create',
                             'check'}.intersection(arguments)
    monitoring_log_level = verbosity_to_log_level(
        global_arguments.monitoring_verbosity)

    try:
        if prune_create_or_check:
            dispatch.call_hooks(
                'ping_monitor',
                hooks,
                config_filename,
                monitor.MONITOR_HOOK_NAMES,
                monitor.State.START,
                monitoring_log_level,
                global_arguments.dry_run,
            )
        if 'prune' in arguments:
            command.execute_hook(
                hooks.get('before_prune'),
                hooks.get('umask'),
                config_filename,
                'pre-prune',
                global_arguments.dry_run,
            )
        if 'create' in arguments:
            command.execute_hook(
                hooks.get('before_backup'),
                hooks.get('umask'),
                config_filename,
                'pre-backup',
                global_arguments.dry_run,
            )
            dispatch.call_hooks(
                'dump_databases',
                hooks,
                config_filename,
                dump.DATABASE_HOOK_NAMES,
                location,
                global_arguments.dry_run,
            )
        if 'check' in arguments:
            command.execute_hook(
                hooks.get('before_check'),
                hooks.get('umask'),
                config_filename,
                'pre-check',
                global_arguments.dry_run,
            )
    except (OSError, CalledProcessError) as error:
        if command.considered_soft_failure(config_filename, error):
            return

        encountered_error = error
        yield from make_error_log_records(
            '{}: Error running pre hook'.format(config_filename), error)

    if not encountered_error:
        for repository_path in location['repositories']:
            try:
                yield from run_actions(
                    arguments=arguments,
                    location=location,
                    storage=storage,
                    retention=retention,
                    consistency=consistency,
                    hooks=hooks,
                    local_path=local_path,
                    remote_path=remote_path,
                    repository_path=repository_path,
                )
            except (OSError, CalledProcessError, ValueError) as error:
                encountered_error = error
                error_repository = repository_path
                yield from make_error_log_records(
                    '{}: Error running actions for repository'.format(
                        repository_path), error)

    if not encountered_error:
        try:
            if 'prune' in arguments:
                command.execute_hook(
                    hooks.get('after_prune'),
                    hooks.get('umask'),
                    config_filename,
                    'post-prune',
                    global_arguments.dry_run,
                )
            if 'create' in arguments:
                dispatch.call_hooks(
                    'remove_database_dumps',
                    hooks,
                    config_filename,
                    dump.DATABASE_HOOK_NAMES,
                    location,
                    global_arguments.dry_run,
                )
                command.execute_hook(
                    hooks.get('after_backup'),
                    hooks.get('umask'),
                    config_filename,
                    'post-backup',
                    global_arguments.dry_run,
                )
            if 'check' in arguments:
                command.execute_hook(
                    hooks.get('after_check'),
                    hooks.get('umask'),
                    config_filename,
                    'post-check',
                    global_arguments.dry_run,
                )
            if {'prune', 'create', 'check'}.intersection(arguments):
                dispatch.call_hooks(
                    'ping_monitor',
                    hooks,
                    config_filename,
                    monitor.MONITOR_HOOK_NAMES,
                    monitor.State.FINISH,
                    monitoring_log_level,
                    global_arguments.dry_run,
                )
        except (OSError, CalledProcessError) as error:
            if command.considered_soft_failure(config_filename, error):
                return

            encountered_error = error
            yield from make_error_log_records(
                '{}: Error running post hook'.format(config_filename), error)

    if encountered_error and prune_create_or_check:
        try:
            command.execute_hook(
                hooks.get('on_error'),
                hooks.get('umask'),
                config_filename,
                'on-error',
                global_arguments.dry_run,
                repository=error_repository,
                error=encountered_error,
                output=getattr(encountered_error, 'output', ''),
            )
            dispatch.call_hooks(
                'ping_monitor',
                hooks,
                config_filename,
                monitor.MONITOR_HOOK_NAMES,
                monitor.State.FAIL,
                monitoring_log_level,
                global_arguments.dry_run,
            )
        except (OSError, CalledProcessError) as error:
            if command.considered_soft_failure(config_filename, error):
                return

            yield from make_error_log_records(
                '{}: Error running on-error hook'.format(config_filename),
                error)