mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2024-11-25 21:41:27 +00:00
feat(backups): sizing up snapshots
This commit is contained in:
parent
1d403b0e94
commit
60dcde458c
|
@ -77,3 +77,13 @@ class Backups:
|
||||||
self.restore_service_from_snapshot(
|
self.restore_service_from_snapshot(
|
||||||
get_service_by_id(snapshot.service_name), snapshot.id
|
get_service_by_id(snapshot.service_name), snapshot.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def service_snapshot_size(self, service: Service, snapshot_id: str) -> float:
|
||||||
|
repo_name = service.get_id()
|
||||||
|
return self.provider.backuper.restored_size(repo_name, snapshot_id)
|
||||||
|
|
||||||
|
# Our dummy service is not yet globally registered so this is not testable yet
|
||||||
|
def snapshot_restored_size(self, snapshot: Snapshot) -> float:
|
||||||
|
return self.service_snapshot_size(
|
||||||
|
get_service_by_id(snapshot.service_name), snapshot.id
|
||||||
|
)
|
||||||
|
|
|
@ -25,3 +25,7 @@ class AbstractBackuper(ABC):
|
||||||
def restore_from_backup(self, repo_name: str, snapshot_id: str, folder: str):
|
def restore_from_backup(self, repo_name: str, snapshot_id: str, folder: str):
|
||||||
"""Restore a target folder using a snapshot"""
|
"""Restore a target folder using a snapshot"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def restored_size(self, repo_name, snapshot_id) -> float:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
|
@ -90,6 +90,25 @@ 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 restored_size(self, repo_name, snapshot_id) -> float:
|
||||||
|
"""
|
||||||
|
Size of a snapshot
|
||||||
|
"""
|
||||||
|
command = self.restic_command(
|
||||||
|
repo_name,
|
||||||
|
"stats",
|
||||||
|
snapshot_id,
|
||||||
|
"--json",
|
||||||
|
)
|
||||||
|
|
||||||
|
with subprocess.Popen(command, stdout=subprocess.PIPE, shell=False) as handle:
|
||||||
|
output = handle.communicate()[0].decode("utf-8")
|
||||||
|
try:
|
||||||
|
parsed_output = self.parse_json_output(output)
|
||||||
|
return parsed_output["total_size"]
|
||||||
|
except ValueError as e:
|
||||||
|
raise ValueError("cannot restore a snapshot: " + output) from e
|
||||||
|
|
||||||
def restore_from_backup(self, repo_name, snapshot_id, folder):
|
def restore_from_backup(self, repo_name, snapshot_id, folder):
|
||||||
"""
|
"""
|
||||||
Restore from backup with restic
|
Restore from backup with restic
|
||||||
|
@ -135,7 +154,7 @@ class ResticBackuper(AbstractBackuper):
|
||||||
if "Is there a repository at the following location?" in output:
|
if "Is there a repository at the following location?" in output:
|
||||||
raise ValueError("No repository! : " + output)
|
raise ValueError("No repository! : " + output)
|
||||||
try:
|
try:
|
||||||
return self.parse_snapshot_output(output)
|
return self.parse_json_output(output)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise ValueError("Cannot load snapshots: ") from e
|
raise ValueError("Cannot load snapshots: ") from e
|
||||||
|
|
||||||
|
@ -152,10 +171,18 @@ class ResticBackuper(AbstractBackuper):
|
||||||
snapshots.append(snapshot)
|
snapshots.append(snapshot)
|
||||||
return snapshots
|
return snapshots
|
||||||
|
|
||||||
def parse_snapshot_output(self, output: str) -> object:
|
def parse_json_output(self, output: str) -> object:
|
||||||
if "[" not in output:
|
indices = [
|
||||||
|
output.find("["),
|
||||||
|
output.find("{"),
|
||||||
|
]
|
||||||
|
indices = [x for x in indices if x != -1]
|
||||||
|
|
||||||
|
if indices == []:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"There is no json in the restic snapshot output : " + output
|
"There is no json in the restic snapshot output : " + output
|
||||||
)
|
)
|
||||||
starting_index = output.find("[")
|
|
||||||
|
starting_index = min(indices)
|
||||||
|
|
||||||
return json.loads(output[starting_index:])
|
return json.loads(output[starting_index:])
|
||||||
|
|
|
@ -127,3 +127,11 @@ def test_restore(backups, dummy_service):
|
||||||
|
|
||||||
backups.restore_service_from_snapshot(dummy_service, snap.id)
|
backups.restore_service_from_snapshot(dummy_service, snap.id)
|
||||||
assert path.exists(path_to_nuke)
|
assert path.exists(path_to_nuke)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sizing(backups, dummy_service):
|
||||||
|
backups.back_up(dummy_service)
|
||||||
|
snap = backups.get_snapshots(dummy_service)[0]
|
||||||
|
size = backups.service_snapshot_size(dummy_service, snap.id)
|
||||||
|
assert size is not None
|
||||||
|
assert size > 0
|
||||||
|
|
Loading…
Reference in a new issue