import argparse
import datetime
import os
import tempfile
import orjson
from cattrs import structure
from ferrosoft.ops import commands
from ferrosoft.ops.models import Tenant, JournalEntry, Journal
[docs]
def backup_database(
args: argparse.Namespace,
backup_date: datetime.datetime,
master_database: str = None,
tenant: Tenant = None,
) -> JournalEntry:
db_name = master_database if tenant is None else tenant.db_name
tenant_args = (
[]
if tenant is None
else [
"--host",
tenant.db_hostname,
"--port=%s" % tenant.db_port,
"--username",
tenant.db_username,
]
)
dump_env = None if tenant is None else {"PGPASSWORD": tenant.db_password}
dump_filename = "%s-%s.pgdump.%s" % (
db_name,
backup_date.isoformat(),
args.compress,
)
dump_absname = os.path.join(args.directory, dump_filename)
pg_dump = [
args.pgdump,
"-w",
*args.dump.split(" "),
*tenant_args,
"-Z",
args.compress,
"-f",
dump_absname,
db_name,
]
commands.run(pg_dump, env=dump_env)
if not os.path.isfile(dump_absname):
raise RuntimeError("pg_dump did not create backup file: %s" % dump_absname)
if args.destination == "s3":
commands.run(
[
args.aws,
"s3",
"cp",
dump_absname,
"s3://%s" % args.bucket,
]
)
elif args.destination == "sftp":
cmd = "put %s %s/%s" % (dump_absname, args.bucket, dump_filename)
commands.run(
[
args.sftp,
"-o",
"PasswordAuthentication=no",
"-P",
str(args.sftp_port),
args.sftp_host,
],
input=cmd.encode(),
)
else:
raise RuntimeError("Unknown destination type: %s" % args.destination)
os.unlink(dump_absname)
return JournalEntry(
filename=dump_filename,
db_name=db_name,
pg_dump_args=" ".join(pg_dump),
tenant=tenant,
)
[docs]
def save_journal(journal: Journal, args: argparse.Namespace):
# noinspection PyUnresolvedReferences
journal_str = orjson.dumps(structure(journal))
dest_file_name = "%s/journal-%s.json" % (
args.bucket,
journal.backup_date.isoformat(),
)
if args.destination == "s3":
commands.run(
[
args.aws,
"s3",
"cp",
"-",
"s3://%s" % dest_file_name,
],
input=journal_str.encode(),
)
elif args.destination == "sftp":
with tempfile.NamedTemporaryFile(mode="w+b") as journal_file:
journal_file.write(journal_str.encode())
journal_file.flush()
cmd = "put %s %s" % (journal_file.name, dest_file_name)
commands.run(
[
args.sftp,
"-o",
"PasswordAuthentication=no",
"-P",
str(args.sftp_port),
args.sftp_host,
],
input=cmd.encode(),
)
else:
raise RuntimeError("Unknown destination type: %s" % args.destination)