rbackup/bin/backup
2019-04-23 23:18:46 -07:00

159 lines
4.5 KiB
Python

#!/usr/bin/python3
"""
.. moduleauthor:: Eric Torres
Command-Line Arguments
======================
-c, --use-checksums use rsync's checksum feature to detect file changes
-d, --dry-run make this backup a dry run
--debug show debug messages
-n, --name name to give to the backup snapshot
-p, --port port that ssh on the destination is listening on
-r, --remote-host address/alias of remote machine to use
-s, --run-post-sync run sync syscall after backup
-u, --umask umask value to use while running backup process
-v, --verbose show info messages
Run a backup, creating a snapshot in the process.
On each run of this script, a new snapshot is made and any unchanged
files are hardlinked into the new snapshot.
A remote host can be specified by passing the -r option, and its port can be
specified by passing the -p option.
TODO serialize relevant data in an object i.e. args and config, send that over the network encrypted
to prepare the repository
and
"""
import argparse
import logging
import os
import sys
import rbackup.config.config_files as config
import rbackup.script as script
from rbackup.struct.repository import Repository
# ========== Constants ==========
LOGFORMAT = "==> %(levelname)s %(message)s"
EXTRA_RSYNC_OPTS = {
"dry_run": "--dry-run",
"delete": "--delete-after",
"checksum": "--checksum",
"update": "--update",
}
# ----- Error Codes -----
E_PERMISSION = 13
# ========== Logging Setup ==========
console_formatter = logging.Formatter(LOGFORMAT)
syslog = logging.getLogger("rbackup")
syslog.setLevel(logging.DEBUG)
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.INFO)
stdout_handler.setFormatter(console_formatter)
stdout_handler.addFilter(lambda record: record.levelno <= logging.INFO)
stderr_handler = logging.StreamHandler(sys.stderr)
stderr_handler.setLevel(logging.WARNING)
stderr_handler.setFormatter(console_formatter)
syslog.addHandler(stdout_handler)
syslog.addHandler(stderr_handler)
# ========== Functions ==========
def parse_cmdline_arguments(**kwargs):
"""Parse command line arguments passed to the script.
All kwargs are passed to ArgumentParser.parse_args().
:rtype: argparse.Namespace object
"""
parser = argparse.ArgumentParser()
parser.add_argument(
"-c",
"--use-checksums",
action="store_const",
dest="extra_rsync_opts",
const=EXTRA_RSYNC_OPTS["checksum"],
help="use rsync's checksumming feature to look for changed files",
)
parser.add_argument(
"-d",
"--dry-run",
action="append_const",
dest="extra_rsync_opts",
const=EXTRA_RSYNC_OPTS["dry_run"],
help="pass --dry-run to rsync",
)
parser.add_argument("--debug", action="store_true", help="log debug messages")
parser.add_argument(
"-n", "--name", default=None, help="name to give to the snapshot"
)
parser.add_argument(
"-p",
"--port",
default=22,
help="port that ssh on the destination is listening on",
)
parser.add_argument(
"-r",
"--remote-host",
default=None,
help="address/alias of remote machine to use",
)
parser.add_argument(
"-s",
"--run-post-sync",
action="store_true",
help="run sync operation after backup is complete",
)
parser.add_argument(
"-u",
"--umask",
type=int,
default=None,
help="umask value to use while running backup process",
)
parser.add_argument(
"-v", "--verbose", action="store_true", help="log info messages"
)
parser.add_argument("repository", help="repository to back up to", metavar="repo")
return parser.parse_args(**kwargs)
# ========== Main Script ==========
if __name__ == "__main__":
args = parse_cmdline_arguments()
dest = (
args.repository
if args.remote_host is None
else f"{args.remote_host}@{os.getlogin()}:{args.port}{args.repository}"
)
try:
parsed_config = config.parse_configfile()
repo = Repository(dest)
except PermissionError as e:
syslog.critical(e)
exit(E_PERMISSION)
else:
script.do_backup(repo, parsed_config, args)
if args.verbose:
stdout_handler.setLevel(logging.INFO)
if args.debug:
stdout_handler.setLevel(logging.DEBUG)
if args.run_post_sync:
syslog.info("Running sync operation")
os.sync()