Beispiel #1
0
def main():  # pragma: no cover
    configure_signals()

    try:
        arguments = parse_arguments(*sys.argv[1:])
    except ValueError as error:
        configure_logging(logging.CRITICAL)
        logger.critical(error)
        exit_with_help_link()
    except SystemExit as error:
        if error.code == 0:
            raise error
        configure_logging(logging.CRITICAL)
        logger.critical('Error parsing arguments: {}'.format(' '.join(
            sys.argv)))
        exit_with_help_link()

    global_arguments = arguments['global']
    if global_arguments.version:
        print(pkg_resources.require('borgmatic')[0].version)
        sys.exit(0)

    config_filenames = tuple(
        collect.collect_config_filenames(global_arguments.config_paths))
    configs, parse_logs = load_configurations(config_filenames)

    colorama.init(
        autoreset=True,
        strip=not should_do_markup(global_arguments.no_color, configs))
    configure_logging(
        verbosity_to_log_level(global_arguments.verbosity),
        verbosity_to_log_level(global_arguments.syslog_verbosity),
    )

    logger.debug('Ensuring legacy configuration is upgraded')
    convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)

    summary_logs = list(
        collect_configuration_run_summary_logs(configs, arguments))

    logger.info('')
    logger.info('summary:')
    [
        logger.handle(log) for log in parse_logs + summary_logs
        if log.levelno >= logger.getEffectiveLevel()
    ]

    if any(log.levelno == logging.CRITICAL for log in summary_logs):
        exit_with_help_link()
Beispiel #2
0
def main():  # pragma: no cover
    configure_signals()
    args = parse_arguments(*sys.argv[1:])
    logging.basicConfig(level=verbosity_to_log_level(args.verbosity),
                        format='%(message)s')

    if args.version:
        print(pkg_resources.require('borgmatic')[0].version)
        sys.exit(0)

    config_filenames = tuple(
        collect.collect_config_filenames(args.config_paths))
    logger.debug('Ensuring legacy configuration is upgraded')
    convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)

    summary_logs = tuple(
        collect_configuration_run_summary_logs(config_filenames, args))

    logger.info('\nsummary:')
    [
        logger.handle(log) for log in summary_logs
        if log.levelno >= logger.getEffectiveLevel()
    ]

    if any(log.levelno == logging.CRITICAL for log in summary_logs):
        logger.critical(
            '\nNeed some help? https://torsion.org/borgmatic/#issues')
        sys.exit(1)
Beispiel #3
0
def main():  # pragma: no cover
    try:
        configure_signals()
        args = parse_arguments(*sys.argv[1:])
        logging.basicConfig(level=verbosity_to_log_level(args.verbosity),
                            format='%(message)s')

        config_filenames = tuple(
            collect.collect_config_filenames(args.config_paths))
        logger.debug('Ensuring legacy configuration is upgraded')
        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:
            run_configuration(config_filename, args)
    except (ValueError, OSError, CalledProcessError) as error:
        print(error, file=sys.stderr)
        print(file=sys.stderr)
        print('Need some help? https://torsion.org/borgmatic/#issues',
              file=sys.stderr)
        sys.exit(1)
Beispiel #4
0
def main():  # pragma: no cover
    configure_signals()

    try:
        args = parse_arguments(*sys.argv[1:])
    except ValueError as error:
        logging.basicConfig(level=logging.CRITICAL, format='%(message)s')
        logger.critical(error)
        exit_with_help_link()

    logging.basicConfig(level=verbosity_to_log_level(args.verbosity), format='%(message)s')

    if args.version:
        print(pkg_resources.require('borgmatic')[0].version)
        sys.exit(0)

    config_filenames = tuple(collect.collect_config_filenames(args.config_paths))
    logger.debug('Ensuring legacy configuration is upgraded')
    convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)

    summary_logs = tuple(collect_configuration_run_summary_logs(config_filenames, args))

    logger.info('\nsummary:')
    [logger.handle(log) for log in summary_logs if log.levelno >= logger.getEffectiveLevel()]

    if any(log.levelno == logging.CRITICAL for log in summary_logs):
        exit_with_help_link()
