#!/usr/bin/env python3
import argparse
import datetime
import logging
import os
import sys
from subprocess import CalledProcessError
import ferrosoft.ops.models
from ferrosoft.ops import backup
arg_parser = argparse.ArgumentParser(
prog=sys.argv[0],
description="Create and store backup of databases",
)
arg_parser.add_argument(
"-m",
"--master",
help="Master database",
default=os.getenv("FP_MASTER_DATABASE"),
)
arg_parser.add_argument(
"-d",
"--directory",
help="Directory where dump files are stored for the duration of backup",
default=os.getenv("FP_BACKUP_DIR", "/tmp"),
)
arg_parser.add_argument(
"-b",
"--bucket",
help="S3 bucket name (or SFTP directory) for backup file storage",
default=os.getenv("FP_BUCKET_NAME", "/"),
)
arg_parser.add_argument(
"--dump",
help="Arguments to pg_dump",
default=os.getenv(
"FP_PG_DUMP_ARGS",
"--clean --disable-triggers --if-exists --no-owner --no-password"
" --quote-all-identifiers --serializable-deferrable",
),
)
arg_parser.add_argument(
"--compress",
help="Argument supported by pg_dump -Z",
default=os.getenv("FP_PG_DUMP_COMPRESS", "zstd"),
)
arg_parser.add_argument(
"--pgdump",
help="Path to pg_dump executable",
default="/usr/bin/pg_dump",
)
arg_parser.add_argument(
"--psql",
help="Path to psql executable",
default="/usr/bin/psql",
)
arg_parser.add_argument(
"--aws",
help="Path to aws executable",
default="/usr/bin/aws",
)
arg_parser.add_argument(
"--sftp",
help="Path to sftp executable",
default="/usr/bin/sftp",
)
arg_parser.add_argument(
"--sftp-host",
help="SFTP host to connect to (OpenSSH compatible)",
default=None,
)
arg_parser.add_argument(
"--sftp-port",
help="SFTP port to connect to",
type=int,
default=22,
)
arg_parser.add_argument(
"-D",
"--destination",
help="Destination storage type",
default="sftp",
const="sftp",
nargs="?",
choices=["sftp", "s3"],
)
[docs]
def main():
args = arg_parser.parse_args()
if args.destination == "sftp" and not args.sftp_host:
print("SFTP host is required for SFTP destination")
sys.exit(1)
backup_date = datetime.datetime.now()
journal = backup.Journal(backup_date)
exit_code = 0
try:
journal.entries.append(
backup.backup_database(args, backup_date, master_database=args.master)
)
for tenant in ferrosoft.ops.models.get_tenants(args.psql):
journal.entries.append(
backup.backup_database(args, backup_date, tenant=tenant)
)
except CalledProcessError:
logging.exception("Process failed")
exit_code = 1
except Exception:
logging.exception("Unexpected error")
finally:
if len(journal.entries) > 0:
backup.save_journal(journal, args)
sys.exit(exit_code)
if __name__ == "__main__":
main()