fix(backups): Do not remove failsafe snapshot after recovery

pull/35/head
Inex Code 2023-07-19 15:59:29 +03:00
parent fa53264136
commit 3067d353d8
2 changed files with 26 additions and 22 deletions

View File

@ -1,5 +1,4 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from operator import add
from os import statvfs from os import statvfs
from typing import List, Optional from typing import List, Optional
@ -58,7 +57,7 @@ class Backups:
# Providers # Providers
@staticmethod @staticmethod
def provider(): def provider() -> AbstractBackupProvider:
return Backups._lookup_provider() return Backups._lookup_provider()
@staticmethod @staticmethod
@ -68,8 +67,8 @@ class Backups:
key: str, key: str,
location: str, location: str,
repo_id: str = "", repo_id: str = "",
): ) -> None:
provider = Backups._construct_provider( provider: AbstractBackupProvider = Backups._construct_provider(
kind, kind,
login, login,
key, key,
@ -79,7 +78,7 @@ class Backups:
Storage.store_provider(provider) Storage.store_provider(provider)
@staticmethod @staticmethod
def reset(reset_json=True): def reset(reset_json=True) -> None:
Storage.reset() Storage.reset()
if reset_json: if reset_json:
try: try:
@ -180,7 +179,7 @@ class Backups:
# Init # Init
@staticmethod @staticmethod
def init_repo(): def init_repo() -> None:
Backups.provider().backupper.init() Backups.provider().backupper.init()
Storage.mark_as_init() Storage.mark_as_init()
@ -199,7 +198,7 @@ class Backups:
# Backup # Backup
@staticmethod @staticmethod
def back_up(service: Service): def back_up(service: Service) -> Snapshot:
"""The top-level function to back up a service""" """The top-level function to back up a service"""
folders = service.get_folders() folders = service.get_folders()
tag = service.get_id() tag = service.get_id()
@ -238,7 +237,11 @@ class Backups:
return job return job
@staticmethod @staticmethod
def _inplace_restore(service: Service, snapshot: Snapshot, job: Job): def _inplace_restore(
service: Service,
snapshot: Snapshot,
job: Job,
) -> None:
failsafe_snapshot = Backups.back_up(service) failsafe_snapshot = Backups.back_up(service)
Jobs.update(job, status=JobStatus.RUNNING) Jobs.update(job, status=JobStatus.RUNNING)
@ -253,13 +256,11 @@ class Backups:
service, failsafe_snapshot.id, verify=False service, failsafe_snapshot.id, verify=False
) )
raise e raise e
# TODO: Do we really have to forget this snapshot? — Inex
Backups.forget_snapshot(failsafe_snapshot)
@staticmethod @staticmethod
def restore_snapshot( def restore_snapshot(
snapshot: Snapshot, strategy=RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE snapshot: Snapshot, strategy=RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE
): ) -> None:
service = get_service_by_id(snapshot.service_name) service = get_service_by_id(snapshot.service_name)
if service is None: if service is None:
raise ValueError( raise ValueError(
@ -290,7 +291,7 @@ class Backups:
@staticmethod @staticmethod
def _assert_restorable( def _assert_restorable(
snapshot: Snapshot, strategy=RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE snapshot: Snapshot, strategy=RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE
): ) -> None:
service = get_service_by_id(snapshot.service_name) service = get_service_by_id(snapshot.service_name)
if service is None: if service is None:
raise ValueError( raise ValueError(
@ -323,7 +324,7 @@ class Backups:
service: Service, service: Service,
snapshot_id: str, snapshot_id: str,
verify=True, verify=True,
): ) -> None:
folders = service.get_folders() folders = service.get_folders()
Backups.provider().backupper.restore_from_backup( Backups.provider().backupper.restore_from_backup(
@ -369,12 +370,12 @@ class Backups:
return snap return snap
@staticmethod @staticmethod
def forget_snapshot(snapshot: Snapshot): def forget_snapshot(snapshot: Snapshot) -> None:
Backups.provider().backupper.forget_snapshot(snapshot.id) Backups.provider().backupper.forget_snapshot(snapshot.id)
Storage.delete_cached_snapshot(snapshot) Storage.delete_cached_snapshot(snapshot)
@staticmethod @staticmethod
def force_snapshot_cache_reload(): def force_snapshot_cache_reload() -> None:
upstream_snapshots = Backups.provider().backupper.get_snapshots() upstream_snapshots = Backups.provider().backupper.get_snapshots()
Storage.invalidate_snapshot_storage() Storage.invalidate_snapshot_storage()
for snapshot in upstream_snapshots: for snapshot in upstream_snapshots:
@ -387,7 +388,7 @@ class Backups:
) )
@staticmethod @staticmethod
def _store_last_snapshot(service_id: str, snapshot: Snapshot): def _store_last_snapshot(service_id: str, snapshot: Snapshot) -> None:
"""What do we do with a snapshot that is just made?""" """What do we do with a snapshot that is just made?"""
# non-expiring timestamp of the last # non-expiring timestamp of the last
Storage.store_last_timestamp(service_id, snapshot) Storage.store_last_timestamp(service_id, snapshot)
@ -401,16 +402,16 @@ class Backups:
return Storage.is_autobackup_set(service.get_id()) return Storage.is_autobackup_set(service.get_id())
@staticmethod @staticmethod
def enable_autobackup(service: Service): def enable_autobackup(service: Service) -> None:
Storage.set_autobackup(service) Storage.set_autobackup(service)
@staticmethod @staticmethod
def disable_autobackup(service: Service): def disable_autobackup(service: Service) -> None:
"""also see disable_all_autobackup()""" """also see disable_all_autobackup()"""
Storage.unset_autobackup(service) Storage.unset_autobackup(service)
@staticmethod @staticmethod
def disable_all_autobackup(): def disable_all_autobackup() -> None:
""" """
Disables all automatic backing up, Disables all automatic backing up,
but does not change per-service settings but does not change per-service settings
@ -423,7 +424,7 @@ class Backups:
return Storage.autobackup_period_minutes() return Storage.autobackup_period_minutes()
@staticmethod @staticmethod
def set_autobackup_period_minutes(minutes: int): def set_autobackup_period_minutes(minutes: int) -> None:
""" """
0 and negative numbers are equivalent to disable. 0 and negative numbers are equivalent to disable.
Setting to a positive number may result in a backup very soon Setting to a positive number may result in a backup very soon
@ -445,7 +446,7 @@ class Backups:
@staticmethod @staticmethod
def services_to_back_up(time: datetime) -> List[Service]: def services_to_back_up(time: datetime) -> List[Service]:
result = [] result: list[Service] = []
for id in Backups._service_ids_to_back_up(time): for id in Backups._service_ids_to_back_up(time):
service = get_service_by_id(id) service = get_service_by_id(id)
if service is None: if service is None:

View File

@ -408,7 +408,10 @@ def test_restore_snapshot_task(
assert file.read() == content assert file.read() == content
snaps = Backups.get_snapshots(dummy_service) snaps = Backups.get_snapshots(dummy_service)
assert len(snaps) == 1 if restore_strategy == RestoreStrategy.INPLACE:
assert len(snaps) == 2
else:
assert len(snaps) == 1
def test_autobackup_enable_service(backups, dummy_service): def test_autobackup_enable_service(backups, dummy_service):