Merge pull request #600 from YunoHost/autopep8

Autopep8
This commit is contained in:
Alexandre Aubin 2018-12-15 15:13:59 +01:00 committed by GitHub
commit 031128951b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 344 additions and 289 deletions

View file

@ -137,7 +137,7 @@ def app_fetchlist(url=None, name=None):
else: else:
appslists_to_be_fetched = appslists.keys() appslists_to_be_fetched = appslists.keys()
import requests # lazy loading this module for performance reasons import requests # lazy loading this module for performance reasons
# Fetch all appslists to be fetched # Fetch all appslists to be fetched
for name in appslists_to_be_fetched: for name in appslists_to_be_fetched:
@ -172,7 +172,7 @@ def app_fetchlist(url=None, name=None):
appslist = appslist_request.text appslist = appslist_request.text
try: try:
json.loads(appslist) json.loads(appslist)
except ValueError, e: except ValueError as e:
logger.error(m18n.n('appslist_retrieve_bad_format', logger.error(m18n.n('appslist_retrieve_bad_format',
appslist=name)) appslist=name))
continue continue
@ -542,7 +542,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
raise YunohostError("app_change_url_failed_nginx_reload", nginx_errors=nginx_errors) raise YunohostError("app_change_url_failed_nginx_reload", nginx_errors=nginx_errors)
logger.success(m18n.n("app_change_url_success", logger.success(m18n.n("app_change_url_success",
app=app, domain=domain, path=path)) app=app, domain=domain, path=path))
hook_callback('post_app_change_url', args=args_list, env=env_dict) hook_callback('post_app_change_url', args=args_list, env=env_dict)
@ -701,7 +701,6 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback
from yunohost.log import OperationLogger from yunohost.log import OperationLogger
# Fetch or extract sources # Fetch or extract sources
try: try:
os.listdir(INSTALL_TMP) os.listdir(INSTALL_TMP)
@ -758,7 +757,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) env_dict["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
# Start register change on system # Start register change on system
operation_logger.extra.update({'env':env_dict}) operation_logger.extra.update({'env': env_dict})
operation_logger.related_to = [s for s in operation_logger.related_to if s[0] != "app"] operation_logger.related_to = [s for s in operation_logger.related_to if s[0] != "app"]
operation_logger.related_to.append(("app", app_id)) operation_logger.related_to.append(("app", app_id))
operation_logger.start() operation_logger.start()
@ -816,8 +815,8 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
# Execute remove script # Execute remove script
operation_logger_remove = OperationLogger('remove_on_failed_install', operation_logger_remove = OperationLogger('remove_on_failed_install',
[('app', app_instance_name)], [('app', app_instance_name)],
env=env_dict_remove) env=env_dict_remove)
operation_logger_remove.start() operation_logger_remove.start()
remove_retcode = hook_exec( remove_retcode = hook_exec(
@ -944,7 +943,6 @@ def app_addaccess(auth, apps, users=[]):
for app in apps: for app in apps:
app_settings = _get_app_settings(app) app_settings = _get_app_settings(app)
if not app_settings: if not app_settings:
continue continue
@ -957,7 +955,7 @@ def app_addaccess(auth, apps, users=[]):
# Start register change on system # Start register change on system
related_to = [('app', app)] related_to = [('app', app)]
operation_logger= OperationLogger('app_addaccess', related_to) operation_logger = OperationLogger('app_addaccess', related_to)
operation_logger.start() operation_logger.start()
allowed_users = set() allowed_users = set()
@ -1020,7 +1018,7 @@ def app_removeaccess(auth, apps, users=[]):
# Start register change on system # Start register change on system
related_to = [('app', app)] related_to = [('app', app)]
operation_logger= OperationLogger('app_removeaccess', related_to) operation_logger = OperationLogger('app_removeaccess', related_to)
operation_logger.start() operation_logger.start()
if remove_all: if remove_all:
@ -1034,7 +1032,7 @@ def app_removeaccess(auth, apps, users=[]):
if allowed_user not in users: if allowed_user not in users:
allowed_users.add(allowed_user) allowed_users.add(allowed_user)
operation_logger.related_to += [ ('user', x) for x in allowed_users ] operation_logger.related_to += [('user', x) for x in allowed_users]
operation_logger.flush() operation_logger.flush()
new_users = ','.join(allowed_users) new_users = ','.join(allowed_users)
app_setting(app, 'allowed_users', new_users) app_setting(app, 'allowed_users', new_users)
@ -1069,7 +1067,7 @@ def app_clearaccess(auth, apps):
# Start register change on system # Start register change on system
related_to = [('app', app)] related_to = [('app', app)]
operation_logger= OperationLogger('app_clearaccess', related_to) operation_logger = OperationLogger('app_clearaccess', related_to)
operation_logger.start() operation_logger.start()
if 'mode' in app_settings: if 'mode' in app_settings:
@ -1126,7 +1124,7 @@ def app_makedefault(operation_logger, auth, app, domain=None):
if domain is None: if domain is None:
domain = app_domain domain = app_domain
operation_logger.related_to.append(('domain',domain)) operation_logger.related_to.append(('domain', domain))
elif domain not in domain_list(auth)['domains']: elif domain not in domain_list(auth)['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
@ -1218,7 +1216,7 @@ def app_register_url(auth, app, domain, path):
# This line can't be moved on top of file, otherwise it creates an infinite # This line can't be moved on top of file, otherwise it creates an infinite
# loop of import with tools.py... # loop of import with tools.py...
from domain import _get_conflicting_apps, _normalize_domain_path from .domain import _get_conflicting_apps, _normalize_domain_path
domain, path = _normalize_domain_path(domain, path) domain, path = _normalize_domain_path(domain, path)
@ -1569,10 +1567,10 @@ def app_config_show_panel(app):
parsed_values[key] = value parsed_values[key] = value
return_code = hook_exec(config_script, return_code = hook_exec(config_script,
args=["show"], args=["show"],
env=env, env=env,
stdout_callback=parse_stdout, stdout_callback=parse_stdout,
) )
if return_code != 0: if return_code != 0:
raise Exception("script/config show return value code: %s (considered as an error)", return_code) raise Exception("script/config show return value code: %s (considered as an error)", return_code)
@ -1656,9 +1654,9 @@ def app_config_apply(app, args):
logger.warning("Ignore key '%s' from arguments because it is not in the config", key) logger.warning("Ignore key '%s' from arguments because it is not in the config", key)
return_code = hook_exec(config_script, return_code = hook_exec(config_script,
args=["apply"], args=["apply"],
env=env, env=env,
) )
if return_code != 0: if return_code != 0:
raise Exception("'script/config apply' return value code: %s (considered as an error)", return_code) raise Exception("'script/config apply' return value code: %s (considered as an error)", return_code)
@ -2185,7 +2183,6 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
elif arg_type == 'password': elif arg_type == 'password':
msignals.display(m18n.n('good_practices_about_user_password')) msignals.display(m18n.n('good_practices_about_user_password'))
try: try:
input_string = msignals.prompt(ask_string, is_password) input_string = msignals.prompt(ask_string, is_password)
except NotImplementedError: except NotImplementedError:
@ -2385,7 +2382,7 @@ def _install_appslist_fetch_cron():
with open(cron_job_file, "w") as f: with open(cron_job_file, "w") as f:
f.write('\n'.join(cron_job)) f.write('\n'.join(cron_job))
_set_permissions(cron_job_file, "root", "root", 0755) _set_permissions(cron_job_file, "root", "root", 0o755)
# FIXME - Duplicate from certificate.py, should be moved into a common helper # FIXME - Duplicate from certificate.py, should be moved into a common helper
@ -2431,7 +2428,7 @@ def _write_appslist_list(appslist_lists):
json.dump(appslist_lists, f) json.dump(appslist_lists, f)
except Exception as e: except Exception as e:
raise YunohostError("Error while writing list of appslist %s: %s" % raise YunohostError("Error while writing list of appslist %s: %s" %
(APPSLISTS_JSON, str(e)), raw_msg=True) (APPSLISTS_JSON, str(e)), raw_msg=True)
def _register_new_appslist(url, name): def _register_new_appslist(url, name):
@ -2541,7 +2538,7 @@ def _patch_php5(app_folder):
continue continue
c = "sed -i -e 's@/etc/php5@/etc/php/7.0@g' " \ c = "sed -i -e 's@/etc/php5@/etc/php/7.0@g' " \
"-e 's@/var/run/php5-fpm@/var/run/php/php7.0-fpm@g' " \ "-e 's@/var/run/php5-fpm@/var/run/php/php7.0-fpm@g' " \
"-e 's@php5@php7.0@g' " \ "-e 's@php5@php7.0@g' " \
"%s" % filename "%s" % filename
os.system(c) os.system(c)

View file

@ -52,6 +52,7 @@ from yunohost.monitor import binary_to_human
from yunohost.tools import tools_postinstall from yunohost.tools import tools_postinstall
from yunohost.service import service_regen_conf from yunohost.service import service_regen_conf
from yunohost.log import OperationLogger from yunohost.log import OperationLogger
from functools import reduce
BACKUP_PATH = '/home/yunohost.backup' BACKUP_PATH = '/home/yunohost.backup'
ARCHIVES_PATH = '%s/archives' % BACKUP_PATH ARCHIVES_PATH = '%s/archives' % BACKUP_PATH
@ -63,6 +64,7 @@ logger = getActionLogger('yunohost.backup')
class BackupRestoreTargetsManager(object): class BackupRestoreTargetsManager(object):
""" """
BackupRestoreTargetsManager manage the targets BackupRestoreTargetsManager manage the targets
in BackupManager and RestoreManager in BackupManager and RestoreManager
@ -176,6 +178,7 @@ class BackupRestoreTargetsManager(object):
class BackupManager(): class BackupManager():
""" """
This class collect files to backup in a list and apply one or several This class collect files to backup in a list and apply one or several
backup method on it. backup method on it.
@ -267,9 +270,9 @@ class BackupManager():
self.work_dir = os.path.join(BACKUP_PATH, 'tmp', name) self.work_dir = os.path.join(BACKUP_PATH, 'tmp', name)
self._init_work_dir() self._init_work_dir()
########################################################################### #
# Misc helpers # # Misc helpers #
########################################################################### #
@property @property
def info(self): def info(self):
@ -321,16 +324,16 @@ class BackupManager():
# FIXME replace isdir by exists ? manage better the case where the path # FIXME replace isdir by exists ? manage better the case where the path
# exists # exists
if not os.path.isdir(self.work_dir): if not os.path.isdir(self.work_dir):
filesystem.mkdir(self.work_dir, 0750, parents=True, uid='admin') filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
elif self.is_tmp_work_dir: elif self.is_tmp_work_dir:
logger.debug("temporary directory for backup '%s' already exists", logger.debug("temporary directory for backup '%s' already exists",
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 YunohostError('backup_output_directory_not_empty') raise YunohostError('backup_output_directory_not_empty')
########################################################################### #
# Backup target management # # Backup target management #
########################################################################### #
def set_system_targets(self, system_parts=[]): def set_system_targets(self, system_parts=[]):
""" """
@ -380,9 +383,9 @@ 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" #
########################################################################### #
def _import_to_list_to_backup(self, tmp_csv): def _import_to_list_to_backup(self, tmp_csv):
""" """
@ -465,9 +468,9 @@ 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 #
########################################################################### #
def collect_files(self): def collect_files(self):
""" """
@ -602,7 +605,7 @@ class BackupManager():
restore_hooks_dir = os.path.join(self.work_dir, "hooks", "restore") restore_hooks_dir = os.path.join(self.work_dir, "hooks", "restore")
if not os.path.exists(restore_hooks_dir): if not os.path.exists(restore_hooks_dir):
filesystem.mkdir(restore_hooks_dir, mode=0750, filesystem.mkdir(restore_hooks_dir, mode=0o750,
parents=True, uid='admin') parents=True, uid='admin')
restore_hooks = hook_list("restore")["hooks"] restore_hooks = hook_list("restore")["hooks"]
@ -668,7 +671,7 @@ class BackupManager():
logger.debug(m18n.n('backup_running_app_script', app=app)) logger.debug(m18n.n('backup_running_app_script', app=app))
try: try:
# Prepare backup directory for the app # Prepare backup directory for the app
filesystem.mkdir(tmp_app_bkp_dir, 0750, True, uid='admin') filesystem.mkdir(tmp_app_bkp_dir, 0o750, True, uid='admin')
# Copy the app settings to be able to call _common.sh # Copy the app settings to be able to call _common.sh
shutil.copytree(app_setting_path, settings_dir) shutil.copytree(app_setting_path, settings_dir)
@ -702,9 +705,9 @@ 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 #
########################################################################### #
def add(self, method): def add(self, method):
""" """
@ -776,6 +779,7 @@ class BackupManager():
class RestoreManager(): class RestoreManager():
""" """
RestoreManager allow to restore a past backup archive RestoreManager allow to restore a past backup archive
@ -824,9 +828,9 @@ class RestoreManager():
self.method = BackupMethod.create(method) self.method = BackupMethod.create(method)
self.targets = BackupRestoreTargetsManager() self.targets = BackupRestoreTargetsManager()
########################################################################### #
# Misc helpers # # Misc helpers #
########################################################################### #
@property @property
def success(self): def success(self):
@ -876,7 +880,7 @@ class RestoreManager():
domain = f.readline().rstrip() domain = f.readline().rstrip()
except IOError: except IOError:
logger.debug("unable to retrieve current_host from the backup", logger.debug("unable to retrieve current_host from the backup",
exc_info=1) exc_info=1)
# FIXME include the current_host by default ? # FIXME include the current_host by default ?
raise YunohostError('backup_invalid_archive') raise YunohostError('backup_invalid_archive')
@ -902,9 +906,9 @@ 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 #
########################################################################### #
def set_system_targets(self, system_parts=[]): def set_system_targets(self, system_parts=[]):
""" """
@ -980,9 +984,9 @@ class RestoreManager():
self.info['apps'].keys(), self.info['apps'].keys(),
unknown_error) unknown_error)
########################################################################### #
# Archive mounting # # Archive mounting #
########################################################################### #
def mount(self): def mount(self):
""" """
@ -1023,9 +1027,9 @@ class RestoreManager():
self._read_info_files() self._read_info_files()
########################################################################### #
# Space computation / checks # # Space computation / checks #
########################################################################### #
def _compute_needed_space(self): def _compute_needed_space(self):
""" """
@ -1082,13 +1086,13 @@ class RestoreManager():
return True return True
elif free_space > needed_space: elif free_space > needed_space:
# TODO Add --force options to avoid the error raising # TODO Add --force options to avoid the error raising
raise YunohostError('restore_may_be_not_enough_disk_space', free_space=free_space, needed_space=needed_space, margin=margin) raise YunohostError('restore_may_be_not_enough_disk_space', free_space=free_space, needed_space=needed_space, margin=margin)
else: else:
raise YunohostError('restore_not_enough_disk_space', free_space=free_space, needed_space=needed_space, margin=margin) raise YunohostError('restore_not_enough_disk_space', free_space=free_space, needed_space=needed_space, margin=margin)
########################################################################### #
# "Actual restore" (reverse step of the backup collect part) # # "Actual restore" (reverse step of the backup collect part) #
########################################################################### #
def restore(self): def restore(self):
""" """
@ -1104,7 +1108,6 @@ class RestoreManager():
# Apply dirty patch to redirect php5 file on php7 # Apply dirty patch to redirect php5 file on php7
self._patch_backup_csv_file() self._patch_backup_csv_file()
self._restore_system() self._restore_system()
self._restore_apps() self._restore_apps()
finally: finally:
@ -1130,7 +1133,7 @@ class RestoreManager():
contains_php5 = True contains_php5 = True
row['source'] = row['source'].replace('/etc/php5', '/etc/php/7.0') \ row['source'] = row['source'].replace('/etc/php5', '/etc/php/7.0') \
.replace('/var/run/php5-fpm', '/var/run/php/php7.0-fpm') \ .replace('/var/run/php5-fpm', '/var/run/php/php7.0-fpm') \
.replace('php5','php7') .replace('php5', 'php7')
newlines.append(row) newlines.append(row)
except (IOError, OSError, csv.Error) as e: except (IOError, OSError, csv.Error) as e:
@ -1260,7 +1263,7 @@ class RestoreManager():
# Check if the app has a restore script # Check if the app has a restore script
app_restore_script_in_archive = os.path.join(app_scripts_in_archive, app_restore_script_in_archive = os.path.join(app_scripts_in_archive,
'restore') 'restore')
if not os.path.isfile(app_restore_script_in_archive): if not os.path.isfile(app_restore_script_in_archive):
logger.warning(m18n.n('unrestore_app', app=app_instance_name)) logger.warning(m18n.n('unrestore_app', app=app_instance_name))
self.targets.set_result("apps", app_instance_name, "Warning") self.targets.set_result("apps", app_instance_name, "Warning")
@ -1273,7 +1276,7 @@ class RestoreManager():
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, 0o400, 0o400, True)
filesystem.chown(app_scripts_new_path, 'admin', None, True) filesystem.chown(app_scripts_new_path, 'admin', None, True)
# Copy the app scripts to a writable temporary folder # Copy the app scripts to a writable temporary folder
@ -1281,7 +1284,7 @@ class RestoreManager():
# in the backup method ? # in the backup method ?
tmp_folder_for_app_restore = tempfile.mkdtemp(prefix='restore') tmp_folder_for_app_restore = tempfile.mkdtemp(prefix='restore')
copytree(app_scripts_in_archive, tmp_folder_for_app_restore) copytree(app_scripts_in_archive, tmp_folder_for_app_restore)
filesystem.chmod(tmp_folder_for_app_restore, 0550, 0550, True) filesystem.chmod(tmp_folder_for_app_restore, 0o550, 0o550, True)
filesystem.chown(tmp_folder_for_app_restore, 'admin', None, True) filesystem.chown(tmp_folder_for_app_restore, 'admin', None, True)
restore_script = os.path.join(tmp_folder_for_app_restore, 'restore') restore_script = os.path.join(tmp_folder_for_app_restore, 'restore')
@ -1298,7 +1301,7 @@ class RestoreManager():
raise_on_error=True, raise_on_error=True,
env=env_dict) env=env_dict)
except: except:
msg = m18n.n('restore_app_failed',app=app_instance_name) msg = m18n.n('restore_app_failed', app=app_instance_name)
logger.exception(msg) logger.exception(msg)
operation_logger.error(msg) operation_logger.error(msg)
@ -1314,8 +1317,8 @@ class RestoreManager():
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
operation_logger = OperationLogger('remove_on_failed_restore', operation_logger = OperationLogger('remove_on_failed_restore',
[('app', app_instance_name)], [('app', app_instance_name)],
env=env_dict_remove) env=env_dict_remove)
operation_logger.start() operation_logger.start()
# Execute remove script # Execute remove script
@ -1359,12 +1362,13 @@ class RestoreManager():
return env_var return env_var
############################################################################### #
# 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
restore a list of files. restore a list of files.
@ -1637,7 +1641,7 @@ class BackupMethod(object):
if size > MB_ALLOWED_TO_ORGANIZE: if size > MB_ALLOWED_TO_ORGANIZE:
try: try:
i = msignals.prompt(m18n.n('backup_ask_for_copying_if_needed', i = msignals.prompt(m18n.n('backup_ask_for_copying_if_needed',
answers='y/N', size=str(size))) answers='y/N', size=str(size)))
except NotImplemented: except NotImplemented:
raise YunohostError('backup_unable_to_organize_files') raise YunohostError('backup_unable_to_organize_files')
else: else:
@ -1646,7 +1650,7 @@ class BackupMethod(object):
# Copy unbinded path # Copy unbinded path
logger.debug(m18n.n('backup_copying_to_organize_the_archive', logger.debug(m18n.n('backup_copying_to_organize_the_archive',
size=str(size))) size=str(size)))
for path in paths_needed_to_be_copied: for path in paths_needed_to_be_copied:
dest = os.path.join(self.work_dir, path['dest']) dest = os.path.join(self.work_dir, path['dest'])
if os.path.isdir(path['source']): if os.path.isdir(path['source']):
@ -1686,6 +1690,7 @@ class BackupMethod(object):
class CopyBackupMethod(BackupMethod): 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
@ -1712,7 +1717,7 @@ class CopyBackupMethod(BackupMethod):
dest_parent = os.path.dirname(dest) dest_parent = os.path.dirname(dest)
if not os.path.exists(dest_parent): if not os.path.exists(dest_parent):
filesystem.mkdir(dest_parent, 0750, True, uid='admin') filesystem.mkdir(dest_parent, 0o750, True, uid='admin')
if os.path.isdir(source): if os.path.isdir(source):
shutil.copytree(source, dest) shutil.copytree(source, dest)
@ -1747,6 +1752,7 @@ class CopyBackupMethod(BackupMethod):
class TarBackupMethod(BackupMethod): class TarBackupMethod(BackupMethod):
""" """
This class compress all files to backup in archive. This class compress all files to backup in archive.
""" """
@ -1777,7 +1783,7 @@ class TarBackupMethod(BackupMethod):
""" """
if not os.path.exists(self.repo): if not os.path.exists(self.repo):
filesystem.mkdir(self.repo, 0750, parents=True, uid='admin') filesystem.mkdir(self.repo, 0o750, parents=True, uid='admin')
# Check free space in output # Check free space in output
self._check_is_enough_free_space() self._check_is_enough_free_space()
@ -1895,6 +1901,7 @@ class BorgBackupMethod(BackupMethod):
class CustomBackupMethod(BackupMethod): class CustomBackupMethod(BackupMethod):
""" """
This class use a bash script/hook "backup_method" to do the This class use a bash script/hook "backup_method" to do the
backup/restore operations. A user can add his own hook inside backup/restore operations. A user can add his own hook inside
@ -1958,9 +1965,9 @@ class CustomBackupMethod(BackupMethod):
self.manager.description] self.manager.description]
############################################################################### #
# "Front-end" # # "Front-end" #
############################################################################### #
def backup_create(name=None, description=None, methods=[], def backup_create(name=None, description=None, methods=[],
output_directory=None, no_compress=False, output_directory=None, no_compress=False,
@ -1980,9 +1987,9 @@ def backup_create(name=None, description=None, methods=[],
# TODO: Add a 'clean' argument to clean output directory # TODO: Add a 'clean' argument to clean output directory
########################################################################### #
# Validate / parse arguments # # Validate / parse arguments #
########################################################################### #
# Validate there is no archive with the same name # Validate there is no archive with the same name
if name and name in backup_list()['archives']: if name and name in backup_list()['archives']:
@ -1995,7 +2002,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 YunohostError('backup_output_directory_forbidden') raise YunohostError('backup_output_directory_forbidden')
# Check that output directory is empty # Check that output directory is empty
@ -2017,9 +2024,9 @@ def backup_create(name=None, description=None, methods=[],
system = [] system = []
apps = [] apps = []
########################################################################### #
# Intialize # # Intialize #
########################################################################### #
# Create yunohost archives directory if it does not exists # Create yunohost archives directory if it does not exists
_create_archive_dir() _create_archive_dir()
@ -2044,9 +2051,9 @@ def backup_create(name=None, description=None, methods=[],
backup_manager.set_system_targets(system) backup_manager.set_system_targets(system)
backup_manager.set_apps_targets(apps) backup_manager.set_apps_targets(apps)
########################################################################### #
# Collect files and put them in the archive # # Collect files and put them in the archive #
########################################################################### #
# Collect files to be backup (by calling app backup script / system hooks) # Collect files to be backup (by calling app backup script / system hooks)
backup_manager.collect_files() backup_manager.collect_files()
@ -2074,9 +2081,9 @@ def backup_restore(auth, name, system=[], apps=[], force=False):
apps -- List of application names to restore apps -- List of application names to restore
""" """
########################################################################### #
# Validate / parse arguments # # Validate / parse arguments #
########################################################################### #
# If no --system or --apps given, restore everything # If no --system or --apps given, restore everything
if system is None and apps is None: if system is None and apps is None:
@ -2105,9 +2112,9 @@ def backup_restore(auth, name, system=[], apps=[], force=False):
# TODO Partial app restore could not work if ldap is not restored before # TODO Partial app restore could not work if ldap is not restored before
# TODO repair mysql if broken and it's a complete restore # TODO repair mysql if broken and it's a complete restore
########################################################################### #
# Initialize # # Initialize #
########################################################################### #
restore_manager = RestoreManager(name) restore_manager = RestoreManager(name)
@ -2116,9 +2123,9 @@ def backup_restore(auth, name, system=[], apps=[], force=False):
restore_manager.assert_enough_free_space() restore_manager.assert_enough_free_space()
########################################################################### #
# Mount the archive then call the restore for each system part / app # # Mount the archive then call the restore for each system part / app #
########################################################################### #
restore_manager.mount() restore_manager.mount()
restore_manager.restore() restore_manager.restore()
@ -2156,7 +2163,7 @@ def backup_list(with_info=False, human_readable=False):
except ValueError: except ValueError:
continue continue
result.append(name) result.append(name)
result.sort(key=lambda x: os.path.getctime(os.path.join(ARCHIVES_PATH, x+".tar.gz"))) result.sort(key=lambda x: os.path.getctime(os.path.join(ARCHIVES_PATH, x + ".tar.gz")))
if result and with_info: if result and with_info:
d = OrderedDict() d = OrderedDict()
@ -2194,7 +2201,7 @@ def backup_info(name, with_details=False, human_readable=False):
# Raise exception if link is broken (e.g. on unmounted external storage) # Raise exception if link is broken (e.g. on unmounted external storage)
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)
info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name) info_file = "%s/%s.info.json" % (ARCHIVES_PATH, name)
@ -2259,7 +2266,7 @@ def backup_delete(name):
""" """
if name not in backup_list()["archives"]: if name not in backup_list()["archives"]:
raise YunohostError('backup_archive_name_unknown', raise YunohostError('backup_archive_name_unknown',
name=name) name=name)
hook_callback('pre_backup_delete', args=[name]) hook_callback('pre_backup_delete', args=[name])
@ -2277,9 +2284,9 @@ def backup_delete(name):
logger.success(m18n.n('backup_deleted')) logger.success(m18n.n('backup_deleted'))
############################################################################### #
# Misc helpers # # Misc helpers #
############################################################################### #
def _create_archive_dir(): def _create_archive_dir():
@ -2288,7 +2295,7 @@ def _create_archive_dir():
if os.path.lexists(ARCHIVES_PATH): if os.path.lexists(ARCHIVES_PATH):
raise YunohostError('backup_output_symlink_dir_broken', path=ARCHIVES_PATH) raise YunohostError('backup_output_symlink_dir_broken', path=ARCHIVES_PATH)
os.mkdir(ARCHIVES_PATH, 0750) os.mkdir(ARCHIVES_PATH, 0o750)
def _call_for_each_path(self, callback, csv_path=None): def _call_for_each_path(self, callback, csv_path=None):

View file

@ -80,9 +80,9 @@ DNS_RESOLVERS = [
"80.67.188.188" # LDN "80.67.188.188" # LDN
] ]
############################################################################### #
# Front-end stuff # # Front-end stuff #
############################################################################### #
def certificate_status(auth, domain_list, full=False): def certificate_status(auth, domain_list, full=False):
@ -149,7 +149,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
for domain in domain_list: for domain in domain_list:
operation_logger = OperationLogger('selfsigned_cert_install', [('domain', domain)], operation_logger = OperationLogger('selfsigned_cert_install', [('domain', domain)],
args={'force': force}) args={'force': force})
# Paths of files and folder we'll need # Paths of files and folder we'll need
date_tag = datetime.utcnow().strftime("%Y%m%d.%H%M%S") date_tag = datetime.utcnow().strftime("%Y%m%d.%H%M%S")
@ -215,10 +215,10 @@ def _certificate_install_selfsigned(domain_list, force=False):
crt_pem.write(ca_pem.read()) crt_pem.write(ca_pem.read())
# Set appropriate permissions # Set appropriate permissions
_set_permissions(new_cert_folder, "root", "root", 0755) _set_permissions(new_cert_folder, "root", "root", 0o755)
_set_permissions(key_file, "root", "ssl-cert", 0640) _set_permissions(key_file, "root", "ssl-cert", 0o640)
_set_permissions(crt_file, "root", "ssl-cert", 0640) _set_permissions(crt_file, "root", "ssl-cert", 0o640)
_set_permissions(conf_file, "root", "root", 0600) _set_permissions(conf_file, "root", "root", 0o600)
# Actually enable the certificate we created # Actually enable the certificate we created
_enable_certificate(domain, new_cert_folder) _enable_certificate(domain, new_cert_folder)
@ -273,8 +273,8 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
for domain in domain_list: for domain in domain_list:
operation_logger = OperationLogger('letsencrypt_cert_install', [('domain', domain)], operation_logger = OperationLogger('letsencrypt_cert_install', [('domain', domain)],
args={'force': force, 'no_checks': no_checks, args={'force': force, 'no_checks': no_checks,
'staging': staging}) 'staging': staging})
logger.info( logger.info(
"Now attempting install of certificate for domain %s!", domain) "Now attempting install of certificate for domain %s!", domain)
@ -298,6 +298,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
logger.error(msg) logger.error(msg)
operation_logger.error(msg) operation_logger.error(msg)
def certificate_renew(auth, domain_list, force=False, no_checks=False, email=False, staging=False): def certificate_renew(auth, domain_list, force=False, no_checks=False, email=False, staging=False):
""" """
Renew Let's Encrypt certificate for given domains (all by default) Renew Let's Encrypt certificate for given domains (all by default)
@ -367,8 +368,8 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal
for domain in domain_list: for domain in domain_list:
operation_logger = OperationLogger('letsencrypt_cert_renew', [('domain', domain)], operation_logger = OperationLogger('letsencrypt_cert_renew', [('domain', domain)],
args={'force': force, 'no_checks': no_checks, args={'force': force, 'no_checks': no_checks,
'staging': staging, 'email': email}) 'staging': staging, 'email': email})
logger.info( logger.info(
"Now attempting renewing of certificate for domain %s !", domain) "Now attempting renewing of certificate for domain %s !", domain)
@ -401,9 +402,10 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal
logger.error("Sending email with details to root ...") logger.error("Sending email with details to root ...")
_email_renewing_failed(domain, e, stack.getvalue()) _email_renewing_failed(domain, e, stack.getvalue())
############################################################################### #
# Back-end stuff # # Back-end stuff #
############################################################################### #
def _install_cron(): def _install_cron():
cron_job_file = "/etc/cron.daily/yunohost-certificate-renew" cron_job_file = "/etc/cron.daily/yunohost-certificate-renew"
@ -412,7 +414,7 @@ def _install_cron():
f.write("#!/bin/bash\n") f.write("#!/bin/bash\n")
f.write("yunohost domain cert-renew --email\n") f.write("yunohost domain cert-renew --email\n")
_set_permissions(cron_job_file, "root", "root", 0755) _set_permissions(cron_job_file, "root", "root", 0o755)
def _email_renewing_failed(domain, exception_message, stack): def _email_renewing_failed(domain, exception_message, stack):
@ -517,8 +519,8 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
if not os.path.exists(TMP_FOLDER): if not os.path.exists(TMP_FOLDER):
os.makedirs(TMP_FOLDER) os.makedirs(TMP_FOLDER)
_set_permissions(WEBROOT_FOLDER, "root", "www-data", 0650) _set_permissions(WEBROOT_FOLDER, "root", "www-data", 0o650)
_set_permissions(TMP_FOLDER, "root", "root", 0640) _set_permissions(TMP_FOLDER, "root", "root", 0o640)
# Regen conf for dnsmasq if needed # Regen conf for dnsmasq if needed
_regen_dnsmasq_if_needed() _regen_dnsmasq_if_needed()
@ -529,7 +531,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
domain_key_file = "%s/%s.pem" % (TMP_FOLDER, domain) domain_key_file = "%s/%s.pem" % (TMP_FOLDER, domain)
_generate_key(domain_key_file) _generate_key(domain_key_file)
_set_permissions(domain_key_file, "root", "ssl-cert", 0640) _set_permissions(domain_key_file, "root", "ssl-cert", 0o640)
_prepare_certificate_signing_request(domain, domain_key_file, TMP_FOLDER) _prepare_certificate_signing_request(domain, domain_key_file, TMP_FOLDER)
@ -563,7 +565,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
raise YunohostError('certmanager_cert_signing_failed') raise YunohostError('certmanager_cert_signing_failed')
import requests # lazy loading this module for performance reasons import requests # lazy loading this module for performance reasons
try: try:
intermediate_certificate = requests.get(INTERMEDIATE_CERTIFICATE_URL, timeout=30).text intermediate_certificate = requests.get(INTERMEDIATE_CERTIFICATE_URL, timeout=30).text
except requests.exceptions.Timeout as e: except requests.exceptions.Timeout as e:
@ -585,12 +587,12 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
os.makedirs(new_cert_folder) os.makedirs(new_cert_folder)
_set_permissions(new_cert_folder, "root", "root", 0655) _set_permissions(new_cert_folder, "root", "root", 0o655)
# Move the private key # Move the private key
domain_key_file_finaldest = os.path.join(new_cert_folder, "key.pem") domain_key_file_finaldest = os.path.join(new_cert_folder, "key.pem")
shutil.move(domain_key_file, domain_key_file_finaldest) shutil.move(domain_key_file, domain_key_file_finaldest)
_set_permissions(domain_key_file_finaldest, "root", "ssl-cert", 0640) _set_permissions(domain_key_file_finaldest, "root", "ssl-cert", 0o640)
# Write the cert # Write the cert
domain_cert_file = os.path.join(new_cert_folder, "crt.pem") domain_cert_file = os.path.join(new_cert_folder, "crt.pem")
@ -599,7 +601,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
f.write(signed_certificate) f.write(signed_certificate)
f.write(intermediate_certificate) f.write(intermediate_certificate)
_set_permissions(domain_cert_file, "root", "ssl-cert", 0640) _set_permissions(domain_cert_file, "root", "ssl-cert", 0o640)
if staging: if staging:
return return
@ -614,7 +616,7 @@ def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False):
def _prepare_certificate_signing_request(domain, key_file, output_folder): def _prepare_certificate_signing_request(domain, key_file, output_folder):
from OpenSSL import crypto # lazy loading this module for performance reasons from OpenSSL import crypto # lazy loading this module for performance reasons
# Init a request # Init a request
csr = crypto.X509Req() csr = crypto.X509Req()
@ -645,7 +647,7 @@ def _get_status(domain):
if not os.path.isfile(cert_file): if not os.path.isfile(cert_file):
raise YunohostError('certmanager_no_cert_file', domain=domain, file=cert_file) raise YunohostError('certmanager_no_cert_file', domain=domain, file=cert_file)
from OpenSSL import crypto # lazy loading this module for performance reasons from OpenSSL import crypto # lazy loading this module for performance reasons
try: try:
cert = crypto.load_certificate( cert = crypto.load_certificate(
crypto.FILETYPE_PEM, open(cert_file).read()) crypto.FILETYPE_PEM, open(cert_file).read())
@ -735,19 +737,19 @@ def _get_status(domain):
"ACME_eligible": ACME_eligible "ACME_eligible": ACME_eligible
} }
############################################################################### #
# Misc small stuff ... # # Misc small stuff ... #
############################################################################### #
def _generate_account_key(): def _generate_account_key():
logger.debug("Generating account key ...") logger.debug("Generating account key ...")
_generate_key(ACCOUNT_KEY_FILE) _generate_key(ACCOUNT_KEY_FILE)
_set_permissions(ACCOUNT_KEY_FILE, "root", "root", 0400) _set_permissions(ACCOUNT_KEY_FILE, "root", "root", 0o400)
def _generate_key(destination_path): def _generate_key(destination_path):
from OpenSSL import crypto # lazy loading this module for performance reasons from OpenSSL import crypto # lazy loading this module for performance reasons
k = crypto.PKey() k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, KEY_SIZE) k.generate_key(crypto.TYPE_RSA, KEY_SIZE)
@ -836,7 +838,7 @@ def _dns_ip_match_public_ip(public_ip, domain):
def _domain_is_accessible_through_HTTP(ip, domain): def _domain_is_accessible_through_HTTP(ip, domain):
import requests # lazy loading this module for performance reasons import requests # lazy loading this module for performance reasons
try: try:
requests.head("http://" + ip, headers={"Host": domain}, timeout=10) requests.head("http://" + ip, headers={"Host": domain}, timeout=10)
except requests.exceptions.Timeout as e: except requests.exceptions.Timeout as e:

