import time from abc import ABC, abstractmethod import gzip import subprocess import uuid from typing import Any from .models import DB, DBBackup # https://medium.com/poka-techblog/5-different-ways-to-backup-your-postgresql-database-using-python-3f06cea4f51 class BackupEngineBase(ABC): def __init__(self, backupdb: DBBackup): self.backup_instance = backupdb self.db_instance = self.backup_instance.db # self.db_instance = db_instance # self.backup_instance = BackupDB.objects.create( # db=self.db_instance, # rel_path="{db_id}-{timestamp}-{rand_gen}.{db_type}.{ext}".format( # db_id=self.db_instance.id, # timestamp=int(time.time()), # rand_gen=uuid.uuid4().hex[:5], # db_type=self.db_instance.db_type, # ext='sql.gz' if self.gzip else 'sql' # ), # ) self.credentials = {"database": self.db_instance.db_name, **self.db_instance.credential.credentials} @property @abstractmethod def cmd_kwargs(self) -> dict[str, Any]: ... @property def format_cmd_kwargs(self): return " ".join([ key if isinstance(value, bool) else f"{key} {value}" for key, value in self.cmd_kwargs.items() if value ]) @property @abstractmethod def cmd(self): ... @property def cmd_format(self): return self.cmd.format(cmd_kwargs=self.format_cmd_kwargs, **self.credentials) def popen(self): return subprocess.Popen(self.cmd_format, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, universal_newlines=True) def file_obj(self, path): return gzip.open(path, "wb") def run(self, task_id=None): self.backup_instance.update_task_id(task_id) try: with self.file_obj(self.backup_instance.abs_path) as f: with self.popen() as proc: self.backup_instance.update_status("running") for line in iter(proc.stdout.readline, ""): f.write(line.encode()) except Exception as e: self.backup_instance.update_status("finished") raise e class MySQLBackupEngine(BackupEngineBase): @property def cmd_kwargs(self) -> dict[str, Any]: return { "--no-tablespaces": True } @property def cmd(self): return "mysqldump {cmd_kwargs} -h {host} -P {port} -u {user} -p{password} {database}" class PostgreSQLBackupEngine(BackupEngineBase): @property def cmd_kwargs(self) -> dict[str, Any]: return { "--no-owner": True, "--no-privileges": True, "--clean": False } @property def cmd(self): return "pg_dump {cmd_kwargs} --dbname=postgresql://{user}:{password}@{host}:{port}/{database}"