feature(backups): repo init tracking

This commit is contained in:
Houkime 2023-03-14 00:39:15 +00:00
parent 4b2cecac8f
commit a2dd47130b
4 changed files with 88 additions and 6 deletions

View file

@ -17,6 +17,7 @@ from selfprivacy_api.backup.providers import get_provider, get_kind
from selfprivacy_api.graphql.queries.providers import BackupProvider from selfprivacy_api.graphql.queries.providers import BackupProvider
REDIS_PROVIDER_KEY = "backups:provider" REDIS_PROVIDER_KEY = "backups:provider"
REDIS_INITTED_CACHE_PREFIX = "backups:initted_services:"
redis = RedisPool().get_connection() redis = RedisPool().get_connection()
@ -67,6 +68,8 @@ class Backups:
@staticmethod @staticmethod
def reset(): def reset():
redis.delete(REDIS_PROVIDER_KEY) redis.delete(REDIS_PROVIDER_KEY)
for key in redis.keys(REDIS_INITTED_CACHE_PREFIX + "*"):
redis.delete(key)
def lookup_provider(self) -> AbstractBackupProvider: def lookup_provider(self) -> AbstractBackupProvider:
redis_provider = Backups.load_provider_redis() redis_provider = Backups.load_provider_redis()
@ -113,6 +116,29 @@ class Backups:
def init_repo(self, service: Service): def init_repo(self, service: Service):
repo_name = service.get_id() repo_name = service.get_id()
self.provider.backuper.init(repo_name) self.provider.backuper.init(repo_name)
self._redis_mark_as_init(service)
def _has_redis_init_mark(self, service: Service) -> bool:
repo_name = service.get_id()
if redis.exists(REDIS_INITTED_CACHE_PREFIX + repo_name):
return True
return False
def _redis_mark_as_init(self, service: Service):
repo_name = service.get_id()
redis.set(REDIS_INITTED_CACHE_PREFIX + repo_name, 1)
def is_initted(self, service: Service) -> bool:
repo_name = service.get_id()
if self._has_redis_init_mark(service):
return True
initted = self.provider.backuper.is_initted(repo_name)
if initted:
self._redis_mark_as_init(service)
return True
return False
def get_snapshots(self, service: Service) -> List[Snapshot]: def get_snapshots(self, service: Service) -> List[Snapshot]:
repo_name = service.get_id() repo_name = service.get_id()

View file

@ -8,6 +8,10 @@ class AbstractBackuper(ABC):
def __init__(self): def __init__(self):
pass pass
@abstractmethod
def is_initted(self, repo_name: str) -> bool:
raise NotImplementedError
@abstractmethod @abstractmethod
def start_backup(self, folder: str, repo_name: str): def start_backup(self, folder: str, repo_name: str):
raise NotImplementedError raise NotImplementedError

View file

@ -90,6 +90,20 @@ class ResticBackuper(AbstractBackuper):
if not "created restic repository" in output: if not "created restic repository" in output:
raise ValueError("cannot init a repo: " + output) raise ValueError("cannot init a repo: " + output)
def is_initted(self, repo_name: str) -> bool:
command = self.restic_command(
repo_name,
"check",
"--json",
)
with subprocess.Popen(command, stdout=subprocess.PIPE, shell=False) as handle:
output = handle.communicate()[0].decode("utf-8")
if not self.has_json(output):
return False
# raise NotImplementedError("error(big): " + output)
return True
def restored_size(self, repo_name, snapshot_id) -> float: def restored_size(self, repo_name, snapshot_id) -> float:
""" """
Size of a snapshot Size of a snapshot
@ -172,6 +186,16 @@ class ResticBackuper(AbstractBackuper):
return snapshots return snapshots
def parse_json_output(self, output: str) -> object: def parse_json_output(self, output: str) -> object:
starting_index = self.json_start(output)
if starting_index == -1:
raise ValueError(
"There is no json in the restic snapshot output : " + output
)
return json.loads(output[starting_index:])
def json_start(self, output: str) -> int:
indices = [ indices = [
output.find("["), output.find("["),
output.find("{"), output.find("{"),
@ -179,10 +203,10 @@ class ResticBackuper(AbstractBackuper):
indices = [x for x in indices if x != -1] indices = [x for x in indices if x != -1]
if indices == []: if indices == []:
raise ValueError( return -1
"There is no json in the restic snapshot output : " + output return min(indices)
)
starting_index = min(indices) def has_json(self, output: str) -> bool:
if self.json_start(output) == -1:
return json.loads(output[starting_index:]) return False
return True

View file

@ -173,3 +173,31 @@ def test_redis_storage(backups_backblaze):
assert isinstance(restored_provider, Backblaze) assert isinstance(restored_provider, Backblaze)
assert restored_provider.login == "ID" assert restored_provider.login == "ID"
assert restored_provider.key == "KEY" assert restored_provider.key == "KEY"
# lowlevel
def test_init_tracking_caching(backups, raw_dummy_service):
assert backups._has_redis_init_mark(raw_dummy_service) is False
backups._redis_mark_as_init(raw_dummy_service)
assert backups._has_redis_init_mark(raw_dummy_service) is True
assert backups.is_initted(raw_dummy_service) is True
# lowlevel
def test_init_tracking_caching2(backups, raw_dummy_service):
assert backups._has_redis_init_mark(raw_dummy_service) is False
backups.init_repo(raw_dummy_service)
assert backups._has_redis_init_mark(raw_dummy_service) is True
# only public API
def test_init_tracking(backups, raw_dummy_service):
assert backups.is_initted(raw_dummy_service) is False
backups.init_repo(raw_dummy_service)
assert backups.is_initted(raw_dummy_service) is True