[fix] Repository list, add, remove

This commit is contained in:
ljf 2022-10-11 02:24:05 +02:00
parent 6eca4bff69
commit 04f85eb860
No known key found for this signature in database
5 changed files with 49 additions and 32 deletions

View file

@ -90,7 +90,8 @@
"backup_archive_system_part_not_available": "System part '{part}' unavailable in this backup",
"backup_archive_writing_error": "Could not add the files '{source}' (named in the archive '{dest}') to be backed up into the compressed archive '{archive}'",
"backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size}MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)",
"backup_borg_init_error": "Unable initialize the borg repository",
"backup_borg_init_error": "Unable initialize the borg repository: {error}",
"backup_borg_already_initialized": "The borg repository '{repository}' already exists, it has been properly added to repositories managed by YunoHost cli.",
"backup_cant_mount_uncompress_archive": "Could not mount the uncompressed archive as write protected",
"backup_cleaning_failed": "Could not clean up the temporary backup folder",
"backup_copying_to_organize_the_archive": "Copying {size}MB to organize the archive",
@ -116,6 +117,8 @@
"backup_output_directory_required": "You must provide an output directory for the backup",
"backup_output_symlink_dir_broken": "Your archive directory '{path}' is a broken symlink. Maybe you forgot to re/mount or plug in the storage medium it points to.",
"backup_permission": "Backup permission for {app}",
"backup_repository_exists": "Backup repository '{backup_repository}' already exists",
"backup_repository_unknown": "Backup repository '{backup_repository}' unknown",
"backup_running_hooks": "Running backup hooks...",
"backup_system_part_failed": "Could not backup the '{part}' system part",
"backup_unable_to_organize_files": "Could not use the quick method to organize files in the archive",

View file

@ -1099,6 +1099,9 @@ backup:
--full:
help: Show more details
action: store_true
--space-used:
help: Display size used
action: store_true
### backup_repository_info()
info:
@ -1111,13 +1114,9 @@ backup:
pattern: &pattern_backup_repository_shortname
- !!str ^[a-zA-Z0-9-_\.]+$
- "pattern_backup_repository_shortname"
-H:
full: --human-readable
help: Print sizes in human readable format
action: store_true
--space-used:
help: Display size used
action: store_false
action: store_true
### backup_repository_add()
add:

View file

@ -1871,12 +1871,12 @@ def backup_delete(name, repository):
#
def backup_repository_list(full=False):
def backup_repository_list(space_used=False, full=False):
"""
List available repositories where put archives
"""
return {"repositories": BackupRepository.list(full)}
return {"repositories": BackupRepository.list(space_used, full)}
def backup_repository_info(shortname, space_used=False):

View file

@ -24,6 +24,7 @@ import json
from datetime import datetime, timedelta
from moulinette import m18n
from moulinette.utils.log import getActionLogger
from yunohost.utils.error import YunohostError
@ -37,7 +38,7 @@ class BorgBackupRepository(LocalBackupRepository):
method_name = "borg"
# TODO logs
def _run_borg_command(self, cmd, stdout=None):
def _run_borg_command(self, cmd, stdout=None, stderr=None):
""" Call a submethod of borg with the good context
"""
env = dict(os.environ)
@ -59,15 +60,16 @@ class BorgBackupRepository(LocalBackupRepository):
# Authorize to move the repository (borgbase do this)
env["BORG_RELOCATED_REPO_ACCESS_IS_OK"] = "yes"
return subprocess.Popen(cmd, env=env, stdout=stdout)
return subprocess.Popen(cmd, env=env,
stdout=stdout, stderr=stderr)
def _call(self, action, cmd, json_output=False):
borg = self._run_borg_command(cmd)
return_code = borg.wait()
if return_code:
raise YunohostError(f"backup_borg_{action}_error")
borg = self._run_borg_command(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
out, err = borg.communicate()
if borg.returncode:
raise YunohostError(f"backup_borg_{action}_error", error=err)
out, _ = borg.communicate()
if json_output:
try:
return json.loads(out)
@ -117,8 +119,20 @@ class BorgBackupRepository(LocalBackupRepository):
if "quota" in self.future_values and self.future_values["quota"]:
cmd += ['--storage-quota', self.quota]
try:
self._call('init', cmd)
except YunohostError as e:
if e.key != "backup_borg_init_error":
raise
else:
# Check if it's possible to read the borg repo with current settings
try:
cmd = ["borg", "info", self.location]
self._call('info', cmd)
except YunohostError:
raise e
self._call('init', cmd)
logger.info(m18n.n("backup_borg_already_initialized", repository=self.location))
def update(self):
raise NotImplementedError()
@ -148,12 +162,11 @@ class BorgBackupRepository(LocalBackupRepository):
return [archive["name"] for archive in response['archives']]
def compute_space_used(self):
if not self.is_remote:
return super().purge()
else:
cmd = ["borg", "info", "--json", self.location]
response = self._call('info', cmd)
return response["cache"]["stats"]["unique_size"]
""" Return the size of this repo on the disk"""
# FIXME this size could be unrelevant, comparison between du and borg sizes doesn't match !
cmd = ["borg", "info", "--json", self.location]
response = self._call('info', cmd, json_output=True)
return response["cache"]["stats"]["unique_size"]
def prune(self, prefix=None, **kwargs):

View file

@ -104,13 +104,14 @@ class BackupRepository(ConfigPanel):
if not full:
return repositories
full_repositories = {}
for repo in repositories:
try:
repositories[repo] = BackupRepository(repo).info(space_used)
except Exception:
logger.error(f"Unable to open repository {repo}")
full_repositories.update(BackupRepository(repo).info(space_used))
except Exception as e:
logger.error(f"Unable to open repository {repo}: {e}")
return repositories
return full_repositories
# =================================================
# Config Panel Hooks
@ -232,18 +233,19 @@ class BackupRepository(ConfigPanel):
self.purge()
rm(self.save_path, force=True)
logger.success(m18n.n("repository_removed", repository=self.shortname))
logger.success(m18n.n("repository_removed", repository=self.entity))
def info(self, space_used=False):
result = super().get(mode="export")
if self.__class__ == BackupRepository and space_used is True:
if space_used is True:
result["space_used"] = self.compute_space_used()
return {self.shortname: result}
return {self.entity: result}
def list_archives(self, with_info):
archives = self.list_archive_name()
self._cast_by_method()
archives = self.list_archives_names()
if with_info:
d = {}
for archive in archives:
@ -267,7 +269,7 @@ class BackupRepository(ConfigPanel):
# List archives with creation date
archives = {}
for archive_name in self.list_archive_name(prefix):
for archive_name in self.list_archives_names(prefix):
archive = BackupArchive(repo=self, name=archive_name)
created_at = archive.info()["created_at"]
archives[created_at] = archive
@ -314,7 +316,7 @@ class BackupRepository(ConfigPanel):
def purge(self):
raise NotImplementedError()
def list_archives_names(self):
def list_archives_names(self, prefix=None):
raise NotImplementedError()
def compute_space_used(self):