From f2aab380855b75664fb850bd58c975226fbafe3d Mon Sep 17 00:00:00 2001 From: Houkime <> Date: Wed, 22 Feb 2023 14:45:11 +0000 Subject: [PATCH] feat(backups): add restore_snapshot and restore_service_from_snapshot --- selfprivacy_api/backup/__init__.py | 16 +++++++++++++++- selfprivacy_api/backup/backuper.py | 5 +++++ selfprivacy_api/backup/restic_backuper.py | 8 +++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/selfprivacy_api/backup/__init__.py b/selfprivacy_api/backup/__init__.py index b328831..4261e35 100644 --- a/selfprivacy_api/backup/__init__.py +++ b/selfprivacy_api/backup/__init__.py @@ -4,12 +4,14 @@ from selfprivacy_api.models.backup.snapshot import Snapshot from selfprivacy_api.utils.singleton_metaclass import SingletonMetaclass +from selfprivacy_api.services import get_service_by_id from selfprivacy_api.services.service import Service + from selfprivacy_api.backup.providers.provider import AbstractBackupProvider from selfprivacy_api.backup.providers import get_provider from selfprivacy_api.graphql.queries.providers import BackupProvider - +# Singleton has a property of being persistent between tests. I don't know what to do with this yet # class Backups(metaclass=SingletonMetaclass): class Backups: """A singleton controller for backups""" @@ -63,3 +65,15 @@ class Backups: repo_name = service.get_id() return self.provider.backuper.get_snapshots(repo_name) + + def restore_service_from_snapshot(self, service: Service, snapshot_id: str): + repo_name = service.get_id() + folder = service.get_location() + + self.provider.backuper.restore_from_backup(repo_name, snapshot_id, folder) + + # Our dummy service is not yet globally registered so this is not testable yet + def restore_snapshot(self, snapshot: Snapshot): + self.restore_service_from_snapshot( + get_service_by_id(snapshot.service_name), snapshot.id + ) diff --git a/selfprivacy_api/backup/backuper.py b/selfprivacy_api/backup/backuper.py index 676a0a1..f4c25a8 100644 --- a/selfprivacy_api/backup/backuper.py +++ b/selfprivacy_api/backup/backuper.py @@ -20,3 +20,8 @@ class AbstractBackuper(ABC): @abstractmethod def init(self, repo_name): raise NotImplementedError + + @abstractmethod + def restore_from_backup(self, repo_name: str, snapshot_id: str, folder: str): + """Restore a target folder using a snapshot""" + raise NotImplementedError diff --git a/selfprivacy_api/backup/restic_backuper.py b/selfprivacy_api/backup/restic_backuper.py index e485e01..0db5a42 100644 --- a/selfprivacy_api/backup/restic_backuper.py +++ b/selfprivacy_api/backup/restic_backuper.py @@ -98,7 +98,13 @@ class ResticBackuper(AbstractBackuper): repo_name, "restore", snapshot_id, "--target", folder ) - subprocess.run(restore_command, shell=False) + with subprocess.Popen( + restore_command, stdout=subprocess.PIPE, shell=False + ) as handle: + + output = handle.communicate()[0].decode("utf-8") + if "restored" not in output: + raise ValueError("cannot restore a snapshot: " + output) def _load_snapshots(self, repo_name) -> object: """