Beispiel #5
0
def main():  # pragma: no cover
    try:
        configure_signals()
        args = parse_arguments(*sys.argv[1:])
        logging.basicConfig(level=verbosity_to_log_level(args.verbosity), format='%(message)s')

        config_filenames = tuple(collect.collect_config_filenames(args.config_paths))
        logger.debug('Ensuring legacy configuration is upgraded')
        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:
            run_configuration(config_filename, args)
    except (ValueError, OSError, CalledProcessError) as error:
        print(error, file=sys.stderr)
        sys.exit(1)
Beispiel #6
0
def test_verbosity_to_log_level_maps_unknown_verbosity_to_warning_level():
    assert module.verbosity_to_log_level('my pants') == logging.WARNING
Beispiel #7
0
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
    assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
Beispiel #8
0
def test_verbosity_to_log_level_maps_unknown_verbosity_to_warning_level():
    assert module.verbosity_to_log_level('my pants') == logging.WARNING
Beispiel #9
0
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
    assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
    assert module.verbosity_to_log_level(module.VERBOSITY_LOTS) == logging.DEBUG
Beispiel #10
0
def main():  # pragma: no cover
    configure_signals()

    try:
        arguments = parse_arguments(*sys.argv[1:])
    except ValueError as error:
        configure_logging(logging.CRITICAL)
        logger.critical(error)
        exit_with_help_link()
    except SystemExit as error:
        if error.code == 0:
            raise error
        configure_logging(logging.CRITICAL)
        logger.critical('Error parsing arguments: {}'.format(' '.join(
            sys.argv)))
        exit_with_help_link()

    global_arguments = arguments['global']
    if global_arguments.version:
        print(pkg_resources.require('borgmatic')[0].version)
        sys.exit(0)

    config_filenames = tuple(
        collect.collect_config_filenames(global_arguments.config_paths))
    configs, parse_logs = load_configurations(config_filenames,
                                              global_arguments.overrides)

    any_json_flags = any(
        getattr(sub_arguments, 'json', False)
        for sub_arguments in arguments.values())
    colorama.init(
        autoreset=True,
        strip=not should_do_markup(global_arguments.no_color or any_json_flags,
                                   configs),
    )
    try:
        configure_logging(
            verbosity_to_log_level(global_arguments.verbosity),
            verbosity_to_log_level(global_arguments.syslog_verbosity),
            verbosity_to_log_level(global_arguments.log_file_verbosity),
            verbosity_to_log_level(global_arguments.monitoring_verbosity),
            global_arguments.log_file,
        )
    except (FileNotFoundError, PermissionError) as error:
        configure_logging(logging.CRITICAL)
        logger.critical('Error configuring logging: {}'.format(error))
        exit_with_help_link()

    logger.debug('Ensuring legacy configuration is upgraded')
    convert.guard_configuration_upgraded(LEGACY_CONFIG_PATH, config_filenames)

    summary_logs = parse_logs + list(
        collect_configuration_run_summary_logs(configs, arguments))
    summary_logs_max_level = max(log.levelno for log in summary_logs)

    for message in ('', 'summary:'):
        log_record(
            levelno=summary_logs_max_level,
            levelname=logging.getLevelName(summary_logs_max_level),
            msg=message,
        )

    for log in summary_logs:
        logger.handle(log)

    if summary_logs_max_level >= logging.CRITICAL:
        exit_with_help_link()
Beispiel #11
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)
Beispiel #12
0
def test_verbosity_to_log_level_maps_unknown_verbosity_to_error_level():
    assert module.verbosity_to_log_level('my pants') == logging.ERROR
Beispiel #13
0
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
    assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
    assert module.verbosity_to_log_level(
        module.VERBOSITY_LOTS) == logging.DEBUG
    assert module.verbosity_to_log_level(
        module.VERBOSITY_ERROR) == logging.ERROR