mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2024-11-22 12:11:26 +00:00
feature(backups): mounting a repo
This commit is contained in:
parent
c5088e0e2c
commit
b6eb27dc5e
|
@ -6,6 +6,8 @@ from typing import List
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
|
from os import listdir
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
from selfprivacy_api.backup.util import output_yielder
|
from selfprivacy_api.backup.util import output_yielder
|
||||||
from selfprivacy_api.backup.backuppers import AbstractBackupper
|
from selfprivacy_api.backup.backuppers import AbstractBackupper
|
||||||
|
@ -52,7 +54,7 @@ class ResticBackupper(AbstractBackupper):
|
||||||
def _password_command(self):
|
def _password_command(self):
|
||||||
return f"echo {LocalBackupSecret.get()}"
|
return f"echo {LocalBackupSecret.get()}"
|
||||||
|
|
||||||
def restic_command(self, *args, tag: str = ""):
|
def restic_command(self, *args, tag: str = "") -> List[str]:
|
||||||
command = [
|
command = [
|
||||||
"restic",
|
"restic",
|
||||||
"-o",
|
"-o",
|
||||||
|
@ -73,6 +75,28 @@ class ResticBackupper(AbstractBackupper):
|
||||||
command.extend(ResticBackupper.__flatten_list(args))
|
command.extend(ResticBackupper.__flatten_list(args))
|
||||||
return command
|
return command
|
||||||
|
|
||||||
|
def mount_repo(self, dir):
|
||||||
|
mount_command = self.restic_command("mount", dir)
|
||||||
|
mount_command.insert(0, "nohup")
|
||||||
|
handle = subprocess.Popen(mount_command, stdout=subprocess.DEVNULL, shell=False)
|
||||||
|
sleep(2)
|
||||||
|
if not "ids" in listdir(dir):
|
||||||
|
raise IOError("failed to mount dir ", dir)
|
||||||
|
return handle
|
||||||
|
|
||||||
|
def unmount_repo(self, dir):
|
||||||
|
mount_command = ["umount", "-l", dir]
|
||||||
|
with subprocess.Popen(
|
||||||
|
mount_command, stdout=subprocess.PIPE, shell=False
|
||||||
|
) as handle:
|
||||||
|
output = handle.communicate()[0].decode("utf-8")
|
||||||
|
# TODO: check for exit code?
|
||||||
|
if "error" in output.lower():
|
||||||
|
return IOError("failed to unmount dir ", dir, ": ", output)
|
||||||
|
|
||||||
|
if not listdir(dir) == []:
|
||||||
|
return IOError("failed to unmount dir ", dir)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __flatten_list(list):
|
def __flatten_list(list):
|
||||||
"""string-aware list flattener"""
|
"""string-aware list flattener"""
|
||||||
|
|
|
@ -5,6 +5,7 @@ from os import remove
|
||||||
from os import listdir
|
from os import listdir
|
||||||
from os import urandom
|
from os import urandom
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from subprocess import Popen
|
||||||
|
|
||||||
import selfprivacy_api.services as services
|
import selfprivacy_api.services as services
|
||||||
from selfprivacy_api.services import Service
|
from selfprivacy_api.services import Service
|
||||||
|
@ -19,6 +20,7 @@ import selfprivacy_api.backup.providers as providers
|
||||||
from selfprivacy_api.backup.providers import AbstractBackupProvider
|
from selfprivacy_api.backup.providers import AbstractBackupProvider
|
||||||
from selfprivacy_api.backup.providers.backblaze import Backblaze
|
from selfprivacy_api.backup.providers.backblaze import Backblaze
|
||||||
from selfprivacy_api.backup.util import sync
|
from selfprivacy_api.backup.util import sync
|
||||||
|
from selfprivacy_api.backup.backuppers.restic_backupper import ResticBackupper
|
||||||
|
|
||||||
|
|
||||||
from selfprivacy_api.backup.tasks import start_backup, restore_snapshot
|
from selfprivacy_api.backup.tasks import start_backup, restore_snapshot
|
||||||
|
@ -325,7 +327,7 @@ def test_backup_larger_file(backups, dummy_service):
|
||||||
updates = job_progress_updates(job_type_id)
|
updates = job_progress_updates(job_type_id)
|
||||||
assert len(updates) > 3
|
assert len(updates) > 3
|
||||||
assert updates[int((len(updates) - 1) / 2.0)] > 10
|
assert updates[int((len(updates) - 1) / 2.0)] > 10
|
||||||
#clean up a bit
|
# clean up a bit
|
||||||
remove(dir)
|
remove(dir)
|
||||||
|
|
||||||
|
|
||||||
|
@ -552,3 +554,22 @@ def test_sync_nonexistent_src(dummy_service):
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
sync(src, dst)
|
sync(src, dst)
|
||||||
|
|
||||||
|
|
||||||
|
# Restic lowlevel
|
||||||
|
def test_mount_umount(backups, dummy_service, tmpdir):
|
||||||
|
Backups.back_up(dummy_service)
|
||||||
|
backupper = Backups.provider().backupper
|
||||||
|
assert isinstance(backupper, ResticBackupper)
|
||||||
|
|
||||||
|
mountpoint = tmpdir / "mount"
|
||||||
|
makedirs(mountpoint)
|
||||||
|
assert path.exists(mountpoint)
|
||||||
|
assert len(listdir(mountpoint)) == 0
|
||||||
|
|
||||||
|
handle = backupper.mount_repo(mountpoint)
|
||||||
|
assert len(listdir(mountpoint)) != 0
|
||||||
|
|
||||||
|
backupper.unmount_repo(mountpoint)
|
||||||
|
# handle.terminate()
|
||||||
|
assert len(listdir(mountpoint)) == 0
|
||||||
|
|
Loading…
Reference in a new issue