mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2025-01-24 01:36:38 +00:00
feature(backups): stop services before backups
This commit is contained in:
parent
a7427f3cb5
commit
40ad1b5ce4
|
@ -6,7 +6,7 @@ from typing import List, Optional
|
||||||
from selfprivacy_api.utils import ReadUserData, WriteUserData
|
from selfprivacy_api.utils import ReadUserData, WriteUserData
|
||||||
|
|
||||||
from selfprivacy_api.services import get_service_by_id
|
from selfprivacy_api.services import get_service_by_id
|
||||||
from selfprivacy_api.services.service import Service
|
from selfprivacy_api.services.service import Service, ServiceStatus, StoppedService
|
||||||
|
|
||||||
from selfprivacy_api.jobs import Jobs, JobStatus, Job
|
from selfprivacy_api.jobs import Jobs, JobStatus, Job
|
||||||
|
|
||||||
|
@ -35,6 +35,18 @@ DEFAULT_JSON_PROVIDER = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NotDeadError(AssertionError):
|
||||||
|
def __init__(self, service: Service):
|
||||||
|
self.service_name = service.get_id()
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Backups:
|
class Backups:
|
||||||
"""A stateless controller class for backups"""
|
"""A stateless controller class for backups"""
|
||||||
|
|
||||||
|
@ -193,13 +205,15 @@ class Backups:
|
||||||
Jobs.update(job, status=JobStatus.RUNNING)
|
Jobs.update(job, status=JobStatus.RUNNING)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
service.pre_backup()
|
with StoppedService(service):
|
||||||
snapshot = Backups.provider().backupper.start_backup(
|
Backups.assert_dead(service) # to be extra sure
|
||||||
folders,
|
service.pre_backup()
|
||||||
tag,
|
snapshot = Backups.provider().backupper.start_backup(
|
||||||
)
|
folders,
|
||||||
Backups._store_last_snapshot(tag, snapshot)
|
tag,
|
||||||
service.post_restore()
|
)
|
||||||
|
Backups._store_last_snapshot(tag, snapshot)
|
||||||
|
service.post_restore()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Jobs.update(job, status=JobStatus.ERROR)
|
Jobs.update(job, status=JobStatus.ERROR)
|
||||||
raise e
|
raise e
|
||||||
|
@ -465,3 +479,11 @@ class Backups:
|
||||||
repo_id="",
|
repo_id="",
|
||||||
)
|
)
|
||||||
Storage.store_provider(provider)
|
Storage.store_provider(provider)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def assert_dead(service: Service):
|
||||||
|
# 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]:
|
||||||
|
raise NotDeadError(service)
|
||||||
|
|
|
@ -303,7 +303,17 @@ def test_snapshots_by_id(backups, dummy_service):
|
||||||
assert Backups.get_snapshot_by_id(snap2.id).id == snap2.id
|
assert Backups.get_snapshot_by_id(snap2.id).id == snap2.id
|
||||||
|
|
||||||
|
|
||||||
def test_backup_service_task(backups, dummy_service):
|
@pytest.fixture(params=["instant_server_stop", "delayed_server_stop"])
|
||||||
|
def simulated_service_stopping_delay(request) -> float:
|
||||||
|
if request.param == "instant_server_stop":
|
||||||
|
return 0.0
|
||||||
|
else:
|
||||||
|
return 0.3
|
||||||
|
|
||||||
|
|
||||||
|
def test_backup_service_task(backups, dummy_service, simulated_service_stopping_delay):
|
||||||
|
dummy_service.set_delay(simulated_service_stopping_delay)
|
||||||
|
|
||||||
handle = start_backup(dummy_service)
|
handle = start_backup(dummy_service)
|
||||||
handle(blocking=True)
|
handle(blocking=True)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue