Files
webpanel/app/db/backup_engine.py
2024-06-04 22:08:15 +02:00

99 lines
3.0 KiB
Python

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}"