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,16 +44,17 @@ 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.
Normally, this error is unreachable because we do try ensure this.
Apparently, not this time.
"""
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.
"""
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(