View file

@ -3,7 +3,9 @@ import glob
from yunohost.tools import Migration from yunohost.tools import Migration
from moulinette.utils.filesystem import chown from moulinette.utils.filesystem import chown
class MyMigration(Migration): class MyMigration(Migration):
"Change certificates group permissions from 'metronome' to 'ssl-cert'" "Change certificates group permissions from 'metronome' to 'ssl-cert'"
all_certificate_files = glob.glob("/etc/yunohost/certs/*/*.pem") all_certificate_files = glob.glob("/etc/yunohost/certs/*/*.pem")

View file

@ -16,6 +16,7 @@ logger = getActionLogger('yunohost.migration')
class MyMigration(Migration): class MyMigration(Migration):
"Migrate Dyndns stuff from MD5 TSIG to SHA512 TSIG" "Migrate Dyndns stuff from MD5 TSIG to SHA512 TSIG"
def backward(self): def backward(self):
@ -70,7 +71,7 @@ class MyMigration(Migration):
os.system("mv /etc/yunohost/dyndns/*+165* /tmp") os.system("mv /etc/yunohost/dyndns/*+165* /tmp")
raise YunohostError('migrate_tsig_failed', domain=domain, raise YunohostError('migrate_tsig_failed', domain=domain,
error_code=str(r.status_code), error=error) error_code=str(r.status_code), error=error)
# remove old certificates # remove old certificates
os.system("mv /etc/yunohost/dyndns/*+157* /tmp") os.system("mv /etc/yunohost/dyndns/*+157* /tmp")
@ -87,4 +88,3 @@ class MyMigration(Migration):
logger.info(m18n.n('migrate_tsig_end')) logger.info(m18n.n('migrate_tsig_end'))
return return

