mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
[fix] Pep8 and syntax
This commit is contained in:
parent
218865a59e
commit
e0fa223d3d
6 changed files with 83 additions and 61 deletions
|
@ -31,7 +31,7 @@ import subprocess
|
||||||
import csv
|
import csv
|
||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
import urllib
|
import urllib.parse
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,13 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette import m18n
|
|
||||||
|
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.repository import LocalBackupRepository
|
from yunohost.utils.network import shf_request
|
||||||
|
from yunohost.repository import LocalBackupRepository, BackupArchive
|
||||||
logger = getActionLogger("yunohost.repository")
|
logger = getActionLogger("yunohost.repository")
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,14 +90,14 @@ class BorgBackupRepository(LocalBackupRepository):
|
||||||
response = shf_request(
|
response = shf_request(
|
||||||
domain=self.domain,
|
domain=self.domain,
|
||||||
service=services[self.method],
|
service=services[self.method],
|
||||||
shf_id=values.pop('shf_id', None),
|
shf_id=self.values.pop('shf_id', None),
|
||||||
data={
|
data={
|
||||||
'origin': self.domain,
|
'origin': self.domain,
|
||||||
'public_key': self.public_key,
|
'public_key': self.public_key,
|
||||||
'quota': self.quota,
|
'quota': self.quota,
|
||||||
'alert': self.alert,
|
'alert': self.alert,
|
||||||
'alert_delay': self.alert_delay,
|
'alert_delay': self.alert_delay,
|
||||||
#password: "XXXXXXXX",
|
# password: "XXXXXXXX",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.new_values['shf_id'] = response['id']
|
self.new_values['shf_id'] = response['id']
|
||||||
|
@ -123,13 +123,13 @@ class BorgBackupRepository(LocalBackupRepository):
|
||||||
|
|
||||||
def purge(self):
|
def purge(self):
|
||||||
if self.is_shf:
|
if self.is_shf:
|
||||||
response = shf_request(
|
shf_request(
|
||||||
domain=self.domain,
|
domain=self.domain,
|
||||||
service="borgbackup",
|
service="borgbackup",
|
||||||
shf_id=values.pop('shf_id', None),
|
shf_id=self.values.pop('shf_id', None),
|
||||||
data={
|
data={
|
||||||
'origin': self.domain,
|
'origin': self.domain,
|
||||||
#password: "XXXXXXXX",
|
# password: "XXXXXXXX",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -179,7 +179,7 @@ class BorgBackupRepository(LocalBackupRepository):
|
||||||
continue
|
continue
|
||||||
period = timedelta(**{unit: 1})
|
period = timedelta(**{unit: 1})
|
||||||
periods += set([(now - period * i, now - period * (i - 1))
|
periods += set([(now - period * i, now - period * (i - 1))
|
||||||
for i in range(qty)])
|
for i in range(qty)])
|
||||||
|
|
||||||
# Delete unneeded archive
|
# Delete unneeded archive
|
||||||
for created_at in sorted(archives, reverse=True):
|
for created_at in sorted(archives, reverse=True):
|
||||||
|
@ -194,7 +194,7 @@ class BorgBackupRepository(LocalBackupRepository):
|
||||||
|
|
||||||
|
|
||||||
class BorgBackupArchive(BackupArchive):
|
class BorgBackupArchive(BackupArchive):
|
||||||
""" Backup prepared files with borg """
|
""" Backup prepared files with borg """
|
||||||
|
|
||||||
def backup(self):
|
def backup(self):
|
||||||
cmd = ['borg', 'create', self.archive_path, './']
|
cmd = ['borg', 'create', self.archive_path, './']
|
||||||
|
@ -244,5 +244,3 @@ class BorgBackupArchive(BackupArchive):
|
||||||
# FIXME How to be sure the place where we mount is secure ?
|
# FIXME How to be sure the place where we mount is secure ?
|
||||||
cmd = ['borg', 'mount', self.archive_path, path]
|
cmd = ['borg', 'mount', self.archive_path, path]
|
||||||
self.repo._call('mount_archive', cmd)
|
self.repo._call('mount_archive', cmd)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,32 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
""" License
|
||||||
|
|
||||||
|
Copyright (C) 2013 Yunohost
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program; if not, see http://www.gnu.org/licenses
|
||||||
|
|
||||||
|
"""
|
||||||
|
from moulinette import m18n
|
||||||
|
from moulinette.utils.log import getActionLogger
|
||||||
|
from moulinette.utils.filesystem import rm
|
||||||
|
|
||||||
|
from yunohost.hook import hook_callback
|
||||||
|
from yunohost.utils.error import YunohostError
|
||||||
|
from yunohost.repository import BackupRepository, BackupArchive
|
||||||
|
logger = getActionLogger("yunohost.repository")
|
||||||
|
|
||||||
|
|
||||||
class HookBackupRepository(BackupRepository):
|
class HookBackupRepository(BackupRepository):
|
||||||
method_name = "hook"
|
method_name = "hook"
|
||||||
|
@ -13,7 +42,7 @@ class HookBackupRepository(BackupRepository):
|
||||||
|
|
||||||
def remove(self, purge=False):
|
def remove(self, purge=False):
|
||||||
if self.__class__ == BackupRepository:
|
if self.__class__ == BackupRepository:
|
||||||
raise NotImplementedError() # purge
|
raise NotImplementedError() # purge
|
||||||
|
|
||||||
rm(self.save_path, force=True)
|
rm(self.save_path, force=True)
|
||||||
logger.success(m18n.n("repository_removed", repository=self.shortname))
|
logger.success(m18n.n("repository_removed", repository=self.shortname))
|
||||||
|
@ -24,8 +53,8 @@ class HookBackupRepository(BackupRepository):
|
||||||
def info(self, space_used=False):
|
def info(self, space_used=False):
|
||||||
result = super().get(mode="export")
|
result = super().get(mode="export")
|
||||||
|
|
||||||
if self.__class__ == BackupRepository and space_used == True:
|
if self.__class__ == BackupRepository and space_used is True:
|
||||||
raise NotImplementedError() # purge
|
raise NotImplementedError() # purge
|
||||||
|
|
||||||
return {self.shortname: result}
|
return {self.shortname: result}
|
||||||
|
|
||||||
|
@ -44,7 +73,7 @@ class HookBackupArchive(BackupArchive):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._call('backup', self.work_dir, self.name, self.repo.location, self.manager.size,
|
self._call('backup', self.work_dir, self.name, self.repo.location, self.manager.size,
|
||||||
self.manager.description)
|
self.manager.description)
|
||||||
|
|
||||||
def restore(self):
|
def restore(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -64,7 +93,7 @@ class HookBackupArchive(BackupArchive):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def info(self):
|
def info(self):
|
||||||
raise NotImplementedError() #compute_space_used
|
raise NotImplementedError() # compute_space_used
|
||||||
""" Return json string of the info.json file
|
""" Return json string of the info.json file
|
||||||
|
|
||||||
Exceptions:
|
Exceptions:
|
||||||
|
@ -82,7 +111,7 @@ class HookBackupArchive(BackupArchive):
|
||||||
"""
|
"""
|
||||||
super().mount()
|
super().mount()
|
||||||
self._call('mount', self.work_dir, self.name, self.repo.location, self.manager.size,
|
self._call('mount', self.work_dir, self.name, self.repo.location, self.manager.size,
|
||||||
self.manager.description)
|
self.manager.description)
|
||||||
|
|
||||||
def extract(self):
|
def extract(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -97,6 +126,7 @@ class HookBackupArchive(BackupArchive):
|
||||||
except YunohostError:
|
except YunohostError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _call(self, *args):
|
def _call(self, *args):
|
||||||
""" Call a submethod of backup method hook
|
""" Call a submethod of backup method hook
|
||||||
|
|
||||||
|
|
|
@ -235,4 +235,3 @@ class TarBackupArchive:
|
||||||
if not os.path.exists(archive_file):
|
if not os.path.exists(archive_file):
|
||||||
raise YunohostError('backup_archive_broken_link',
|
raise YunohostError('backup_archive_broken_link',
|
||||||
path=archive_file)
|
path=archive_file)
|
||||||
|
|
||||||
|
|
|
@ -23,25 +23,26 @@
|
||||||
|
|
||||||
Manage backup repositories
|
Manage backup repositories
|
||||||
"""
|
"""
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import tarfile
|
||||||
import urllib.parse
|
import tempfile
|
||||||
|
|
||||||
from moulinette import Moulinette, m18n
|
from moulinette import Moulinette, m18n
|
||||||
from moulinette.core import MoulinetteError
|
from moulinette.core import MoulinetteError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import read_file, read_yaml, write_to_json, rm, mkdir, chmod, chown
|
from moulinette.utils.filesystem import read_file, rm, mkdir
|
||||||
from moulinette.utils.network import download_text, download_json
|
from moulinette.utils.network import download_text
|
||||||
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
|
|
||||||
from yunohost.utils.config import ConfigPanel, Question
|
from yunohost.utils.config import ConfigPanel
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError, YunohostValidationError
|
||||||
from yunohost.utils.filesystem import space_used_in_directory, disk_usage, binary_to_human
|
from yunohost.utils.filesystem import disk_usage, binary_to_human, free_space_in_directory
|
||||||
from yunohost.utils.network import get_ssh_public_key, shf_request, SHF_BASE_URL
|
from yunohost.utils.network import get_ssh_public_key, SHF_BASE_URL
|
||||||
from yunohost.log import OperationLogger, is_unit_operation
|
|
||||||
|
|
||||||
logger = getActionLogger('yunohost.repository')
|
logger = getActionLogger('yunohost.repository')
|
||||||
REPOSITORIES_DIR = '/etc/yunohost/repositories'
|
REPOSITORIES_DIR = '/etc/yunohost/repositories'
|
||||||
|
@ -104,12 +105,11 @@ class BackupRepository(ConfigPanel):
|
||||||
for repo in repositories:
|
for repo in repositories:
|
||||||
try:
|
try:
|
||||||
repositories[repo] = BackupRepository(repo).info(space_used)
|
repositories[repo] = BackupRepository(repo).info(space_used)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
logger.error(f"Unable to open repository {repo}")
|
logger.error(f"Unable to open repository {repo}")
|
||||||
|
|
||||||
return repositories
|
return repositories
|
||||||
|
|
||||||
|
|
||||||
# =================================================
|
# =================================================
|
||||||
# Config Panel Hooks
|
# Config Panel Hooks
|
||||||
# =================================================
|
# =================================================
|
||||||
|
@ -117,19 +117,18 @@ class BackupRepository(ConfigPanel):
|
||||||
def post_ask__domain(self, question):
|
def post_ask__domain(self, question):
|
||||||
""" Detect if the domain support Self-Hosting Federation protocol
|
""" Detect if the domain support Self-Hosting Federation protocol
|
||||||
"""
|
"""
|
||||||
#import requests
|
# import requests
|
||||||
# FIXME What if remote server is self-signed ?
|
# FIXME What if remote server is self-signed ?
|
||||||
# FIXME What if remote server is unreachable temporarily ?
|
# FIXME What if remote server is unreachable temporarily ?
|
||||||
url = SHF_BASE_URL.format(domain=question.value) + "/"
|
url = SHF_BASE_URL.format(domain=question.value) + "/"
|
||||||
try:
|
try:
|
||||||
#r = requests.get(url, timeout=10)
|
# r = requests.get(url, timeout=10)
|
||||||
download_text(url, timeout=10)
|
download_text(url, timeout=10)
|
||||||
except MoulinetteError as e:
|
except MoulinetteError:
|
||||||
logger.debug("SHF not running")
|
logger.debug("SHF not running")
|
||||||
return { 'is_shf': False }
|
return {'is_shf': False}
|
||||||
logger.debug("SHF running")
|
logger.debug("SHF running")
|
||||||
return { 'is_shf': True }
|
return {'is_shf': True}
|
||||||
|
|
||||||
|
|
||||||
# =================================================
|
# =================================================
|
||||||
# Config Panel Override
|
# Config Panel Override
|
||||||
|
@ -156,7 +155,7 @@ class BackupRepository(ConfigPanel):
|
||||||
|
|
||||||
def _parse_pre_answered(self, *args):
|
def _parse_pre_answered(self, *args):
|
||||||
super()._parse_pre_answered(*args)
|
super()._parse_pre_answered(*args)
|
||||||
if 'location' in self.args:
|
if 'location' in self.args:
|
||||||
self.args.update(BackupRepository.split_location(self.args['location']))
|
self.args.update(BackupRepository.split_location(self.args['location']))
|
||||||
if 'domain' in self.args:
|
if 'domain' in self.args:
|
||||||
self.args['is_remote'] = bool(self.args['domain'])
|
self.args['is_remote'] = bool(self.args['domain'])
|
||||||
|
@ -179,7 +178,6 @@ class BackupRepository(ConfigPanel):
|
||||||
self.new_values.pop(prop, None)
|
self.new_values.pop(prop, None)
|
||||||
super()._apply()
|
super()._apply()
|
||||||
|
|
||||||
|
|
||||||
# =================================================
|
# =================================================
|
||||||
# BackupMethod encapsulation
|
# BackupMethod encapsulation
|
||||||
# =================================================
|
# =================================================
|
||||||
|
@ -237,7 +235,7 @@ class BackupRepository(ConfigPanel):
|
||||||
def info(self, space_used=False):
|
def info(self, space_used=False):
|
||||||
result = super().get(mode="export")
|
result = super().get(mode="export")
|
||||||
|
|
||||||
if self.__class__ == BackupRepository and space_used == True:
|
if self.__class__ == BackupRepository and space_used is True:
|
||||||
result["space_used"] = self.compute_space_used()
|
result["space_used"] = self.compute_space_used()
|
||||||
|
|
||||||
return {self.shortname: result}
|
return {self.shortname: result}
|
||||||
|
@ -245,7 +243,7 @@ class BackupRepository(ConfigPanel):
|
||||||
def list(self, with_info):
|
def list(self, with_info):
|
||||||
archives = self.list_archive_name()
|
archives = self.list_archive_name()
|
||||||
if with_info:
|
if with_info:
|
||||||
d = OrderedDict()
|
d = {}
|
||||||
for archive in archives:
|
for archive in archives:
|
||||||
try:
|
try:
|
||||||
d[archive] = BackupArchive(repo=self, name=archive).info()
|
d[archive] = BackupArchive(repo=self, name=archive).info()
|
||||||
|
@ -289,7 +287,7 @@ class BackupRepository(ConfigPanel):
|
||||||
continue
|
continue
|
||||||
period = timedelta(**{unit: 1})
|
period = timedelta(**{unit: 1})
|
||||||
periods += set([(now - period * i, now - period * (i - 1))
|
periods += set([(now - period * i, now - period * (i - 1))
|
||||||
for i in range(qty)])
|
for i in range(qty)])
|
||||||
|
|
||||||
# Delete unneeded archive
|
# Delete unneeded archive
|
||||||
for created_at in sorted(archives, reverse=True):
|
for created_at in sorted(archives, reverse=True):
|
||||||
|
@ -412,7 +410,7 @@ class BackupArchive:
|
||||||
raise YunohostError(
|
raise YunohostError(
|
||||||
"backup_archive_cant_retrieve_info_json", archive=self.archive_path
|
"backup_archive_cant_retrieve_info_json", archive=self.archive_path
|
||||||
)
|
)
|
||||||
extract_paths = []
|
|
||||||
if f"{leading_dot}backup.csv" in files_in_archive:
|
if f"{leading_dot}backup.csv" in files_in_archive:
|
||||||
yield f"{leading_dot}backup.csv"
|
yield f"{leading_dot}backup.csv"
|
||||||
else:
|
else:
|
||||||
|
@ -447,7 +445,7 @@ class BackupArchive:
|
||||||
if not os.path.lexists(archive_file):
|
if not os.path.lexists(archive_file):
|
||||||
archive_file += ".gz"
|
archive_file += ".gz"
|
||||||
if not os.path.lexists(archive_file):
|
if not os.path.lexists(archive_file):
|
||||||
raise YunohostValidationError("backup_archive_name_unknown", name=name)
|
raise YunohostValidationError("backup_archive_name_unknown", name=self.name)
|
||||||
|
|
||||||
# If symlink, retrieve the real path
|
# If symlink, retrieve the real path
|
||||||
if os.path.islink(archive_file):
|
if os.path.islink(archive_file):
|
||||||
|
@ -491,7 +489,7 @@ class BackupArchive:
|
||||||
raise YunohostError('backup_info_json_not_implemented')
|
raise YunohostError('backup_info_json_not_implemented')
|
||||||
try:
|
try:
|
||||||
info = json.load(info_json)
|
info = json.load(info_json)
|
||||||
except:
|
except Exception:
|
||||||
logger.debug("unable to load info json", exc_info=1)
|
logger.debug("unable to load info json", exc_info=1)
|
||||||
raise YunohostError('backup_invalid_archive')
|
raise YunohostError('backup_invalid_archive')
|
||||||
|
|
||||||
|
@ -558,7 +556,8 @@ class BackupArchive:
|
||||||
raise YunohostError("backup_cleaning_failed")
|
raise YunohostError("backup_cleaning_failed")
|
||||||
|
|
||||||
if self.manager.is_tmp_work_dir:
|
if self.manager.is_tmp_work_dir:
|
||||||
filesystem.rm(self.work_dir, True, True)
|
rm(self.work_dir, True, True)
|
||||||
|
|
||||||
def _organize_files(self):
|
def _organize_files(self):
|
||||||
"""
|
"""
|
||||||
Mount all csv src in their related path
|
Mount all csv src in their related path
|
||||||
|
@ -587,11 +586,11 @@ class BackupArchive:
|
||||||
|
|
||||||
# Be sure the parent dir of destination exists
|
# Be sure the parent dir of destination exists
|
||||||
if not os.path.isdir(dest_dir):
|
if not os.path.isdir(dest_dir):
|
||||||
filesystem.mkdir(dest_dir, parents=True)
|
mkdir(dest_dir, parents=True)
|
||||||
|
|
||||||
# For directory, attempt to mount bind
|
# For directory, attempt to mount bind
|
||||||
if os.path.isdir(src):
|
if os.path.isdir(src):
|
||||||
filesystem.mkdir(dest, parents=True, force=True)
|
mkdir(dest, parents=True, force=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["mount", "--rbind", src, dest])
|
subprocess.check_call(["mount", "--rbind", src, dest])
|
||||||
|
@ -688,7 +687,6 @@ class BackupArchive:
|
||||||
if self.__class__ == BackupArchive:
|
if self.__class__ == BackupArchive:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
def download(self):
|
def download(self):
|
||||||
if self.__class__ == BackupArchive:
|
if self.__class__ == BackupArchive:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -712,9 +710,3 @@ class BackupArchive:
|
||||||
def mount(self):
|
def mount(self):
|
||||||
if self.__class__ == BackupArchive:
|
if self.__class__ == BackupArchive:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,10 +49,13 @@ from yunohost.log import OperationLogger
|
||||||
logger = getActionLogger("yunohost.config")
|
logger = getActionLogger("yunohost.config")
|
||||||
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
CONFIG_PANEL_VERSION_SUPPORTED = 1.0
|
||||||
|
|
||||||
# Those js-like evaluate functions are used to eval safely visible attributes
|
|
||||||
# The goal is to evaluate in the same way than js simple-evaluate
|
|
||||||
# https://github.com/shepherdwind/simple-evaluate
|
|
||||||
def evaluate_simple_ast(node, context=None):
|
def evaluate_simple_ast(node, context=None):
|
||||||
|
"""
|
||||||
|
Those js-like evaluate functions are used to eval safely visible attributes
|
||||||
|
The goal is to evaluate in the same way than js simple-evaluate
|
||||||
|
https://github.com/shepherdwind/simple-evaluate
|
||||||
|
"""
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
|
|
||||||
|
@ -1130,9 +1133,9 @@ class DomainQuestion(Question):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def normalize(value, option={}):
|
def normalize(value, option={}):
|
||||||
if value.startswith("https://"):
|
if value.startswith("https://"):
|
||||||
value = value[len("https://") :]
|
value = value[len("https://"):]
|
||||||
elif value.startswith("http://"):
|
elif value.startswith("http://"):
|
||||||
value = value[len("http://") :]
|
value = value[len("http://"):]
|
||||||
|
|
||||||
# Remove trailing slashes
|
# Remove trailing slashes
|
||||||
value = value.rstrip("/").lower()
|
value = value.rstrip("/").lower()
|
||||||
|
|
Loading…
Add table
Reference in a new issue