[mod] pep8 on backup.py

This commit is contained in:
Laurent Peuch 2017-08-20 22:49:21 +02:00
parent 83971afb9c
commit 40a5bcc96b

View file

@ -75,7 +75,6 @@ class BackupRestoreTargetsManager(object):
"apps": {} "apps": {}
} }
def set_result(self, category, element, value): def set_result(self, category, element, value):
""" """
Change (or initialize) the current status/result of a given target. Change (or initialize) the current status/result of a given target.
@ -89,7 +88,7 @@ class BackupRestoreTargetsManager(object):
"Warning", "Error" and "Skipped" "Warning", "Error" and "Skipped"
""" """
levels = [ "Unknown", "Success", "Warning", "Error", "Skipped" ] levels = ["Unknown", "Success", "Warning", "Error", "Skipped"]
assert value in levels assert value in levels
@ -102,7 +101,6 @@ class BackupRestoreTargetsManager(object):
else: else:
self.results[category][element] = value self.results[category][element] = value
def set_wanted(self, category, def set_wanted(self, category,
wanted_targets, available_targets, wanted_targets, available_targets,
error_if_wanted_target_is_unavailable): error_if_wanted_target_is_unavailable):
@ -138,12 +136,12 @@ class BackupRestoreTargetsManager(object):
# validate that each target is actually available # validate that each target is actually available
else: else:
self.targets[category] = [part for part in wanted_targets self.targets[category] = [part for part in wanted_targets
if part in available_targets] if part in available_targets]
# Display an error for each target asked by the user but which is # Display an error for each target asked by the user but which is
# unknown # unknown
unavailable_targets = [part for part in wanted_targets unavailable_targets = [part for part in wanted_targets
if part not in available_targets] if part not in available_targets]
for target in unavailable_targets: for target in unavailable_targets:
self.set_result(category, target, "Skipped") self.set_result(category, target, "Skipped")
@ -156,7 +154,6 @@ class BackupRestoreTargetsManager(object):
return self.list(category, exclude=["Skipped"]) return self.list(category, exclude=["Skipped"])
def list(self, category, include=None, exclude=None): def list(self, category, include=None, exclude=None):
""" """
List targets in a given category. List targets in a given category.
@ -170,11 +167,11 @@ class BackupRestoreTargetsManager(object):
if include: if include:
return [target for target in self.targets[category] return [target for target in self.targets[category]
if self.results[category][target] in include] if self.results[category][target] in include]
if exclude: if exclude:
return [target for target in self.targets[category] return [target for target in self.targets[category]
if self.results[category][target] not in exclude] if self.results[category][target] not in exclude]
class BackupManager(): class BackupManager():
@ -258,7 +255,6 @@ class BackupManager():
} }
self.targets = BackupRestoreTargetsManager() self.targets = BackupRestoreTargetsManager()
# Define backup name if needed # Define backup name if needed
if not name: if not name:
name = self._define_backup_name() name = self._define_backup_name()
@ -330,7 +326,7 @@ class BackupManager():
self.work_dir) self.work_dir)
# FIXME May be we should clean the workdir here # FIXME May be we should clean the workdir here
raise MoulinetteError( raise MoulinetteError(
errno.EIO, m18n.n('backup_output_directory_not_empty')) errno.EIO, m18n.n('backup_output_directory_not_empty'))
########################################################################### ###########################################################################
# Backup target management # # Backup target management #
@ -352,7 +348,6 @@ class BackupManager():
system_parts, hook_list('backup')["hooks"], system_parts, hook_list('backup')["hooks"],
unknown_error) unknown_error)
def set_apps_targets(self, apps=[]): def set_apps_targets(self, apps=[]):
""" """
Define and validate targetted apps to be backuped Define and validate targetted apps to be backuped
@ -385,7 +380,6 @@ class BackupManager():
logger.warning(m18n.n('backup_with_no_restore_script_for_app', app=app)) logger.warning(m18n.n('backup_with_no_restore_script_for_app', app=app))
self.targets.set_result("apps", app, "Warning") self.targets.set_result("apps", app, "Warning")
########################################################################### ###########################################################################
# Management of files to backup / "The CSV" # # Management of files to backup / "The CSV" #
########################################################################### ###########################################################################
@ -400,7 +394,6 @@ class BackupManager():
""" """
_call_for_each_path(self, BackupManager._add_to_list_to_backup, tmp_csv) _call_for_each_path(self, BackupManager._add_to_list_to_backup, tmp_csv)
def _add_to_list_to_backup(self, source, dest=None): def _add_to_list_to_backup(self, source, dest=None):
""" """
Mark file or directory to backup Mark file or directory to backup
@ -431,7 +424,6 @@ class BackupManager():
dest = os.path.join(dest, os.path.basename(source)) dest = os.path.join(dest, os.path.basename(source))
self.paths_to_backup.append({'source': source, 'dest': dest}) self.paths_to_backup.append({'source': source, 'dest': dest})
def _write_csv(self): def _write_csv(self):
""" """
Write the backup list into a CSV Write the backup list into a CSV
@ -473,7 +465,6 @@ class BackupManager():
logger.error(m18n.n('backup_csv_addition_failed')) logger.error(m18n.n('backup_csv_addition_failed'))
self.csv_file.close() self.csv_file.close()
########################################################################### ###########################################################################
# File collection from system parts and apps # # File collection from system parts and apps #
########################################################################### ###########################################################################
@ -516,7 +507,6 @@ class BackupManager():
filesystem.rm(self.work_dir, True, True) filesystem.rm(self.work_dir, True, True)
raise MoulinetteError(errno.EINVAL, m18n.n('backup_nothings_done')) raise MoulinetteError(errno.EINVAL, m18n.n('backup_nothings_done'))
# Add unlisted files from backup tmp dir # Add unlisted files from backup tmp dir
self._add_to_list_to_backup('backup.csv') self._add_to_list_to_backup('backup.csv')
self._add_to_list_to_backup('info.json') self._add_to_list_to_backup('info.json')
@ -537,7 +527,6 @@ class BackupManager():
with open("%s/info.json" % self.work_dir, 'w') as f: with open("%s/info.json" % self.work_dir, 'w') as f:
f.write(json.dumps(self.info)) f.write(json.dumps(self.info))
def _get_env_var(self, app=None): def _get_env_var(self, app=None):
""" """
Define environment variables for apps or system backup scripts. Define environment variables for apps or system backup scripts.
@ -567,7 +556,6 @@ class BackupManager():
return env_var return env_var
def _collect_system_files(self): def _collect_system_files(self):
""" """
List file to backup for each selected system part List file to backup for each selected system part
@ -633,7 +621,6 @@ class BackupManager():
logger.error(m18n.n('backup_system_part_failed', part=part)) logger.error(m18n.n('backup_system_part_failed', part=part))
self.targets.set_result("system", part, "Error") self.targets.set_result("system", part, "Error")
def _collect_apps_files(self): def _collect_apps_files(self):
""" Prepare backup for each selected apps """ """ Prepare backup for each selected apps """
@ -642,7 +629,6 @@ class BackupManager():
for app_instance_name in apps_targets: for app_instance_name in apps_targets:
self._collect_app_files(app_instance_name) self._collect_app_files(app_instance_name)
def _collect_app_files(self, app): def _collect_app_files(self, app):
""" """
List files to backup for the app into the paths_to_backup dict. List files to backup for the app into the paths_to_backup dict.
@ -716,7 +702,6 @@ class BackupManager():
filesystem.rm(tmp_script, force=True) filesystem.rm(tmp_script, force=True)
filesystem.rm(env_dict["YNH_BACKUP_CSV"], force=True) filesystem.rm(env_dict["YNH_BACKUP_CSV"], force=True)
########################################################################### ###########################################################################
# Actual backup archive creation / method management # # Actual backup archive creation / method management #
########################################################################### ###########################################################################
@ -733,7 +718,6 @@ class BackupManager():
""" """
self.methods.append(method) self.methods.append(method)
def backup(self): def backup(self):
"""Apply backup methods""" """Apply backup methods"""
@ -742,7 +726,6 @@ class BackupManager():
method.mount_and_backup(self) method.mount_and_backup(self)
logger.info(m18n.n('backup_method_' + method.method_name + '_finished')) logger.info(m18n.n('backup_method_' + method.method_name + '_finished'))
def _compute_backup_size(self): def _compute_backup_size(self):
""" """
Compute backup global size and details size for each apps and system Compute backup global size and details size for each apps and system
@ -777,7 +760,7 @@ class BackupManager():
category = splitted_dest[0] category = splitted_dest[0]
if category == 'apps': if category == 'apps':
for app_key in self.apps_return: for app_key in self.apps_return:
if row['dest'].startswith('apps/'+app_key): if row['dest'].startswith('apps/' + app_key):
self.size_details['apps'][app_key] += size self.size_details['apps'][app_key] += size
break break
# OR Add size to the correct system element # OR Add size to the correct system element
@ -854,7 +837,6 @@ class RestoreManager():
return len(successful_apps) != 0 \ return len(successful_apps) != 0 \
or len(successful_system) != 0 or len(successful_system) != 0
def _read_info_files(self): def _read_info_files(self):
""" """
Read the info file from inside an archive Read the info file from inside an archive
@ -878,7 +860,6 @@ class RestoreManager():
logger.debug("restoring from backup '%s' created on %s", self.name, logger.debug("restoring from backup '%s' created on %s", self.name,
time.ctime(self.info['created_at'])) time.ctime(self.info['created_at']))
def _postinstall_if_needed(self): def _postinstall_if_needed(self):
""" """
Post install yunohost if needed Post install yunohost if needed
@ -903,7 +884,6 @@ class RestoreManager():
logger.debug("executing the post-install...") logger.debug("executing the post-install...")
tools_postinstall(domain, 'yunohost', True) tools_postinstall(domain, 'yunohost', True)
def clean(self): def clean(self):
""" """
End a restore operations by cleaning the working directory and End a restore operations by cleaning the working directory and
@ -923,7 +903,6 @@ class RestoreManager():
logger.warning(m18n.n('restore_cleaning_failed')) logger.warning(m18n.n('restore_cleaning_failed'))
filesystem.rm(self.work_dir, True, True) filesystem.rm(self.work_dir, True, True)
########################################################################### ###########################################################################
# Restore target manangement # # Restore target manangement #
########################################################################### ###########################################################################
@ -1002,7 +981,6 @@ class RestoreManager():
self.info['apps'].keys(), self.info['apps'].keys(),
unknown_error) unknown_error)
########################################################################### ###########################################################################
# Archive mounting # # Archive mounting #
########################################################################### ###########################################################################
@ -1138,7 +1116,6 @@ class RestoreManager():
finally: finally:
self.clean() self.clean()
def _restore_system(self): def _restore_system(self):
""" Restore user and system parts """ """ Restore user and system parts """
@ -1166,7 +1143,6 @@ class RestoreManager():
service_regen_conf() service_regen_conf()
def _restore_apps(self): def _restore_apps(self):
"""Restore all apps targeted""" """Restore all apps targeted"""
@ -1175,7 +1151,6 @@ class RestoreManager():
for app in apps_targets: for app in apps_targets:
self._restore_app(app) self._restore_app(app)
def _restore_app(self, app_instance_name): def _restore_app(self, app_instance_name):
""" """
Restore an app Restore an app
@ -1236,7 +1211,7 @@ class RestoreManager():
try: try:
# Restore app settings # Restore app settings
app_settings_new_path = os.path.join('/etc/yunohost/apps/', app_settings_new_path = os.path.join('/etc/yunohost/apps/',
app_instance_name) app_instance_name)
app_scripts_new_path = os.path.join(app_settings_new_path, 'scripts') app_scripts_new_path = os.path.join(app_settings_new_path, 'scripts')
shutil.copytree(app_settings_in_archive, app_settings_new_path) shutil.copytree(app_settings_in_archive, app_settings_new_path)
filesystem.chmod(app_settings_new_path, 0400, 0400, True) filesystem.chmod(app_settings_new_path, 0400, 0400, True)
@ -1285,7 +1260,6 @@ class RestoreManager():
# Cleaning app directory # Cleaning app directory
shutil.rmtree(app_settings_new_path, ignore_errors=True) shutil.rmtree(app_settings_new_path, ignore_errors=True)
# TODO Cleaning app hooks # TODO Cleaning app hooks
else: else:
self.targets.set_result("apps", app_instance_name, "Success") self.targets.set_result("apps", app_instance_name, "Success")
@ -1293,7 +1267,6 @@ class RestoreManager():
# Cleaning temporary scripts directory # Cleaning temporary scripts directory
shutil.rmtree(tmp_folder_for_app_restore, ignore_errors=True) shutil.rmtree(tmp_folder_for_app_restore, ignore_errors=True)
def _get_env_var(self, app=None): def _get_env_var(self, app=None):
""" Define environment variable for hooks call """ """ Define environment variable for hooks call """
env_var = {} env_var = {}
@ -1318,6 +1291,7 @@ class RestoreManager():
# Backup methods # # Backup methods #
############################################################################### ###############################################################################
class BackupMethod(object): class BackupMethod(object):
""" """
BackupMethod is an abstract class that represents a way to backup and BackupMethod is an abstract class that represents a way to backup and
@ -1364,7 +1338,8 @@ class BackupMethod(object):
method = BackupMethod.create("copy") method = BackupMethod.create("copy")
method.mount(restore_manager) method.mount(restore_manager)
""" """
def __init__(self, repo = None):
def __init__(self, repo=None):
""" """
BackupMethod constructors BackupMethod constructors
@ -1479,10 +1454,10 @@ class BackupMethod(object):
""" """
mount_lines = subprocess.check_output("mount").split("\n") mount_lines = subprocess.check_output("mount").split("\n")
points_to_umount = [ line.split(" ")[2] points_to_umount = [line.split(" ")[2]
for line in mount_lines for line in mount_lines
if len(line) >= 3 if len(line) >= 3
and line.split(" ")[2].startswith(directory) ] and line.split(" ")[2].startswith(directory)]
ret = 0 ret = 0
for point in reversed(points_to_umount): for point in reversed(points_to_umount):
ret = subprocess.call(["umount", point]) ret = subprocess.call(["umount", point])
@ -1556,8 +1531,8 @@ class BackupMethod(object):
# To check if dest is mounted, use /proc/mounts that # To check if dest is mounted, use /proc/mounts that
# escape spaces as \040 # escape spaces as \040
raw_mounts = read_file("/proc/mounts").strip().split('\n') raw_mounts = read_file("/proc/mounts").strip().split('\n')
mounts = [ m.split()[1] for m in raw_mounts ] mounts = [m.split()[1] for m in raw_mounts]
mounts = [ m.replace("\\040", " ") for m in mounts ] mounts = [m.replace("\\040", " ") for m in mounts]
if dest in mounts: if dest in mounts:
subprocess.check_call(["umount", "-R", dest]) subprocess.check_call(["umount", "-R", dest])
else: else:
@ -1585,7 +1560,7 @@ class BackupMethod(object):
# Compute size to copy # Compute size to copy
size = sum(disk_usage(path['source']) for path in paths_needed_to_be_copied) size = sum(disk_usage(path['source']) for path in paths_needed_to_be_copied)
size /= (1024 * 1024) # Convert bytes to megabytes size /= (1024 * 1024) # Convert bytes to megabytes
# Ask confirmation for copying # Ask confirmation for copying
if size > MB_ALLOWED_TO_ORGANIZE: if size > MB_ALLOWED_TO_ORGANIZE:
@ -1632,7 +1607,7 @@ class BackupMethod(object):
bm_class = { bm_class = {
'copy': CopyBackupMethod, 'copy': CopyBackupMethod,
'tar': TarBackupMethod, 'tar': TarBackupMethod,
'borg': BorgBackupMethod 'borg': BorgBackupMethod
} }
if method in ["copy", "tar", "borg"]: if method in ["copy", "tar", "borg"]:
@ -1646,7 +1621,8 @@ class CopyBackupMethod(BackupMethod):
This class just do an uncompress copy of each file in a location, and This class just do an uncompress copy of each file in a location, and
could be the inverse for restoring could be the inverse for restoring
""" """
def __init__(self, repo = None):
def __init__(self, repo=None):
super(CopyBackupMethod, self).__init__(repo) super(CopyBackupMethod, self).__init__(repo)
@property @property
@ -1712,18 +1688,15 @@ class TarBackupMethod(BackupMethod):
def __init__(self, repo=None): def __init__(self, repo=None):
super(TarBackupMethod, self).__init__(repo) super(TarBackupMethod, self).__init__(repo)
@property @property
def method_name(self): def method_name(self):
return 'tar' return 'tar'
@property @property
def _archive_file(self): def _archive_file(self):
"""Return the compress archive path""" """Return the compress archive path"""
return os.path.join(self.repo, self.name + '.tar.gz') return os.path.join(self.repo, self.name + '.tar.gz')
def backup(self): def backup(self):
""" """
Compress prepared files Compress prepared files
@ -1774,7 +1747,6 @@ class TarBackupMethod(BackupMethod):
if not os.path.isfile(link): if not os.path.isfile(link):
os.symlink(self._archive_file, link) os.symlink(self._archive_file, link)
def mount(self, restore_manager): def mount(self, restore_manager):
""" """
Mount the archive. We avoid copy to be able to restore on system without Mount the archive. We avoid copy to be able to restore on system without
@ -1845,7 +1817,6 @@ class TarBackupMethod(BackupMethod):
] ]
tar.extractall(members=subdir_and_files, path=self.work_dir) tar.extractall(members=subdir_and_files, path=self.work_dir)
# Extract apps backup # Extract apps backup
for app in apps_targets: for app in apps_targets:
subdir_and_files = [ subdir_and_files = [
@ -1855,26 +1826,23 @@ class TarBackupMethod(BackupMethod):
tar.extractall(members=subdir_and_files, path=self.work_dir) tar.extractall(members=subdir_and_files, path=self.work_dir)
class BorgBackupMethod(BackupMethod): class BorgBackupMethod(BackupMethod):
@property @property
def method_name(self): def method_name(self):
return 'borg' return 'borg'
def backup(self): def backup(self):
""" Backup prepared files with borg """ """ Backup prepared files with borg """
super(CopyBackupMethod, self).backup() super(CopyBackupMethod, self).backup()
# TODO run borg create command # TODO run borg create command
raise MoulinetteError( raise MoulinetteError(
errno.EIO, m18n.n('backup_borg_not_implemented')) errno.EIO, m18n.n('backup_borg_not_implemented'))
def mount(self, mnt_path): def mount(self, mnt_path):
raise MoulinetteError( raise MoulinetteError(
errno.EIO, m18n.n('backup_borg_not_implemented')) errno.EIO, m18n.n('backup_borg_not_implemented'))
class CustomBackupMethod(BackupMethod): class CustomBackupMethod(BackupMethod):
@ -1883,18 +1851,17 @@ class CustomBackupMethod(BackupMethod):
backup/restore operations. A user can add his own hook inside backup/restore operations. A user can add his own hook inside
/etc/yunohost/hooks.d/backup_method/ /etc/yunohost/hooks.d/backup_method/
""" """
def __init__(self, repo = None, method = None,**kwargs):
def __init__(self, repo=None, method=None, **kwargs):
super(CustomBackupMethod, self).__init__(repo) super(CustomBackupMethod, self).__init__(repo)
self.args = kwargs self.args = kwargs
self.method = method self.method = method
self._need_mount = None self._need_mount = None
@property @property
def method_name(self): def method_name(self):
return 'borg' return 'borg'
def need_mount(self): def need_mount(self):
"""Call the backup_method hook to know if we need to organize files """Call the backup_method hook to know if we need to organize files
@ -1910,7 +1877,6 @@ class CustomBackupMethod(BackupMethod):
self._need_mount = True if ret['succeed'] else False self._need_mount = True if ret['succeed'] else False
return self._need_mount return self._need_mount
def backup(self): def backup(self):
""" """
Launch a custom script to backup Launch a custom script to backup
@ -1939,7 +1905,6 @@ class CustomBackupMethod(BackupMethod):
raise MoulinetteError(errno.EIO, raise MoulinetteError(errno.EIO,
m18n.n('backup_custom_mount_error')) m18n.n('backup_custom_mount_error'))
def _get_args(self, action): def _get_args(self, action):
"""Return the arguments to give to the custom script""" """Return the arguments to give to the custom script"""
return [action, self.work_dir, self.name, self.repo, self.manager.size, return [action, self.work_dir, self.name, self.repo, self.manager.size,
@ -2006,7 +1971,7 @@ def backup_create(name=None, description=None, methods=[],
# Check for forbidden folders # Check for forbidden folders
if output_directory.startswith(ARCHIVES_PATH) or \ if output_directory.startswith(ARCHIVES_PATH) or \
re.match(r'^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$', re.match(r'^/(|(bin|boot|dev|etc|lib|root|run|sbin|sys|usr|var)(|/.*))$',
output_directory): output_directory):
raise MoulinetteError(errno.EINVAL, raise MoulinetteError(errno.EINVAL,
m18n.n('backup_output_directory_forbidden')) m18n.n('backup_output_directory_forbidden'))
@ -2172,7 +2137,6 @@ def backup_restore(auth, name,
restore_manager.mount() restore_manager.mount()
restore_manager.restore() restore_manager.restore()
# Check if something has been restored # Check if something has been restored
if restore_manager.success: if restore_manager.success:
logger.success(m18n.n('restore_complete')) logger.success(m18n.n('restore_complete'))
@ -2334,6 +2298,7 @@ def backup_delete(name):
# Misc helpers # # Misc helpers #
############################################################################### ###############################################################################
def _create_archive_dir(): def _create_archive_dir():
""" Create the YunoHost archives directory if doesn't exist """ """ Create the YunoHost archives directory if doesn't exist """
if not os.path.isdir(ARCHIVES_PATH): if not os.path.isdir(ARCHIVES_PATH):
@ -2361,4 +2326,3 @@ def disk_usage(path):
du_output = subprocess.check_output(['du', '-sb', path]) du_output = subprocess.check_output(['du', '-sb', path])
return int(du_output.split()[0].decode('utf-8')) return int(du_output.split()[0].decode('utf-8'))