View file

@ -24,6 +24,7 @@ YUNOHOST_PACKAGES = ["yunohost", "yunohost-admin", "moulinette", "ssowat"]
class MyMigration(Migration): class MyMigration(Migration):
"Upgrade the system to Debian Stretch and Yunohost 3.0" "Upgrade the system to Debian Stretch and Yunohost 3.0"
mode = "manual" mode = "manual"
@ -168,11 +169,11 @@ class MyMigration(Migration):
# - switch yunohost's repo to forge # - switch yunohost's repo to forge
for f in sources_list: for f in sources_list:
command = "sed -i -e 's@ jessie @ stretch @g' " \ command = "sed -i -e 's@ jessie @ stretch @g' " \
"-e '/backports/ s@^#*@#@' " \ "-e '/backports/ s@^#*@#@' " \
"-e 's@ jessie/updates @ stretch/updates @g' " \ "-e 's@ jessie/updates @ stretch/updates @g' " \
"-e 's@ jessie-updates @ stretch-updates @g' " \ "-e 's@ jessie-updates @ stretch-updates @g' " \
"-e 's@repo.yunohost@forge.yunohost@g' " \ "-e 's@repo.yunohost@forge.yunohost@g' " \
"{}".format(f) "{}".format(f)
os.system(command) os.system(command)
def get_apps_equivs_packages(self): def get_apps_equivs_packages(self):
@ -286,7 +287,7 @@ class MyMigration(Migration):
# Create tmp directory if it does not exists # Create tmp directory if it does not exists
tmp_dir = os.path.join("/tmp/", self.name) tmp_dir = os.path.join("/tmp/", self.name)
if not os.path.exists(tmp_dir): if not os.path.exists(tmp_dir):
os.mkdir(tmp_dir, 0700) os.mkdir(tmp_dir, 0o700)
for f in self.files_to_keep: for f in self.files_to_keep:
dest_file = f.strip('/').replace("/", "_") dest_file = f.strip('/').replace("/", "_")

