mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2024-11-28 06:51:28 +00:00
feature(backups): repo init tracking
This commit is contained in:
parent
e02c1a878b
commit
b4a3658c78
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue