def main(): parser = build_parser() args = parser.parse_args() subcommand = args.subcommand # Adjust logging level if terse output is set. if args.terse: log_help.set_level(logging.WARNING) # Handle version printing specially, because it doesn't need # credentials. if subcommand == 'version': import pkgutil print(pkgutil.get_data('wal_e', 'VERSION').decode('ascii').strip()) sys.exit(0) # Print a start-up message right away. # # Otherwise, it is hard to tell when and how WAL-E started in logs # because often emits status output too late. rendered = render_subcommand(args) if rendered is not None: logger.info(msg='starting WAL-E', detail='The subcommand is "{0}".'.format(rendered)) try: backup_cxt = configure_backup_cxt(args) if subcommand == 'backup-fetch': monkeypatch_tarfile_copyfileobj() external_program_check([LZOP_BIN]) backup_cxt.database_fetch(args.PG_CLUSTER_DIRECTORY, args.BACKUP_NAME, blind_restore=args.blind_restore, restore_spec=args.restore_spec, pool_size=args.pool_size) elif subcommand == 'backup-list': backup_cxt.backup_list(query=args.QUERY, detail=args.detail) elif subcommand == 'backup-push': monkeypatch_tarfile_copyfileobj() if args.while_offline: # we need to query pg_config first for the # pg_controldata's bin location external_program_check([CONFIG_BIN]) parser = PgControlDataParser(args.PG_CLUSTER_DIRECTORY) controldata_bin = parser.controldata_bin() external_programs = [LZOP_BIN, PV_BIN, controldata_bin] else: external_programs = [LZOP_BIN, PSQL_BIN, PV_BIN] external_program_check(external_programs) rate_limit = args.rate_limit while_offline = args.while_offline backup_cxt.database_backup(args.PG_CLUSTER_DIRECTORY, rate_limit=rate_limit, while_offline=while_offline, pool_size=args.pool_size) elif subcommand == 'wal-fetch': external_program_check([LZOP_BIN]) res = backup_cxt.wal_restore(args.WAL_SEGMENT, args.WAL_DESTINATION, args.prefetch) if not res: sys.exit(1) elif subcommand == 'wal-prefetch': external_program_check([LZOP_BIN]) backup_cxt.wal_prefetch(args.BASE_DIRECTORY, args.SEGMENT) elif subcommand == 'wal-push': external_program_check([LZOP_BIN]) backup_cxt.wal_archive(args.WAL_SEGMENT, concurrency=args.pool_size) elif subcommand == 'delete': # Set up pruning precedence, optimizing for *not* deleting data # # Canonicalize the passed arguments into the value # "is_dry_run_really" if args.dry_run is False and args.confirm is True: # Actually delete data *only* if there are *no* --dry-runs # present and --confirm is present. logger.info(msg='deleting data in the store') is_dry_run_really = False else: logger.info(msg='performing dry run of data deletion') is_dry_run_really = True # This is not necessary, but "just in case" to find bugs. def just_error(*args, **kwargs): assert False, ('About to delete something in ' 'dry-run mode. Please report a bug.') # Handle the subcommands and route them to the right # implementations. if args.delete_subcommand == 'old-versions': backup_cxt.delete_old_versions(is_dry_run_really) elif args.delete_subcommand == 'everything': backup_cxt.delete_all(is_dry_run_really) elif args.delete_subcommand == 'retain': backup_cxt.delete_with_retention(is_dry_run_really, args.NUM_TO_RETAIN) elif args.delete_subcommand == 'before': segment_info = extract_segment(args.BEFORE_SEGMENT_EXCLUSIVE) assert segment_info is not None backup_cxt.delete_before(is_dry_run_really, segment_info) else: assert False, 'Should be rejected by argument parsing.' else: logger.error( msg='subcommand not implemented', detail=( 'The submitted subcommand was {0}.'.format(subcommand)), hint='Check for typos or consult wal-e --help.') sys.exit(127) # Report on all encountered exceptions, and raise the last one # to take advantage of the final catch-all reporting and exit # code management. if backup_cxt.exceptions: for exc in backup_cxt.exceptions[:-1]: if isinstance(exc, UserException): logger.log(level=exc.severity, msg=exc.msg, detail=exc.detail, hint=exc.hint) else: logger.error(msg=exc) raise backup_cxt.exceptions[-1] except UserException as e: logger.log(level=e.severity, msg=e.msg, detail=e.detail, hint=e.hint) sys.exit(1) except Exception as e: logger.critical( msg='An unprocessed exception has avoided all error handling', detail=''.join(traceback.format_exception(*sys.exc_info()))) sys.exit(2)
def main(): parser = build_parser() args = parser.parse_args() subcommand = args.subcommand # Adjust logging level if terse output is set. if args.terse: log_help.set_level(logging.WARNING) # Handle version printing specially, because it doesn't need # credentials. if subcommand == 'version': import pkgutil print pkgutil.get_data('wal_e', 'VERSION').strip() sys.exit(0) # Print a start-up message right away. # # Otherwise, it is hard to tell when and how WAL-E started in logs # because often emits status output too late. logger.info(msg='starting WAL-E', detail=('The subcommand is "{0}".' .format(render_subcommand(args)))) try: backup_cxt = configure_backup_cxt(args) if subcommand == 'backup-fetch': monkeypatch_tarfile_copyfileobj() external_program_check([LZOP_BIN]) backup_cxt.database_fetch( args.PG_CLUSTER_DIRECTORY, args.BACKUP_NAME, blind_restore=args.blind_restore, restore_spec=args.restore_spec, pool_size=args.pool_size) elif subcommand == 'backup-list': backup_cxt.backup_list(query=args.QUERY, detail=args.detail) elif subcommand == 'backup-push': monkeypatch_tarfile_copyfileobj() if args.while_offline: # we need to query pg_config first for the # pg_controldata's bin location external_program_check([CONFIG_BIN]) parser = PgControlDataParser(args.PG_CLUSTER_DIRECTORY) controldata_bin = parser.controldata_bin() external_programs = [ LZOP_BIN, PV_BIN, controldata_bin] else: external_programs = [LZOP_BIN, PSQL_BIN, PV_BIN] external_program_check(external_programs) rate_limit = args.rate_limit while_offline = args.while_offline backup_cxt.database_backup( args.PG_CLUSTER_DIRECTORY, rate_limit=rate_limit, while_offline=while_offline, pool_size=args.pool_size) elif subcommand == 'wal-fetch': external_program_check([LZOP_BIN]) res = backup_cxt.wal_restore(args.WAL_SEGMENT, args.WAL_DESTINATION) if not res: sys.exit(1) elif subcommand == 'wal-push': external_program_check([LZOP_BIN]) backup_cxt.wal_archive(args.WAL_SEGMENT, concurrency=args.pool_size) elif subcommand == 'delete': # Set up pruning precedence, optimizing for *not* deleting data # # Canonicalize the passed arguments into the value # "is_dry_run_really" if args.dry_run is False and args.confirm is True: # Actually delete data *only* if there are *no* --dry-runs # present and --confirm is present. logger.info(msg='deleting data in the store') is_dry_run_really = False else: logger.info(msg='performing dry run of data deletion') is_dry_run_really = True import boto.s3.key import boto.s3.bucket # This is not necessary, but "just in case" to find bugs. def just_error(*args, **kwargs): assert False, ('About to delete something in ' 'dry-run mode. Please report a bug.') boto.s3.key.Key.delete = just_error boto.s3.bucket.Bucket.delete_keys = just_error # Handle the subcommands and route them to the right # implementations. if args.delete_subcommand == 'old-versions': backup_cxt.delete_old_versions(is_dry_run_really) elif args.delete_subcommand == 'everything': backup_cxt.delete_all(is_dry_run_really) elif args.delete_subcommand == 'retain': backup_cxt.delete_with_retention(is_dry_run_really, args.NUM_TO_RETAIN) elif args.delete_subcommand == 'before': segment_info = extract_segment(args.BEFORE_SEGMENT_EXCLUSIVE) assert segment_info is not None backup_cxt.delete_before(is_dry_run_really, segment_info) else: assert False, 'Should be rejected by argument parsing.' else: logger.error(msg='subcommand not implemented', detail=('The submitted subcommand was {0}.' .format(subcommand)), hint='Check for typos or consult wal-e --help.') sys.exit(127) # Report on all encountered exceptions, and raise the last one # to take advantage of the final catch-all reporting and exit # code management. if backup_cxt.exceptions: for exc in backup_cxt.exceptions[:-1]: if isinstance(exc, UserException): logger.log(level=exc.severity, msg=exc.msg, detail=exc.detail, hint=exc.hint) else: logger.error(msg=exc) raise backup_cxt.exceptions[-1] except UserException, e: logger.log(level=e.severity, msg=e.msg, detail=e.detail, hint=e.hint) sys.exit(1)