View file

@ -19,6 +19,7 @@ MIGRATION_COMMENT = "; YunoHost note : this file was automatically moved from {}
class MyMigration(Migration): class MyMigration(Migration):
"Migrate php5-fpm 'pool' conf files to php7 stuff" "Migrate php5-fpm 'pool' conf files to php7 stuff"
def migrate(self): def migrate(self):
@ -58,7 +59,7 @@ class MyMigration(Migration):
_run_service_command("enable", "php7.0-fpm") _run_service_command("enable", "php7.0-fpm")
os.system("systemctl stop php5-fpm") os.system("systemctl stop php5-fpm")
os.system("systemctl disable php5-fpm") os.system("systemctl disable php5-fpm")
os.system("rm /etc/logrotate.d/php5-fpm") # We remove this otherwise the logrotate cron will be unhappy os.system("rm /etc/logrotate.d/php5-fpm") # We remove this otherwise the logrotate cron will be unhappy
# Get list of nginx conf file # Get list of nginx conf file
nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf") nginx_conf_files = glob.glob("/etc/nginx/conf.d/*.d/*.conf")

View file

@ -11,6 +11,7 @@ logger = getActionLogger('yunohost.migration')
class MyMigration(Migration): class MyMigration(Migration):
"Migrate DBs from Postgresql 9.4 to 9.6 after migrating to Stretch" "Migrate DBs from Postgresql 9.4 to 9.6 after migrating to Stretch"
def migrate(self): def migrate(self):

View file

@ -15,7 +15,9 @@ from yunohost.tools import Migration
logger = getActionLogger('yunohost.migration') logger = getActionLogger('yunohost.migration')
SMALL_PWD_LIST = ["yunohost", "olinuxino", "olinux", "raspberry", "admin", "root", "test", "rpi"] SMALL_PWD_LIST = ["yunohost", "olinuxino", "olinux", "raspberry", "admin", "root", "test", "rpi"]
class MyMigration(Migration): class MyMigration(Migration):
"Synchronize admin and root passwords" "Synchronize admin and root passwords"
def migrate(self): def migrate(self):

View file

@ -8,8 +8,10 @@ from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import mkdir, rm from moulinette.utils.filesystem import mkdir, rm
from yunohost.tools import Migration from yunohost.tools import Migration
from yunohost.service import service_regen_conf, _get_conf_hashes, \ from yunohost.service import service_regen_conf, \
_calculate_hash, _run_service_command _get_conf_hashes, \
_calculate_hash, \
_run_service_command
from yunohost.settings import settings_set from yunohost.settings import settings_set
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
@ -19,6 +21,7 @@ SSHD_CONF = '/etc/ssh/sshd_config'
class MyMigration(Migration): class MyMigration(Migration):
""" """
This is the first step of a couple of migrations that ensure SSH conf is This is the first step of a couple of migrations that ensure SSH conf is
managed by YunoHost (even if the "from_script" flag is present, which was managed by YunoHost (even if the "from_script" flag is present, which was
@ -48,7 +51,7 @@ class MyMigration(Migration):
# Create sshd_config.d dir # Create sshd_config.d dir
if not os.path.exists(SSHD_CONF + '.d'): if not os.path.exists(SSHD_CONF + '.d'):
mkdir(SSHD_CONF + '.d', 0755, uid='root', gid='root') mkdir(SSHD_CONF + '.d', 0o755, uid='root', gid='root')
# Here, we make it so that /etc/ssh/sshd_config is managed # Here, we make it so that /etc/ssh/sshd_config is managed
# by the regen conf (in particular in the case where the # by the regen conf (in particular in the case where the

View file

@ -3,7 +3,8 @@ import re
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.tools import Migration from yunohost.tools import Migration
from yunohost.service import service_regen_conf, _get_conf_hashes, \ from yunohost.service import service_regen_conf, \
_get_conf_hashes, \
_calculate_hash _calculate_hash
from yunohost.settings import settings_set, settings_get from yunohost.settings import settings_set, settings_get
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
@ -12,7 +13,9 @@ logger = getActionLogger('yunohost.migration')
SSHD_CONF = '/etc/ssh/sshd_config' SSHD_CONF = '/etc/ssh/sshd_config'
class MyMigration(Migration): class MyMigration(Migration):
""" """
In this second step, the admin is asked if it's okay to use In this second step, the admin is asked if it's okay to use
the recommended SSH configuration - which also implies the recommended SSH configuration - which also implies

View file

@ -115,8 +115,8 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix']) service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
app_ssowatconf(auth) app_ssowatconf(auth)
except Exception, e: except Exception as e:
from sys import exc_info; from sys import exc_info
t, v, tb = exc_info() t, v, tb = exc_info()
# Force domain removal silently # Force domain removal silently

View file

@ -104,7 +104,7 @@ def _dyndns_available(provider, domain):
except MoulinetteError as e: except MoulinetteError as e:
logger.error(str(e)) logger.error(str(e))
raise YunohostError('dyndns_could_not_check_available', raise YunohostError('dyndns_could_not_check_available',
domain=domain, provider=provider) domain=domain, provider=provider)
return r == u"Domain %s is available" % domain return r == u"Domain %s is available" % domain
@ -149,7 +149,7 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
with open(key_file) as f: with open(key_file) as f:
key = f.readline().strip().split(' ', 6)[-1] key = f.readline().strip().split(' ', 6)[-1]
import requests # lazy loading this module for performance reasons import requests # lazy loading this module for performance reasons
# Send subscription # Send subscription
try: try:
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30) r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
@ -211,7 +211,7 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
exception=e, exception=e,
number=migration.number, number=migration.number,
name=migration.name), name=migration.name),
exc_info=1) exc_info=1)
return return
# Extract 'host', e.g. 'nohost.me' from 'foo.nohost.me' # Extract 'host', e.g. 'nohost.me' from 'foo.nohost.me'
@ -225,7 +225,6 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
'zone %s' % host, 'zone %s' % host,
] ]
old_ipv4 = check_output("dig @%s +short %s" % (dyn_host, domain)).strip() or None old_ipv4 = check_output("dig @%s +short %s" % (dyn_host, domain)).strip() or None
old_ipv6 = check_output("dig @%s +short aaaa %s" % (dyn_host, domain)).strip() or None old_ipv6 = check_output("dig @%s +short aaaa %s" % (dyn_host, domain)).strip() or None
@ -252,7 +251,7 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
logger.info("Updated needed, going on...") logger.info("Updated needed, going on...")
dns_conf = _build_dns_conf(domain) dns_conf = _build_dns_conf(domain)
del dns_conf["extra"] # Ignore records from the 'extra' category del dns_conf["extra"] # Ignore records from the 'extra' category
# Delete the old records for all domain/subdomains # Delete the old records for all domain/subdomains
@ -273,7 +272,7 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None,
# should be muc.the.domain.tld. or the.domain.tld # should be muc.the.domain.tld. or the.domain.tld
if record["value"] == "@": if record["value"] == "@":
record["value"] = domain record["value"] = domain
record["value"] = record["value"].replace(";","\;") record["value"] = record["value"].replace(";", "\;")
action = "update add {name}.{domain}. {ttl} {type} {value}".format(domain=domain, **record) action = "update add {name}.{domain}. {ttl} {type} {value}".format(domain=domain, **record)
action = action.replace(" @.", " ") action = action.replace(" @.", " ")

View file

@ -374,10 +374,10 @@ def firewall_upnp(action='status', no_refresh=False):
try: try:
# Add new port mapping # Add new port mapping
upnpc.addportmapping(port, protocol, upnpc.lanaddr, upnpc.addportmapping(port, protocol, upnpc.lanaddr,
port, 'yunohost firewall: port %d' % port, '') port, 'yunohost firewall: port %d' % port, '')
except: except:
logger.debug('unable to add port %d using UPnP', logger.debug('unable to add port %d using UPnP',
port, exc_info=1) port, exc_info=1)
enabled = False enabled = False
if enabled != firewall['uPnP']['enabled']: if enabled != firewall['uPnP']['enabled']:

View file

@ -354,7 +354,7 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
# prepend environment variables # prepend environment variables
cmd = '{0} {1}'.format( cmd = '{0} {1}'.format(
' '.join(['{0}={1}'.format(k, shell_quote(v)) ' '.join(['{0}={1}'.format(k, shell_quote(v))
for k, v in env.items()]), cmd) for k, v in env.items()]), cmd)
command.append(cmd.format(script=cmd_script, args=cmd_args)) command.append(cmd.format(script=cmd_script, args=cmd_args))
if logger.isEnabledFor(log.DEBUG): if logger.isEnabledFor(log.DEBUG):
@ -369,8 +369,8 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
) )
if stdinfo: if stdinfo:
callbacks = ( callbacks[0], callbacks[1], callbacks = (callbacks[0], callbacks[1],
lambda l: logger.info(l.rstrip())) lambda l: logger.info(l.rstrip()))
logger.debug("About to run the command '%s'" % command) logger.debug("About to run the command '%s'" % command)

View file

@ -283,6 +283,7 @@ def is_unit_operation(entities=['app', 'domain', 'service', 'user'],
class OperationLogger(object): class OperationLogger(object):
""" """
Instances of this class represents unit operation done on the ynh instance. Instances of this class represents unit operation done on the ynh instance.
@ -423,7 +424,7 @@ class OperationLogger(object):
else: else:
if is_api: if is_api:
msg = "<strong>" + m18n.n('log_link_to_failed_log', msg = "<strong>" + m18n.n('log_link_to_failed_log',
name=self.name, desc=desc) + "</strong>" name=self.name, desc=desc) + "</strong>"
else: else:
msg = m18n.n('log_help_to_get_failed_log', name=self.name, msg = m18n.n('log_help_to_get_failed_log', name=self.name,
desc=desc) desc=desc)

View file

@ -288,7 +288,7 @@ def monitor_system(units=None, human_readable=False):
else: else:
raise YunohostError('unit_unknown', unit=u) raise YunohostError('unit_unknown', unit=u)
if len(units) == 1 and type(result[units[0]]) is not str: if len(units) == 1 and not isinstance(result[units[0]], str):
return result[units[0]] return result[units[0]]
return result return result
@ -404,7 +404,7 @@ def monitor_enable(with_stats=False):
""" """
from yunohost.service import (service_status, service_enable, from yunohost.service import (service_status, service_enable,
service_start) service_start)
glances = service_status('glances') glances = service_status('glances')
if glances['status'] != 'running': if glances['status'] != 'running':
@ -414,7 +414,7 @@ def monitor_enable(with_stats=False):
# Install crontab # Install crontab
if with_stats: if with_stats:
# day: every 5 min # week: every 1 h # month: every 4 h # # day: every 5 min # week: every 1 h # month: every 4 h #
rules = ('*/5 * * * * root {cmd} day >> /dev/null\n' rules = ('*/5 * * * * root {cmd} day >> /dev/null\n'
'3 * * * * root {cmd} week >> /dev/null\n' '3 * * * * root {cmd} week >> /dev/null\n'
'6 */4 * * * root {cmd} month >> /dev/null').format( '6 */4 * * * root {cmd} month >> /dev/null').format(
@ -431,7 +431,7 @@ def monitor_disable():
""" """
from yunohost.service import (service_status, service_disable, from yunohost.service import (service_status, service_disable,
service_stop) service_stop)
glances = service_status('glances') glances = service_status('glances')
if glances['status'] != 'inactive': if glances['status'] != 'inactive':

View file

@ -151,6 +151,7 @@ def service_stop(names):
raise YunohostError('service_stop_failed', service=name, logs=_get_journalctl_logs(name)) raise YunohostError('service_stop_failed', service=name, logs=_get_journalctl_logs(name))
logger.debug(m18n.n('service_already_stopped', service=name)) logger.debug(m18n.n('service_already_stopped', service=name))
@is_unit_operation() @is_unit_operation()
def service_enable(operation_logger, names): def service_enable(operation_logger, names):
""" """
@ -377,7 +378,7 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
if not names: if not names:
operation_logger.name_parameter_override = 'all' operation_logger.name_parameter_override = 'all'
elif len(names) != 1: elif len(names) != 1:
operation_logger.name_parameter_override = str(len(operation_logger.related_to))+'_services' operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
operation_logger.start() operation_logger.start()
# Clean pending conf directory # Clean pending conf directory
@ -389,7 +390,7 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
shutil.rmtree(os.path.join(PENDING_CONF_DIR, name), shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
ignore_errors=True) ignore_errors=True)
else: else:
filesystem.mkdir(PENDING_CONF_DIR, 0755, True) filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
# Format common hooks arguments # Format common hooks arguments
common_args = [1 if force else 0, 1 if dry_run else 0] common_args = [1 if force else 0, 1 if dry_run else 0]
@ -400,7 +401,7 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
def _pre_call(name, priority, path, args): def _pre_call(name, priority, path, args):
# create the pending conf directory for the service # create the pending conf directory for the service
service_pending_path = os.path.join(PENDING_CONF_DIR, name) service_pending_path = os.path.join(PENDING_CONF_DIR, name)
filesystem.mkdir(service_pending_path, 0755, True, uid='root') filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
# return the arguments to pass to the script # return the arguments to pass to the script
return pre_args + [service_pending_path, ] return pre_args + [service_pending_path, ]
@ -418,7 +419,7 @@ def service_regen_conf(operation_logger, names=[], with_diff=False, force=False,
if not names: if not names:
raise YunohostError('service_regenconf_failed', raise YunohostError('service_regenconf_failed',
services=', '.join(pre_result['failed'])) services=', '.join(pre_result['failed']))
# Set the processing method # Set the processing method
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True _regen = _process_regen_conf if not dry_run else lambda *a, **k: True
@ -603,7 +604,7 @@ def _run_service_command(action, service):
cmd = 'systemctl %s %s' % (action, service) cmd = 'systemctl %s %s' % (action, service)
need_lock = services[service].get('need_lock', False) \ need_lock = services[service].get('need_lock', False) \
and action in ['start', 'stop', 'restart', 'reload'] and action in ['start', 'stop', 'restart', 'reload']
try: try:
# Launch the command # Launch the command
@ -637,10 +638,10 @@ def _give_lock(action, service, p):
else: else:
systemctl_PID_name = "ControlPID" systemctl_PID_name = "ControlPID"
cmd_get_son_PID ="systemctl show %s -p %s" % (service, systemctl_PID_name) cmd_get_son_PID = "systemctl show %s -p %s" % (service, systemctl_PID_name)
son_PID = 0 son_PID = 0
# As long as we did not found the PID and that the command is still running # As long as we did not found the PID and that the command is still running
while son_PID == 0 and p.poll() == None: while son_PID == 0 and p.poll() is None:
# Call systemctl to get the PID # Call systemctl to get the PID
# Output of the command is e.g. ControlPID=1234 # Output of the command is e.g. ControlPID=1234
son_PID = subprocess.check_output(cmd_get_son_PID.split()) \ son_PID = subprocess.check_output(cmd_get_son_PID.split()) \
@ -657,11 +658,12 @@ def _give_lock(action, service, p):
return son_PID return son_PID
def _remove_lock(PID_to_remove): def _remove_lock(PID_to_remove):
# FIXME ironically not concurrency safe because it's not atomic... # FIXME ironically not concurrency safe because it's not atomic...
PIDs = filesystem.read_file(MOULINETTE_LOCK).split("\n") PIDs = filesystem.read_file(MOULINETTE_LOCK).split("\n")
PIDs_to_keep = [ PID for PID in PIDs if int(PID) != PID_to_remove ] PIDs_to_keep = [PID for PID in PIDs if int(PID) != PID_to_remove]
filesystem.write_to_file(MOULINETTE_LOCK, '\n'.join(PIDs_to_keep)) filesystem.write_to_file(MOULINETTE_LOCK, '\n'.join(PIDs_to_keep))
@ -775,6 +777,7 @@ def _find_previous_log_file(file):
return None return None
def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True): def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
"""Compare two files and return the differences """Compare two files and return the differences
@ -919,22 +922,22 @@ def _process_regen_conf(system_conf, new_conf=None, save=True):
backup_dir = os.path.dirname(backup_path) backup_dir = os.path.dirname(backup_path)
if not os.path.isdir(backup_dir): if not os.path.isdir(backup_dir):
filesystem.mkdir(backup_dir, 0755, True) filesystem.mkdir(backup_dir, 0o755, True)
shutil.copy2(system_conf, backup_path) shutil.copy2(system_conf, backup_path)
logger.debug(m18n.n('service_conf_file_backed_up', logger.debug(m18n.n('service_conf_file_backed_up',
conf=system_conf, backup=backup_path)) conf=system_conf, backup=backup_path))
try: try:
if not new_conf: if not new_conf:
os.remove(system_conf) os.remove(system_conf)
logger.debug(m18n.n('service_conf_file_removed', logger.debug(m18n.n('service_conf_file_removed',
conf=system_conf)) conf=system_conf))
else: else:
system_dir = os.path.dirname(system_conf) system_dir = os.path.dirname(system_conf)
if not os.path.isdir(system_dir): if not os.path.isdir(system_dir):
filesystem.mkdir(system_dir, 0755, True) filesystem.mkdir(system_dir, 0o755, True)
shutil.copyfile(new_conf, system_conf) shutil.copyfile(new_conf, system_conf)
logger.debug(m18n.n('service_conf_file_updated', logger.debug(m18n.n('service_conf_file_updated',

View file

@ -88,12 +88,12 @@ def settings_set(key, value):
if key_type == "bool": if key_type == "bool":
if not isinstance(value, bool): if not isinstance(value, bool):
raise YunohostError('global_settings_bad_type_for_setting', setting=key, raise YunohostError('global_settings_bad_type_for_setting', setting=key,
received_type=type(value).__name__, expected_type=key_type) received_type=type(value).__name__, expected_type=key_type)
elif key_type == "int": elif key_type == "int":
if not isinstance(value, int) or isinstance(value, bool): if not isinstance(value, int) or isinstance(value, bool):
if isinstance(value, str): if isinstance(value, str):
try: try:
value=int(value) value = int(value)
except: except:
raise YunohostError('global_settings_bad_type_for_setting', raise YunohostError('global_settings_bad_type_for_setting',
setting=key, setting=key,
@ -101,19 +101,19 @@ def settings_set(key, value):
expected_type=key_type) expected_type=key_type)
else: else:
raise YunohostError('global_settings_bad_type_for_setting', setting=key, raise YunohostError('global_settings_bad_type_for_setting', setting=key,
received_type=type(value).__name__, expected_type=key_type) received_type=type(value).__name__, expected_type=key_type)
elif key_type == "string": elif key_type == "string":
if not isinstance(value, basestring): if not isinstance(value, basestring):
raise YunohostError('global_settings_bad_type_for_setting', setting=key, raise YunohostError('global_settings_bad_type_for_setting', setting=key,
received_type=type(value).__name__, expected_type=key_type) received_type=type(value).__name__, expected_type=key_type)
elif key_type == "enum": elif key_type == "enum":
if value not in settings[key]["choices"]: if value not in settings[key]["choices"]:
raise YunohostError('global_settings_bad_choice_for_enum', setting=key, raise YunohostError('global_settings_bad_choice_for_enum', setting=key,
received_type=type(value).__name__, received_type=type(value).__name__,
expected_type=", ".join(settings[key]["choices"])) expected_type=", ".join(settings[key]["choices"]))
else: else:
raise YunohostError('global_settings_unknown_type', setting=key, raise YunohostError('global_settings_unknown_type', setting=key,
unknown_type=key_type) unknown_type=key_type)
settings[key]["value"] = value settings[key]["value"] = value

View file

@ -98,7 +98,7 @@ def user_ssh_add_key(auth, username, key, comment):
# create empty file to set good permissions # create empty file to set good permissions
write_to_file(authorized_keys_file, "") write_to_file(authorized_keys_file, "")
chown(authorized_keys_file, uid=user["uid"][0]) chown(authorized_keys_file, uid=user["uid"][0])
chmod(authorized_keys_file, 0600) chmod(authorized_keys_file, 0o600)
authorized_keys_content = read_file(authorized_keys_file) authorized_keys_content = read_file(authorized_keys_file)

View file

@ -7,12 +7,14 @@ sys.path.append("..")
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption("--yunodebug", action="store_true", default=False) parser.addoption("--yunodebug", action="store_true", default=False)
############################################################################### #
# Tweak translator to raise exceptions if string keys are not defined # # Tweak translator to raise exceptions if string keys are not defined #
############################################################################### #
old_translate = moulinette.core.Translator.translate old_translate = moulinette.core.Translator.translate
def new_translate(self, key, *args, **kwargs): def new_translate(self, key, *args, **kwargs):
if key not in self._translations[self.default_locale].keys(): if key not in self._translations[self.default_locale].keys():
@ -21,14 +23,15 @@ def new_translate(self, key, *args, **kwargs):
return old_translate(self, key, *args, **kwargs) return old_translate(self, key, *args, **kwargs)
moulinette.core.Translator.translate = new_translate moulinette.core.Translator.translate = new_translate
def new_m18nn(self, key, *args, **kwargs): def new_m18nn(self, key, *args, **kwargs):
return self._namespaces[self._current_namespace].translate(key, *args, **kwargs) return self._namespaces[self._current_namespace].translate(key, *args, **kwargs)
moulinette.core.Moulinette18n.n = new_m18nn moulinette.core.Moulinette18n.n = new_m18nn
############################################################################### #
# Init the moulinette to have the cli loggers stuff # # Init the moulinette to have the cli loggers stuff #
############################################################################### #
def pytest_cmdline_main(config): def pytest_cmdline_main(config):

View file

@ -17,7 +17,7 @@ APPSLISTS_JSON = '/etc/yunohost/appslists.json'
def setup_function(function): def setup_function(function):
# Clear all appslist # Clear all appslist
files = glob.glob(REPO_PATH+"/*") files = glob.glob(REPO_PATH + "/*")
for f in files: for f in files:
os.remove(f) os.remove(f)
@ -42,9 +42,9 @@ def cron_job_is_there():
return r == 0 return r == 0
############################################################################### #
# Test listing of appslists and registering of appslists # # Test listing of appslists and registering of appslists #
############################################################################### #
def test_appslist_list_empty(): def test_appslist_list_empty():
@ -103,9 +103,9 @@ def test_appslist_list_register_conflict_url():
assert "plopette" not in appslist_dict.keys() assert "plopette" not in appslist_dict.keys()
############################################################################### #
# Test fetching of appslists # # Test fetching of appslists #
############################################################################### #
def test_appslist_fetch(): def test_appslist_fetch():
@ -244,9 +244,9 @@ def test_appslist_fetch_timeout():
app_fetchlist() app_fetchlist()
############################################################################### #
# Test remove of appslist # # Test remove of appslist #
############################################################################### #
def test_appslist_remove(): def test_appslist_remove():
@ -274,9 +274,9 @@ def test_appslist_remove_unknown():
app_removelist("dummy") app_removelist("dummy")
############################################################################### #
# Test migration from legacy appslist system # # Test migration from legacy appslist system #
############################################################################### #
def add_legacy_cron(name, url): def add_legacy_cron(name, url):

View file

@ -22,6 +22,7 @@ def setup_function(function):
except: except:
pass pass
def teardown_function(function): def teardown_function(function):
try: try:
@ -50,18 +51,18 @@ def test_urlavailable():
def test_registerurl(): def test_registerurl():
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp")) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"))
assert not domain_url_available(auth, maindomain, "/urlregisterapp") assert not domain_url_available(auth, maindomain, "/urlregisterapp")
# Try installing at same location # Try installing at same location
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp")) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"))
def test_registerurl_baddomain(): def test_registerurl_baddomain():
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install(auth, "./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp")) args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp"))

