home-backup/home_backup/user_service/backups.py

171 lines
5.2 KiB
Python
Raw Normal View History

2020-04-16 19:19:21 +00:00
import asyncio
2020-04-16 20:21:29 +00:00
from . import remotes
2020-04-16 17:37:16 +00:00
from .. import utils
class Backup():
name:str
2020-04-16 20:21:29 +00:00
btype:str
2020-04-16 17:37:16 +00:00
periode:int
blocked:set
2020-04-16 19:19:21 +00:00
to_backup:list
2020-04-16 20:21:29 +00:00
remote:remotes.Remote
2020-04-16 19:19:21 +00:00
2020-04-16 20:21:29 +00:00
def __init__(self, name:str, btype:str="borgbackup", periode:int=None, blocked:list=[], to_backup:list=[], remote:remotes.Remote=None):
2020-04-16 17:37:16 +00:00
# Check args
utils.valid_name_check(name)
if periode is not None and not isinstance(periode, int):
raise TypeError("Periode have to be an integer or null.")
if periode is not None and periode < 0:
raise ValueError("periode can't be negetive.")
blocked = set(blocked)
for i in blocked:
utils.valid_name_check(i)
2020-04-16 19:19:21 +00:00
to_backup = set(to_backup)
for i in to_backup:
if not isinstance(i, str):
raise TypeError("to_backup have to be a string.")
if ":" in i:
raise ValueError(": isn't allowed a char.")
2020-04-16 20:21:29 +00:00
if not isinstance(btype, str):
raise TypeError("btype has to be a string.")
if btype not in ("borgbackup",):
raise ValueError("%s is an unknown backup tool." % repr(btype))
if remote is not None and not isinstance(remote, remotes.Remote):
raise TypeError("remote has to be an remote object.")
# Check type
if btype == "borgbackup":
if remote is None:
raise ValueError("remote is required for borg backup.")
if remote.rtype != "borgbackup":
raise ValueError("remote has to be an borg backup target.")
else:
raise NotImplementedError("%s isn't an implemented type." % btype)
2020-04-16 17:37:16 +00:00
# Set values
self.name = name
self.periode = periode
2020-04-16 20:21:29 +00:00
self.blocked = blocked
2020-04-16 19:19:21 +00:00
self.to_backup = to_backup
2020-04-16 20:21:29 +00:00
self.btype = btype
self.remote = remote
2020-04-16 17:37:16 +00:00
def get_next_scedule(self, latest, zero):
if self.periode is not None:
tmp = (latest - zero) // self.periode
return zero + self.periode * (tmp + 1)
else:
raise NotImplementedError("No implemented types.")
def dump_config(self):
result = {}
2020-04-16 20:21:29 +00:00
result["type"] = self.btype
2020-04-16 17:37:16 +00:00
if self.blocked:
result["blocked"] = ",".join(self.blocked)
if self.periode is not None:
result["periode"] = str(self.periode)
2020-04-16 19:19:21 +00:00
if self.to_backup:
result["to_backup"] = ":".join(self.to_backup)
2020-04-16 20:21:29 +00:00
if self.remote:
result["remote"] = self.remote.name
2020-04-16 17:37:16 +00:00
return result
@staticmethod
2020-04-16 20:21:29 +00:00
def load_backup(name:str, conf, remotes):
2020-04-16 17:37:16 +00:00
# Load informations
2020-04-16 20:21:29 +00:00
conf = dict(conf.items())
btype = conf["type"]
del conf["type"]
2020-04-16 17:37:16 +00:00
periode = None
2020-04-16 20:21:29 +00:00
if "periode" in conf:
periode = int(conf["periode"])
del conf["periode"]
2020-04-16 17:37:16 +00:00
blocked = []
2020-04-16 20:21:29 +00:00
if "blocked" in conf:
blocked = conf["blocked"].split(",")
del conf["blocked"]
2020-04-16 19:19:21 +00:00
to_backup = []
2020-04-16 20:21:29 +00:00
if "to_backup" in conf:
to_backup = conf["to_backup"].split(":")
del conf["to_backup"]
remote = None
if "remote" in conf:
remote = conf["remote"]
if remote not in remotes.keys():
raise ValueError("Remote %s doesn't exists but is required." & remote)
remote = remotes[remote]
del conf["remote"]
2020-04-16 17:37:16 +00:00
# Generate backup
2020-04-16 20:21:29 +00:00
utils.check_empty_data_dict(conf)
2020-04-16 17:37:16 +00:00
2020-04-16 20:21:29 +00:00
return Backup(name=name, btype=btype, periode=periode, blocked=blocked, to_backup=to_backup, remote=remote)
2020-04-16 19:19:21 +00:00
async def run_backup(self, subvolumes:list):
2020-04-16 20:21:29 +00:00
print("Subvolumes: %s" % repr(subvolumes))
# RPC implementations
async def add_backup(data):
# Import config
from . import config
# Load base values
name = data["name"]
del data["name"]
info = data["info"]
if not isinstance(info, dict):
raise TypeError("info has to be an object.")
del data["info"]
btype = data["type"]
del data["type"]
utils.check_empty_data_dict(data)
# Load info
periode = None
if "periode" in info:
periode = int(info["periode"])
del info["periode"]
blocked = []
if "blocked" in info:
blocked = info["blocked"]
del info["blocked"]
to_backup = []
if "to_backup" in info:
to_backup = info["to_backup"]
del info["to_backup"]
remote = None
if "remote" in info:
remote = info["remote"]
del info["remote"]
utils.check_empty_data_dict(info)
# Add backup
async with config.config_lock:
# Check if backup exists
for _ in filter(lambda x: x.name == name, config.backups):
return {"status": "fail-already-exists"}
# Search for remote
if remote is not None:
if remote not in config.remotes:
return {"status": "fail-remote-missing"}
remote = config.remotes[remote]
# Add backup
backup = Backup(name=name, btype=btype, periode=periode, blocked=blocked, to_backup=to_backup, remote=remote)
config.backups.append(backup)
await config.save_config()
return {"status": "success"}