fix(backups): backup strategies were unused
continuous-integration/drone/push Build is failing Details

pull/35/head
Inex Code 2023-07-18 20:15:22 +03:00
parent 20f3e5c564
commit 8b504993d0
3 changed files with 54 additions and 22 deletions

View File

@ -1,12 +1,15 @@
from datetime import datetime, timedelta
from operator import add
from os import statvfs, path, walk
from os import statvfs
from typing import List, Optional
from selfprivacy_api.utils import ReadUserData, WriteUserData
from selfprivacy_api.services import get_service_by_id
from selfprivacy_api.services.service import Service, ServiceStatus, StoppedService
from selfprivacy_api.services.service import (
Service,
ServiceStatus,
StoppedService,
)
from selfprivacy_api.jobs import Jobs, JobStatus, Job
@ -41,7 +44,8 @@ class NotDeadError(AssertionError):
def __str__(self):
return f"""
Service {self.service_name} should be either stopped or dead from an error before we back up.
Service {self.service_name} should be either stopped or dead from
an error before we back up.
Normally, this error is unreachable because we do try ensure this.
Apparently, not this time.
"""
@ -50,7 +54,7 @@ class NotDeadError(AssertionError):
class Backups:
"""A stateless controller class for backups"""
### Providers
# Providers
@staticmethod
def provider():
@ -172,7 +176,7 @@ class Backups:
user_data["backup"] = DEFAULT_JSON_PROVIDER
### Init
# Init
@staticmethod
def init_repo():
@ -191,7 +195,7 @@ class Backups:
return False
### Backup
# Backup
@staticmethod
def back_up(service: Service):
@ -221,7 +225,8 @@ class Backups:
Jobs.update(job, status=JobStatus.FINISHED)
return snapshot
### Restoring
# Restoring
@staticmethod
def _ensure_queued_restore_job(service, snapshot) -> Job:
job = get_restore_job(service)
@ -237,12 +242,17 @@ class Backups:
Jobs.update(job, status=JobStatus.RUNNING)
try:
Backups._restore_service_from_snapshot(service, snapshot.id, verify=False)
Backups._restore_service_from_snapshot(
service,
snapshot.id,
verify=False,
)
except Exception as e:
Backups._restore_service_from_snapshot(
service, failsafe_snapshot.id, verify=False
)
raise e
# TODO: Do we really have to forget this snapshot? — Inex
Backups.forget_snapshot(failsafe_snapshot)
@staticmethod
@ -295,8 +305,9 @@ class Backups:
else:
raise NotImplementedError(
"""
We do not know if there is enough space for restoration because there is some novel restore strategy used!
This is a developer's fault, open a issue please
We do not know if there is enough space for restoration because
there is some novel restore strategy used!
This is a developer's fault, open an issue please
"""
)
available_space = Backups.space_usable_for_service(service)
@ -307,15 +318,20 @@ class Backups:
)
@staticmethod
def _restore_service_from_snapshot(service: Service, snapshot_id: str, verify=True):
def _restore_service_from_snapshot(
service: Service,
snapshot_id: str,
verify=True,
):
folders = service.get_folders()
Backups.provider().backupper.restore_from_backup(
snapshot_id,
folders,
verify=verify,
)
### Snapshots
# Snapshots
@staticmethod
def get_snapshots(service: Service) -> List[Snapshot]:
@ -377,7 +393,7 @@ class Backups:
# expiring cache entry
Storage.cache_snapshot(snapshot)
### Autobackup
# Autobackup
@staticmethod
def is_autobackup_enabled(service: Service) -> bool:
@ -472,7 +488,7 @@ class Backups:
)
]
### Helpers
# Helpers
@staticmethod
def space_usable_for_service(service: Service) -> int:
@ -501,5 +517,8 @@ class Backups:
# if we backup the service that is failing to restore it to the
# previous snapshot, its status can be FAILED
# And obviously restoring a failed service is the moun route
if service.get_status() not in [ServiceStatus.INACTIVE, ServiceStatus.FAILED]:
if service.get_status() not in [
ServiceStatus.INACTIVE,
ServiceStatus.FAILED,
]:
raise NotDeadError(service)

View File

@ -30,7 +30,12 @@ class AbstractBackupper(ABC):
raise NotImplementedError
@abstractmethod
def restore_from_backup(self, snapshot_id: str, folders: List[str], verify=True):
def restore_from_backup(
self,
snapshot_id: str,
folders: List[str],
verify=True,
):
"""Restore a target folder using a snapshot"""
raise NotImplementedError

View File

@ -81,7 +81,7 @@ class ResticBackupper(AbstractBackupper):
mount_command.insert(0, "nohup")
handle = subprocess.Popen(mount_command, stdout=subprocess.DEVNULL, shell=False)
sleep(2)
if not "ids" in listdir(dir):
if "ids" not in listdir(dir):
raise IOError("failed to mount dir ", dir)
return handle
@ -211,7 +211,12 @@ class ResticBackupper(AbstractBackupper):
except ValueError as e:
raise ValueError("cannot restore a snapshot: " + output) from e
def restore_from_backup(self, snapshot_id, folders: List[str], verify=True):
def restore_from_backup(
self,
snapshot_id,
folders: List[str],
verify=True,
):
"""
Restore from backup with restic
"""
@ -236,6 +241,9 @@ class ResticBackupper(AbstractBackupper):
dst = folder
sync(src, dst)
if not verify:
self.unmount_repo(dir)
def do_restore(self, snapshot_id, target="/", verify=False):
"""barebones restic restore"""
restore_command = self.restic_command(