View file

@ -22,6 +22,7 @@ AUTH_IDENTIFIER = ('ldap', 'ldap-anonymous')
AUTH_PARAMETERS = {'uri': 'ldap://localhost:389', 'base_dn': 'dc=yunohost,dc=org'} AUTH_PARAMETERS = {'uri': 'ldap://localhost:389', 'base_dn': 'dc=yunohost,dc=org'}
auth = None auth = None
def setup_function(function): def setup_function(function):
global maindomain global maindomain
@ -87,9 +88,9 @@ def teardown_function(function):
shutil.rmtree("/opt/test_backup_output_directory") shutil.rmtree("/opt/test_backup_output_directory")
############################################################################### #
# Helpers # # Helpers #
############################################################################### #
def app_is_installed(app): def app_is_installed(app):
@ -111,6 +112,7 @@ def backup_test_dependencies_are_met():
return True return True
def tmp_backup_directory_is_empty(): def tmp_backup_directory_is_empty():
if not os.path.exists("/home/yunohost.backup/tmp/"): if not os.path.exists("/home/yunohost.backup/tmp/"):
@ -118,6 +120,7 @@ def tmp_backup_directory_is_empty():
else: else:
return len(os.listdir('/home/yunohost.backup/tmp/')) == 0 return len(os.listdir('/home/yunohost.backup/tmp/')) == 0
def clean_tmp_backup_directory(): def clean_tmp_backup_directory():
if tmp_backup_directory_is_empty(): if tmp_backup_directory_is_empty():
@ -125,10 +128,10 @@ def clean_tmp_backup_directory():
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("/home/yunohost.backup/tmp") ] and line.split(" ")[2].startswith("/home/yunohost.backup/tmp")]
for point in reversed(points_to_umount): for point in reversed(points_to_umount):
os.system("umount %s" % point) os.system("umount %s" % point)
@ -138,6 +141,7 @@ def clean_tmp_backup_directory():
shutil.rmtree("/home/yunohost.backup/tmp/") shutil.rmtree("/home/yunohost.backup/tmp/")
def reset_ssowat_conf(): def reset_ssowat_conf():
# Make sure we have a ssowat # Make sure we have a ssowat
@ -191,9 +195,10 @@ def add_archive_system_from_2p4():
os.system("cp ./tests/apps/backup_system_from_2p4/backup.tar.gz \ os.system("cp ./tests/apps/backup_system_from_2p4/backup.tar.gz \
/home/yunohost.backup/archives/backup_system_from_2p4.tar.gz") /home/yunohost.backup/archives/backup_system_from_2p4.tar.gz")
############################################################################### #
# System backup # # System backup #
############################################################################### #
def test_backup_only_ldap(): def test_backup_only_ldap():
@ -220,9 +225,10 @@ def test_backup_system_part_that_does_not_exists(mocker):
m18n.n.assert_any_call('backup_hook_unknown', hook="yolol") m18n.n.assert_any_call('backup_hook_unknown', hook="yolol")
m18n.n.assert_any_call('backup_nothings_done') m18n.n.assert_any_call('backup_nothings_done')
############################################################################### #
# System backup and restore # # System backup and restore #
############################################################################### #
def test_backup_and_restore_all_sys(): def test_backup_and_restore_all_sys():
@ -250,9 +256,9 @@ def test_backup_and_restore_all_sys():
assert os.path.exists("/etc/ssowat/conf.json") assert os.path.exists("/etc/ssowat/conf.json")
############################################################################### #
# System restore from 2.4 # # System restore from 2.4 #
############################################################################### #
@pytest.mark.with_system_archive_from_2p4 @pytest.mark.with_system_archive_from_2p4
def test_restore_system_from_Ynh2p4(monkeypatch, mocker): def test_restore_system_from_Ynh2p4(monkeypatch, mocker):
@ -265,19 +271,20 @@ def test_restore_system_from_Ynh2p4(monkeypatch, mocker):
# Restore system archive from 2.4 # Restore system archive from 2.4
try: try:
backup_restore(auth, name=backup_list()["archives"][1], backup_restore(auth, name=backup_list()["archives"][1],
system=[], system=[],
apps=None, apps=None,
force=True) force=True)
finally: finally:
# Restore system as it was # Restore system as it was
backup_restore(auth, name=backup_list()["archives"][0], backup_restore(auth, name=backup_list()["archives"][0],
system=[], system=[],
apps=None, apps=None,
force=True) force=True)
#
# App backup #
#
###############################################################################
# App backup #
###############################################################################
@pytest.mark.with_backup_recommended_app_installed @pytest.mark.with_backup_recommended_app_installed
def test_backup_script_failure_handling(monkeypatch, mocker): def test_backup_script_failure_handling(monkeypatch, mocker):
@ -300,6 +307,7 @@ def test_backup_script_failure_handling(monkeypatch, mocker):
m18n.n.assert_any_call('backup_app_failed', app='backup_recommended_app') m18n.n.assert_any_call('backup_app_failed', app='backup_recommended_app')
@pytest.mark.with_backup_recommended_app_installed @pytest.mark.with_backup_recommended_app_installed
def test_backup_not_enough_free_space(monkeypatch, mocker): def test_backup_not_enough_free_space(monkeypatch, mocker):
@ -385,6 +393,7 @@ def test_backup_with_different_output_directory():
assert len(archives_info["system"].keys()) == 1 assert len(archives_info["system"].keys()) == 1
assert "conf_ssh" in archives_info["system"].keys() assert "conf_ssh" in archives_info["system"].keys()
@pytest.mark.clean_opt_dir @pytest.mark.clean_opt_dir
def test_backup_with_no_compress(): def test_backup_with_no_compress():
# Create the backup # Create the backup
@ -396,15 +405,15 @@ def test_backup_with_no_compress():
assert os.path.exists("/opt/test_backup_output_directory/info.json") assert os.path.exists("/opt/test_backup_output_directory/info.json")
############################################################################### #
# App restore # # App restore #
############################################################################### #
@pytest.mark.with_wordpress_archive_from_2p4 @pytest.mark.with_wordpress_archive_from_2p4
def test_restore_app_wordpress_from_Ynh2p4(): def test_restore_app_wordpress_from_Ynh2p4():
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
@pytest.mark.with_wordpress_archive_from_2p4 @pytest.mark.with_wordpress_archive_from_2p4
@ -422,7 +431,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_app_failed', app='wordpress') m18n.n.assert_any_call('restore_app_failed', app='wordpress')
m18n.n.assert_any_call('restore_nothings_done') m18n.n.assert_any_call('restore_nothings_done')
@ -443,12 +452,12 @@ def test_restore_app_not_enough_free_space(monkeypatch, mocker):
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_not_enough_disk_space', m18n.n.assert_any_call('restore_not_enough_disk_space',
free_space=0, free_space=0,
margin=ANY, margin=ANY,
needed_space=ANY) needed_space=ANY)
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
@ -462,7 +471,7 @@ def test_restore_app_not_in_backup(mocker):
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["yoloswag"]) apps=["yoloswag"])
m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag") m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag")
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
@ -475,14 +484,14 @@ def test_restore_app_already_installed(mocker):
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
assert _is_installed("wordpress") assert _is_installed("wordpress")
mocker.spy(m18n, "n") mocker.spy(m18n, "n")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(auth, system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_already_installed_app', app="wordpress") m18n.n.assert_any_call('restore_already_installed_app', app="wordpress")
m18n.n.assert_any_call('restore_nothings_done') m18n.n.assert_any_call('restore_nothings_done')
@ -531,9 +540,10 @@ def _test_backup_and_restore_app(app):
assert app_is_installed(app) assert app_is_installed(app)
############################################################################### #
# Some edge cases # # Some edge cases #
############################################################################### #
def test_restore_archive_with_no_json(mocker): def test_restore_archive_with_no_json(mocker):
@ -555,10 +565,9 @@ def test_backup_binds_are_readonly(monkeypatch):
self.manager = backup_manager self.manager = backup_manager
self._organize_files() self._organize_files()
confssh = os.path.join(self.work_dir, "conf/ssh") confssh = os.path.join(self.work_dir, "conf/ssh")
output = subprocess.check_output("touch %s/test 2>&1 || true" % confssh, output = subprocess.check_output("touch %s/test 2>&1 || true" % confssh,
shell=True, env={'LANG' : 'en_US.UTF-8'}) shell=True, env={'LANG': 'en_US.UTF-8'})
assert "Read-only file system" in output assert "Read-only file system" in output
@ -568,7 +577,7 @@ def test_backup_binds_are_readonly(monkeypatch):
self.clean() self.clean()
monkeypatch.setattr("yunohost.backup.BackupMethod.mount_and_backup", monkeypatch.setattr("yunohost.backup.BackupMethod.mount_and_backup",
custom_mount_and_backup) custom_mount_and_backup)
# Create the backup # Create the backup
backup_create(system=[]) backup_create(system=[])

View file

@ -53,6 +53,7 @@ def test_appchangeurl():
check_changeurl_app("/newchangeurl") check_changeurl_app("/newchangeurl")
def test_appchangeurl_sameurl(): def test_appchangeurl_sameurl():
install_changeurl_app("/changeurl") install_changeurl_app("/changeurl")
check_changeurl_app("/changeurl") check_changeurl_app("/changeurl")

View file

@ -18,7 +18,8 @@ def teardown_function(function):
def test_settings_get_bool(): def test_settings_get_bool():
assert settings_get("example.bool") == True assert settings_get("example.bool")
def test_settings_get_full_bool(): def test_settings_get_full_bool():
assert settings_get("example.bool", True) == {"type": "bool", "value": True, "default": True, "description": "Example boolean option"} assert settings_get("example.bool", True) == {"type": "bool", "value": True, "default": True, "description": "Example boolean option"}
@ -27,6 +28,7 @@ def test_settings_get_full_bool():
def test_settings_get_int(): def test_settings_get_int():
assert settings_get("example.int") == 42 assert settings_get("example.int") == 42
def test_settings_get_full_int(): def test_settings_get_full_int():
assert settings_get("example.int", True) == {"type": "int", "value": 42, "default": 42, "description": "Example int option"} assert settings_get("example.int", True) == {"type": "int", "value": 42, "default": 42, "description": "Example int option"}
@ -34,6 +36,7 @@ def test_settings_get_full_int():
def test_settings_get_string(): def test_settings_get_string():
assert settings_get("example.string") == "yolo swag" assert settings_get("example.string") == "yolo swag"
def test_settings_get_full_string(): def test_settings_get_full_string():
assert settings_get("example.string", True) == {"type": "string", "value": "yolo swag", "default": "yolo swag", "description": "Example string option"} assert settings_get("example.string", True) == {"type": "string", "value": "yolo swag", "default": "yolo swag", "description": "Example string option"}
@ -41,6 +44,7 @@ def test_settings_get_full_string():
def test_settings_get_enum(): def test_settings_get_enum():
assert settings_get("example.enum") == "a" assert settings_get("example.enum") == "a"
def test_settings_get_full_enum(): def test_settings_get_full_enum():
assert settings_get("example.enum", True) == {"type": "enum", "value": "a", "default": "a", "description": "Example enum option", "choices": ["a", "b", "c"]} assert settings_get("example.enum", True) == {"type": "enum", "value": "a", "default": "a", "description": "Example enum option", "choices": ["a", "b", "c"]}
@ -152,7 +156,6 @@ def test_reset_all_backup():
assert settings_after_modification == json.load(open(old_settings_backup_path, "r")) assert settings_after_modification == json.load(open(old_settings_backup_path, "r"))
def test_unknown_keys(): def test_unknown_keys():
unknown_settings_path = SETTINGS_PATH_OTHER_LOCATION % "unknown" unknown_settings_path = SETTINGS_PATH_OTHER_LOCATION % "unknown"
unknown_setting = { unknown_setting = {

View file

@ -136,7 +136,7 @@ def tools_adminpw(auth, new_password, check_strength=True):
new_hash = _hash_user_password(new_password) new_hash = _hash_user_password(new_password)
try: try:
auth.update("cn=admin", { "userPassword": new_hash, }) auth.update("cn=admin", {"userPassword": new_hash, })
except: except:
logger.exception('unable to change admin password') logger.exception('unable to change admin password')
raise YunohostError('admin_password_change_failed') raise YunohostError('admin_password_change_failed')
@ -265,7 +265,7 @@ def _is_inside_container():
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
out, _ = p.communicate() out, _ = p.communicate()
container = ['lxc','lxd','docker'] container = ['lxc', 'lxd', 'docker']
return out.split()[0] in container return out.split()[0] in container
@ -323,7 +323,6 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
else: else:
dyndns = False dyndns = False
operation_logger.start() operation_logger.start()
logger.info(m18n.n('yunohost_installing')) logger.info(m18n.n('yunohost_installing'))
@ -539,7 +538,7 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
# If API call # If API call
if is_api: if is_api:
critical_packages = ("moulinette", "yunohost", critical_packages = ("moulinette", "yunohost",
"yunohost-admin", "ssowat", "python") "yunohost-admin", "ssowat", "python")
critical_upgrades = set() critical_upgrades = set()
for pkg in cache.get_changes(): for pkg in cache.get_changes():
@ -575,7 +574,6 @@ def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=Fal
else: else:
logger.info(m18n.n('packages_no_upgrade')) logger.info(m18n.n('packages_no_upgrade'))
if not ignore_apps: if not ignore_apps:
try: try:
app_upgrade(auth) app_upgrade(auth)
@ -719,7 +717,7 @@ def _check_if_vulnerable_to_meltdown():
try: try:
call = subprocess.Popen("bash %s --batch json --variant 3" % call = subprocess.Popen("bash %s --batch json --variant 3" %
SCRIPT_PATH, shell=True, SCRIPT_PATH, shell=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
output, _ = call.communicate() output, _ = call.communicate()
@ -815,12 +813,12 @@ def tools_migrations_list(pending=False, done=False):
migrations = [m for m in migrations if m.number > last_migration] migrations = [m for m in migrations if m.number > last_migration]
# Reduce to dictionnaries # Reduce to dictionnaries
migrations = [{ "id": migration.id, migrations = [{"id": migration.id,
"number": migration.number, "number": migration.number,
"name": migration.name, "name": migration.name,
"mode": migration.mode, "mode": migration.mode,
"description": migration.description, "description": migration.description,
"disclaimer": migration.disclaimer } for migration in migrations ] "disclaimer": migration.disclaimer} for migration in migrations]
return {"migrations": migrations} return {"migrations": migrations}
@ -914,7 +912,7 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai
accept_disclaimer = False accept_disclaimer = False
# Start register change on system # Start register change on system
operation_logger= OperationLogger('tools_migrations_migrate_' + mode) operation_logger = OperationLogger('tools_migrations_migrate_' + mode)
operation_logger.start() operation_logger.start()
if not skip: if not skip:
@ -934,9 +932,9 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai
# migration failed, let's stop here but still update state because # migration failed, let's stop here but still update state because
# we managed to run the previous ones # we managed to run the previous ones
msg = m18n.n('migrations_migration_has_failed', msg = m18n.n('migrations_migration_has_failed',
exception=e, exception=e,
number=migration.number, number=migration.number,
name=migration.name) name=migration.name)
logger.error(msg, exc_info=1) logger.error(msg, exc_info=1)
operation_logger.error(msg) operation_logger.error(msg)
break break
@ -967,6 +965,7 @@ def tools_migrations_migrate(target=None, skip=False, auto=False, accept_disclai
write_to_json(MIGRATIONS_STATE_PATH, state) write_to_json(MIGRATIONS_STATE_PATH, state)
def tools_migrations_state(): def tools_migrations_state():
""" """
Show current migration state Show current migration state
@ -1009,7 +1008,7 @@ def _get_migrations_list():
migrations = [] migrations = []
try: try:
import data_migrations from . import data_migrations
except ImportError: except ImportError:
# not data migrations present, return empty list # not data migrations present, return empty list
return migrations return migrations
@ -1032,7 +1031,7 @@ def _get_migration_by_name(migration_name):
""" """
try: try:
import data_migrations from . import data_migrations
except ImportError: except ImportError:
raise AssertionError("Unable to find migration with name %s" % migration_name) raise AssertionError("Unable to find migration with name %s" % migration_name)
@ -1051,7 +1050,7 @@ def _load_migration(migration_file):
number, name = migration_id.split("_", 1) number, name = migration_id.split("_", 1)
logger.debug(m18n.n('migrations_loading_migration', logger.debug(m18n.n('migrations_loading_migration',
number=number, name=name)) number=number, name=name))
try: try:
# this is python builtin method to import a module using a name, we # this is python builtin method to import a module using a name, we
@ -1064,7 +1063,8 @@ def _load_migration(migration_file):
traceback.print_exc() traceback.print_exc()
raise YunohostError('migrations_error_failed_to_load_migration', raise YunohostError('migrations_error_failed_to_load_migration',
number=number, name=name) number=number, name=name)
def _skip_all_migrations(): def _skip_all_migrations():
""" """
@ -1115,4 +1115,3 @@ class Migration(object):
@property @property
def description(self): def description(self):
return m18n.n("migration_description_%s" % self.id) return m18n.n("migration_description_%s" % self.id)

View file

@ -40,6 +40,7 @@ from yunohost.log import is_unit_operation
logger = getActionLogger('yunohost.user') logger = getActionLogger('yunohost.user')
def user_list(auth, fields=None): def user_list(auth, fields=None):
""" """
List users List users
@ -98,7 +99,7 @@ def user_list(auth, fields=None):
@is_unit_operation([('username', 'user')]) @is_unit_operation([('username', 'user')])
def user_create(operation_logger, auth, username, firstname, lastname, mail, password, def user_create(operation_logger, auth, username, firstname, lastname, mail, password,
mailbox_quota="0"): mailbox_quota="0"):
""" """
Create user Create user
@ -262,8 +263,8 @@ def user_delete(operation_logger, auth, username, purge=False):
@is_unit_operation([('username', 'user')], exclude=['auth', 'change_password']) @is_unit_operation([('username', 'user')], exclude=['auth', 'change_password'])
def user_update(operation_logger, auth, username, firstname=None, lastname=None, mail=None, def user_update(operation_logger, auth, username, firstname=None, lastname=None, mail=None,
change_password=None, add_mailforward=None, remove_mailforward=None, change_password=None, add_mailforward=None, remove_mailforward=None,
add_mailalias=None, remove_mailalias=None, mailbox_quota=None): add_mailalias=None, remove_mailalias=None, mailbox_quota=None):
""" """
Update user informations Update user informations
@ -466,18 +467,23 @@ def user_info(auth, username):
# #
import yunohost.ssh import yunohost.ssh
def user_ssh_allow(auth, username): def user_ssh_allow(auth, username):
return yunohost.ssh.user_ssh_allow(auth, username) return yunohost.ssh.user_ssh_allow(auth, username)
def user_ssh_disallow(auth, username): def user_ssh_disallow(auth, username):
return yunohost.ssh.user_ssh_disallow(auth, username) return yunohost.ssh.user_ssh_disallow(auth, username)
def user_ssh_list_keys(auth, username): def user_ssh_list_keys(auth, username):
return yunohost.ssh.user_ssh_list_keys(auth, username) return yunohost.ssh.user_ssh_list_keys(auth, username)
def user_ssh_add_key(auth, username, key, comment): def user_ssh_add_key(auth, username, key, comment):
return yunohost.ssh.user_ssh_add_key(auth, username, key, comment) return yunohost.ssh.user_ssh_add_key(auth, username, key, comment)
def user_ssh_remove_key(auth, username, key): def user_ssh_remove_key(auth, username, key):
return yunohost.ssh.user_ssh_remove_key(auth, username, key) return yunohost.ssh.user_ssh_remove_key(auth, username, key)
@ -485,6 +491,7 @@ def user_ssh_remove_key(auth, username, key):
# End SSH subcategory # End SSH subcategory
# #
def _convertSize(num, suffix=''): def _convertSize(num, suffix=''):
for unit in ['K', 'M', 'G', 'T', 'P', 'E', 'Z']: for unit in ['K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1024.0: if abs(num) < 1024.0:
@ -520,6 +527,3 @@ def _hash_user_password(password):
salt = '$6$' + salt + '$' salt = '$6$' + salt + '$'
return '{CRYPT}' + crypt.crypt(str(password), salt) return '{CRYPT}' + crypt.crypt(str(password), salt)

View file

@ -22,17 +22,19 @@
from moulinette.core import MoulinetteError from moulinette.core import MoulinetteError
from moulinette import m18n from moulinette import m18n
class YunohostError(MoulinetteError): class YunohostError(MoulinetteError):
""" """
Yunohost base exception Yunohost base exception
The (only?) main difference with MoulinetteError being that keys The (only?) main difference with MoulinetteError being that keys
are translated via m18n.n (namespace) instead of m18n.g (global?) are translated via m18n.n (namespace) instead of m18n.g (global?)
""" """
def __init__(self, key, raw_msg=False, *args, **kwargs):
if raw_msg: def __init__(self, key, __raw_msg__=False, *args, **kwargs):
if __raw_msg__:
msg = key msg = key
else: else:
msg = m18n.n(key, *args, **kwargs) msg = m18n.n(key, *args, **kwargs)
super(YunohostError, self).__init__(msg, raw_msg=True) super(YunohostError, self).__init__(msg, __raw_msg__=True)

View file

@ -20,10 +20,12 @@
""" """
import os import os
def free_space_in_directory(dirpath): def free_space_in_directory(dirpath):
stat = os.statvfs(dirpath) stat = os.statvfs(dirpath)
return stat.f_frsize * stat.f_bavail return stat.f_frsize * stat.f_bavail
def space_used_by_directory(dirpath): def space_used_by_directory(dirpath):
stat = os.statvfs(dirpath) stat = os.statvfs(dirpath)
return stat.f_frsize * stat.f_blocks return stat.f_frsize * stat.f_blocks

View file

@ -71,7 +71,7 @@ def get_gateway():
return addr.popitem()[1] if len(addr) == 1 else None return addr.popitem()[1] if len(addr) == 1 else None
############################################################################### #
def _extract_inet(string, skip_netmask=False, skip_loopback=True): def _extract_inet(string, skip_netmask=False, skip_loopback=True):

View file

@ -33,6 +33,7 @@ logger = logging.getLogger('yunohost.utils.packages')
# Exceptions ----------------------------------------------------------------- # Exceptions -----------------------------------------------------------------
class PackageException(Exception): class PackageException(Exception):
"""Base exception related to a package """Base exception related to a package
Represent an exception related to the package named `pkgname`. If no Represent an exception related to the package named `pkgname`. If no
@ -50,16 +51,19 @@ class PackageException(Exception):
class UnknownPackage(PackageException): class UnknownPackage(PackageException):
"""The package is not found in the cache.""" """The package is not found in the cache."""
message_key = 'package_unknown' message_key = 'package_unknown'
class UninstalledPackage(PackageException): class UninstalledPackage(PackageException):
"""The package is not installed.""" """The package is not installed."""
message_key = 'package_not_installed' message_key = 'package_not_installed'
class InvalidSpecifier(ValueError): class InvalidSpecifier(ValueError):
"""An invalid specifier was found.""" """An invalid specifier was found."""
@ -68,6 +72,7 @@ class InvalidSpecifier(ValueError):
# See: https://github.com/pypa/packaging # See: https://github.com/pypa/packaging
class Specifier(object): class Specifier(object):
"""Unique package version specifier """Unique package version specifier
Restrict a package version according to the `spec`. It must be a string Restrict a package version according to the `spec`. It must be a string
@ -257,6 +262,7 @@ class Specifier(object):
class SpecifierSet(object): class SpecifierSet(object):
"""A set of package version specifiers """A set of package version specifiers
Combine several Specifier separated by a comma. It allows to restrict Combine several Specifier separated by a comma. It allows to restrict

View file

@ -38,9 +38,11 @@ STRENGTH_LEVELS = [
(12, 1, 1, 1, 1), (12, 1, 1, 1, 1),
] ]
def assert_password_is_strong_enough(profile, password): def assert_password_is_strong_enough(profile, password):
PasswordValidator(profile).validate(password) PasswordValidator(profile).validate(password)
class PasswordValidator(object): class PasswordValidator(object):
def __init__(self, profile): def __init__(self, profile):
@ -157,7 +159,7 @@ class PasswordValidator(object):
# and the strength of the password (e.g. [11, 2, 7, 2, 0]) # and the strength of the password (e.g. [11, 2, 7, 2, 0])
# and compare the values 1-by-1. # and compare the values 1-by-1.
# If one False is found, the password does not satisfy the level # If one False is found, the password does not satisfy the level
if False in [s>=c for s, c in zip(strength, level_criterias)]: if False in [s >= c for s, c in zip(strength, level_criterias)]:
break break
# Otherwise, the strength of the password is at least of the current level. # Otherwise, the strength of the password is at least of the current level.
strength_level = level + 1 strength_level = level + 1
@ -186,7 +188,7 @@ if __name__ == '__main__':
if len(sys.argv) < 2: if len(sys.argv) < 2:
import getpass import getpass
pwd = getpass.getpass("") pwd = getpass.getpass("")
#print("usage: password.py PASSWORD") # print("usage: password.py PASSWORD")
else: else:
pwd = sys.argv[1] pwd = sys.argv[1]
status, msg = PasswordValidator('user').validation_summary(pwd) status, msg = PasswordValidator('user').validation_summary(pwd)

View file

@ -5,6 +5,7 @@ import json
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
def yunopaste(data): def yunopaste(data):
paste_server = "https://paste.yunohost.org" paste_server = "https://paste.yunohost.org"