From c59c3fa43889fafc5732f89422c5efcc8be672af Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Thu, 26 Sep 2019 19:25:06 +0200 Subject: [PATCH 001/317] [enh] Add some advice about a strange locale problem with postgresql --- data/helpers.d/postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index d252ae2dc..a4cb50393 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -276,7 +276,7 @@ ynh_psql_test_if_first_run() { local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf local logfile=/var/log/postgresql/postgresql-9.6-main.log else - ynh_die "postgresql shoud be 9.4 or 9.6" + ynh_die "postgresql shoud be 9.4 or 9.6 or it could be a problem of locale see https://serverfault.com/questions/426989/postgresql-etc-postgresql-doesnt-exist" fi ynh_systemd_action --service_name=postgresql --action=start From 4500f56c32f93ca30698b905d384aca04e580a78 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 27 Sep 2019 11:54:44 +0200 Subject: [PATCH 002/317] [fix] Psql user should own the database --- data/helpers.d/postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index d252ae2dc..e40553f9e 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -87,7 +87,7 @@ ynh_psql_create_db() { # grant all privilegies to user if [ -n "$user" ]; then - sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" + sql+="OWNER ${user} GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" fi ynh_psql_execute_as_root --sql="$sql" From b41d7b47a48dc3e3fb44284a43831da86e8efec6 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Fri, 27 Sep 2019 11:59:11 +0200 Subject: [PATCH 003/317] [fix] SQL error --- data/helpers.d/postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index e40553f9e..1dac6715d 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -87,7 +87,7 @@ ynh_psql_create_db() { # grant all privilegies to user if [ -n "$user" ]; then - sql+="OWNER ${user} GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" + sql+="ALTER DATABASE ${db} OWNER TO ${user}; GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" fi ynh_psql_execute_as_root --sql="$sql" From 0081d988ab635e859a406db3f5ab3203331c0cb5 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 18:45:49 +0100 Subject: [PATCH 004/317] Replace __PHPVERSION__ by $YNH_PHP_VERSION in nginx conf files --- data/helpers.d/nginx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/helpers.d/nginx b/data/helpers.d/nginx index e3e45d2d4..b34ebb4e1 100644 --- a/data/helpers.d/nginx +++ b/data/helpers.d/nginx @@ -12,6 +12,7 @@ # __PORT__ by $port # __NAME__ by $app # __FINALPATH__ by $final_path +# __PHPVERSION__ by $YNH_PHP_VERSION ($YNH_PHP_VERSION is either the default php version or the version defined for the app) # # And dynamic variables (from the last example) : # __PATH_2__ by $path_2 @@ -44,6 +45,7 @@ ynh_add_nginx_config () { if test -n "${final_path:-}"; then ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf" fi + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$finalnginxconf" # Replace all other variable given as arguments for var_to_replace in $others_var From a489a06daa01e195d35f159658f8805a2af4c349 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 18:49:27 +0100 Subject: [PATCH 005/317] Use the default php version into the php helpers --- data/helpers.d/php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 41af467c5..56d35cee8 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -1,5 +1,9 @@ #!/bin/bash +# Declare the actual php version to use. +# A packager willing to use another version of php can override the variable into its _common.sh. +YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} + # Create a dedicated php-fpm config # # usage: ynh_add_fpm_config [--phpversion=7.X] @@ -14,8 +18,8 @@ ynh_add_fpm_config () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - # Configure PHP-FPM 7.0 by default - phpversion="${phpversion:-7.0}" + # Set the default PHP-FPM version by default + phpversion="${phpversion:-$YNH_PHP_VERSION}" local fpm_config_dir="/etc/php/$phpversion/fpm" local fpm_service="php${phpversion}-fpm" @@ -26,6 +30,7 @@ ynh_add_fpm_config () { fi ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" + ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion finalphpconf="$fpm_config_dir/pool.d/$app.conf" ynh_backup_if_checksum_is_different --file="$finalphpconf" cp ../conf/php-fpm.conf "$finalphpconf" @@ -56,10 +61,10 @@ ynh_add_fpm_config () { ynh_remove_fpm_config () { local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) - # Assume php version 7 if not set + # Assume default php version if not set if [ -z "$fpm_config_dir" ]; then - fpm_config_dir="/etc/php/7.0/fpm" - fpm_service="php7.0-fpm" + fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm" + fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm" fi ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 From 940162a31ff6836273ddaa209abb4d3813b8db62 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 18:52:43 +0100 Subject: [PATCH 006/317] Set the default version for php And propagate it as an env variable for apps. --- src/yunohost/app.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index b05d7b818..2311ab8e5 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -59,6 +59,7 @@ APPS_CATALOG_CONF = '/etc/yunohost/apps_catalog.yml' APPS_CATALOG_CRON_PATH = "/etc/cron.daily/yunohost-fetch-apps-catalog" APPS_CATALOG_API_VERSION = 2 APPS_CATALOG_DEFAULT_URL = "https://app.yunohost.org/default" +APPS_DEFAULT_PHP_VERSION = "7.0" re_github_repo = re.compile( r'^(http[s]?://|git@)github.com[/:]' @@ -347,6 +348,7 @@ def app_change_url(operation_logger, app, domain, path): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_dict["YNH_APP_OLD_DOMAIN"] = old_domain env_dict["YNH_APP_OLD_PATH"] = old_path @@ -483,6 +485,7 @@ def app_upgrade(app=[], url=None, file=None): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Start register change on system related_to = [('app', app_instance_name)] @@ -695,6 +698,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) + env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Start register change on system operation_logger.extra.update({'env': env_dict}) @@ -803,6 +807,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu env_dict_remove["YNH_APP_ID"] = app_id env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) + env_dict_remove["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Execute remove script operation_logger_remove = OperationLogger('remove_on_failed_install', @@ -980,6 +985,7 @@ def app_remove(operation_logger, app): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION operation_logger.extra.update({'env': env_dict}) operation_logger.flush() @@ -1403,6 +1409,7 @@ def app_action_run(operation_logger, app, action, args=None): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_dict["YNH_ACTION"] = action _, path = tempfile.mkstemp() @@ -1466,6 +1473,7 @@ def app_config_show_panel(operation_logger, app): "YNH_APP_ID": app_id, "YNH_APP_INSTANCE_NAME": app, "YNH_APP_INSTANCE_NUMBER": str(app_instance_nb), + "YNH_DEFAULT_PHP_VERSION": APPS_DEFAULT_PHP_VERSION, } return_code, parsed_values = hook_exec(config_script, @@ -1539,6 +1547,7 @@ def app_config_apply(operation_logger, app, args): "YNH_APP_ID": app_id, "YNH_APP_INSTANCE_NAME": app, "YNH_APP_INSTANCE_NUMBER": str(app_instance_nb), + "YNH_DEFAULT_PHP_VERSION": APPS_DEFAULT_PHP_VERSION, } args = dict(urlparse.parse_qsl(args, keep_blank_values=True)) if args else {} From 55d17a61017378b907a79bbeee5fb614737956e0 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 19:11:06 +0100 Subject: [PATCH 007/317] Add the helper ynh_install_php --- data/helpers.d/php | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/data/helpers.d/php b/data/helpers.d/php index 41af467c5..224c0a3d9 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -65,3 +65,83 @@ ynh_remove_fpm_config () { ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 ynh_systemd_action --service_name=$fpm_service --action=reload } + +# Install another version of php. +# +# usage: ynh_install_php --phpversion=phpversion [--package=packages] +# | arg: -v, --phpversion - Version of php to install. +# | arg: -p, --package - Additionnal php packages to install +ynh_install_php () { + # Declare an array to define the options of this helper. + local legacy_args=vp + declare -Ar args_array=( [v]=phpversion= [p]=package= ) + local phpversion + local package + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package=${package:-} + + # Store phpversion into the config of this app + ynh_app_setting_set $app phpversion $phpversion + + if [ "$phpversion" == "7.0" ] + then + ynh_die "Do not use ynh_install_php to install php7.0" + fi + + # Store the ID of this app and the version of php requested for it + echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version" + + # Add an extra repository for those packages + ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version + + # Install requested dependencies from this extra repository. + # Install php-fpm first, otherwise php will install apache as a dependency. + ynh_add_app_dependencies --package="php${phpversion}-fpm" + ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package" + + # Set php7.0 back as the default version for php-cli. + update-alternatives --set php /usr/bin/php7.0 + + # Pin this extra repository after packages are installed to prevent sury of doing shit + ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" 200 --name=extra_php_version + ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" 600 --name=extra_php_version --append + + # Advertise service in admin panel + yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" +} + +# Remove the specific version of php used by the app. +# +# usage: ynh_install_php +ynh_remove_php () { + # Get the version of php used by this app + local phpversion=$(ynh_app_setting_get $app phpversion) + + if [ "$phpversion" == "7.0" ] || [ -z "$phpversion" ] + then + if [ "$phpversion" == "7.0" ] + then + ynh_print_err "Do not use ynh_remove_php to install php7.0" + fi + return 0 + fi + + # Remove the line for this app + sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version" + + # If no other app uses this version of php, remove it. + if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version" + then + # Purge php dependences for this version. + ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common" + # Remove the service from the admin panel + yunohost service remove php${phpversion}-fpm + fi + + # If no other app uses alternate php versions, remove the extra repo for php + if [ ! -s "/etc/php/ynh_app_version" ] + then + ynh_secure_remove /etc/php/ynh_app_version + fi +} From 7a5760db55986b2bbf7cc642f70c792c5b3310c4 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 19:55:38 +0100 Subject: [PATCH 008/317] Add the helper ynh_install_extra_app_dependencies And the helpers used by this one. --- data/helpers.d/apt | 275 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 272 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 55c85c90b..0f973dda5 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -205,7 +205,8 @@ ynh_package_install_from_equivs () { # Requires YunoHost version 2.6.4 or higher. ynh_install_app_dependencies () { local dependencies=$@ - local dependencies=${dependencies// /, } + # Add a comma for each space between packages. But not add a comma if the space separate a version specification. (See below) + dependencies="$(echo "$dependencies" | sed 's/\([^\<=\>]\)\ \([^(]\)/\1, \2/g')" local dependencies=${dependencies//|/ | } local manifest_path="../manifest.json" if [ ! -e "$manifest_path" ]; then @@ -218,6 +219,20 @@ ynh_install_app_dependencies () { fi local dep_app=${app//_/-} # Replace all '_' by '-' + # Handle specific versions + if [[ "$dependencies" =~ [\<=\>] ]] + then + # Replace version specifications by relationships syntax + # https://www.debian.org/doc/debian-policy/ch-relationships.html + # Sed clarification + # [^(\<=\>] ignore if it begins by ( or < = >. To not apply twice. + # [\<=\>] matches < = or > + # \+ matches one or more occurence of the previous characters, for >= or >>. + # [^,]\+ matches all characters except ',' + # Ex: 'package>=1.0' will be replaced by 'package (>= 1.0)' + dependencies="$(echo "$dependencies" | sed 's/\([^(\<=\>]\)\([\<=\>]\+\)\([^,]\+\)/\1 (\2 \3)/g')" + fi + # # Epic ugly hack to fix the goddamn dependency nightmare of sury # Sponsored by the "Djeezusse Fokin Kraiste Why Do Adminsys Has To Be So Fucking Complicated I Should Go Grow Potatoes Instead Of This Shit" collective @@ -233,8 +248,11 @@ ynh_install_app_dependencies () { if ! grep -nrq "sury" /etc/apt/sources.list* then # Re-add sury - echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury.list - wget -O /etc/apt/trusted.gpg.d/sury.gpg https://packages.sury.org/php/apt.gpg + ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version + + # Pin this sury repository to prevent sury of doing shit + ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" 200 --name=extra_php_version + ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" 600 --name=extra_php_version --append fi fi fi @@ -255,6 +273,38 @@ EOF ynh_app_setting_set --app=$app --key=apt_dependencies --value="$dependencies" } +# Add dependencies to install with ynh_install_app_dependencies +# +# [internal] +# +# usage: ynh_add_app_dependencies --package=phpversion [--replace] +# | arg: -p, --package - Packages to add as dependencies for the app. +# | arg: -r, --replace - Replace dependencies instead of adding to existing ones. +ynh_add_app_dependencies () { + # Declare an array to define the options of this helper. + local legacy_args=pr + declare -Ar args_array=( [p]=package= [r]=replace) + local package + local replace + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + replace=${replace:-0} + + local current_dependencies="" + if [ $replace -eq 0 ] + then + local dep_app=${app//_/-} # Replace all '_' by '-' + if ynh_package_is_installed --package="${dep_app}-ynh-deps" + then + current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) " + fi + + current_dependencies=${current_dependencies// | /|} + fi + + ynh_install_app_dependencies "${current_dependencies}${package}" +} + # Remove fake package and its dependencies # # Dependencies will removed only if no other package need them. @@ -266,3 +316,222 @@ ynh_remove_app_dependencies () { local dep_app=${app//_/-} # Replace all '_' by '-' ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used. } + +#================================================= + +# Install packages from an extra repository properly. +# +# usage: ynh_install_extra_app_dependencies --repo="repo" --package="dep1 dep2" [--key=key_url] [--name=name] +# | arg: -r, --repo - Complete url of the extra repository. +# | arg: -p, --package - The packages to install from this extra repository +# | arg: -k, --key - url to get the public key. +# | arg: -n, --name - Name for the files for this repo, $app as default value. +ynh_install_extra_app_dependencies () { + # Declare an array to define the options of this helper. + local legacy_args=rpkn + declare -Ar args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) + local repo + local package + local key + local name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + key=${key:-0} + + # Set a key only if asked + if [ -n "$key" ] + then + key="--key=$key" + fi + # Add an extra repository for those packages + ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name + + # Install requested dependencies from this extra repository. + ynh_add_app_dependencies --package="$package" + + # Remove this extra repository after packages are installed + ynh_remove_extra_repo --name=$app +} + +# Add an extra repository correctly, pin it and get the key. +# +# [internal] +# +# usage: ynh_install_extra_repo --repo="repo" [--key=key_url] [--priority=priority_value] [--name=name] [--append] +# | arg: -r, --repo - Complete url of the extra repository. +# | arg: -k, --key - url to get the public key. +# | arg: -p, --priority - Priority for the pin +# | arg: -n, --name - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. +ynh_install_extra_repo () { + # Declare an array to define the options of this helper. + local legacy_args=rkpna + declare -Ar args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) + local repo + local key + local priority + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + append=${append:-0} + key=${key:-0} + priority=${priority:-} + + if [ $append -eq 1 ] + then + append="--append" + wget_append="tee -a" + else + append="" + wget_append="tee" + fi + + # Split the repository into uri, suite and components. + # Remove "deb " at the beginning of the repo. + repo="${repo#deb }" + + # Get the uri + local uri="$(echo "$repo" | awk '{ print $1 }')" + + # Get the suite + local suite="$(echo "$repo" | awk '{ print $2 }')" + + # Get the components + local component="${repo##$uri $suite }" + + # Add the repository into sources.list.d + ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append + + # Pin the new repo with the default priority, so it won't be used for upgrades. + # Build $pin from the uri without http and any sub path + local pin="${uri#*://}" + pin="${pin%%/*}" + # Set a priority only if asked + if [ -n "$priority" ] + then + priority="--priority=$priority" + fi + ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append + + # Get the public key for the repo + if [ -n "$key" ] + then + mkdir -p "/etc/apt/trusted.gpg.d" + wget -q "$key" -O - | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null + fi + + # Update the list of package with the new repo + ynh_package_update +} + +# Remove an extra repository and the assiociated configuration. +# +# [internal] +# +# usage: ynh_remove_extra_repo [--name=name] +# | arg: -n, --name - Name for the files for this repo, $app as default value. +ynh_remove_extra_repo () { + # Declare an array to define the options of this helper. + local legacy_args=n + declare -Ar args_array=( [n]=name= ) + local name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + + ynh_secure_remove "/etc/apt/sources.list.d/$name.list" + ynh_secure_remove "/etc/apt/preferences.d/$name" + ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.gpg" + ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.asc" + + # Update the list of package to exclude the old repo + ynh_package_update +} + +# Add a repository. +# +# [internal] +# +# usage: ynh_add_repo --uri=uri --suite=suite --component=component [--name=name] [--append] +# | arg: -u, --uri - Uri of the repository. +# | arg: -s, --suite - Suite of the repository. +# | arg: -c, --component - Component of the repository. +# | arg: -n, --name - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. +# +# Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable +# uri suite component +# ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable +# +ynh_add_repo () { + # Declare an array to define the options of this helper. + local legacy_args=uscna + declare -Ar args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) + local uri + local suite + local component + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + append=${append:-0} + + if [ $append -eq 1 ] + then + append="tee -a" + else + append="tee" + fi + + mkdir -p "/etc/apt/sources.list.d" + # Add the new repo in sources.list.d + echo "deb $uri $suite $component" \ + | $append "/etc/apt/sources.list.d/$name.list" +} + +# Pin a repository. +# +# [internal] +# +# usage: ynh_pin_repo --package=packages --pin=pin_filter [--priority=priority_value] [--name=name] [--append] +# | arg: -p, --package - Packages concerned by the pin. Or all, *. +# | arg: -i, --pin - Filter for the pin. +# | arg: -p, --priority - Priority for the pin +# | arg: -n, --name - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. +# +# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html for information about pinning. +# +ynh_pin_repo () { + # Declare an array to define the options of this helper. + local legacy_args=pirna + declare -Ar args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) + local package + local pin + local priority + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package="${package:-*}" + priority=${priority:-50} + name="${name:-$app}" + append=${append:-0} + + if [ $append -eq 1 ] + then + append="tee -a" + else + append="tee" + fi + + mkdir -p "/etc/apt/preferences.d" + echo "Package: $package +Pin: $pin +Pin-Priority: $priority" \ + | $append "/etc/apt/preferences.d/$name" +} From 7ba253cb18b4badaa5467101417b5e06327155e6 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 20:08:00 +0100 Subject: [PATCH 009/317] Add the helper ynh_get_scalable_phpfpm And adapt ynh_add_fpm_config to generate a fpm config file without a template by using ynh_get_scalable_phpfpm --- data/helpers.d/php | 252 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 244 insertions(+), 8 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 224c0a3d9..5e7a7ec78 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,18 +2,47 @@ # Create a dedicated php-fpm config # -# usage: ynh_add_fpm_config [--phpversion=7.X] +# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] # | arg: -v, --phpversion - Version of php to use. +# | arg: -t, --use_template - Use this helper in template mode. +# +# ----------------------------------------------------------------------------- +# +# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint +# | arg: -v, --phpversion - Version of php to use.# +# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). +# low - Less than 20Mb of ram by pool. +# medium - Between 20Mb and 40Mb of ram by pool. +# high - More than 40Mb of ram by pool. +# Or specify exactly the footprint, the load of the service as Mb by pool instead of having a standard value. +# To have this value, use the following command and stress the service. +# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP +# +# | arg: -u, --usage - Expected usage of the service (low/medium/high). +# low - Personal usage, behind the sso. +# medium - Low usage, few people or/and publicly accessible. +# high - High usage, frequently visited website. # # Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { # Declare an array to define the options of this helper. - local legacy_args=v - declare -Ar args_array=( [v]=phpversion= ) + local legacy_args=vtuf + declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= ) local phpversion + local use_template + local usage + local footprint # Manage arguments with getopts ynh_handle_getopts_args "$@" + # The default behaviour is to use the template. + use_template="${use_template:-1}" + usage="${usage:-}" + footprint="${footprint:-}" + if [ -n "$usage" ] || [ -n "$footprint" ]; then + use_template=0 + fi + # Configure PHP-FPM 7.0 by default phpversion="${phpversion:-7.0}" @@ -28,11 +57,65 @@ ynh_add_fpm_config () { ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" finalphpconf="$fpm_config_dir/pool.d/$app.conf" ynh_backup_if_checksum_is_different --file="$finalphpconf" - cp ../conf/php-fpm.conf "$finalphpconf" - ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" - ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" + + if [ $use_template -eq 1 ] + then + # Usage 1, use the template in ../conf/php-fpm.conf + cp ../conf/php-fpm.conf "$finalphpconf" + ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" + ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" + ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" + + else + # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm + ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint + + # Copy the default file + cp "$fpm_config_dir/pool.d/www.conf" "$finalphpconf" + + # Replace standard variables into the default file + ynh_replace_string --match_string="^\[www\]" --replace_string="[$app]" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*listen = .*" --replace_string="listen = /var/run/php/php$phpversion-fpm-$app.sock" --target_file="$finalphpconf" + ynh_replace_string --match_string="^user = .*" --replace_string="user = $app" --target_file="$finalphpconf" + ynh_replace_string --match_string="^group = .*" --replace_string="group = $app" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*chdir = .*" --replace_string="chdir = $final_path" --target_file="$finalphpconf" + + # Configure fpm children + ynh_replace_string --match_string=".*pm = .*" --replace_string="pm = $php_pm" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_children = .*" --replace_string="pm.max_children = $php_max_children" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_requests = .*" --replace_string="pm.max_requests = 500" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*request_terminate_timeout = .*" --replace_string="request_terminate_timeout = 1d" --target_file="$finalphpconf" + if [ "$php_pm" = "dynamic" ] + then + ynh_replace_string --match_string=".*pm.start_servers = .*" --replace_string="pm.start_servers = $php_start_servers" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.min_spare_servers = .*" --replace_string="pm.min_spare_servers = $php_min_spare_servers" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_spare_servers = .*" --replace_string="pm.max_spare_servers = $php_max_spare_servers" --target_file="$finalphpconf" + elif [ "$php_pm" = "ondemand" ] + then + ynh_replace_string --match_string=".*pm.process_idle_timeout = .*" --replace_string="pm.process_idle_timeout = 10s" --target_file="$finalphpconf" + fi + + # Comment unused parameters + if [ "$php_pm" != "dynamic" ] + then + ynh_replace_string --match_string=".*\(pm.start_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*\(pm.min_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*\(pm.max_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + fi + if [ "$php_pm" != "ondemand" ] + then + ynh_replace_string --match_string=".*\(pm.process_idle_timeout = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + fi + + # Concatene the extra config. + if [ -e ../conf/extra_php-fpm.conf ]; then + cat ../conf/extra_php-fpm.conf >> "$finalphpconf" + fi + fi + + + chown root: "$finalphpconf" ynh_store_file_checksum --file="$finalphpconf" @@ -45,6 +128,7 @@ ynh_add_fpm_config () { chown root: "$finalphpini" ynh_store_file_checksum "$finalphpini" fi + ynh_systemd_action --service_name=$fpm_service --action=reload } @@ -145,3 +229,155 @@ ynh_remove_php () { ynh_secure_remove /etc/php/ynh_app_version fi } + +# Define the values to configure php-fpm +# +# usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print] +# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). +# low - Less than 20Mb of ram by pool. +# medium - Between 20Mb and 40Mb of ram by pool. +# high - More than 40Mb of ram by pool. +# Or specify exactly the footprint, the load of the service as Mb by pool instead of having a standard value. +# To have this value, use the following command and stress the service. +# watch -n0.5 ps -o user,cmd,%cpu,rss -u APP +# +# | arg: -u, --usage - Expected usage of the service (low/medium/high). +# low - Personal usage, behind the sso. +# medium - Low usage, few people or/and publicly accessible. +# high - High usage, frequently visited website. +# +# | arg: -p, --print - Print the result +# +# +# The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. +# So it will be used to defined 'pm.max_children' +# A lower value for the footprint will allow more children for 'pm.max_children'. And so for +# 'pm.start_servers', 'pm.min_spare_servers' and 'pm.max_spare_servers' which are defined from the +# value of 'pm.max_children' +# NOTE: 'pm.max_children' can't exceed 4 times the number of processor's cores. +# +# The usage value will defined the way php will handle the children for the pool. +# A value set as 'low' will set the process manager to 'ondemand'. Children will start only if the +# service is used, otherwise no child will stay alive. This config gives the lower footprint when the +# service is idle. But will use more proc since it has to start a child as soon it's used. +# Set as 'medium', the process manager will be at dynamic. If the service is idle, a number of children +# equal to pm.min_spare_servers will stay alive. So the service can be quick to answer to any request. +# The number of children can grow if needed. The footprint can stay low if the service is idle, but +# not null. The impact on the proc is a little bit less than 'ondemand' as there's always a few +# children already available. +# Set as 'high', the process manager will be set at 'static'. There will be always as many children as +# 'pm.max_children', the footprint is important (but will be set as maximum a quarter of the maximum +# RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many +# children ready to answer. +ynh_get_scalable_phpfpm () { + local legacy_args=ufp + # Declare an array to define the options of this helper. + declare -Ar args_array=( [u]=usage= [f]=footprint= [p]=print ) + local usage + local footprint + local print + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + # Set all characters as lowercase + footprint=${footprint,,} + usage=${usage,,} + print=${print:-0} + + if [ "$footprint" = "low" ] + then + footprint=20 + elif [ "$footprint" = "medium" ] + then + footprint=35 + elif [ "$footprint" = "high" ] + then + footprint=50 + fi + + # Define the way the process manager handle child processes. + if [ "$usage" = "low" ] + then + php_pm=ondemand + elif [ "$usage" = "medium" ] + then + php_pm=dynamic + elif [ "$usage" = "high" ] + then + php_pm=static + else + ynh_die --message="Does not recognize '$usage' as an usage value." + fi + + # Get the total of RAM available, except swap. + local max_ram=$(ynh_check_ram --no_swap) + + less0() { + # Do not allow value below 1 + if [ $1 -le 0 ] + then + echo 1 + else + echo $1 + fi + } + + # Define pm.max_children + # The value of pm.max_children is the total amount of ram divide by 2 and divide again by the footprint of a pool for this app. + # So if php-fpm start the maximum of children, it won't exceed half of the ram. + php_max_children=$(( $max_ram / 2 / $footprint )) + # If process manager is set as static, use half less children. + # Used as static, there's always as many children as the value of pm.max_children + if [ "$php_pm" = "static" ] + then + php_max_children=$(( $php_max_children / 2 )) + fi + php_max_children=$(less0 $php_max_children) + + # To not overload the proc, limit the number of children to 4 times the number of cores. + local core_number=$(nproc) + local max_proc=$(( $core_number * 4 )) + if [ $php_max_children -gt $max_proc ] + then + php_max_children=$max_proc + fi + + if [ "$php_pm" = "dynamic" ] + then + # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager + php_min_spare_servers=$(( $php_max_children / 8 )) + php_min_spare_servers=$(less0 $php_min_spare_servers) + + php_max_spare_servers=$(( $php_max_children / 2 )) + php_max_spare_servers=$(less0 $php_max_spare_servers) + + php_start_servers=$(( $php_min_spare_servers + ( $php_max_spare_servers - $php_min_spare_servers ) /2 )) + php_start_servers=$(less0 $php_start_servers) + else + php_min_spare_servers=0 + php_max_spare_servers=0 + php_start_servers=0 + fi + + if [ $print -eq 1 ] + then + ynh_debug --message="Footprint=${footprint}Mb by pool." + ynh_debug --message="Process manager=$php_pm" + ynh_debug --message="Max RAM=${max_ram}Mb" + if [ "$php_pm" != "static" ]; then + ynh_debug --message="\nMax estimated footprint=$(( $php_max_children * $footprint ))" + ynh_debug --message="Min estimated footprint=$(( $php_min_spare_servers * $footprint ))" + fi + if [ "$php_pm" = "dynamic" ]; then + ynh_debug --message="Estimated average footprint=$(( $php_max_spare_servers * $footprint ))" + elif [ "$php_pm" = "static" ]; then + ynh_debug --message="Estimated footprint=$(( $php_max_children * $footprint ))" + fi + ynh_debug --message="\nRaw php-fpm values:" + ynh_debug --message="pm.max_children = $php_max_children" + if [ "$php_pm" = "dynamic" ]; then + ynh_debug --message="pm.start_servers = $php_start_servers" + ynh_debug --message="pm.min_spare_servers = $php_min_spare_servers" + ynh_debug --message="pm.max_spare_servers = $php_max_spare_servers" + fi + fi +} From 96095624f5c506340954a2b86b41a41ba93b0f7f Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 9 Feb 2020 20:10:27 +0100 Subject: [PATCH 010/317] Add the helper ynh_check_ram --- data/helpers.d/hardware | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 data/helpers.d/hardware diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware new file mode 100644 index 000000000..11012a3d1 --- /dev/null +++ b/data/helpers.d/hardware @@ -0,0 +1,72 @@ +#!/bin/bash + +# Check the amount of available RAM +# +# usage: ynh_check_ram [--required=RAM required in Mb] [--no_swap|--only_swap] [--free_ram] +# | arg: -r, --required= - Amount of RAM required in Mb. The helper will return 0 is there's enough RAM, or 1 otherwise. +# If --required isn't set, the helper will print the amount of RAM, in Mb. +# | arg: -s, --no_swap - Ignore swap +# | arg: -o, --only_swap - Ignore real RAM, consider only swap. +# | arg: -f, --free_ram - Count only free RAM, not the total amount of RAM available. +ynh_check_ram () { + # Declare an array to define the options of this helper. + declare -Ar args_array=( [r]=required= [s]=no_swap [o]=only_swap [f]=free_ram ) + local required + local no_swap + local only_swap + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + required=${required:-} + no_swap=${no_swap:-0} + only_swap=${only_swap:-0} + + local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') + local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') + local total_ram_swap=$(( total_ram + total_swap )) + + local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}') + local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}') + local free_ram_swap=$(( free_ram + free_swap )) + + # Use the total amount of ram + local ram=$total_ram_swap + if [ $free_ram -eq 1 ] + then + # Use the total amount of free ram + ram=$free_ram_swap + if [ $no_swap -eq 1 ] + then + # Use only the amount of free ram + ram=$free_ram + elif [ $only_swap -eq 1 ] + then + # Use only the amount of free swap + ram=$free_swap + fi + else + if [ $no_swap -eq 1 ] + then + # Use only the amount of free ram + ram=$total_ram + elif [ $only_swap -eq 1 ] + then + # Use only the amount of free swap + ram=$total_swap + fi + fi + + if [ -n "$required" ] + then + # Return 1 if the amount of ram isn't enough. + if [ $ram -lt $required ] + then + return 1 + else + return 0 + fi + + # If no RAM is required, return the amount of available ram. + else + echo $ram + fi +} From e3bcc4b4c93053f9c728929b2b7ab7f610f9d0fa Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 24 Feb 2020 13:54:43 +0100 Subject: [PATCH 011/317] Fix pin priority issue --- data/helpers.d/apt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 0f973dda5..756f077ab 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -251,8 +251,8 @@ ynh_install_app_dependencies () { ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version # Pin this sury repository to prevent sury of doing shit - ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" 200 --name=extra_php_version - ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" 600 --name=extra_php_version --append + ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version + ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append fi fi fi From 052ade602d2d9d74ea37d373aa5693e44179d66b Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 10 Mar 2020 21:02:40 +0100 Subject: [PATCH 012/317] Fix missing option in ynh_install_php --- data/helpers.d/php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 5e7a7ec78..817be7f4d 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -188,8 +188,8 @@ ynh_install_php () { update-alternatives --set php /usr/bin/php7.0 # Pin this extra repository after packages are installed to prevent sury of doing shit - ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" 200 --name=extra_php_version - ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" 600 --name=extra_php_version --append + ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version + ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append # Advertise service in admin panel yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" From b7a5847c30473ae4c180aaee9eabee421d6a29db Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 10 Mar 2020 21:05:04 +0100 Subject: [PATCH 013/317] Add a line between each pin instructions --- data/helpers.d/apt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 756f077ab..def430055 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -532,6 +532,7 @@ ynh_pin_repo () { mkdir -p "/etc/apt/preferences.d" echo "Package: $package Pin: $pin -Pin-Priority: $priority" \ +Pin-Priority: $priority +" \ | $append "/etc/apt/preferences.d/$name" } From 9b698e669d2e3af5f24b23e5127f748f341429f3 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Fri, 27 Mar 2020 23:59:35 +0100 Subject: [PATCH 014/317] Fix those damn locales --- locales/de.json | 2 +- locales/fr.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/locales/de.json b/locales/de.json index ac9efddb2..5587a4e48 100644 --- a/locales/de.json +++ b/locales/de.json @@ -308,7 +308,7 @@ "experimental_feature": "Warnung: Diese Funktion ist experimentell und gilt nicht als stabil. Sie sollten sie nur verwenden, wenn Sie wissen, was Sie tun.", "error_when_removing_sftpuser_group": "Fehler beim Versuch, die Gruppe sftpusers zu entfernen", "edit_permission_with_group_all_users_not_allowed": "Sie dürfen die Berechtigung für die Gruppe \"all_users\" nicht bearbeiten. Verwenden Sie stattdessen \"yunohost user permission clear APP\" oder \"yunohost user permission add APP -u USER\".", - "edit_group_not_allowed": "Du bist nicht berechtigt zum Bearbeiten der Gruppe {group: s}", + "edit_group_not_allowed": "Du bist nicht berechtigt zum Bearbeiten der Gruppe {group:s}", "dyndns_domain_not_provided": "Der DynDNS-Anbieter {provider:s} kann die Domain(s) {domain:s} nicht bereitstellen.", "dyndns_could_not_check_available": "Konnte nicht überprüfen, ob {domain:s} auf {provider:s} verfügbar ist.", "dyndns_could_not_check_provide": "Konnte nicht überprüft, ob {provider:s} die Domain(s) {domain:s} bereitstellen kann.", diff --git a/locales/fr.json b/locales/fr.json index 53aedc1ae..f175a5704 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -280,7 +280,7 @@ "certmanager_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être résolu depuis votre serveur YunoHost. Cela peut se produire si vous avez récemment modifié votre enregistrement DNS. Si c'est le cas, merci d’attendre quelques heures qu’il se propage. Si le problème persiste, envisager d’ajouter {domain:s} au fichier /etc/hosts. (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces vérifications.)", "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.", "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.", - "appslist_retrieve_bad_format": "Impossible de lire la liste des applications extraites '{appslist: s}'", + "appslist_retrieve_bad_format": "Impossible de lire la liste des applications extraites '{appslist:s}'", "domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).", "yunohost_ca_creation_success": "L’autorité de certification locale créée.", "appslist_name_already_tracked": "Une liste d'applications enregistrées portant le nom {name:s} existe déjà.", @@ -607,11 +607,11 @@ "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", "system_groupname_exists": "Le nom de groupe existe déjà dans le groupe du systèmes", "tools_update_failed_to_app_fetchlist": "Impossible de mettre à jour les listes d'applications de YunoHost car: {error}", - "user_already_in_group": "L'utilisateur '{user:}' est déjà dans le groupe '{group: s}'", - "user_not_in_group": "L'utilisateur '{user: s}' ne fait pas partie du groupe {group: s}", + "user_already_in_group": "L'utilisateur '{user:}' est déjà dans le groupe '{group:s}'", + "user_not_in_group": "L'utilisateur '{user:s}' ne fait pas partie du groupe {group:s}", "migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", "permission_not_found": "Autorisation '{permission:s}' introuvable", - "permission_name_not_valid": "Choisissez un nom d'autorisation autorisé pour '{permission: s}'", + "permission_name_not_valid": "Choisissez un nom d'autorisation autorisé pour '{permission:s}'", "permission_update_failed": "Impossible de mettre à jour la permission '{permission}': {error}", "permission_generated": "Base de données des autorisations mise à jour", "permission_updated": "Permission '{permission:s}' mise à jour", @@ -626,13 +626,13 @@ "migrations_success_forward": "Migration {id} terminée", "need_define_permission_before": "Redéfinissez l'autorisation à l'aide de 'yunohost user permission add -u USER' avant de supprimer un groupe autorisé", "operation_interrupted": "L'opération a été interrompue manuellement ?", - "permission_already_clear": "L'autorisation '{permission: s}' est déjà vide pour l'application {app: s}", + "permission_already_clear": "L'autorisation '{permission:s}' est déjà vide pour l'application {app:s}", "permission_already_exist": "L'autorisation '{permission}' existe déjà", "permission_created": "Permission '{permission:s}' créée", "permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {erreur}", "permission_deleted": "Permission '{permission:s}' supprimée", "permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}", - "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur: s}' dans le groupe '{groupe: s}'", + "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur:s}' dans le groupe '{groupe:s}'", "migration_description_0011_setup_group_permission": "Initialiser les groupes d'utilisateurs et autorisations pour les applications et les services", "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration", "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}", From 5ded6ecbe6677e9de21ca9e9272e1943428a667b Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sat, 28 Mar 2020 00:04:32 +0100 Subject: [PATCH 015/317] Merge resolved --- locales/oc.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/locales/oc.json b/locales/oc.json index 55f7a002a..a06520ae5 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -439,13 +439,8 @@ "log_service_regen_conf": "Regenerar la configuracion sistèma de « {} »", "log_user_create": "Ajustar l’utilizaire « {} »", "log_user_delete": "Levar l’utilizaire « {} »", -<<<<<<< HEAD - "log_user_update": "Actualizar las informacions a l’utilizaire « {} »", - "log_tools_maindomain": "Far venir « {} » lo domeni màger", -======= "log_user_update": "Actualizar las informacions de l’utilizaire « {} »", - "log_domain_main_domain": "Far venir « {} » lo domeni màger", ->>>>>>> b968dff2... Translated using Weblate (Occitan) + "log_tools_maindomain": "Far venir « {} » lo domeni màger", "log_tools_migrations_migrate_forward": "Migrar", "log_tools_migrations_migrate_backward": "Tornar en arrièr", "log_tools_postinstall": "Realizar la post installacion del servidor YunoHost", From 3574527311eaa3c9a169cd8e6d04283a3a2e47ad Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 28 Mar 2020 00:33:52 +0100 Subject: [PATCH 016/317] Fix mess due to automatic translation tools ~_~ --- locales/ar.json | 6 +++--- locales/ca.json | 4 ++-- locales/de.json | 6 +++--- locales/eo.json | 20 ++++++++++---------- locales/fr.json | 12 ++++++------ locales/nl.json | 2 +- locales/oc.json | 18 +++++++++--------- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index 936b54d2e..6bcbb9333 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -182,7 +182,7 @@ "firewall_reloaded": "The firewall has been reloaded", "firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.", "format_datetime_short": "%m/%d/%Y %I:%M %p", - "global_settings_bad_choice_for_enum": "Bad value for setting {setting:s}, received {received_type:s}, except {expected_type:s}", + "global_settings_bad_choice_for_enum": "Bad value for setting {setting:s}, received {choice:s}, except {available_choices:s}", "global_settings_bad_type_for_setting": "Bad type for setting {setting:s}, received {received_type:s}, except {expected_type:s}", "global_settings_cant_open_settings": "Failed to open settings file, reason: {reason:s}", "global_settings_cant_serialize_settings": "Failed to serialize settings data, reason: {reason:s}", @@ -227,8 +227,8 @@ "migrations_current_target": "Migration target is {}", "migrations_error_failed_to_load_migration": "ERROR: failed to load migration {number} {name}", "migrations_forward": "Migrating forward", - "migrations_loading_migration": "Loading migration {number} {name}…", - "migrations_migration_has_failed": "Migration {number} {name} has failed with exception {exception}, aborting", + "migrations_loading_migration": "Loading migration {id}…", + "migrations_migration_has_failed": "Migration {id} has failed with exception {exception}, aborting", "migrations_no_migrations_to_run": "No migrations to run", "migrations_show_currently_running_migration": "Running migration {number} {name}…", "migrations_show_last_migration": "Last ran migration is {}", diff --git a/locales/ca.json b/locales/ca.json index 5d9ed318d..61d832c30 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -167,7 +167,7 @@ "domain_created": "S'ha creat el domini", "domain_creation_failed": "No s'ha pogut crear el domini {domain}: {error}", "domain_deleted": "S'ha eliminat el domini", - "domain_deletion_failed": "No s'ha pogut eliminar el domini {domini}: {error}", + "domain_deletion_failed": "No s'ha pogut eliminar el domini {domain}: {error}", "domain_exists": "El domini ja existeix", "app_action_cannot_be_ran_because_required_services_down": "Aquests serveis necessaris haurien d'estar funcionant per poder executar aquesta acció: {services} Intenteu reiniciar-los per continuar (i possiblement investigar perquè estan aturats).", "domain_dns_conf_is_just_a_recommendation": "Aquesta ordre mostra la configuració *recomanada*. En cap cas fa la configuració del DNS. És la vostra responsabilitat configurar la zona DNS en el vostre registrar en acord amb aquesta recomanació.", @@ -459,7 +459,7 @@ "service_description_yunohost-firewall": "Gestiona els ports de connexió oberts i tancats als serveis", "service_disable_failed": "No s'han pogut fer que el servei «{service:s}» no comenci a l'arrancada.\n\nRegistres recents: {logs:s}", "service_disabled": "El servei «{service:s}» ja no començarà al arrancar el sistema.", - "service_enable_failed": "No s'ha pogut fer que el servei «{service:s}» comenci automàticament a l'arrancada.\n\nRegistres recents: {log:s}", + "service_enable_failed": "No s'ha pogut fer que el servei «{service:s}» comenci automàticament a l'arrancada.\n\nRegistres recents: {logs:s}", "service_enabled": "El servei «{service:s}» començarà automàticament durant l'arrancada del sistema.", "service_no_log": "No hi ha cap registre pel servei «{service:s}»", "service_regen_conf_is_deprecated": "«yunohost service regen-conf» està desfasat! Utilitzeu «yunohost tools regen-conf» en el seu lloc.", diff --git a/locales/de.json b/locales/de.json index 5587a4e48..d259fb7b9 100644 --- a/locales/de.json +++ b/locales/de.json @@ -302,7 +302,7 @@ "app_change_url_success": "{app:s} URL ist nun {domain:s}{path:s}", "backup_applying_method_borg": "Sende alle Dateien zur Sicherung ins borg-backup repository…", "invalid_url_format": "ungültiges URL Format", - "global_settings_bad_type_for_setting": "Falscher Typ für Einstellung {setting:s}. Empfangen: {receive_type:s}, aber erwartet: {expected_type:s}", + "global_settings_bad_type_for_setting": "Falscher Typ für Einstellung {setting:s}. Empfangen: {received_type:s}, aber erwartet: {expected_type:s}", "global_settings_bad_choice_for_enum": "Falsche Wahl für die Einstellung {setting:s}. Habe '{choice:s}' erhalten, aber es stehen nur folgende Auswahlmöglichkeiten zur Verfügung: {available_choices:s}", "file_does_not_exist": "Die Datei {path:s} existiert nicht.", "experimental_feature": "Warnung: Diese Funktion ist experimentell und gilt nicht als stabil. Sie sollten sie nur verwenden, wenn Sie wissen, was Sie tun.", @@ -333,7 +333,7 @@ "backup_custom_mount_error": "Bei der benutzerdefinierten Sicherungsmethode ist beim Arbeitsschritt \"Einhängen/Verbinden\" ein Fehler aufgetreten", "backup_custom_backup_error": "Bei der benutzerdefinierten Sicherungsmethode ist beim Arbeitsschritt \"Sicherung\" ein Fehler aufgetreten", "backup_csv_creation_failed": "Die zur Wiederherstellung erforderliche CSV-Datei kann nicht erstellt werden", - "backup_couldnt_bind": "{Src:s} konnte nicht an {dest:s} angebunden werden.", + "backup_couldnt_bind": "{src:s} konnte nicht an {dest:s} angebunden werden.", "backup_borg_not_implemented": "Die Borg-Sicherungsmethode ist noch nicht implementiert", "backup_ask_for_copying_if_needed": "Möchten Sie die Sicherung mit {size:s} MB temporär durchführen? (Dieser Weg wird verwendet, da einige Dateien nicht mit einer effizienteren Methode vorbereitet werden konnten).", "backup_actually_backuping": "Erstellt ein Backup-Archiv aus den gesammelten Dateien …", @@ -343,7 +343,7 @@ "apps_permission_restoration_failed": "Erteilen der Berechtigung '{permission:s}' für die Wiederherstellung der App {app:s} erforderlich", "apps_permission_not_found": "Keine Berechtigung für die installierten Apps gefunden", "app_upgrade_some_app_failed": "Einige Anwendungen können nicht aktualisiert werden", - "app_upgrade_app_name": "{App} wird jetzt aktualisiert…", + "app_upgrade_app_name": "{app} wird jetzt aktualisiert…", "app_upgrade_several_apps": "Die folgenden Apps werden aktualisiert: {apps}", "app_start_restore": "Anwendung {app} wird wiederhergestellt…", "app_start_backup": "Sammeln von Dateien, die für {app} gesichert werden sollen…", diff --git a/locales/eo.json b/locales/eo.json index 906648120..5047fff09 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -74,7 +74,7 @@ "backup_invalid_archive": "Ĉi tio ne estas rezerva ar archiveivo", "ask_current_admin_password": "Pasvorto pri aktuala administrado", "backup_creation_failed": "Ne povis krei la rezervan ar archiveivon", - "backup_hook_unknown": "La rezerva hoko '{hoko:s}' estas nekonata", + "backup_hook_unknown": "La rezerva hoko '{hook:s}' estas nekonata", "backup_custom_backup_error": "Propra rezerva metodo ne povis preterpasi la paŝon \"sekurkopio\"", "ask_main_domain": "Ĉefa domajno", "backup_method_tar_finished": "TAR-rezerva ar archiveivo kreita", @@ -97,15 +97,15 @@ "app_start_backup": "Kolekti dosierojn por esti subtenata por la '{app}' …", "backup_archive_name_exists": "Rezerva arkivo kun ĉi tiu nomo jam ekzistas.", "backup_applying_method_tar": "Krei la rezervan TAR-ar archiveivon …", - "backup_method_custom_finished": "Propra rezerva metodo '{metodo:s}' finiĝis", - "appslist_retrieve_error": "Ne eblas akiri la forajn listojn '{appslist:s}': {eraro:s}", + "backup_method_custom_finished": "Propra rezerva metodo '{method:s}' finiĝis", + "appslist_retrieve_error": "Ne eblas akiri la forajn listojn '{appslist:s}': {error:s}", "app_already_installed_cant_change_url": "Ĉi tiu app estas jam instalita. La URL ne povas esti ŝanĝita nur per ĉi tiu funkcio. Rigardu \"app changeurl\" se ĝi haveblas.", "app_not_correctly_installed": "{app:s} ŝajnas esti malĝuste instalita", "app_removed": "{app:s} forigita", "backup_delete_error": "Ne povis forigi '{path:s}'", "app_package_need_update": "La pakaĵo {app} devas esti ĝisdatigita por sekvi YunoHost-ŝanĝojn", "backup_nothings_done": "Nenio por ŝpari", - "backup_applying_method_custom": "Nomante la kutiman rezervan metodon '{metodo:s}' …", + "backup_applying_method_custom": "Nomante la kutiman rezervan metodon '{method:s}' …", "appslist_fetched": "Ĝisdatigis la liston de aplikoj '{appslist:s}'", "backup_app_failed": "Ne eblis rezervi la programon '{app:s}'", "app_upgrade_some_app_failed": "Iuj aplikoj ne povis esti altgradigitaj", @@ -268,7 +268,7 @@ "pattern_positive_number": "Devas esti pozitiva nombro", "monitor_stats_file_not_found": "Ne povis trovi la statistikan dosieron", "certmanager_error_no_A_record": "Neniu DNS 'A' rekordo trovita por '{domain:s}'. Vi bezonas atentigi vian domajnan nomon al via maŝino por povi instali atestilon Lasu-Ĉifri. (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)", - "update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}", + "update_apt_cache_failed": "Ne eblis ĝisdatigi la kaŝmemoron de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}", "migrations_no_migrations_to_run": "Neniuj migradoj por funkcii", "executing_command": "Plenumanta komandon '{command:s}' …", "diagnosis_no_apps": "Neniu tia instalita app", @@ -332,7 +332,7 @@ "tools_upgrade_at_least_one": "Bonvolu specifi '--apps' aŭ '--system'", "service_already_stopped": "La servo '{service:s}' jam ĉesis", "unit_unknown": "Nekonata unuo '{unit:s}'", - "migration_0003_modified_files": "Bonvolu noti, ke la jenaj dosieroj estis trovitaj mane kaj modifitaj kaj povus esti anstataŭigitaj sekve de la ĝisdatigo: {manual_modified_files}", + "migration_0003_modified_files": "Bonvolu noti, ke la jenaj dosieroj estis trovitaj mane kaj modifitaj kaj povus esti anstataŭigitaj sekve de la ĝisdatigo: {manually_modified_files}", "tools_upgrade_cant_both": "Ne eblas ĝisdatigi ambaŭ sistemon kaj programojn samtempe", "restore_extracting": "Eltirante bezonatajn dosierojn el la ar theivo…", "upnp_port_open_failed": "Ne povis malfermi havenon per UPnP", @@ -390,7 +390,7 @@ "regenconf_up_to_date": "La agordo jam estas ĝisdatigita por kategorio '{category}'", "migration_0003_patching_sources_list": "Patching the sources.lists …", "global_settings_setting_security_ssh_compatibility": "Kongruo vs sekureca kompromiso por la SSH-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", - "migrations_need_to_accept_disclaimer": "Por funkciigi la migradon {id}, via devas akcepti la sekvan malakcepton:\n---\n{malavantaĝo}\n---\nSe vi akceptas funkcii la migradon, bonvolu rekonduki la komandon kun la opcio '--accept-disclaimer'.", + "migrations_need_to_accept_disclaimer": "Por funkciigi la migradon {id}, via devas akcepti la sekvan malakcepton:\n---\n{disclaimer}\n---\nSe vi akceptas funkcii la migradon, bonvolu rekonduki la komandon kun la opcio '--accept-disclaimer'.", "regenconf_file_remove_failed": "Ne povis forigi la agordodosieron '{conf}'", "not_enough_disk_space": "Ne sufiĉe libera spaco sur '{path:s}'", "migration_0006_disclaimer": "YunoHost nun atendas, ke la pasvortoj de admin kaj radiko estos sinkronigitaj. Ĉi tiu migrado anstataŭigas vian radikan pasvorton kun la administran pasvorton.", @@ -465,10 +465,10 @@ "global_settings_cant_open_settings": "Ne eblis malfermi agordojn, tial: {reason:s}", "user_created": "Uzanto kreita", "service_description_avahi-daemon": "Permesas al vi atingi vian servilon uzante 'yunohost.local' en via loka reto", - "certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domajno:s}! (Uzu --forte pretervidi)", + "certmanager_attempt_to_replace_valid_cert": "Vi provas anstataŭigi bonan kaj validan atestilon por domajno {domain:s}! (Uzu --forte pretervidi)", "monitor_stats_period_unavailable": "Ne ekzistas disponeblaj statistikoj por la periodo", "regenconf_updated": "Agordo ĝisdatigita por '{category}'", - "update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourcelist}", + "update_apt_cache_warning": "Io iris malbone dum la ĝisdatigo de la kaŝmemoro de APT (paka administranto de Debian). Jen rubujo de la sources.list-linioj, kiuj povus helpi identigi problemajn liniojn:\n{sourceslist}", "regenconf_dry_pending_applying": "Kontrolado de pritraktata agordo, kiu estus aplikita por kategorio '{category}'…", "regenconf_file_copy_failed": "Ne povis kopii la novan agordodosieron '{new}' al '{conf}'", "global_settings_setting_example_string": "Ekzemple korda elekto", @@ -487,7 +487,7 @@ "mysql_db_creation_failed": "Ne povis krei MySQL-datumbazon", "ldap_initialized": "LDAP inicializis", "migrate_tsig_not_needed": "Vi ne ŝajnas uzi DynDNS-domajnon, do neniu migrado necesas.", - "certmanager_domain_cert_not_selfsigned": "La atestilo por domajno {domajno:s} ne estas mem-subskribita. Ĉu vi certas, ke vi volas anstataŭigi ĝin? (Uzu '--force' por fari tion.)", + "certmanager_domain_cert_not_selfsigned": "La atestilo por domajno {domain:s} ne estas mem-subskribita. Ĉu vi certas, ke vi volas anstataŭigi ĝin? (Uzu '--force' por fari tion.)", "certmanager_unable_to_parse_self_CA_name": "Ne povis trapasi nomon de mem-subskribinta aŭtoritato (dosiero: {file:s})", "log_selfsigned_cert_install": "Instalu mem-subskribitan atestilon sur '{}' domajno", "log_tools_reboot": "Reklamu vian servilon", diff --git a/locales/fr.json b/locales/fr.json index f175a5704..4ea52c8af 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -242,7 +242,7 @@ "user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur", "user_info_failed": "Impossible de récupérer les informations de l’utilisateur", "user_unknown": "L'utilisateur {user:s} est inconnu", - "user_update_failed": "Impossible de mettre à jour l'utilisateur {utilisateur}: {erreur}", + "user_update_failed": "Impossible de mettre à jour l'utilisateur {user}: {error}", "user_updated": "L’utilisateur a été modifié", "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", @@ -320,7 +320,7 @@ "backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde", "backup_archive_mount_failed": "Le montage de l’archive de sauvegarde a échoué", "backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'", - "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {taille:s} temporairement? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)", + "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size:s} temporairement? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)", "backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée", "backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée", "backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive", @@ -466,7 +466,7 @@ "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6", "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !", "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système… :(", - "migration_0005_not_enough_space": "Laissez suffisamment d'espace disponible dans {chemin} pour exécuter la migration.", + "migration_0005_not_enough_space": "Laissez suffisamment d'espace disponible dans {path} pour exécuter la migration.", "recommend_to_add_first_user": "La post-installation est terminée mais YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant la commande 'yunohost user create $nomdutilisateur' ou bien via l’interface d’administration web.", "service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX", "users_available": "Liste des utilisateurs disponibles :", @@ -600,7 +600,7 @@ "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales", "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}", - "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {erreur:s}", + "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {error:s}", "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", "migration_0011_migration_failed_trying_to_rollback": "La migration a échouée… Tentative de restauration du système.", "migration_0011_rollback_success": "Système restauré.", @@ -629,10 +629,10 @@ "permission_already_clear": "L'autorisation '{permission:s}' est déjà vide pour l'application {app:s}", "permission_already_exist": "L'autorisation '{permission}' existe déjà", "permission_created": "Permission '{permission:s}' créée", - "permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {erreur}", + "permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {error}", "permission_deleted": "Permission '{permission:s}' supprimée", "permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}", - "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{utilisateur:s}' dans le groupe '{groupe:s}'", + "remove_user_of_group_not_allowed": "Vous n'êtes pas autorisé à supprimer l'utilisateur '{user:s}' dans le groupe '{group:s}'", "migration_description_0011_setup_group_permission": "Initialiser les groupes d'utilisateurs et autorisations pour les applications et les services", "migration_0011_LDAP_config_dirty": "Il semble que vous ayez personnalisé votre configuration LDAP. Pour cette migration, la configuration LDAP doit être mise à jour.\nVous devez enregistrer votre configuration actuelle, réintialiser la configuration d'origine en exécutant 'yunohost tools regen-conf -f', puis réessayer la migration", "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}", diff --git a/locales/nl.json b/locales/nl.json index 832ca4ea2..9406d9bea 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -82,7 +82,7 @@ "port_available": "Poort {port:d} is beschikbaar", "port_unavailable": "Poort {port:d} is niet beschikbaar", "restore_app_failed": "De app '{app:s}' kon niet worden terug gezet", - "restore_hook_unavailable": "De herstel-hook '{hook:s}' is niet beschikbaar op dit systeem", + "restore_hook_unavailable": "De herstel-hook '{part:s}' is niet beschikbaar op dit systeem", "service_add_failed": "Kan service '{service:s}' niet toevoegen", "service_already_started": "Service '{service:s}' draait al", "service_cmd_exec_failed": "Kan '{command:s}' niet uitvoeren", diff --git a/locales/oc.json b/locales/oc.json index a06520ae5..00d7aa5c5 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -144,7 +144,7 @@ "domain_created": "Domeni creat", "domain_creation_failed": "Creacion del domeni {domain}: impossibla", "domain_deleted": "Domeni suprimit", - "domain_deletion_failed": "Supression impossibla del domeni {domini}: {error}", + "domain_deletion_failed": "Supression impossibla del domeni {domain}: {error}", "domain_dyndns_invalid": "Domeni incorrècte per una utilizacion amb DynDNS", "domain_dyndns_root_unknown": "Domeni DynDNS màger desconegut", "domain_exists": "Lo domeni existís ja", @@ -247,7 +247,7 @@ "firewall_reload_failed": "Impossible de recargar lo parafuòc", "firewall_reloaded": "Parafuòc recargat", "firewall_rules_cmd_failed": "Unas règlas del parafuòc an fracassat. Per mai informacions, consultatz lo jornal.", - "global_settings_bad_choice_for_enum": "La valor del paramètre {setting:s} es incorrècta. Recebut : {received_type:s}, mas las opcions esperadas son : {expected_type:s}", + "global_settings_bad_choice_for_enum": "La valor del paramètre {setting:s} es incorrècta. Recebut : {choice:s}, mas las opcions esperadas son : {available_choices:s}", "global_settings_bad_type_for_setting": "Lo tipe del paramètre {setting:s} es incorrècte, recebut : {received_type:s}, esperat {expected_type:s}", "global_settings_cant_write_settings": "Fracàs de l’escritura del fichièr de configuracion, rason : {reason:s}", "global_settings_setting_example_enum": "Exemple d’opcion de tipe enumeracion", @@ -491,7 +491,7 @@ "migration_0007_cannot_restart": "SSH pòt pas èsser reavit aprèp aver ensajat d’anullar la migracion numèro 6.", "migrations_success": "Migracion {number} {name} reüssida !", "service_conf_now_managed_by_yunohost": "Lo fichièr de configuracion « {conf} » es ara gerit per YunoHost.", - "service_reloaded": "Lo servici « {servici:s} » es estat tornat cargar", + "service_reloaded": "Lo servici « {service:s} » es estat tornat cargar", "already_up_to_date": "I a pas res a far ! Tot es ja a jorn !", "app_action_cannot_be_ran_because_required_services_down": "Aquestas aplicacions necessitan d’èsser lançadas per poder executar aquesta accion : {services}. Abans de contunhar deuriatz ensajar de reaviar los servicis seguents (e tanben cercar perque son tombats en pana) : {services}", "confirm_app_install_warning": "Atencion : aquesta aplicacion fonciona mas non es pas ben integrada amb YunoHost. Unas foncionalitats coma l’autentificacion unica e la còpia de seguretat/restauracion pòdon èsser indisponiblas. volètz l’installar de totas manièras ? [{answers:s}] ", @@ -584,16 +584,16 @@ "migration_0011_migrate_permission": "Migracion de las permission dels paramètres d’aplicacion a LDAP…", "migration_0011_update_LDAP_database": "Actualizacion de la basa de donadas LDAP…", "migration_0011_update_LDAP_schema": "Actualizacion de l’esquèma LDAP…", - "permission_already_exist": "La permission « {permission:s} » per l’aplicacion {app:s} existís ja", - "permission_created": "Permission creada « {permission:s} » per l’aplicacion{app:s}", + "permission_already_exist": "La permission « {permission:s} » existís ja", + "permission_created": "Permission « {permission:s} » creada", "permission_creation_failed": "Creacion impossibla de la permission", - "permission_deleted": "Permission « {permission:s} » per l’aplicacion {app:s} suprimida", - "permission_deletion_failed": "Fracàs de la supression de la permission « {permission:s} » per l’aplicacion {app:s}", - "permission_not_found": "Permission « {permission:s} » pas trobada per l’aplicacion {app:s}", + "permission_deleted": "Permission « {permission:s} » suprimida", + "permission_deletion_failed": "Fracàs de la supression de la permission « {permission:s} »", + "permission_not_found": "Permission « {permission:s} » pas trobada", "permission_name_not_valid": "Lo nom de la permission « {permission:s} » es pas valid", "permission_update_failed": "Fracàs de l’actualizacion de la permission", "permission_generated": "La basa de donadas de las permission es estada actualizada", - "permission_updated": "La permission « {permission:s} » per l’aplicacion {app:s} es estada actualizada", + "permission_updated": "La permission « {permission:s} » es estada actualizada", "permission_update_nothing_to_do": "Cap de permission d’actualizar", "remove_main_permission_not_allowed": "Se pòt pas suprimir la permission màger", "remove_user_of_group_not_allowed": "Sètz pas autorizat a suprimir {user:s} del grop {group:s}", From 0397aa91d94364a6652987b51af702f258ba1863 Mon Sep 17 00:00:00 2001 From: kay0u Date: Fri, 27 Mar 2020 23:50:50 +0000 Subject: [PATCH 017/317] Update changelog for 3.7.0.11 release --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 1f137ba16..cc026e268 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.7.0.11) stable; urgency=low + + - [fix] Mess due to automatic translation tools ~_~ + + -- Kay0u Fri, 27 Mar 2020 23:49:45 +0000 + yunohost (3.7.0.10) stable; urgency=low - [fix] On some weird setup, this folder and content ain't readable by group ... gotta make sure to make rx for group other slapd will explode From a2b4e151e4ab016f9d96d698848beaaaf848886d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 28 Mar 2020 14:51:19 +0100 Subject: [PATCH 018/317] Ugh, this gotta go into an m18n.n to work... --- src/yunohost/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 34b367d7d..4a047b58f 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -577,7 +577,7 @@ def user_group_create(operation_logger, groupname, gid=None, primary_group=False all_existing_groupnames = {x.gr_name for x in grp.getgrall()} if groupname in all_existing_groupnames: if primary_group: - logger.warning('group_already_exist_on_system_but_removing_it', group=groupname) + logger.warning(m18n.n('group_already_exist_on_system_but_removing_it', group=groupname)) subprocess.check_call("sed --in-place '/^%s:/d' /etc/group" % groupname, shell=True) else: raise YunohostError('group_already_exist_on_system', group=groupname) From f54701eacc7ed8589ab0d9fc90c3d5c751fb90cc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 28 Mar 2020 14:52:42 +0100 Subject: [PATCH 019/317] Update changelog for 3.7.0.12 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index cc026e268..9bcaea043 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.7.0.12) stable; urgency=low + + - Fix previous buggy hotfix about deleting existing primary groups ... + + -- Alexandre Aubin Sat, 28 Mar 2020 14:52:00 +0000 + yunohost (3.7.0.11) stable; urgency=low - [fix] Mess due to automatic translation tools ~_~ From 23617a9386e2549f5288dcbcf1b0349bc0eb7ca7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 3 Apr 2020 03:41:37 +0200 Subject: [PATCH 020/317] Update dovecot SSL conf according to Mozilla recommentation --- data/templates/dovecot/dovecot.conf | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/data/templates/dovecot/dovecot.conf b/data/templates/dovecot/dovecot.conf index 477ccbfb1..0a3c185ee 100644 --- a/data/templates/dovecot/dovecot.conf +++ b/data/templates/dovecot/dovecot.conf @@ -12,10 +12,25 @@ protocols = imap sieve {% if pop3_enabled == "True" %}pop3{% endif %} mail_plugins = $mail_plugins quota -ssl = yes +############################################################################### + +# generated 2020-04-03, Mozilla Guideline v5.4, Dovecot 2.2.27, OpenSSL 1.1.1l, intermediate configuration +# https://ssl-config.mozilla.org/#server=dovecot&version=2.2.27&config=intermediate&openssl=1.1.1l&guideline=5.4 + +ssl = required + ssl_cert = Date: Fri, 3 Apr 2020 03:41:52 +0200 Subject: [PATCH 021/317] Update postfix SSL conf according to Moz^Cla recommentation --- data/templates/postfix/main.cf | 44 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 045b8edd0..79a551a6c 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -18,35 +18,39 @@ append_dot_mydomain = no readme_directory = no # -- TLS for incoming connections -# By default, TLS is disabled in the Postfix SMTP server, so no difference to -# plain Postfix is visible. Explicitly switch it on with "smtpd_tls_security_level = may". -smtpd_tls_security_level=may +############################################################################### +# generated 2020-04-03, Mozilla Guideline v5.4, Postfix 3.1.14, OpenSSL 1.1.1l, intermediate configuration +# https://ssl-config.mozilla.org/#server=postfix&version=3.1.14&config=intermediate&openssl=1.1.1l&guideline=5.4 -# Sending AUTH data over an unencrypted channel poses a security risk. -# When TLS layer encryption is optional ("smtpd_tls_security_level = may"), it -# may however still be useful to only offer AUTH when TLS is active. To maintain -# compatibility with non-TLS clients, the default is to accept AUTH without -# encryption. In order to change this behavior, we set "smtpd_tls_auth_only = yes". -smtpd_tls_auth_only=yes +# (No modern conf support until we're on buster...) +# {% if compatibility == "intermediate" %} {% else %} {% endif %} + +smtpd_use_tls = yes + +smtpd_tls_security_level = may +smtpd_tls_auth_only = yes smtpd_tls_cert_file = /etc/yunohost/certs/{{ main_domain }}/crt.pem smtpd_tls_key_file = /etc/yunohost/certs/{{ main_domain }}/key.pem -smtpd_tls_exclude_ciphers = aNULL, MD5, DES, ADH, RC4, 3DES +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 +smtpd_tls_mandatory_ciphers = medium + +# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem +# not actually 1024 bits, this applies to all DHE >= 1024 bits +# smtpd_tls_dh1024_param_file = /path/to/dhparam.pem + +tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 +tls_preempt_cipherlist = no +############################################################################### smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_loglevel=1 -{% if compatibility == "intermediate" %} -smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3 -{% else %} -smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1 -{% endif %} -smtpd_tls_mandatory_ciphers=high -smtpd_tls_eecdh_grade = ultra # -- TLS for outgoing connections # Use TLS if this is supported by the remote SMTP server, otherwise use plaintext. smtp_tls_security_level=may smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache -smtp_tls_exclude_ciphers = $smtpd_tls_exclude_ciphers -smtp_tls_mandatory_ciphers= $smtpd_tls_mandatory_ciphers +smtp_tls_exclude_ciphers = aNULL, MD5, DES, ADH, RC4, 3DES +smtp_tls_mandatory_ciphers= high smtp_tls_loglevel=1 # Configure Root CA certificates @@ -167,4 +171,4 @@ default_destination_rate_delay = 5s # By default it's possible to detect if the email adress exist # So it's easly possible to scan a server to know which email adress is valid # and after to send spam -disable_vrfy_command = yes \ No newline at end of file +disable_vrfy_command = yes From b8a1687f88f4abd159c0845559c6352739ef0ca0 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 3 Apr 2020 20:30:00 +0200 Subject: [PATCH 022/317] Use a dedicated php service for each app --- data/helpers.d/php | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 41af467c5..5167afa2a 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -18,7 +18,7 @@ ynh_add_fpm_config () { phpversion="${phpversion:-7.0}" local fpm_config_dir="/etc/php/$phpversion/fpm" - local fpm_service="php${phpversion}-fpm" + local fpm_service="php${phpversion}-fpm-$app" # Configure PHP-FPM 5 on Debian Jessie if [ "$(ynh_get_debian_release)" == "jessie" ]; then fpm_config_dir="/etc/php5/fpm" @@ -45,7 +45,27 @@ ynh_add_fpm_config () { chown root: "$finalphpini" ynh_store_file_checksum "$finalphpini" fi - ynh_systemd_action --service_name=$fpm_service --action=reload + + # Create a config for a dedicated php-fpm service for the app + echo " +[Unit] +Description=PHP $phpversion FastCGI Process Manager for $app +After=network.target + +[Service] +Type=notify +PIDFile=/run/php/php${phpversion}-fpm-$app.pid +ExecStart=/usr/sbin/php-fpm${phpversion} --nodaemonize --fpm-config $finalphpconf --pid /run/php/php${phpversion}-fpm-$app.pid +ExecReload=/bin/kill -USR2 \$MAINPID + +[Install] +WantedBy=multi-user.target +" > ../conf/$fpm_service + + # Create this dedicated php-fpm service + ynh_add_systemd_config --service=$fpm_service --template=$fpm_service + + ynh_systemd_action --service_name=$fpm_service --action=restart } # Remove the dedicated php-fpm config @@ -61,7 +81,10 @@ ynh_remove_fpm_config () { fpm_config_dir="/etc/php/7.0/fpm" fpm_service="php7.0-fpm" fi + + # Remove the dedicated service php-fpm service + ynh_remove_systemd_config --service=$fpm_service + ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 - ynh_systemd_action --service_name=$fpm_service --action=reload } From 147b2490074d4d306fd68e43a8502afd597d2737 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 4 Apr 2020 01:19:49 +0200 Subject: [PATCH 023/317] Proper migration to new directory --- data/helpers.d/php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 5167afa2a..3c5390f56 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -17,17 +17,36 @@ ynh_add_fpm_config () { # Configure PHP-FPM 7.0 by default phpversion="${phpversion:-7.0}" - local fpm_config_dir="/etc/php/$phpversion/fpm" + local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" + local old_fpm_config_dir="/etc/php/$phpversion/fpm" local fpm_service="php${phpversion}-fpm-$app" # Configure PHP-FPM 5 on Debian Jessie if [ "$(ynh_get_debian_release)" == "jessie" ]; then fpm_config_dir="/etc/php5/fpm" fpm_service="php5-fpm" fi + + # Create the directory for fpm pools + mkdir -p "$fpm_config_dir/pool.d" + ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" finalphpconf="$fpm_config_dir/pool.d/$app.conf" - ynh_backup_if_checksum_is_different --file="$finalphpconf" + + # Migrate from mutual php service to dedicated one. + if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] + then + ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." + # Create a backup of the old file before migration + ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" + # Remove the old php config file + ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" + # Reload php to release the socket and allow the dedicated service to use it + systemctl reload php${phpversion}-fpm + else + ynh_backup_if_checksum_is_different --file="$finalphpconf" + fi + cp ../conf/php-fpm.conf "$finalphpconf" ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" From f7ac93b0b74b370674ec9492047b679eb02a459b Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 18:31:16 +0200 Subject: [PATCH 024/317] We in fact only have ssl 1.1.0l, not 1.1.1l on Stretch. --- data/templates/dovecot/dovecot.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/templates/dovecot/dovecot.conf b/data/templates/dovecot/dovecot.conf index 0a3c185ee..8fc0e75ae 100644 --- a/data/templates/dovecot/dovecot.conf +++ b/data/templates/dovecot/dovecot.conf @@ -14,8 +14,8 @@ mail_plugins = $mail_plugins quota ############################################################################### -# generated 2020-04-03, Mozilla Guideline v5.4, Dovecot 2.2.27, OpenSSL 1.1.1l, intermediate configuration -# https://ssl-config.mozilla.org/#server=dovecot&version=2.2.27&config=intermediate&openssl=1.1.1l&guideline=5.4 +# generated 2020-04-03, Mozilla Guideline v5.4, Dovecot 2.2.27, OpenSSL 1.1.0l, intermediate configuration +# https://ssl-config.mozilla.org/#server=dovecot&version=2.2.27&config=intermediate&openssl=1.1.0l&guideline=5.4 ssl = required @@ -25,7 +25,7 @@ ssl_key = Date: Sun, 5 Apr 2020 18:31:33 +0200 Subject: [PATCH 025/317] We in fact only have ssl 1.1.0l, not 1.1.1l on Stretch. --- data/templates/postfix/main.cf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 79a551a6c..2642fd8f0 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -19,8 +19,8 @@ readme_directory = no # -- TLS for incoming connections ############################################################################### -# generated 2020-04-03, Mozilla Guideline v5.4, Postfix 3.1.14, OpenSSL 1.1.1l, intermediate configuration -# https://ssl-config.mozilla.org/#server=postfix&version=3.1.14&config=intermediate&openssl=1.1.1l&guideline=5.4 +# generated 2020-04-03, Mozilla Guideline v5.4, Postfix 3.1.14, OpenSSL 1.1.0l, intermediate configuration +# https://ssl-config.mozilla.org/#server=postfix&version=3.1.14&config=intermediate&openssl=1.1.0l&guideline=5.4 # (No modern conf support until we're on buster...) # {% if compatibility == "intermediate" %} {% else %} {% endif %} From a4d28efa6c249e7585f48e222ff8510e287b7889 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 22:37:24 +0200 Subject: [PATCH 026/317] less0 -> at_least_one --- data/helpers.d/php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 817be7f4d..4f5e63dfd 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -311,7 +311,7 @@ ynh_get_scalable_phpfpm () { # Get the total of RAM available, except swap. local max_ram=$(ynh_check_ram --no_swap) - less0() { + at_least_one() { # Do not allow value below 1 if [ $1 -le 0 ] then @@ -331,7 +331,7 @@ ynh_get_scalable_phpfpm () { then php_max_children=$(( $php_max_children / 2 )) fi - php_max_children=$(less0 $php_max_children) + php_max_children=$(at_least_one $php_max_children) # To not overload the proc, limit the number of children to 4 times the number of cores. local core_number=$(nproc) @@ -345,13 +345,13 @@ ynh_get_scalable_phpfpm () { then # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager php_min_spare_servers=$(( $php_max_children / 8 )) - php_min_spare_servers=$(less0 $php_min_spare_servers) + php_min_spare_servers=$(at_least_one $php_min_spare_servers) php_max_spare_servers=$(( $php_max_children / 2 )) - php_max_spare_servers=$(less0 $php_max_spare_servers) + php_max_spare_servers=$(at_least_one $php_max_spare_servers) php_start_servers=$(( $php_min_spare_servers + ( $php_max_spare_servers - $php_min_spare_servers ) /2 )) - php_start_servers=$(less0 $php_start_servers) + php_start_servers=$(at_least_one $php_start_servers) else php_min_spare_servers=0 php_max_spare_servers=0 From 810e5b0d0909da9393367694790dc645144897f8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 22:53:56 +0200 Subject: [PATCH 027/317] no_swap -> ignore_swap --- data/helpers.d/hardware | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index 11012a3d1..11c7b27dc 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -2,22 +2,22 @@ # Check the amount of available RAM # -# usage: ynh_check_ram [--required=RAM required in Mb] [--no_swap|--only_swap] [--free_ram] +# usage: ynh_check_ram [--required=RAM required in Mb] [--ignore_swap|--only_swap] [--free_ram] # | arg: -r, --required= - Amount of RAM required in Mb. The helper will return 0 is there's enough RAM, or 1 otherwise. # If --required isn't set, the helper will print the amount of RAM, in Mb. -# | arg: -s, --no_swap - Ignore swap +# | arg: -s, --ignore_swap - Ignore swap # | arg: -o, --only_swap - Ignore real RAM, consider only swap. # | arg: -f, --free_ram - Count only free RAM, not the total amount of RAM available. -ynh_check_ram () { +ynh_available_ram () { # Declare an array to define the options of this helper. - declare -Ar args_array=( [r]=required= [s]=no_swap [o]=only_swap [f]=free_ram ) + declare -Ar args_array=( [r]=required= [s]=ignore_swap [o]=only_swap [f]=free_ram ) local required - local no_swap + local ignore_swap local only_swap # Manage arguments with getopts ynh_handle_getopts_args "$@" required=${required:-} - no_swap=${no_swap:-0} + ignore_swap=${ignore_swap:-0} only_swap=${only_swap:-0} local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') @@ -34,7 +34,7 @@ ynh_check_ram () { then # Use the total amount of free ram ram=$free_ram_swap - if [ $no_swap -eq 1 ] + if [ $ignore_swap -eq 1 ] then # Use only the amount of free ram ram=$free_ram @@ -44,7 +44,7 @@ ynh_check_ram () { ram=$free_swap fi else - if [ $no_swap -eq 1 ] + if [ $ignore_swap -eq 1 ] then # Use only the amount of free ram ram=$total_ram From 195214bdbfcab61979fe2bb83c05e6d2483765b8 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 5 Apr 2020 23:18:58 +0200 Subject: [PATCH 028/317] Update data/helpers.d/php Co-Authored-By: Kayou --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 3c5390f56..13036684b 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -103,7 +103,7 @@ ynh_remove_fpm_config () { # Remove the dedicated service php-fpm service ynh_remove_systemd_config --service=$fpm_service - + yunohost service remove $fpm_service ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 } From cbf573c34689502b815a6ea29fce3350ad0d2b29 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 23:57:43 +0200 Subject: [PATCH 029/317] Try to improve the semantic of RAM helper --- data/helpers.d/hardware | 86 +++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index 11c7b27dc..be669568e 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -1,24 +1,25 @@ #!/bin/bash -# Check the amount of available RAM +# Get the total or free amount of RAM+swap on the system # -# usage: ynh_check_ram [--required=RAM required in Mb] [--ignore_swap|--only_swap] [--free_ram] -# | arg: -r, --required= - Amount of RAM required in Mb. The helper will return 0 is there's enough RAM, or 1 otherwise. -# If --required isn't set, the helper will print the amount of RAM, in Mb. -# | arg: -s, --ignore_swap - Ignore swap -# | arg: -o, --only_swap - Ignore real RAM, consider only swap. -# | arg: -f, --free_ram - Count only free RAM, not the total amount of RAM available. -ynh_available_ram () { +# usage: ynh_get_ram [--free|--total] [--ignore_swap|--only_swap] +# | arg: -f, --free - Count free RAM+swap +# | arg: -t, --total - Count total RAM+swap +# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM +# | arg: -o, --only_swap - Ignore real RAM, consider only swap +ynh_get_ram () { # Declare an array to define the options of this helper. - declare -Ar args_array=( [r]=required= [s]=ignore_swap [o]=only_swap [f]=free_ram ) - local required + declare -Ar args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local free + local total local ignore_swap local only_swap # Manage arguments with getopts ynh_handle_getopts_args "$@" - required=${required:-} ignore_swap=${ignore_swap:-0} only_swap=${only_swap:-0} + free=${free:-0} + total=${total:-0} local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') @@ -29,11 +30,10 @@ ynh_available_ram () { local free_ram_swap=$(( free_ram + free_swap )) # Use the total amount of ram - local ram=$total_ram_swap - if [ $free_ram -eq 1 ] + if [ $free -eq 1 ] then # Use the total amount of free ram - ram=$free_ram_swap + local ram=$free_ram_swap if [ $ignore_swap -eq 1 ] then # Use only the amount of free ram @@ -43,7 +43,9 @@ ynh_available_ram () { # Use only the amount of free swap ram=$free_swap fi - else + elif [ $total -eq 1 ] + then + local ram=$total_ram_swap if [ $ignore_swap -eq 1 ] then # Use only the amount of free ram @@ -53,20 +55,46 @@ ynh_available_ram () { # Use only the amount of free swap ram=$total_swap fi + else + echo "Uhoh, you should choose --free or --total when using ynh_get_ram" >&2 + ram=0 fi - if [ -n "$required" ] - then - # Return 1 if the amount of ram isn't enough. - if [ $ram -lt $required ] - then - return 1 - else - return 0 - fi - - # If no RAM is required, return the amount of available ram. - else - echo $ram - fi + echo $ram +} + +# Return 0 or 1 depending if the system has a given amount of RAM+swap free or total +# +# usage: ynh_require_ram [--amount=RAM required in Mb] [--free|--total] [--ignore_swap|--only_swap] +# | arg: -a, --amount - The amount to require, in Mb +# | arg: -f, --free - Count free RAM+swap +# | arg: -t, --total - Count total RAM+swap +# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM +# | arg: -o, --only_swap - Ignore real RAM, consider only swap +ynh_require_ram () { + # Declare an array to define the options of this helper. + declare -Ar args_array=( [a]=amount= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local amount + local free + local total + local ignore_swap + local only_swap + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + amount=${amount:-0} + # Dunno if that's the right way to do, but that's some black magic to be able to + # forward the bool args to ynh_get_ram easily? + free=${free:+--free} + total=${total:+--total} + ignore_swap=${ignore_swap:+--ignore_swap} + only_swap=${only_swap:+--only_swap} + + local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap) + + if [ $ram -lt $amount ] + then + return 1 + else + return 0 + fi } From fdc0ecf6e5346b629a48d0f50bd72916314b966c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 6 Apr 2020 00:20:16 +0200 Subject: [PATCH 030/317] Propagate change in RAM helper to php helper where it's used --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 4f5e63dfd..78c4f1bc0 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -309,7 +309,7 @@ ynh_get_scalable_phpfpm () { fi # Get the total of RAM available, except swap. - local max_ram=$(ynh_check_ram --no_swap) + local max_ram=$(ynh_get_ram --total --ignore_swap) at_least_one() { # Do not allow value below 1 From 3234b14b78657ccf36fba2e38d5aa0209d1cd453 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 6 Apr 2020 12:54:05 +0200 Subject: [PATCH 031/317] Update data/helpers.d/php Co-Authored-By: Alexandre Aubin --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 817be7f4d..24314b52f 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -246,7 +246,7 @@ ynh_remove_php () { # medium - Low usage, few people or/and publicly accessible. # high - High usage, frequently visited website. # -# | arg: -p, --print - Print the result +# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app) # # # The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. From 3a7b93d8aac481f41f3dcea3b4e0b6409b0fc0c9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 18:12:24 +0200 Subject: [PATCH 032/317] Get rid of domain-specific acme-challenge snippet, use a single snippet including in every conf --- data/hooks/conf_regen/15-nginx | 15 ++++++ .../nginx/plain/acme-challenge.conf.inc | 5 ++ data/templates/nginx/server.tpl.conf | 2 + locales/en.json | 1 - src/yunohost/certificate.py | 47 ------------------- 5 files changed, 22 insertions(+), 48 deletions(-) create mode 100644 data/templates/nginx/plain/acme-challenge.conf.inc diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index 11e5f596c..90d99ff5e 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -110,6 +110,21 @@ do_post_regen() { mkdir -p "/etc/nginx/conf.d/${domain}.d" done + # Get rid of legacy lets encrypt snippets + for domain in $domain_list; do + # If the legacy letsencrypt / acme-challenge domain-specific snippet is still there + if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ] + then + # And if we're effectively including the new domain-independant snippet now + if grep -q "include /etc/nginx/conf.d/acme-challenge.conf.inc;" /etc/nginx/conf.d/${domain}.conf + then + # Delete the old domain-specific snippet + rm /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf + fi + fi + done + + # Reload nginx configuration pgrep nginx && service nginx reload } diff --git a/data/templates/nginx/plain/acme-challenge.conf.inc b/data/templates/nginx/plain/acme-challenge.conf.inc new file mode 100644 index 000000000..aae3e0eb3 --- /dev/null +++ b/data/templates/nginx/plain/acme-challenge.conf.inc @@ -0,0 +1,5 @@ +location ^~ '/.well-known/acme-challenge/' +{ + default_type "text/plain"; + alias /tmp/acme-challenge-public/; +} diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 6316960c4..485079883 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -10,6 +10,8 @@ server { access_by_lua_file /usr/share/ssowat/access.lua; + include /etc/nginx/conf.d/acme-challenge.conf.inc; + include /etc/nginx/conf.d/{{ domain }}.d/*.conf; location /yunohost/admin { diff --git a/locales/en.json b/locales/en.json index 567b6a460..f6aa35f67 100644 --- a/locales/en.json +++ b/locales/en.json @@ -120,7 +120,6 @@ "certmanager_cert_renew_success": "Let's Encrypt certificate renewed for the domain '{domain:s}'", "certmanager_cert_signing_failed": "Could not sign the new certificate", "certmanager_certificate_fetching_or_enabling_failed": "Trying to use the new certificate for {domain:s} did not work…", - "certmanager_conflicting_nginx_file": "Could not prepare domain for ACME challenge: the NGINX configuration file {filepath:s} is conflicting and should be removed first", "certmanager_couldnt_fetch_intermediate_cert": "Timed out when trying to fetch intermediate certificate from Let's Encrypt. Certificate installation/renewal aborted—please try again later.", "certmanager_domain_cert_not_selfsigned": "The certificate for domain {domain:s} is not self-signed. Are you sure you want to replace it? (Use '--force' to do so.)", "certmanager_domain_dns_ip_differs_from_public_ip": "The DNS 'A' record for the domain '{domain:s}' is different from this server's IP. If you recently modified your A record, please wait for it to propagate (some DNS propagation checkers are available online). (If you know what you are doing, use '--no-checks' to turn off those checks.)", diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index 5fae59060..fd792ccae 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -285,7 +285,6 @@ def _certificate_install_letsencrypt(domain_list, force=False, no_checks=False, operation_logger.start() - _configure_for_acme_challenge(domain) _fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks) _install_cron(no_checks=no_checks) @@ -468,52 +467,6 @@ Subject: %s smtp.quit() -def _configure_for_acme_challenge(domain): - - nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain - nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder - - nginx_configuration = ''' -location ^~ '/.well-known/acme-challenge/' -{ - default_type "text/plain"; - alias %s; -} - ''' % WEBROOT_FOLDER - - # Check there isn't a conflicting file for the acme-challenge well-known - # uri - for path in glob.glob('%s/*.conf' % nginx_conf_folder): - - if path == nginx_conf_file: - continue - - with open(path) as f: - contents = f.read() - - if '/.well-known/acme-challenge' in contents: - raise YunohostError('certmanager_conflicting_nginx_file', filepath=path) - - # Write the conf - if os.path.exists(nginx_conf_file): - logger.debug( - "Nginx configuration file for ACME challenge already exists for domain, skipping.") - return - - logger.debug( - "Adding Nginx configuration file for Acme challenge for domain %s.", domain) - - with open(nginx_conf_file, "w") as f: - f.write(nginx_configuration) - - # Assume nginx conf is okay, and reload it - # (FIXME : maybe add a check that it is, using nginx -t, haven't found - # any clean function already implemented in yunohost to do this though) - _run_service_command("reload", "nginx") - - app_ssowatconf() - - def _check_acme_challenge_configuration(domain): # Check nginx conf file exists nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain From 748dcfd8c5f869dd6d78fe471c9a1eb30d1a3334 Mon Sep 17 00:00:00 2001 From: pitchum Date: Sat, 4 Apr 2020 14:36:01 +0200 Subject: [PATCH 033/317] Setup XMPP components for each domain, not only the main domain. --- data/hooks/conf_regen/12-metronome | 8 +-- data/templates/metronome/domain.tpl.cfg.lua | 56 +++++++++++++++++++++ data/templates/metronome/metronome.cfg.lua | 47 ----------------- src/yunohost/certificate.py | 16 +++--- 4 files changed, 67 insertions(+), 60 deletions(-) diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index 5c9c67f11..903e9fb2e 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -48,11 +48,11 @@ do_post_regen() { # create metronome directories for domains for domain in $domain_list; do mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" + # http_upload directory must be writable by metronome and readable by nginx + mkdir -p "/var/xmpp-upload/${domain}/upload" + chmod g+s "/var/xmpp-upload/${domain}/upload" + chown -R metronome:www-data "/var/xmpp-upload/${domain}" done - # http_upload directory must be writable by metronome and readable by nginx - mkdir -p "/var/xmpp-upload/${main_domain}/upload" - chmod g+s "/var/xmpp-upload/${main_domain}/upload" - chown -R metronome:www-data "/var/xmpp-upload/${main_domain}" # fix some permissions diff --git a/data/templates/metronome/domain.tpl.cfg.lua b/data/templates/metronome/domain.tpl.cfg.lua index e7f6bcef7..aa2f45e5a 100644 --- a/data/templates/metronome/domain.tpl.cfg.lua +++ b/data/templates/metronome/domain.tpl.cfg.lua @@ -1,4 +1,5 @@ VirtualHost "{{ domain }}" + enable = true ssl = { key = "/etc/yunohost/certs/{{ domain }}/key.pem"; certificate = "/etc/yunohost/certs/{{ domain }}/crt.pem"; @@ -13,3 +14,58 @@ VirtualHost "{{ domain }}" namefield = "cn", }, } + + -- Discovery items + disco_items = { + { "muc.{{ domain }}" }, + { "pubsub.{{ domain }}" }, + { "jabber.{{ domain }}" }, + { "vjud.{{ domain }}" }, + { "xmpp-upload.{{ domain }}" }, + }; + +-- contact_info = { +-- abuse = { "mailto:abuse@{{ domain }}", "xmpp:admin@{{ domain }}" }; +-- admin = { "mailto:root@{{ domain }}", "xmpp:admin@{{ domain }}" }; +-- }; + +------ Components ------ +-- You can specify components to add hosts that provide special services, +-- like multi-user conferences, and transports. + +---Set up a MUC (multi-user chat) room server +Component "muc.{{ domain }}" "muc" + name = "{{ domain }} Chatrooms" + + modules_enabled = { + "muc_limits"; + "muc_log"; + "muc_log_mam"; + "muc_log_http"; + "muc_vcard"; + } + + muc_event_rate = 0.5 + muc_burst_factor = 10 + +---Set up a PubSub server +Component "pubsub.{{ domain }}" "pubsub" + name = "{{ domain }} Publish/Subscribe" + + unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server) + +---Set up a HTTP Upload service +Component "xmpp-upload.{{ domain }}" "http_upload" + name = "{{ domain }} Sharing Service" + + http_file_path = "/var/xmpp-upload/{{ domain }}/upload" + http_external_url = "https://xmpp-upload.{{ domain }}:443" + http_file_base_path = "/upload" + http_file_size_limit = 6*1024*1024 + http_file_quota = 60*1024*1024 + http_upload_file_size_limit = 100 * 1024 * 1024 -- bytes + http_upload_quota = 10 * 1024 * 1024 * 1024 -- bytes + +---Set up a VJUD service +Component "vjud.{{ domain }}" "vjud" + vjud_disco_name = "{{ domain }} User Directory" diff --git a/data/templates/metronome/metronome.cfg.lua b/data/templates/metronome/metronome.cfg.lua index b35684add..c1ea83281 100644 --- a/data/templates/metronome/metronome.cfg.lua +++ b/data/templates/metronome/metronome.cfg.lua @@ -81,14 +81,6 @@ http_interfaces = { "127.0.0.1", "::1" } -- Enable IPv6 use_ipv6 = true --- Discovery items -disco_items = { - { "muc.{{ main_domain }}" }, - { "pubsub.{{ main_domain }}" }, - { "xmpp-upload.{{ main_domain }}" }, - { "vjud.{{ main_domain }}" } -}; - -- BOSH configuration (mod_bosh) consider_bosh_secure = true cross_domain_bosh = true @@ -119,45 +111,6 @@ log = { Component "localhost" "http" modules_enabled = { "bosh" } ----Set up a MUC (multi-user chat) room server -Component "muc.{{ main_domain }}" "muc" - name = "{{ main_domain }} Chatrooms" - - modules_enabled = { - "muc_limits"; - "muc_log"; - "muc_log_mam"; - "muc_log_http"; - "muc_vcard"; - } - - muc_event_rate = 0.5 - muc_burst_factor = 10 - ----Set up a PubSub server -Component "pubsub.{{ main_domain }}" "pubsub" - name = "{{ main_domain }} Publish/Subscribe" - - unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server) - ----Set up a HTTP Upload service -Component "xmpp-upload.{{ main_domain }}" "http_upload" - name = "{{ main_domain }} Sharing Service" - - http_file_path = "/var/xmpp-upload/{{ main_domain }}/upload" - http_external_url = "https://xmpp-upload.{{ main_domain }}:443" - http_file_base_path = "/upload" - http_file_size_limit = 6*1024*1024 - http_file_quota = 60*1024*1024 - http_upload_file_size_limit = 100 * 1024 * 1024 -- bytes - http_upload_quota = 10 * 1024 * 1024 * 1024 -- bytes - - ----Set up a VJUD service -Component "vjud.{{ main_domain }}" "vjud" - ud_disco_name = "{{ main_domain }} User Directory" - - ----------- Virtual hosts ----------- -- You need to add a VirtualHost entry for each domain you wish Metronome to serve. -- Settings under each VirtualHost entry apply *only* to that host. diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index 5fae59060..c6f520b4e 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -639,15 +639,13 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): # Set the domain csr.get_subject().CN = domain - from yunohost.domain import _get_maindomain - if domain == _get_maindomain(): - # Include xmpp-upload subdomain in subject alternate names - subdomain="xmpp-upload." + domain - try: - _dns_ip_match_public_ip(get_public_ip(), subdomain) - csr.add_extensions([crypto.X509Extension("subjectAltName", False, "DNS:" + subdomain)]) - except YunohostError: - logger.warning(m18n.n('certmanager_warning_subdomain_dns_record', subdomain=subdomain, domain=domain)) + # Include xmpp-upload subdomain in subject alternate names + subdomain="xmpp-upload." + domain + try: + _dns_ip_match_public_ip(get_public_ip(), subdomain) + csr.add_extensions([crypto.X509Extension("subjectAltName", False, "DNS:" + subdomain)]) + except YunohostError: + logger.warning(m18n.n('certmanager_warning_subdomain_dns_record', subdomain=subdomain, domain=domain)) # Set the key with open(key_file, 'rt') as f: From cf3b98b5237db1f67a28af7d9fd4f5852dc0a593 Mon Sep 17 00:00:00 2001 From: pitchum Date: Sat, 4 Apr 2020 15:06:44 +0200 Subject: [PATCH 034/317] Fix nginx config for xmpp-upload. --- data/templates/nginx/server.tpl.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 6316960c4..5a5176688 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -71,7 +71,7 @@ server { root /dev/null; location /upload/ { - alias /var/xmpp-upload/{{ domain }}/upload; + alias /var/xmpp-upload/{{ domain }}/upload/; # Pass all requests to metronome, except for GET and HEAD requests. limit_except GET HEAD { proxy_pass http://localhost:5290; From 22c88dc47e57980058265ae1083a5a8ef4284310 Mon Sep 17 00:00:00 2001 From: pitchum Date: Mon, 6 Apr 2020 20:38:42 +0200 Subject: [PATCH 035/317] Enable XMPP features only on "parent domains". --- data/actionsmap/yunohost.yml | 4 ++++ data/hooks/conf_regen/12-metronome | 2 +- src/yunohost/domain.py | 11 ++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 3a4c9db97..cd1c4916f 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -399,6 +399,10 @@ domain: list: action_help: List domains api: GET /domains + arguments: + --exclude-subdomains: + help: Filter out domains that are obviously subdomains of other declared domains + action: store_true ### domain_add() add: diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index 903e9fb2e..25ccd40ac 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -43,7 +43,7 @@ do_post_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --exclude-subdomains --output-as plain --quiet) # create metronome directories for domains for domain in $domain_list; do diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 23b5a4179..a1ac65b81 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -41,7 +41,7 @@ from yunohost.hook import hook_callback logger = getActionLogger('yunohost.domain') -def domain_list(): +def domain_list(exclude_subdomains=False): """ List domains @@ -49,16 +49,21 @@ def domain_list(): filter -- LDAP filter used to search offset -- Starting number for domain fetching limit -- Maximum number of domain fetched + exclude_subdomains -- Filter out domains that are subdomains of other declared domains """ from yunohost.utils.ldap import _get_ldap_interface ldap = _get_ldap_interface() - result = ldap.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain']) + result = [entry['virtualdomain'][0] for entry in ldap.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain'])] result_list = [] for domain in result: - result_list.append(domain['virtualdomain'][0]) + if exclude_subdomains: + parent_domain = domain.split(".", 1)[1] + if parent_domain in result: + continue + result_list.append(domain) return {'domains': result_list} From f390f02077294cc1033977601071ba242da4bf85 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 3 Apr 2020 03:12:09 +0200 Subject: [PATCH 036/317] Update nginx security.conf.inc with new Mozilla recommendation --- data/templates/nginx/security.conf.inc | 28 ++++++++++++-------------- data/templates/nginx/server.tpl.conf | 12 ++++------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/data/templates/nginx/security.conf.inc b/data/templates/nginx/security.conf.inc index 28d12055b..79a891a21 100644 --- a/data/templates/nginx/security.conf.inc +++ b/data/templates/nginx/security.conf.inc @@ -1,24 +1,22 @@ -{% if compatibility == "modern" %} -# Ciphers with modern compatibility -# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=modern -# The following configuration use modern ciphers, but remove compatibility with some old clients (android < 5.0, Internet Explorer < 10, ...) -ssl_protocols TLSv1.2; -ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; -ssl_prefer_server_ciphers on; -{% else %} -# As suggested by Mozilla : https://wiki.mozilla.org/Security/Server_Side_TLS and https://en.wikipedia.org/wiki/Curve25519 -ssl_ecdh_curve secp521r1:secp384r1:prime256v1; -ssl_prefer_server_ciphers on; +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:10m; # about 40000 sessions +ssl_session_tickets off; + +# nginx 1.10 in stretch doesn't support TLS1.3 and Mozilla doesn't have any +# "modern" config recommendation with it. +# So until buster the modern conf is same as intermediate +{% if compatibility == "modern" %} {% else %} {% endif %} # Ciphers with intermediate compatibility -# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=nginx-1.6.2&openssl=1.0.1t&hsts=yes&profile=intermediate -ssl_protocols TLSv1 TLSv1.1 TLSv1.2; -ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; +# generated 2020-04-03, Mozilla Guideline v5.4, nginx 1.10.3, OpenSSL 1.1.1l, intermediate configuration +# https://ssl-config.mozilla.org/#server=nginx&version=1.10.3&config=intermediate&openssl=1.1.1l&guideline=5.4 +ssl_protocols TLSv1.2; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +ssl_prefer_server_ciphers off; # Uncomment the following directive after DH generation # > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048 #ssl_dhparam /etc/ssl/private/dh2048.pem; -{% endif %} # Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners # https://wiki.mozilla.org/Security/Guidelines/Web_Security diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 6316960c4..dcfd139ba 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -33,12 +33,10 @@ server { listen [::]:443 ssl http2; server_name {{ domain }}; + include /etc/nginx/conf.d/security.conf.inc; + ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem; ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem; - ssl_session_timeout 5m; - ssl_session_cache shared:SSL:50m; - - include /etc/nginx/conf.d/security.conf.inc; {% if domain_cert_ca != "Self-signed" %} more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload"; @@ -85,12 +83,10 @@ server { client_max_body_size 105M; # Choose a value a bit higher than the max upload configured in XMPP server } + include /etc/nginx/conf.d/security.conf.inc; + ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem; ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem; - ssl_session_timeout 5m; - ssl_session_cache shared:SSL:50m; - - include /etc/nginx/conf.d/security.conf.inc; {% if domain_cert_ca != "Self-signed" %} more_set_headers "Strict-Transport-Security : max-age=63072000; includeSubDomains; preload"; From 71cc4fde97514b580705c6af517e6e2635e6bd5e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 5 Apr 2020 18:32:03 +0200 Subject: [PATCH 037/317] We in fact only have ssl 1.1.0l, not 1.1.1l on Stretch. --- data/templates/nginx/security.conf.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/templates/nginx/security.conf.inc b/data/templates/nginx/security.conf.inc index 79a891a21..a7e1ac718 100644 --- a/data/templates/nginx/security.conf.inc +++ b/data/templates/nginx/security.conf.inc @@ -8,8 +8,8 @@ ssl_session_tickets off; {% if compatibility == "modern" %} {% else %} {% endif %} # Ciphers with intermediate compatibility -# generated 2020-04-03, Mozilla Guideline v5.4, nginx 1.10.3, OpenSSL 1.1.1l, intermediate configuration -# https://ssl-config.mozilla.org/#server=nginx&version=1.10.3&config=intermediate&openssl=1.1.1l&guideline=5.4 +# generated 2020-04-03, Mozilla Guideline v5.4, nginx 1.10.3, OpenSSL 1.1.0l, intermediate configuration +# https://ssl-config.mozilla.org/#server=nginx&version=1.10.3&config=intermediate&openssl=1.1.0l&guideline=5.4 ssl_protocols TLSv1.2; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; From c06fe42078d13ccf6494ac23ee9cef99d1895c64 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 8 Apr 2020 21:33:34 +0200 Subject: [PATCH 038/317] Hmgn don't change the value for the session cache size otherwise that break test for restore from old version for stupid reasons -.- --- data/templates/nginx/security.conf.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/nginx/security.conf.inc b/data/templates/nginx/security.conf.inc index a7e1ac718..ff3d2ee99 100644 --- a/data/templates/nginx/security.conf.inc +++ b/data/templates/nginx/security.conf.inc @@ -1,5 +1,5 @@ ssl_session_timeout 1d; -ssl_session_cache shared:SSL:10m; # about 40000 sessions +ssl_session_cache shared:SSL:50m; # about 200000 sessions ssl_session_tickets off; # nginx 1.10 in stretch doesn't support TLS1.3 and Mozilla doesn't have any From 3c8442925852a27a73c21a51cc84738c51a37861 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 20 Nov 2019 15:31:55 +0100 Subject: [PATCH 039/317] Improve messages wording ? More consistent service 'X' vs. 'X' service --- locales/en.json | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/locales/en.json b/locales/en.json index 4bde03919..6a2af5e41 100644 --- a/locales/en.json +++ b/locales/en.json @@ -446,7 +446,7 @@ "regenconf_file_updated": "Configuration file '{conf}' updated", "regenconf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost (category {category}).", "regenconf_up_to_date": "The configuration is already up-to-date for category '{category}'", - "regenconf_updated": "Configuration for category '{category}' updated", + "regenconf_updated": "Configuration updated for '{category}'", "regenconf_would_be_updated": "The configuration would have been updated for category '{category}'", "regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for category '{category}'…", "regenconf_failed": "Could not regenerate the configuration for category(s): {categories}", @@ -495,24 +495,23 @@ "service_description_ssh": "Allows you to connect remotely to your server via a terminal (SSH protocol)", "service_description_yunohost-api": "Manages interactions between the YunoHost web interface and the system", "service_description_yunohost-firewall": "Manages open and close connection ports to services", - "service_disable_failed": "Could not turn off the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_disabled": "The '{service:s}' service was turned off", - "service_enable_failed": "Could not turn on the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_enabled": "The '{service:s}' service was turned off", - "service_no_log": "No logs to display for the service '{service:s}'", + "service_disable_failed": "Could not make the service '{service:s}' not start at boot.\n\nRecent service logs:{logs:s}", + "service_disabled": "The service '{service:s}' will not be started anymore when system boots.", + "service_enable_failed": "Could not make the service '{service:s}' automatically start at boot.\n\nRecent service logs:{logs:s}", + "service_enabled": "The service '{service:s}' will now be automatically started during system boots.", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.", "service_remove_failed": "Could not remove the service '{service:s}'", - "service_removed": "'{service:s}' service removed", + "service_removed": "Service '{service:s}' removed", "service_reload_failed": "Could not reload the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_reloaded": "The '{service:s}' service was reloaded", + "service_reloaded": "Service '{service:s}' reloaded", "service_restart_failed": "Could not restart the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_restarted": "'{service:s}' service restarted", + "service_restarted": "Service '{service:s}' restarted", "service_reload_or_restart_failed": "Could not reload or restart the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_reloaded_or_restarted": "The '{service:s}' service was reloaded or restarted", + "service_reloaded_or_restarted": "The service '{service:s}' was reloaded or restarted", "service_start_failed": "Could not start the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_started": "'{service:s}' service started", + "service_started": "Service '{service:s}' started", "service_stop_failed": "Could not stop the service '{service:s}'\n\nRecent service logs:{logs:s}", - "service_stopped": "The '{service:s}' service stopped", + "service_stopped": "Service '{service:s}' stopped", "service_unknown": "Unknown service '{service:s}'", "ssowat_conf_generated": "SSOwat configuration generated", "ssowat_conf_updated": "SSOwat configuration updated", From 031f8a6e3814dd9c387814e1c1c61b284df95174 Mon Sep 17 00:00:00 2001 From: Matthew DeAbreu Date: Wed, 20 Nov 2019 09:52:01 -0800 Subject: [PATCH 040/317] ensure metronome owns domain dir When adding new domains to Yunohost a directory for each newly added domain is created in `/var/lib/metronome` unfortunately since the directory is created with `sudo mkdir` that means `root:root` owns the directory. Metronome will now fail to write to the directory. --- data/hooks/conf_regen/12-metronome | 1 + 1 file changed, 1 insertion(+) diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index 4214722fc..f3df22317 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -51,6 +51,7 @@ do_post_regen() { # create metronome directories for domains for domain in $domain_list; do sudo mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" + sudo chown -R metronome: /var/lib/metronome/${domain//./%2e}/ done [[ -z "$regen_conf_files" ]] \ From 1f623830b3b54e49bf776d47295de98eced004d5 Mon Sep 17 00:00:00 2001 From: Matthew DeAbreu Date: Fri, 22 Nov 2019 09:02:01 -0800 Subject: [PATCH 041/317] Update 12-metronome simplify change by reordering operations --- data/hooks/conf_regen/12-metronome | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index f3df22317..7047af660 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -41,19 +41,18 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 - # fix some permissions - sudo chown -R metronome: /var/lib/metronome/ - sudo chown -R metronome: /etc/metronome/conf.d/ - # retrieve variables domain_list=$(sudo yunohost domain list --output-as plain --quiet) # create metronome directories for domains for domain in $domain_list; do sudo mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" - sudo chown -R metronome: /var/lib/metronome/${domain//./%2e}/ done + # fix some permissions + sudo chown -R metronome: /var/lib/metronome/ + sudo chown -R metronome: /etc/metronome/conf.d/ + [[ -z "$regen_conf_files" ]] \ || sudo service metronome restart } From be88a2835a5663c64d31917581772c5d754ef51c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 27 Nov 2019 23:58:36 +0100 Subject: [PATCH 042/317] Remove those random sudo which are useless yet triggers LDAP warning when LDAP is in bad state --- data/helpers.d/apt | 2 +- data/helpers.d/backup | 24 +++++++++++----------- data/helpers.d/logging | 4 ++-- data/helpers.d/logrotate | 6 +++--- data/helpers.d/mysql | 8 ++++---- data/helpers.d/nginx | 2 +- data/helpers.d/php | 8 ++++---- data/helpers.d/postgresql | 10 ++++----- data/helpers.d/setting | 4 ++-- data/helpers.d/string | 2 +- data/helpers.d/systemd | 8 ++++---- data/helpers.d/user | 6 +++--- data/hooks/backup/05-conf_ldap | 4 ++-- data/hooks/conf_regen/01-yunohost | 14 ++++++------- data/hooks/conf_regen/02-ssl | 6 +++--- data/hooks/conf_regen/06-slapd | 2 +- data/hooks/conf_regen/09-nslcd | 2 +- data/hooks/conf_regen/12-metronome | 12 +++++------ data/hooks/conf_regen/15-nginx | 8 ++++---- data/hooks/conf_regen/19-postfix | 4 ++-- data/hooks/conf_regen/25-dovecot | 20 +++++++++--------- data/hooks/conf_regen/31-rspamd | 24 +++++++++++----------- data/hooks/conf_regen/34-mysql | 16 +++++++-------- data/hooks/conf_regen/37-avahi-daemon | 2 +- data/hooks/conf_regen/40-glances | 2 +- data/hooks/conf_regen/43-dnsmasq | 4 ++-- data/hooks/conf_regen/46-nsswitch | 2 +- data/hooks/conf_regen/52-fail2ban | 2 +- data/hooks/restore/05-conf_ldap | 2 +- data/hooks/restore/08-conf_ssh | 4 ++-- data/hooks/restore/11-conf_ynh_mysql | 16 +++++++-------- data/hooks/restore/14-conf_ssowat | 2 +- data/hooks/restore/17-data_home | 2 +- data/hooks/restore/20-conf_ynh_firewall | 4 ++-- data/hooks/restore/21-conf_ynh_certs | 8 ++++---- data/hooks/restore/23-data_mail | 8 ++++---- data/hooks/restore/26-conf_xmpp | 6 +++--- data/hooks/restore/29-conf_nginx | 4 ++-- data/hooks/restore/32-conf_cron | 4 ++-- data/hooks/restore/40-conf_ynh_currenthost | 2 +- src/yunohost/tools.py | 6 +++--- 41 files changed, 138 insertions(+), 138 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index da2740d01..55c85c90b 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -13,7 +13,7 @@ ynh_wait_dpkg_free() { for try in `seq 1 17` do # Check if /var/lib/dpkg/lock is used by another process - if sudo lsof /var/lib/dpkg/lock > /dev/null + if lsof /var/lib/dpkg/lock > /dev/null then echo "apt is already in use..." # Sleep an exponential time at each round diff --git a/data/helpers.d/backup b/data/helpers.d/backup index d3ffffcd3..590e951a5 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -179,7 +179,7 @@ ynh_restore () { # usage: _get_archive_path ORIGIN_PATH _get_archive_path () { # For security reasons we use csv python library to read the CSV - sudo python -c " + python -c " import sys import csv with open(sys.argv[1], 'r') as backup_file: @@ -302,7 +302,7 @@ ynh_store_file_checksum () { ynh_handle_getopts_args "$@" local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' - ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(sudo md5sum "$file" | cut -d' ' -f1) + ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut -d' ' -f1) # If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup if [ -n "${backup_file_checksum-}" ] @@ -339,11 +339,11 @@ ynh_backup_if_checksum_is_different () { backup_file_checksum="" if [ -n "$checksum_value" ] then # Proceed only if a value was stored into the app settings - if [ -e $file ] && ! echo "$checksum_value $file" | sudo md5sum -c --status + if [ -e $file ] && ! echo "$checksum_value $file" | md5sum -c --status then # If the checksum is now different backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')" - sudo mkdir -p "$(dirname "$backup_file_checksum")" - sudo cp -a "$file" "$backup_file_checksum" # Backup the current file + mkdir -p "$(dirname "$backup_file_checksum")" + cp -a "$file" "$backup_file_checksum" # Backup the current file ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum" echo "$backup_file_checksum" # Return the name of the backup file fi @@ -394,7 +394,7 @@ ynh_backup_before_upgrade () { if [ "$NO_BACKUP_UPGRADE" -eq 0 ] then # Check if a backup already exists with the prefix 1 - if sudo yunohost backup list | grep -q $app_bck-pre-upgrade1 + if yunohost backup list | grep -q $app_bck-pre-upgrade1 then # Prefix becomes 2 to preserve the previous backup backup_number=2 @@ -402,14 +402,14 @@ ynh_backup_before_upgrade () { fi # Create backup - sudo BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug + BACKUP_CORE_ONLY=1 yunohost backup create --apps $app --name $app_bck-pre-upgrade$backup_number --debug if [ "$?" -eq 0 ] then # If the backup succeeded, remove the previous backup - if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number + if yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number then # Remove the previous backup only if it exists - sudo yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null + yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null fi else ynh_die --message="Backup failed, the upgrade process was aborted." @@ -438,12 +438,12 @@ ynh_restore_upgradebackup () { if [ "$NO_BACKUP_UPGRADE" -eq 0 ] then # Check if an existing backup can be found before removing and restoring the application. - if sudo yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number + if yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number then # Remove the application then restore it - sudo yunohost app remove $app + yunohost app remove $app # Restore the backup - sudo yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug + yunohost backup restore $app_bck-pre-upgrade$backup_number --apps $app --force --debug ynh_die --message="The app was restored to the way it was before the failed upgrade." fi else diff --git a/data/helpers.d/logging b/data/helpers.d/logging index be33b75a5..89fb89c6e 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -46,10 +46,10 @@ ynh_print_info() { # Requires YunoHost version 2.6.4 or higher. ynh_no_log() { local ynh_cli_log=/var/log/yunohost/yunohost-cli.log - sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move + cp -a ${ynh_cli_log} ${ynh_cli_log}-move eval $@ local exit_code=$? - sudo mv ${ynh_cli_log}-move ${ynh_cli_log} + mv ${ynh_cli_log}-move ${ynh_cli_log} return $? } diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 82cdee6a5..9e2429218 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -90,8 +90,8 @@ $logfile { $su_directive } EOF - sudo mkdir -p $(dirname "$logfile") # Create the log directory, if not exist - cat ${app}-logrotate | sudo $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee) + mkdir -p $(dirname "$logfile") # Create the log directory, if not exist + cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee) } # Remove the app's logrotate config. @@ -101,6 +101,6 @@ EOF # Requires YunoHost version 2.6.4 or higher. ynh_remove_logrotate () { if [ -e "/etc/logrotate.d/$app" ]; then - sudo rm "/etc/logrotate.d/$app" + rm "/etc/logrotate.d/$app" fi } diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index e9cf59b3c..91d4abcd2 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -44,7 +44,7 @@ ynh_mysql_execute_as_root() { ynh_handle_getopts_args "$@" database="${database:-}" - ynh_mysql_connect_as --user="root" --password="$(sudo cat $MYSQL_ROOT_PWD_FILE)" \ + ynh_mysql_connect_as --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" \ --database="$database" <<< "$sql" } @@ -65,7 +65,7 @@ ynh_mysql_execute_file_as_root() { ynh_handle_getopts_args "$@" database="${database:-}" - ynh_mysql_connect_as --user="root" --password="$(sudo cat $MYSQL_ROOT_PWD_FILE)" \ + ynh_mysql_connect_as --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" \ --database="$database" < "$file" } @@ -126,7 +126,7 @@ ynh_mysql_dump_db() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - mysqldump -u "root" -p"$(sudo cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database" + mysqldump -u "root" -p"$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database" } # Create a user @@ -223,7 +223,7 @@ ynh_mysql_remove_db () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - local mysql_root_password=$(sudo cat $MYSQL_ROOT_PWD_FILE) + local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE) if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists ynh_mysql_drop_db $db_name # Remove the database else diff --git a/data/helpers.d/nginx b/data/helpers.d/nginx index ce6b61d3c..e3e45d2d4 100644 --- a/data/helpers.d/nginx +++ b/data/helpers.d/nginx @@ -22,7 +22,7 @@ ynh_add_nginx_config () { finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" local others_var=${1:-} ynh_backup_if_checksum_is_different --file="$finalnginxconf" - sudo cp ../conf/nginx.conf "$finalnginxconf" + cp ../conf/nginx.conf "$finalnginxconf" # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. # Substitute in a nginx config file only if the variable is not empty diff --git a/data/helpers.d/php b/data/helpers.d/php index c9e3ba9ed..41af467c5 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -28,12 +28,12 @@ ynh_add_fpm_config () { ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" finalphpconf="$fpm_config_dir/pool.d/$app.conf" ynh_backup_if_checksum_is_different --file="$finalphpconf" - sudo cp ../conf/php-fpm.conf "$finalphpconf" + cp ../conf/php-fpm.conf "$finalphpconf" ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" - sudo chown root: "$finalphpconf" + chown root: "$finalphpconf" ynh_store_file_checksum --file="$finalphpconf" if [ -e "../conf/php-fpm.ini" ] @@ -41,8 +41,8 @@ ynh_add_fpm_config () { echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2 finalphpini="$fpm_config_dir/conf.d/20-$app.ini" ynh_backup_if_checksum_is_different "$finalphpini" - sudo cp ../conf/php-fpm.ini "$finalphpini" - sudo chown root: "$finalphpini" + cp ../conf/php-fpm.ini "$finalphpini" + chown root: "$finalphpini" ynh_store_file_checksum "$finalphpini" fi ynh_systemd_action --service_name=$fpm_service --action=reload diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index d252ae2dc..6d8524e54 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -45,7 +45,7 @@ ynh_psql_execute_as_root() { ynh_handle_getopts_args "$@" database="${database:-}" - ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \ + ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ --database="$database" <<<"$sql" } @@ -66,7 +66,7 @@ ynh_psql_execute_file_as_root() { ynh_handle_getopts_args "$@" database="${database:-}" - ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \ + ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ --database="$database" <"$file" } @@ -160,7 +160,7 @@ ynh_psql_user_exists() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then return 1 else return 0 @@ -179,7 +179,7 @@ ynh_psql_database_exists() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(sudo cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then return 1 else return 0 @@ -243,7 +243,7 @@ ynh_psql_remove_db() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - local psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE) + local psql_root_password=$(cat $PSQL_ROOT_PWD_FILE) if ynh_psql_database_exists --database=$db_name; then # Check if the database exists ynh_psql_drop_db $db_name # Remove the database else diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 9f68cb5d9..384fdc399 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -222,7 +222,7 @@ ynh_webpath_available () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost domain url-available $domain $path_url + yunohost domain url-available $domain $path_url } # Register/book a web path for an app @@ -245,7 +245,7 @@ ynh_webpath_register () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost app register-url $app $domain $path_url + yunohost app register-url $app $domain $path_url } # Create a new permission for the app diff --git a/data/helpers.d/string b/data/helpers.d/string index fcbc5190d..e50f781fe 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -49,7 +49,7 @@ ynh_replace_string () { match_string=${match_string//${delimit}/"\\${delimit}"} replace_string=${replace_string//${delimit}/"\\${delimit}"} - sudo sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" + sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" } # Substitute/replace a special string by another in a file diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 105678b88..960382f8f 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -28,7 +28,7 @@ ynh_add_systemd_config () { finalsystemdconf="/etc/systemd/system/$service.service" ynh_backup_if_checksum_is_different --file="$finalsystemdconf" - sudo cp ../conf/$template "$finalsystemdconf" + cp ../conf/$template "$finalsystemdconf" # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. # Substitute in a nginx config file only if the variable is not empty @@ -40,9 +40,9 @@ ynh_add_systemd_config () { fi ynh_store_file_checksum --file="$finalsystemdconf" - sudo chown root: "$finalsystemdconf" - sudo systemctl enable $service - sudo systemctl daemon-reload + chown root: "$finalsystemdconf" + systemctl enable $service + systemctl daemon-reload } # Remove the dedicated systemd config diff --git a/data/helpers.d/user b/data/helpers.d/user index e7890ccb2..7051ed4c0 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -16,7 +16,7 @@ ynh_user_exists() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost user list --output-as json | grep -q "\"username\": \"${username}\"" + yunohost user list --output-as json | grep -q "\"username\": \"${username}\"" } # Retrieve a YunoHost user information @@ -38,7 +38,7 @@ ynh_user_get_info() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - sudo yunohost user info "$username" --output-as plain | ynh_get_plain_key "$key" + yunohost user info "$username" --output-as plain | ynh_get_plain_key "$key" } # Get the list of YunoHost users @@ -50,7 +50,7 @@ ynh_user_get_info() { # # Requires YunoHost version 2.4.0 or higher. ynh_user_list() { - sudo yunohost user list --output-as plain --quiet \ + yunohost user list --output-as plain --quiet \ | awk '/^##username$/{getline; print}' } diff --git a/data/hooks/backup/05-conf_ldap b/data/hooks/backup/05-conf_ldap index 9ae22095e..75b4c2075 100755 --- a/data/hooks/backup/05-conf_ldap +++ b/data/hooks/backup/05-conf_ldap @@ -11,7 +11,7 @@ backup_dir="${1}/conf/ldap" # Backup the configuration ynh_backup "/etc/ldap/slapd.conf" "${backup_dir}/slapd.conf" -sudo slapcat -b cn=config -l "${backup_dir}/cn=config.master.ldif" +slapcat -b cn=config -l "${backup_dir}/cn=config.master.ldif" # Backup the database -sudo slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif" +slapcat -b dc=yunohost,dc=org -l "${backup_dir}/dc=yunohost-dc=org.ldif" diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost index f22de7a53..1abfca35e 100755 --- a/data/hooks/conf_regen/01-yunohost +++ b/data/hooks/conf_regen/01-yunohost @@ -38,25 +38,25 @@ do_pre_regen() { if [[ -f $services_path ]]; then tmp_services_path="${services_path}-tmp" new_services_path="${services_path}-new" - sudo cp "$services_path" "$tmp_services_path" + cp "$services_path" "$tmp_services_path" _update_services "$new_services_path" || { - sudo mv "$tmp_services_path" "$services_path" + mv "$tmp_services_path" "$services_path" exit 1 } if [[ -f $new_services_path ]]; then # replace services.yml with new one - sudo mv "$new_services_path" "$services_path" - sudo mv "$tmp_services_path" "${services_path}-old" + mv "$new_services_path" "$services_path" + mv "$tmp_services_path" "${services_path}-old" else - sudo rm -f "$tmp_services_path" + rm -f "$tmp_services_path" fi else - sudo cp services.yml /etc/yunohost/services.yml + cp services.yml /etc/yunohost/services.yml fi } _update_services() { - sudo python2 - << EOF + python2 - << EOF import yaml diff --git a/data/hooks/conf_regen/02-ssl b/data/hooks/conf_regen/02-ssl index 1df3a3260..a893b21e1 100755 --- a/data/hooks/conf_regen/02-ssl +++ b/data/hooks/conf_regen/02-ssl @@ -99,13 +99,13 @@ do_post_regen() { [[ -f "${index_txt}" ]] || { if [[ -f "${index_txt}.saved" ]]; then # use saved database from 2.2 - sudo cp "${index_txt}.saved" "${index_txt}" + cp "${index_txt}.saved" "${index_txt}" elif [[ -f "${index_txt}.old" ]]; then # ... or use the state-1 database - sudo cp "${index_txt}.old" "${index_txt}" + cp "${index_txt}.old" "${index_txt}" else # ... or create an empty one - sudo touch "${index_txt}" + touch "${index_txt}" fi } diff --git a/data/hooks/conf_regen/06-slapd b/data/hooks/conf_regen/06-slapd index 50149392b..2fa108baa 100755 --- a/data/hooks/conf_regen/06-slapd +++ b/data/hooks/conf_regen/06-slapd @@ -127,7 +127,7 @@ do_post_regen() { # wait a maximum time of 5 minutes # yes, force-reload behave like a restart number_of_wait=0 - while ! sudo su admin -c '' && ((number_of_wait < 60)) + while ! su admin -c '' && ((number_of_wait < 60)) do sleep 5 ((number_of_wait += 1)) diff --git a/data/hooks/conf_regen/09-nslcd b/data/hooks/conf_regen/09-nslcd index 5071ac1fd..7090fc758 100755 --- a/data/hooks/conf_regen/09-nslcd +++ b/data/hooks/conf_regen/09-nslcd @@ -14,7 +14,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service nslcd restart + || service nslcd restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index 7047af660..fbd956e7c 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -14,7 +14,7 @@ do_pre_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # install main conf file cat metronome.cfg.lua \ @@ -42,19 +42,19 @@ do_post_regen() { regen_conf_files=$1 # retrieve variables - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # create metronome directories for domains for domain in $domain_list; do - sudo mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" + mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" done # fix some permissions - sudo chown -R metronome: /var/lib/metronome/ - sudo chown -R metronome: /etc/metronome/conf.d/ + chown -R metronome: /var/lib/metronome/ + chown -R metronome: /etc/metronome/conf.d/ [[ -z "$regen_conf_files" ]] \ - || sudo service metronome restart + || service metronome restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index 59654a771..55a5494b2 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -45,7 +45,7 @@ do_pre_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.nginx.compatibility')" @@ -102,15 +102,15 @@ do_post_regen() { [ -z "$regen_conf_files" ] && exit 0 # retrieve variables - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # create NGINX conf directories for domains for domain in $domain_list; do - sudo mkdir -p "/etc/nginx/conf.d/${domain}.d" + mkdir -p "/etc/nginx/conf.d/${domain}.d" done # Reload nginx configuration - pgrep nginx && sudo service nginx reload + pgrep nginx && service nginx reload } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index b37425984..0f09f0299 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -20,7 +20,7 @@ do_pre_regen() { # prepare main.cf conf file main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(sudo yunohost domain list --output-as plain --quiet | tr '\n' ' ') + domain_list=$(yunohost domain list --output-as plain --quiet | tr '\n' ' ') # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.postfix.compatibility')" @@ -49,7 +49,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || { sudo service postfix restart && sudo service postsrsd restart; } + || { service postfix restart && service postsrsd restart; } } diff --git a/data/hooks/conf_regen/25-dovecot b/data/hooks/conf_regen/25-dovecot index 4c5ae24c1..2638c7f6f 100755 --- a/data/hooks/conf_regen/25-dovecot +++ b/data/hooks/conf_regen/25-dovecot @@ -35,28 +35,28 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 - sudo mkdir -p "/etc/dovecot/yunohost.d/pre-ext.d" - sudo mkdir -p "/etc/dovecot/yunohost.d/post-ext.d" + mkdir -p "/etc/dovecot/yunohost.d/pre-ext.d" + mkdir -p "/etc/dovecot/yunohost.d/post-ext.d" # create vmail user id vmail > /dev/null 2>&1 \ - || sudo adduser --system --ingroup mail --uid 500 vmail + || adduser --system --ingroup mail --uid 500 vmail # fix permissions - sudo chown -R vmail:mail /etc/dovecot/global_script - sudo chmod 770 /etc/dovecot/global_script - sudo chown root:mail /var/mail - sudo chmod 1775 /var/mail + chown -R vmail:mail /etc/dovecot/global_script + chmod 770 /etc/dovecot/global_script + chown root:mail /var/mail + chmod 1775 /var/mail [ -z "$regen_conf_files" ] && exit 0 # compile sieve script [[ "$regen_conf_files" =~ dovecot\.sieve ]] && { - sudo sievec /etc/dovecot/global_script/dovecot.sieve - sudo chown -R vmail:mail /etc/dovecot/global_script + sievec /etc/dovecot/global_script/dovecot.sieve + chown -R vmail:mail /etc/dovecot/global_script } - sudo service dovecot restart + service dovecot restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/31-rspamd b/data/hooks/conf_regen/31-rspamd index d263d9cc9..26fea4336 100755 --- a/data/hooks/conf_regen/31-rspamd +++ b/data/hooks/conf_regen/31-rspamd @@ -22,11 +22,11 @@ do_post_regen() { ## # create DKIM directory with proper permission - sudo mkdir -p /etc/dkim - sudo chown _rspamd /etc/dkim + mkdir -p /etc/dkim + chown _rspamd /etc/dkim # retrieve domain list - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # create DKIM key for domains for domain in $domain_list; do @@ -34,30 +34,30 @@ do_post_regen() { [ ! -f "$domain_key" ] && { # We use a 1024 bit size because nsupdate doesn't seem to be able to # handle 2048... - sudo opendkim-genkey --domain="$domain" \ + opendkim-genkey --domain="$domain" \ --selector=mail --directory=/etc/dkim -b 1024 - sudo mv /etc/dkim/mail.private "$domain_key" - sudo mv /etc/dkim/mail.txt "/etc/dkim/${domain}.mail.txt" + mv /etc/dkim/mail.private "$domain_key" + mv /etc/dkim/mail.txt "/etc/dkim/${domain}.mail.txt" } done # fix DKIM keys permissions - sudo chown _rspamd /etc/dkim/*.mail.key - sudo chmod 400 /etc/dkim/*.mail.key + chown _rspamd /etc/dkim/*.mail.key + chmod 400 /etc/dkim/*.mail.key regen_conf_files=$1 [ -z "$regen_conf_files" ] && exit 0 # compile sieve script [[ "$regen_conf_files" =~ rspamd\.sieve ]] && { - sudo sievec /etc/dovecot/global_script/rspamd.sieve - sudo chown -R vmail:mail /etc/dovecot/global_script - sudo systemctl restart dovecot + sievec /etc/dovecot/global_script/rspamd.sieve + chown -R vmail:mail /etc/dovecot/global_script + systemctl restart dovecot } # Restart rspamd due to the upgrade # https://rspamd.com/announce/2016/08/01/rspamd-1.3.1.html - sudo systemctl -q restart rspamd.service + systemctl -q restart rspamd.service } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/34-mysql b/data/hooks/conf_regen/34-mysql index 8f7b5455e..43f9fdde1 100755 --- a/data/hooks/conf_regen/34-mysql +++ b/data/hooks/conf_regen/34-mysql @@ -18,12 +18,12 @@ do_post_regen() { if [ ! -f /etc/yunohost/mysql ]; then # ensure that mysql is running - sudo systemctl -q is-active mysql.service \ - || sudo service mysql start + systemctl -q is-active mysql.service \ + || service mysql start # generate and set new root password mysql_password=$(ynh_string_random 10) - sudo mysqladmin -s -u root -pyunohost password "$mysql_password" || { + mysqladmin -s -u root -pyunohost password "$mysql_password" || { if [ $FORCE -eq 1 ]; then echo "It seems that you have already configured MySQL." \ "YunoHost needs to have a root access to MySQL to runs its" \ @@ -31,13 +31,13 @@ do_post_regen() { "You can find this new password in /etc/yunohost/mysql." >&2 # set new password with debconf - sudo debconf-set-selections << EOF + debconf-set-selections << EOF $MYSQL_PKG mysql-server/root_password password $mysql_password $MYSQL_PKG mysql-server/root_password_again password $mysql_password EOF # reconfigure Debian package - sudo dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1 + dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1 else echo "It seems that you have already configured MySQL." \ "YunoHost needs to have a root access to MySQL to runs its" \ @@ -49,12 +49,12 @@ EOF } # store new root password - echo "$mysql_password" | sudo tee /etc/yunohost/mysql - sudo chmod 400 /etc/yunohost/mysql + echo "$mysql_password" | tee /etc/yunohost/mysql + chmod 400 /etc/yunohost/mysql fi [[ -z "$regen_conf_files" ]] \ - || sudo service mysql restart + || service mysql restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/37-avahi-daemon b/data/hooks/conf_regen/37-avahi-daemon index 655a2e054..239c3ad0c 100755 --- a/data/hooks/conf_regen/37-avahi-daemon +++ b/data/hooks/conf_regen/37-avahi-daemon @@ -15,7 +15,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service avahi-daemon restart + || service avahi-daemon restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/40-glances b/data/hooks/conf_regen/40-glances index a19d35d56..70b8f4b5a 100755 --- a/data/hooks/conf_regen/40-glances +++ b/data/hooks/conf_regen/40-glances @@ -14,7 +14,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service glances restart + || service glances restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/43-dnsmasq b/data/hooks/conf_regen/43-dnsmasq index ed795c058..90e96a04c 100755 --- a/data/hooks/conf_regen/43-dnsmasq +++ b/data/hooks/conf_regen/43-dnsmasq @@ -26,7 +26,7 @@ do_pre_regen() { ynh_validate_ip4 "$ipv4" || ipv4='127.0.0.1' ipv6=$(curl -s -6 https://ip6.yunohost.org 2>/dev/null || true) ynh_validate_ip6 "$ipv6" || ipv6='' - domain_list=$(sudo yunohost domain list --output-as plain --quiet) + domain_list=$(yunohost domain list --output-as plain --quiet) # add domain conf files for domain in $domain_list; do @@ -51,7 +51,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service dnsmasq restart + || service dnsmasq restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/46-nsswitch b/data/hooks/conf_regen/46-nsswitch index 06a596e44..fa9b07511 100755 --- a/data/hooks/conf_regen/46-nsswitch +++ b/data/hooks/conf_regen/46-nsswitch @@ -14,7 +14,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service unscd restart + || service unscd restart } FORCE=${2:-0} diff --git a/data/hooks/conf_regen/52-fail2ban b/data/hooks/conf_regen/52-fail2ban index 950f27b5b..3cb499db7 100755 --- a/data/hooks/conf_regen/52-fail2ban +++ b/data/hooks/conf_regen/52-fail2ban @@ -20,7 +20,7 @@ do_post_regen() { regen_conf_files=$1 [[ -z "$regen_conf_files" ]] \ - || sudo service fail2ban restart + || service fail2ban restart } FORCE=${2:-0} diff --git a/data/hooks/restore/05-conf_ldap b/data/hooks/restore/05-conf_ldap index eb6824993..74093136d 100644 --- a/data/hooks/restore/05-conf_ldap +++ b/data/hooks/restore/05-conf_ldap @@ -5,7 +5,7 @@ if [[ $EUID -ne 0 ]]; then # We need to execute this script as root, since the ldap # service will be shut down during the operation (and sudo # won't be available) - sudo /bin/bash $(readlink -f $0) $1 + /bin/bash $(readlink -f $0) $1 else diff --git a/data/hooks/restore/08-conf_ssh b/data/hooks/restore/08-conf_ssh index 0c0f9bf9b..4b69d1696 100644 --- a/data/hooks/restore/08-conf_ssh +++ b/data/hooks/restore/08-conf_ssh @@ -1,8 +1,8 @@ backup_dir="$1/conf/ssh" if [ -d /etc/ssh/ ]; then - sudo cp -a $backup_dir/. /etc/ssh - sudo service ssh restart + cp -a $backup_dir/. /etc/ssh + service ssh restart else echo "SSH is not installed" fi diff --git a/data/hooks/restore/11-conf_ynh_mysql b/data/hooks/restore/11-conf_ynh_mysql index 24cdb1e79..f54641d6f 100644 --- a/data/hooks/restore/11-conf_ynh_mysql +++ b/data/hooks/restore/11-conf_ynh_mysql @@ -9,15 +9,15 @@ service mysql status >/dev/null 2>&1 \ # retrieve current and new password [ -f /etc/yunohost/mysql ] \ - && curr_pwd=$(sudo cat /etc/yunohost/mysql) -new_pwd=$(sudo cat "${backup_dir}/root_pwd" || sudo cat "${backup_dir}/mysql") + && curr_pwd=$(cat /etc/yunohost/mysql) +new_pwd=$(cat "${backup_dir}/root_pwd" || cat "${backup_dir}/mysql") [ -z "$curr_pwd" ] && curr_pwd="yunohost" [ -z "$new_pwd" ] && { new_pwd=$(ynh_string_random 10) } # attempt to change it -sudo mysqladmin -s -u root -p"$curr_pwd" password "$new_pwd" || { +mysqladmin -s -u root -p"$curr_pwd" password "$new_pwd" || { echo "It seems that you have already configured MySQL." \ "YunoHost needs to have a root access to MySQL to runs its" \ @@ -25,18 +25,18 @@ sudo mysqladmin -s -u root -p"$curr_pwd" password "$new_pwd" || { "You can find this new password in /etc/yunohost/mysql." >&2 # set new password with debconf - sudo debconf-set-selections << EOF + debconf-set-selections << EOF $MYSQL_PKG mysql-server/root_password password $new_pwd $MYSQL_PKG mysql-server/root_password_again password $new_pwd EOF # reconfigure Debian package - sudo dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1 + dpkg-reconfigure -freadline -u "$MYSQL_PKG" 2>&1 } # store new root password -echo "$new_pwd" | sudo tee /etc/yunohost/mysql -sudo chmod 400 /etc/yunohost/mysql +echo "$new_pwd" | tee /etc/yunohost/mysql +chmod 400 /etc/yunohost/mysql # reload the grant tables -sudo mysqladmin -s -u root -p"$new_pwd" reload +mysqladmin -s -u root -p"$new_pwd" reload diff --git a/data/hooks/restore/14-conf_ssowat b/data/hooks/restore/14-conf_ssowat index 01ac787ee..71a011488 100644 --- a/data/hooks/restore/14-conf_ssowat +++ b/data/hooks/restore/14-conf_ssowat @@ -1,3 +1,3 @@ backup_dir="$1/conf/ssowat" -sudo cp -a $backup_dir/. /etc/ssowat +cp -a $backup_dir/. /etc/ssowat diff --git a/data/hooks/restore/17-data_home b/data/hooks/restore/17-data_home index a7ba2733c..6226eab6d 100644 --- a/data/hooks/restore/17-data_home +++ b/data/hooks/restore/17-data_home @@ -1,3 +1,3 @@ backup_dir="$1/data/home" -sudo cp -a $backup_dir/. /home +cp -a $backup_dir/. /home diff --git a/data/hooks/restore/20-conf_ynh_firewall b/data/hooks/restore/20-conf_ynh_firewall index c0ee18818..1789aed1e 100644 --- a/data/hooks/restore/20-conf_ynh_firewall +++ b/data/hooks/restore/20-conf_ynh_firewall @@ -1,4 +1,4 @@ backup_dir="$1/conf/ynh/firewall" -sudo cp -a $backup_dir/. /etc/yunohost -sudo yunohost firewall reload +cp -a $backup_dir/. /etc/yunohost +yunohost firewall reload diff --git a/data/hooks/restore/21-conf_ynh_certs b/data/hooks/restore/21-conf_ynh_certs index 34e651319..983bfb5a1 100644 --- a/data/hooks/restore/21-conf_ynh_certs +++ b/data/hooks/restore/21-conf_ynh_certs @@ -1,7 +1,7 @@ backup_dir="$1/conf/ynh/certs" -sudo mkdir -p /etc/yunohost/certs/ +mkdir -p /etc/yunohost/certs/ -sudo cp -a $backup_dir/. /etc/yunohost/certs/ -sudo service nginx reload -sudo service metronome reload +cp -a $backup_dir/. /etc/yunohost/certs/ +service nginx reload +service metronome reload diff --git a/data/hooks/restore/23-data_mail b/data/hooks/restore/23-data_mail index 81b9b923f..f9fd6e699 100644 --- a/data/hooks/restore/23-data_mail +++ b/data/hooks/restore/23-data_mail @@ -1,8 +1,8 @@ backup_dir="$1/data/mail" -sudo cp -a $backup_dir/. /var/mail/ || echo 'No mail found' -sudo chown -R vmail:mail /var/mail/ +cp -a $backup_dir/. /var/mail/ || echo 'No mail found' +chown -R vmail:mail /var/mail/ # Restart services to use migrated certs -sudo service postfix restart -sudo service dovecot restart +service postfix restart +service dovecot restart diff --git a/data/hooks/restore/26-conf_xmpp b/data/hooks/restore/26-conf_xmpp index 61692b316..a300a7268 100644 --- a/data/hooks/restore/26-conf_xmpp +++ b/data/hooks/restore/26-conf_xmpp @@ -1,7 +1,7 @@ backup_dir="$1/conf/xmpp" -sudo cp -a $backup_dir/etc/. /etc/metronome -sudo cp -a $backup_dir/var/. /var/lib/metronome +cp -a $backup_dir/etc/. /etc/metronome +cp -a $backup_dir/var/. /var/lib/metronome # Restart to apply new conf and certs -sudo service metronome restart +service metronome restart diff --git a/data/hooks/restore/29-conf_nginx b/data/hooks/restore/29-conf_nginx index 0795f53df..7288f52f3 100644 --- a/data/hooks/restore/29-conf_nginx +++ b/data/hooks/restore/29-conf_nginx @@ -1,7 +1,7 @@ backup_dir="$1/conf/nginx" # Copy all conf except apps specific conf located in DOMAIN.d -sudo find $backup_dir/ -mindepth 1 -maxdepth 1 -name '*.d' -or -exec sudo cp -a {} /etc/nginx/conf.d/ \; +find $backup_dir/ -mindepth 1 -maxdepth 1 -name '*.d' -or -exec cp -a {} /etc/nginx/conf.d/ \; # Restart to use new conf and certs -sudo service nginx restart +service nginx restart diff --git a/data/hooks/restore/32-conf_cron b/data/hooks/restore/32-conf_cron index 68657963e..59a2bde61 100644 --- a/data/hooks/restore/32-conf_cron +++ b/data/hooks/restore/32-conf_cron @@ -1,6 +1,6 @@ backup_dir="$1/conf/cron" -sudo cp -a $backup_dir/. /etc/cron.d +cp -a $backup_dir/. /etc/cron.d # Restart just in case -sudo service cron restart +service cron restart diff --git a/data/hooks/restore/40-conf_ynh_currenthost b/data/hooks/restore/40-conf_ynh_currenthost index a0bdf94d3..700e806b4 100644 --- a/data/hooks/restore/40-conf_ynh_currenthost +++ b/data/hooks/restore/40-conf_ynh_currenthost @@ -1,3 +1,3 @@ backup_dir="$1/conf/ynh" -sudo cp -a "${backup_dir}/current_host" /etc/yunohost/current_host +cp -a "${backup_dir}/current_host" /etc/yunohost/current_host diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index f4bb83c15..a3aa26fc5 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -233,9 +233,9 @@ def _set_hostname(hostname, pretty_hostname=None): # Then call hostnamectl commands = [ - "sudo hostnamectl --static set-hostname".split() + [hostname], - "sudo hostnamectl --transient set-hostname".split() + [hostname], - "sudo hostnamectl --pretty set-hostname".split() + [pretty_hostname] + "hostnamectl --static set-hostname".split() + [hostname], + "hostnamectl --transient set-hostname".split() + [hostname], + "hostnamectl --pretty set-hostname".split() + [pretty_hostname] ] for command in commands: From f56f4724c36a5261d53c8c78f30d62c12f85fe0e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 22 Mar 2020 01:23:55 +0100 Subject: [PATCH 043/317] Attempt to anonymize data pasted to paste.yunohost.org (in particular domain names) --- src/yunohost/utils/yunopaste.py | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/yunohost/utils/yunopaste.py b/src/yunohost/utils/yunopaste.py index 89c62d761..530295735 100644 --- a/src/yunohost/utils/yunopaste.py +++ b/src/yunohost/utils/yunopaste.py @@ -2,14 +2,23 @@ import requests import json +import logging +from yunohost.domain import _get_maindomain, domain_list +from yunohost.utils.network import get_public_ip from yunohost.utils.error import YunohostError +logger = logging.getLogger('yunohost.utils.yunopaste') def yunopaste(data): paste_server = "https://paste.yunohost.org" + try: + data = anonymize(data) + except Exception as e: + logger.warning("For some reason, YunoHost was not able to anonymize the pasted data. Sorry about that. Be careful about sharing the link, as it may contain somewhat private infos like domain names or IP addresses. Error: %s" % e) + try: r = requests.post("%s/documents" % paste_server, data=data, timeout=30) except Exception as e: @@ -24,3 +33,39 @@ def yunopaste(data): raise YunohostError("Uhoh, couldn't parse the answer from paste.yunohost.org : %s" % r.text, raw_msg=True) return "%s/raw/%s" % (paste_server, url) + + +def anonymize(data): + + # First, let's replace every occurence of the main domain by "domain.tld" + # This should cover a good fraction of the info leaked + main_domain = _get_maindomain() + data = data.replace(main_domain, "maindomain.tld") + + # Next, let's replace other domains. We do this in increasing lengths, + # because e.g. knowing that the domain is a sub-domain of another domain may + # still be informative. + # So e.g. if there's jitsi.foobar.com as a subdomain of foobar.com, it may + # be interesting to know that the log is about a supposedly dedicated domain + # for jisti (hopefully this explanation make sense). + domains = domain_list()["domains"] + domains = sorted(domains, key=lambda d: len(d)) + + count = 2 + for domain in domains: + if domain not in data: + continue + data = data.replace(domain, "domain%s.tld" % count) + count += 1 + + # We also want to anonymize the ips + ipv4 = get_public_ip() + ipv6 = get_public_ip(6) + + if ipv4: + data = data.replace(str(ipv4), "xx.xx.xx.xx") + + if ipv6: + data = data.replace(str(ipv6), "xx:xx:xx:xx:xx:xx") + + return data From 210d5f3fc4b5ce5630ad81b795828377fbf4575e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 22 Mar 2020 01:28:37 +0100 Subject: [PATCH 044/317] [enh] Tell apt to explain what's wrong when there are unmet dependencies (#889) * Ask apt to explain what's wrong when dependencies fail to install * Add comment explaining the syntax Co-Authored-By: Maniack Crudelis Co-authored-by: Maniack Crudelis --- data/helpers.d/apt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 55c85c90b..b2c781faf 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -186,7 +186,10 @@ ynh_package_install_from_equivs () { (cd "$TMPDIR" equivs-build ./control 1> /dev/null dpkg --force-depends -i "./${pkgname}_${pkgversion}_all.deb" 2>&1) - ynh_package_install -f || ynh_die --message="Unable to install dependencies" + # If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies + # Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell). + # Be careful with the syntax : the semicolon + space at the end is important! + ynh_package_install -f || { apt-get check 2>&1; ynh_die --message="Unable to install dependencies"; } [[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir. # check if the package is actually installed From d17fcaf94f9bb2f9f601033ccd700ce4917f98e3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 23 Mar 2020 19:35:41 +0100 Subject: [PATCH 045/317] When dumping debug info after app script failure, be slightly smarter and stop at ynh_die to have more meaningul lines being shown --- src/yunohost/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 3feca796e..21e31d34d 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1139,7 +1139,7 @@ def dump_app_log_extract_for_debugging(operation_logger): line = line.strip().split(": ", 1)[1] lines_to_display.append(line) - if line.endswith("+ ynh_exit_properly"): + if line.endswith("+ ynh_exit_properly") or " + ynh_die " in line: break elif len(lines_to_display) > 20: lines_to_display.pop(0) From af8981e4e033d7426700333020fbbfe27455222c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Mar 2020 20:54:57 +0200 Subject: [PATCH 046/317] Lazy loading might improve performances a bit --- src/yunohost/domain.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 3f906748b..18c4bd8e2 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -32,8 +32,7 @@ from moulinette.core import MoulinetteError from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger -import yunohost.certificate - +from yunohost.app import app_ssowatconf from yunohost.regenconf import regen_conf from yunohost.utils.network import get_public_ip from yunohost.log import is_unit_operation @@ -105,6 +104,7 @@ def domain_add(operation_logger, domain, dyndns=False): dyndns_subscribe(domain=domain) try: + import yunohost.certificate yunohost.certificate._certificate_install_selfsigned([domain], False) attr_dict = { @@ -234,14 +234,17 @@ def domain_dns_conf(domain, ttl=None): def domain_cert_status(domain_list, full=False): + import yunohost.certificate return yunohost.certificate.certificate_status(domain_list, full) def domain_cert_install(domain_list, force=False, no_checks=False, self_signed=False, staging=False): + import yunohost.certificate return yunohost.certificate.certificate_install(domain_list, force, no_checks, self_signed, staging) def domain_cert_renew(domain_list, force=False, no_checks=False, email=False, staging=False): + import yunohost.certificate return yunohost.certificate.certificate_renew(domain_list, force, no_checks, email, staging) From 7d3238140c0913641cd2b5405c7b759659b50567 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 3 Apr 2020 00:12:58 +0200 Subject: [PATCH 047/317] Force locale to C/en to avoid perl whining and flooding logs about the damn missing locale --- data/helpers.d/apt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index b2c781faf..7859d44c5 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -94,7 +94,7 @@ ynh_package_version() { # Requires YunoHost version 2.4.0.3 or higher. ynh_apt() { ynh_wait_dpkg_free - DEBIAN_FRONTEND=noninteractive apt-get -y $@ + LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get -y $@ } # Update package index files @@ -184,7 +184,7 @@ ynh_package_install_from_equivs () { ynh_wait_dpkg_free cp "$controlfile" "${TMPDIR}/control" (cd "$TMPDIR" - equivs-build ./control 1> /dev/null + LC_ALL=C equivs-build ./control 1> /dev/null dpkg --force-depends -i "./${pkgname}_${pkgversion}_all.deb" 2>&1) # If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies # Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell). From 1eef9b6760f70d86ea58edad17f0ef76abd36085 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 3 Apr 2020 01:32:05 +0200 Subject: [PATCH 048/317] Do not redact stuff corresponding to --manifest_key --- src/yunohost/log.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yunohost/log.py b/src/yunohost/log.py index 72e497b5d..cd08bdfe0 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -315,9 +315,9 @@ class RedactingFormatter(Formatter): try: # This matches stuff like db_pwd=the_secret or admin_password=other_secret # (the secret part being at least 3 chars to avoid catching some lines like just "db_pwd=") - # For 'key', we require to at least have one word char [a-zA-Z0-9_] before it to avoid catching "--key" used in many helpers - match = re.search(r'(pwd|pass|password|secret|\wkey|token)=(\S{3,})$', record.strip()) - if match and match.group(2) not in self.data_to_redact: + # Some names like "key" or "manifest_key" are ignored, used in helpers like ynh_app_setting_set or ynh_read_manifest + match = re.search(r'(pwd|pass|password|secret|\w+key|token)=(\S{3,})$', record.strip()) + if match and match.group(2) not in self.data_to_redact and match.group(1) not in ["key", "manifest_key"]: self.data_to_redact.append(match.group(2)) except Exception as e: logger.warning("Failed to parse line to try to identify data to redact ... : %s" % e) From a886053de76927d6186bad1c5a05bd33ff31bd4f Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Thu, 9 Apr 2020 12:29:44 +0200 Subject: [PATCH 049/317] [fix] uid will be tested as a string --- src/yunohost/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 4a047b58f..bc19bc5ea 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -165,8 +165,8 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, operation_logger.start() # Get random UID/GID - all_uid = {x.pw_uid for x in pwd.getpwall()} - all_gid = {x.gr_gid for x in grp.getgrall()} + all_uid = {str(x.pw_uid) for x in pwd.getpwall()} + all_gid = {str(x.gr_gid) for x in grp.getgrall()} uid_guid_found = False while not uid_guid_found: From 5aa25563062c972d542fd2800b3c8aa863111400 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sun, 5 Apr 2020 19:44:39 +0200 Subject: [PATCH 050/317] [fix] config_appy return link --- src/yunohost/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 21e31d34d..4e4878f9e 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -1947,6 +1947,7 @@ def app_config_apply(operation_logger, app, args): logger.success("Config updated as expected") return { + "app": app, "logs": operation_logger.success(), } From 5b0269622a90936b3b194ca2f3d0541df49fa85c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 30 Mar 2020 20:09:26 +0200 Subject: [PATCH 051/317] Attempt to simplify permission migration --- data/helpers.d/setting | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 384fdc399..557afb332 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -197,7 +197,7 @@ EOF if [[ "$1" == "set" ]] && [[ "${4:-}" == "/" ]] then ynh_permission_update --permission "main" --add "visitors" - elif [[ "$1" == "delete" ]] && [[ "${current_value:-}" == "/" ]] + elif [[ "$1" == "delete" ]] && [[ "${current_value:-}" == "/" ]] && [[ -n "$(ynh_app_setting_get --app=$2 --key='is_public' )" ]] then ynh_permission_update --permission "main" --remove "visitors" fi From 729aeb2425985182950d3a967361c351b290fc8b Mon Sep 17 00:00:00 2001 From: Kay0u Date: Mon, 30 Mar 2020 19:36:41 +0200 Subject: [PATCH 052/317] add ynh_permission_has_user --- data/actionsmap/yunohost.yml | 9 +++++++++ data/helpers.d/setting | 19 +++++++++++++++++++ src/yunohost/permission.py | 22 ++++++++++++++++++++++ src/yunohost/user.py | 6 ++++++ 4 files changed, 56 insertions(+) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 245b3615d..af697efc0 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -296,6 +296,15 @@ user: help: Display all info known about each permission, including the full user list of each group it is granted to. action: store_true + ### user_permission_info() + info: + action_help: Get information about a specific permission + api: GET /users/permissions/ + arguments: + permission: + help: Name of the permission to fetch info about + extra: + pattern: *pattern_username ### user_permission_update() update: diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 557afb332..917d4def7 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -367,3 +367,22 @@ ynh_permission_update() { yunohost user permission update "$app.$permission" ${add:-} ${remove:-} } + +# Check if a permission exists +# +# usage: ynh_permission_has_user --permission=permission --user=user +# | arg: -p, --permission - the permission to check +# | arg: -u, --user - the user seek in the permission +# +# Requires YunoHost version 3.7.1 or higher. +ynh_permission_has_user() { + declare -Ar args_array=( [p]=permission= [u]=user) + local permission + ynh_handle_getopts_args "$@" + + if ! ynh_permission_exists --permission $permission + return 1 + fi + + yunohost user permission info $permission | grep -w -q "$user" +} \ No newline at end of file diff --git a/src/yunohost/permission.py b/src/yunohost/permission.py index 71472eeaf..79b346a1f 100644 --- a/src/yunohost/permission.py +++ b/src/yunohost/permission.py @@ -196,6 +196,28 @@ def user_permission_reset(operation_logger, permission, sync_perm=True): return new_permission + +def user_permission_info(permission, sync_perm=True): + """ + Return informations about a specific permission + + Keyword argument: + permission -- Name of the permission (e.g. mail or nextcloud or wordpress.editors) + """ + + # By default, manipulate main permission + if "." not in permission: + permission = permission + ".main" + + # Fetch existing permission + + existing_permission = user_permission_list(full=True)["permissions"].get(permission, None) + if existing_permission is None: + raise YunohostError('permission_not_found', permission=permission) + + return existing_permission + + # # # The followings methods are *not* directly exposed. diff --git a/src/yunohost/user.py b/src/yunohost/user.py index bc19bc5ea..69baf4435 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -792,6 +792,12 @@ def user_permission_reset(permission, sync_perm=True): sync_perm=sync_perm) +def user_permission_info(permission, sync_perm=True): + import yunohost.permission + return yunohost.permission.user_permission_info(permission, + sync_perm=sync_perm) + + # # SSH subcategory # From 9e1cc92ce823c3679fecee05faa5eab506222aa7 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 30 Mar 2020 19:58:06 +0200 Subject: [PATCH 053/317] Let's have a working helper --- data/helpers.d/setting | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 917d4def7..1ab2b6efe 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -374,15 +374,22 @@ ynh_permission_update() { # | arg: -p, --permission - the permission to check # | arg: -u, --user - the user seek in the permission # +# example: ynh_permission_has_user --permission=nextcloud.main --user=visitors +# # Requires YunoHost version 3.7.1 or higher. ynh_permission_has_user() { - declare -Ar args_array=( [p]=permission= [u]=user) + local legacy_args=pu + # Declare an array to define the options of this helper. + declare -Ar args_array=( [p]=permission= [u]=user= ) local permission + local user + # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ! ynh_permission_exists --permission $permission + if ! ynh_permission_exists --permission=$permission + then return 1 fi yunohost user permission info $permission | grep -w -q "$user" -} \ No newline at end of file +} From 3e6cbe4e845d4355c937bd17510fd858f89a5b3a Mon Sep 17 00:00:00 2001 From: Kay0u Date: Mon, 30 Mar 2020 21:32:29 +0200 Subject: [PATCH 054/317] Add legacy_args, fix the helper --- data/actionsmap/yunohost.yml | 2 -- data/helpers.d/setting | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index af697efc0..efded2450 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -303,8 +303,6 @@ user: arguments: permission: help: Name of the permission to fetch info about - extra: - pattern: *pattern_username ### user_permission_update() update: diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 1ab2b6efe..c859fc398 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -270,6 +270,8 @@ ynh_webpath_register () { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_create() { + # Declare an array to define the options of this helper. + local legacy_args=pua declare -Ar args_array=( [p]=permission= [u]=url= [a]=allowed= ) local permission local url @@ -298,6 +300,8 @@ ynh_permission_create() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_delete() { + # Declare an array to define the options of this helper. + local legacy_args=p declare -Ar args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -312,6 +316,8 @@ ynh_permission_delete() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_exists() { + # Declare an array to define the options of this helper. + local legacy_args=p declare -Ar args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -327,6 +333,8 @@ ynh_permission_exists() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_url() { + # Declare an array to define the options of this helper. + local legacy_args=pu declare -Ar args_array=([p]=permission= [u]=url=) local permission local url @@ -352,6 +360,8 @@ ynh_permission_url() { # example: ynh_permission_update --permission admin --add samdoe --remove all_users # Requires YunoHost version 3.7.0 or higher. ynh_permission_update() { + # Declare an array to define the options of this helper. + local legacy_args=par declare -Ar args_array=( [p]=permission= [a]=add= [r]=remove= ) local permission local add @@ -391,5 +401,5 @@ ynh_permission_has_user() { return 1 fi - yunohost user permission info $permission | grep -w -q "$user" + yunohost user permission info "$app.$permission" | grep -w -q "$user" } From a221b7b9f0bc9b00d97bb6aba69d5e7c5166125e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 14:53:34 +0200 Subject: [PATCH 055/317] Update changelog for 3.7.1 --- debian/changelog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debian/changelog b/debian/changelog index 9bcaea043..018807b16 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +yunohost (3.7.1) stable; urgency=low + + - [enh] Add ynh_permission_has_user helper (#905) + - [mod] Change behavior of ynh_setting_delete to try to make migrating away from legacy permissions easier (#906) + - [fix] app_config_apply should also return 'app' info (#918) + - [fix] uid/gid conflicts in user_create because of inconsistent comparison (#924) + - [fix] Ensure metronome owns its directories (1f623830, 031f8a6e) + - [mod] Remove useless sudos in helpers (be88a283) + - [enh] Improve message wording for services (3c844292) + - [enh] Attempt to anonymize data pasted to paste.yunohost.org (f56f4724) + - [enh] Lazy load yunohost.certificate to possibly improve perfs (af8981e4) + - [fix] Improve logging / debugging (1eef9b67, 7d323814, d17fcaf9, 210d5f3f) + + Thanks to all contributors <3 ! (Bram, Kay0u, Maniack, Matthew D.) + + -- Alexandre Aubin Thu, 9 April 2020 14:52:00 +0000 + yunohost (3.7.0.12) stable; urgency=low - Fix previous buggy hotfix about deleting existing primary groups ... From 68d6ed911e97d2274638facc0082773bb9a476d7 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Thu, 9 Apr 2020 17:37:04 +0200 Subject: [PATCH 056/317] [fix] also invalidate group cache --- src/yunohost/user.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index fd67314d8..af5ff77fb 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -201,8 +201,9 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, except Exception as e: raise YunohostError('user_creation_failed', user=username, error=e) - # Invalidate passwd to take user creation into account + # Invalidate passwd and group to take user and group creation into account subprocess.call(['nscd', '-i', 'passwd']) + subprocess.call(['nscd', '-i', 'group']) try: # Attempt to create user home folder From 4968f1aa7df184c9c731a2fb3c2d4f4aa04a719e Mon Sep 17 00:00:00 2001 From: Kayou Date: Thu, 9 Apr 2020 18:08:51 +0200 Subject: [PATCH 057/317] [fix] custom_portal and custom_overlay redirect --- data/templates/nginx/plain/yunohost_panel.conf.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/nginx/plain/yunohost_panel.conf.inc b/data/templates/nginx/plain/yunohost_panel.conf.inc index 1c5a2d656..53a69d705 100644 --- a/data/templates/nginx/plain/yunohost_panel.conf.inc +++ b/data/templates/nginx/plain/yunohost_panel.conf.inc @@ -4,5 +4,5 @@ sub_filter_once on; # Apply to other mime types than text/html sub_filter_types application/xhtml+xml; # Prevent YunoHost panel files from being blocked by specific app rules -location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json) { +location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json|ynhtheme/custom_portal.js|ynhtheme/custom_overlay.css) { } From 3d44560e26f15d23dfdf474908001f1a651ee2cb Mon Sep 17 00:00:00 2001 From: kay0u Date: Thu, 9 Apr 2020 19:51:18 +0000 Subject: [PATCH 058/317] remove the placeholder --- debian/changelog | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index d64900b25..364757b92 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,3 @@ -yunohost (3.8.0~alpha) testing; urgency=low - - Placeholder for upcoming 3.8 to avoid funky stuff with version numbers in - builds etc. - - -- Alexandre Aubin Mon, 16 Mar 2020 01:00:00 +0000 - yunohost (3.7.1) stable; urgency=low - [enh] Add ynh_permission_has_user helper (#905) @@ -20,7 +13,7 @@ yunohost (3.7.1) stable; urgency=low Thanks to all contributors <3 ! (Bram, Kay0u, Maniack, Matthew D.) - -- Alexandre Aubin Thu, 9 April 2020 14:52:00 +0000 + -- Alexandre Aubin Thu, 9 Apr 2020 14:52:00 +0000 yunohost (3.7.0.12) stable; urgency=low From d8dbf81f77bb9615559cd4875b5ce759f8b0d969 Mon Sep 17 00:00:00 2001 From: kay0u Date: Thu, 9 Apr 2020 20:10:49 +0000 Subject: [PATCH 059/317] Update changelog for 3.8.0 release --- debian/changelog | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/debian/changelog b/debian/changelog index 364757b92..29f086b09 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,50 @@ +yunohost (3.8.0) testing; urgency=low + + # Major stuff + + - [enh] New diagnosis system (#534, #872, #919, a416044, a354425, 4ab3653, decb372, e686dc6, b5d18d6, 69bc124, 937d339, cc2288c, aaa9805, 526a3a2) + - [enh] App categories (#778, #853) + - [enh] Support XMPP http upload (#831) + - [enh] Many small improvements in the way we manage services (#838, fa5c0e9, dd92a34, c97a839) + - [enh] Add subcategories management in bash completion (#839) + - [mod] Add conflict with apache2 and bind9, other minor changes in Depends (#909, 3bd6a7a, 0a482fd) + - [enh] Setting to enable POP3 in email stack (#791) + - [enh] Better UX for CLI/API to change maindomain (#796) + + # Misc technical + + - Update ciphers for nginx, postfix and dovecot according to new Mozilla recommendation (#913, #914) + - Get rid of domain-specific acme-challenge snippet, use a single snippet included in every conf (#917) + - [enh] Persist cookies between multiple ynh_local_curl calls for the same app (#884, #903) + - [fix] ynh_find_port didn't detect port already used on UDP (#827, #907) + - [fix] prevent firefox to mix CA and server certificate (#857) + - [enh] add operation logger for config panel (#869) + - [fix] psql helpers: Revoke sessions before dropping tables (#895) + - [fix] moulinette logs were never displayed #lol (#758) + + # Tests, cleaning, refactoring + + - Add core CI, improve/fix tests (#856, #863, 6eb8efb, c4590ab, 711cc35, 6c24755) + - Refactoring (#805, 101d3be, #784) + - Drop some very-old deprecated app helpers (though still somewhat supporting them through hacky patching) (#780) + - Drop glances and the old monitoring system (#821) + - Drop app_debug (#824) + - Drop app's status.json (#834) + - Drop ynh_add_skipped/(un)protected_uris helpers (#910) + - Use a common security.conf.inc instead of having cipher setting in each nginx's domain file (1285776, 4d99cbe, be8427d, 22b9565) + - Don't add weird tmp redirected_urls after postinstall (#902) + - Don't do weird stuff with yunohost-firewall during debian's postinst (978d9d5) + + # i18n, messaging + + - Unit tests / lint / cleaning for translation files (#901) + - Improve message wording, spelling (8b0c9e5, 9fe43b1, f69ab4c, 0decb64, 986f38f, 8d40c73, 8fe343a, 1d84f17) + - Improve translations for French, Catalan, Bengali (Bangladesh), Italian, Dutch, Norwegian Bokmål, Chinese, Occitan, Spanish, Esperanto, German, Nepali, Portuguese, Arabic, Russian, Hungarian, Hindi, Polish, Greek + + Thanks to all contributors <3 ! (Aeris One, Aleks, Allan N., Alvaro, Armando F., Arthur L., Augustin T., Bram, ButterflyOfFire, Damien P., Gustavo M., Jeroen F., Jimmy M., Josué, Kay0u, Maniack Crudelis, Mario, Matthew D., Mélanie C., Patrick B., Quentí, Yasss Gurl, amirale qt, Elie G., ljf, pitchum, Romain R., tituspijean, xaloc33, yalh76) + + -- Kay0u Thu, 09 Apr 2020 19:59:18 +0000 + yunohost (3.7.1) stable; urgency=low - [enh] Add ynh_permission_has_user helper (#905) From b06e8c0f7a77fab4ad09720053a726caf36b50d7 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Thu, 9 Apr 2020 23:47:16 +0200 Subject: [PATCH 060/317] Minor fix to avoid the key to be used if not asked --- data/helpers.d/apt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index def430055..286985026 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -337,7 +337,7 @@ ynh_install_extra_app_dependencies () { # Manage arguments with getopts ynh_handle_getopts_args "$@" name="${name:-$app}" - key=${key:-0} + key=${key:-} # Set a key only if asked if [ -n "$key" ] @@ -377,7 +377,7 @@ ynh_install_extra_repo () { ynh_handle_getopts_args "$@" name="${name:-$app}" append=${append:-0} - key=${key:-0} + key=${key:-} priority=${priority:-} if [ $append -eq 1 ] From 0b17aece2ea72e87708e64e806d2c356c44bce52 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 10 Apr 2020 00:05:56 +0200 Subject: [PATCH 061/317] Various insignificant corrections --- data/helpers.d/hardware | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index be669568e..f98006aae 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -10,16 +10,16 @@ ynh_get_ram () { # Declare an array to define the options of this helper. declare -Ar args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) - local free - local total + local free + local total local ignore_swap local only_swap # Manage arguments with getopts ynh_handle_getopts_args "$@" ignore_swap=${ignore_swap:-0} only_swap=${only_swap:-0} - free=${free:-0} - total=${total:-0} + free=${free:-0} + total=${total:-0} local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') @@ -43,9 +43,9 @@ ynh_get_ram () { # Use only the amount of free swap ram=$free_swap fi - elif [ $total -eq 1 ] - then - local ram=$total_ram_swap + elif [ $total -eq 1 ] + then + local ram=$total_ram_swap if [ $ignore_swap -eq 1 ] then # Use only the amount of free ram @@ -55,9 +55,9 @@ ynh_get_ram () { # Use only the amount of free swap ram=$total_swap fi - else - echo "Uhoh, you should choose --free or --total when using ynh_get_ram" >&2 - ram=0 + else + ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram" + ram=0 fi echo $ram @@ -65,25 +65,25 @@ ynh_get_ram () { # Return 0 or 1 depending if the system has a given amount of RAM+swap free or total # -# usage: ynh_require_ram [--amount=RAM required in Mb] [--free|--total] [--ignore_swap|--only_swap] -# | arg: -a, --amount - The amount to require, in Mb +# usage: ynh_require_ram --required=RAM required in Mb [--free|--total] [--ignore_swap|--only_swap] +# | arg: -r, --required - The amount to require, in Mb # | arg: -f, --free - Count free RAM+swap # | arg: -t, --total - Count total RAM+swap # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -o, --only_swap - Ignore real RAM, consider only swap ynh_require_ram () { # Declare an array to define the options of this helper. - declare -Ar args_array=( [a]=amount= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) - local amount + declare -Ar args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local required local free local total - local ignore_swap - local only_swap - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - amount=${amount:-0} + local ignore_swap + local only_swap + # Manage arguments with getopts + ynh_handle_getopts_args "$@" # Dunno if that's the right way to do, but that's some black magic to be able to # forward the bool args to ynh_get_ram easily? + # If the variable $free is not empty, set it to '--free' free=${free:+--free} total=${total:+--total} ignore_swap=${ignore_swap:+--ignore_swap} @@ -91,7 +91,7 @@ ynh_require_ram () { local ram=$(ynh_get_ram $free $total $ignore_swap $only_swap) - if [ $ram -lt $amount ] + if [ $ram -lt $required ] then return 1 else From bdeac5a92575ffb22cdd8c5073929bcce5c5a4df Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 10 Apr 2020 00:17:50 +0200 Subject: [PATCH 062/317] Move the comments about php where we can read it --- data/helpers.d/php | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 24314b52f..92fab46f6 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -23,6 +23,28 @@ # medium - Low usage, few people or/and publicly accessible. # high - High usage, frequently visited website. # +# +# The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. +# So it will be used to defined 'pm.max_children' +# A lower value for the footprint will allow more children for 'pm.max_children'. And so for +# 'pm.start_servers', 'pm.min_spare_servers' and 'pm.max_spare_servers' which are defined from the +# value of 'pm.max_children' +# NOTE: 'pm.max_children' can't exceed 4 times the number of processor's cores. +# +# The usage value will defined the way php will handle the children for the pool. +# A value set as 'low' will set the process manager to 'ondemand'. Children will start only if the +# service is used, otherwise no child will stay alive. This config gives the lower footprint when the +# service is idle. But will use more proc since it has to start a child as soon it's used. +# Set as 'medium', the process manager will be at dynamic. If the service is idle, a number of children +# equal to pm.min_spare_servers will stay alive. So the service can be quick to answer to any request. +# The number of children can grow if needed. The footprint can stay low if the service is idle, but +# not null. The impact on the proc is a little bit less than 'ondemand' as there's always a few +# children already available. +# Set as 'high', the process manager will be set at 'static'. There will be always as many children as +# 'pm.max_children', the footprint is important (but will be set as maximum a quarter of the maximum +# RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many +# children ready to answer. +# # Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { # Declare an array to define the options of this helper. @@ -232,6 +254,8 @@ ynh_remove_php () { # Define the values to configure php-fpm # +# [internal] +# # usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print] # | arg: -f, --footprint - Memory footprint of the service (low/medium/high). # low - Less than 20Mb of ram by pool. @@ -247,28 +271,6 @@ ynh_remove_php () { # high - High usage, frequently visited website. # # | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app) -# -# -# The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. -# So it will be used to defined 'pm.max_children' -# A lower value for the footprint will allow more children for 'pm.max_children'. And so for -# 'pm.start_servers', 'pm.min_spare_servers' and 'pm.max_spare_servers' which are defined from the -# value of 'pm.max_children' -# NOTE: 'pm.max_children' can't exceed 4 times the number of processor's cores. -# -# The usage value will defined the way php will handle the children for the pool. -# A value set as 'low' will set the process manager to 'ondemand'. Children will start only if the -# service is used, otherwise no child will stay alive. This config gives the lower footprint when the -# service is idle. But will use more proc since it has to start a child as soon it's used. -# Set as 'medium', the process manager will be at dynamic. If the service is idle, a number of children -# equal to pm.min_spare_servers will stay alive. So the service can be quick to answer to any request. -# The number of children can grow if needed. The footprint can stay low if the service is idle, but -# not null. The impact on the proc is a little bit less than 'ondemand' as there's always a few -# children already available. -# Set as 'high', the process manager will be set at 'static'. There will be always as many children as -# 'pm.max_children', the footprint is important (but will be set as maximum a quarter of the maximum -# RAM) but the impact on the proc is lower. The service will be quick to answer as there's always many -# children ready to answer. ynh_get_scalable_phpfpm () { local legacy_args=ufp # Declare an array to define the options of this helper. From 017b0e929c7f6a07f7828013316da7fcc3fe80f5 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 10 Apr 2020 00:31:06 +0200 Subject: [PATCH 063/317] Use YNH_DEFAULT_PHP_VERSION instead of 7.0 --- data/helpers.d/php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 07bf5ab7c..29b9995d4 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -195,9 +195,9 @@ ynh_install_php () { # Store phpversion into the config of this app ynh_app_setting_set $app phpversion $phpversion - if [ "$phpversion" == "7.0" ] + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] then - ynh_die "Do not use ynh_install_php to install php7.0" + ynh_die "Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION" fi # Store the ID of this app and the version of php requested for it @@ -211,12 +211,12 @@ ynh_install_php () { ynh_add_app_dependencies --package="php${phpversion}-fpm" ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package" - # Set php7.0 back as the default version for php-cli. - update-alternatives --set php /usr/bin/php7.0 + # Set the default php version back as the default version for php-cli. + update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION # Pin this extra repository after packages are installed to prevent sury of doing shit ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version - ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append + ynh_pin_repo --package="php${$YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append # Advertise service in admin panel yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" @@ -229,11 +229,11 @@ ynh_remove_php () { # Get the version of php used by this app local phpversion=$(ynh_app_setting_get $app phpversion) - if [ "$phpversion" == "7.0" ] || [ -z "$phpversion" ] + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] || [ -z "$phpversion" ] then - if [ "$phpversion" == "7.0" ] + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] then - ynh_print_err "Do not use ynh_remove_php to install php7.0" + ynh_print_err "Do not use ynh_remove_php to install php$YNH_DEFAULT_PHP_VERSION" fi return 0 fi From 475754de1ed2f6c11a249f36c81a6b8233591286 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 10 Apr 2020 00:35:28 +0200 Subject: [PATCH 064/317] Add legacy_args --- data/helpers.d/hardware | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index f98006aae..46e27caf4 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -9,6 +9,7 @@ # | arg: -o, --only_swap - Ignore real RAM, consider only swap ynh_get_ram () { # Declare an array to define the options of this helper. + local legacy_args=ftso declare -Ar args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local free local total @@ -73,6 +74,7 @@ ynh_get_ram () { # | arg: -o, --only_swap - Ignore real RAM, consider only swap ynh_require_ram () { # Declare an array to define the options of this helper. + local legacy_args=rftso declare -Ar args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local required local free From 1e6da91c783ce565087d1be96815b2b85864c0e6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 00:29:49 +0200 Subject: [PATCH 065/317] Add automail conf for https, + increase priority for automail conf and diagnosis --- data/templates/nginx/server.tpl.conf | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index 093e96b0e..f2e9de2de 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -18,11 +18,11 @@ server { return 301 https://$http_host$request_uri; } - location /.well-known/ynh-diagnosis/ { + location ^~ '/.well-known/ynh-diagnosis/' { alias /tmp/.well-known/ynh-diagnosis/; } - location /.well-known/autoconfig/mail/ { + location ^~ '/.well-known/autoconfig/mail/' { alias /var/www/.well-known/{{ domain }}/autoconfig/mail/; } @@ -52,6 +52,10 @@ server { resolver_timeout 5s; {% endif %} + location ^~ '/.well-known/autoconfig/mail/' { + alias /var/www/.well-known/{{ domain }}/autoconfig/mail/; + } + access_by_lua_file /usr/share/ssowat/access.lua; include /etc/nginx/conf.d/{{ domain }}.d/*.conf; From 7b38b064d71d129cc11be2fa72bede9c81a579ef Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 11 Apr 2020 01:54:32 +0200 Subject: [PATCH 066/317] Fixes and enhancements --- data/helpers.d/apt | 2 +- data/helpers.d/php | 76 +++++++++++++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 09b881bdc..9a038ac4d 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -255,7 +255,7 @@ ynh_install_app_dependencies () { # Pin this sury repository to prevent sury of doing shit ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version - ynh_pin_repo --package="php7.0*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append + ynh_pin_repo --package="php${$YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append fi fi fi diff --git a/data/helpers.d/php b/data/helpers.d/php index 680f37245..bdd68e4bb 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -13,7 +13,7 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # ----------------------------------------------------------------------------- # # usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint -# | arg: -v, --phpversion - Version of php to use.# +# | arg: -v, --phpversion - Version of php to use. # | arg: -f, --footprint - Memory footprint of the service (low/medium/high). # low - Less than 20Mb of ram by pool. # medium - Between 20Mb and 40Mb of ram by pool. @@ -61,7 +61,7 @@ ynh_add_fpm_config () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - # The default behaviour is to use the template. + # The default behaviour is to use the template. use_template="${use_template:-1}" usage="${usage:-}" footprint="${footprint:-}" @@ -72,6 +72,13 @@ ynh_add_fpm_config () { # Set the default PHP-FPM version by default phpversion="${phpversion:-$YNH_PHP_VERSION}" + # If the requested php version is not the default version for YunoHost + if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] + then + # Install this specific version of php. + ynh_install_php --phpversion=$phpversion + fi + local fpm_config_dir="/etc/php/$phpversion/fpm" local fpm_service="php${phpversion}-fpm" # Configure PHP-FPM 5 on Debian Jessie @@ -87,7 +94,7 @@ ynh_add_fpm_config () { if [ $use_template -eq 1 ] then - # Usage 1, use the template in ../conf/php-fpm.conf + # Usage 1, use the template in ../conf/php-fpm.conf cp ../conf/php-fpm.conf "$finalphpconf" ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" @@ -95,7 +102,9 @@ ynh_add_fpm_config () { ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" else - # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm + # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm + + # Define the values to use for the configuration of php. ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint # Copy the default file @@ -141,14 +150,12 @@ ynh_add_fpm_config () { fi fi - - chown root: "$finalphpconf" ynh_store_file_checksum --file="$finalphpconf" if [ -e "../conf/php-fpm.ini" ] then - echo "Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." >&2 + ynh_print_warn -message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." finalphpini="$fpm_config_dir/conf.d/20-$app.ini" ynh_backup_if_checksum_is_different "$finalphpini" cp ../conf/php-fpm.ini "$finalphpini" @@ -167,18 +174,36 @@ ynh_add_fpm_config () { ynh_remove_fpm_config () { local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) - # Assume default php version if not set + # Get the version of php used by this app + local phpversion=$(ynh_app_setting_get $app phpversion) + + # Assume default PHP-FPM version by default + phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}" + + # Assume default php files if not set if [ -z "$fpm_config_dir" ]; then fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm" fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm" fi ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 - ynh_systemd_action --service_name=$fpm_service --action=reload + + if ynh_package_is_installed --package="php${phpversion}-fpm"; then + ynh_systemd_action --service_name=$fpm_service --action=reload + fi + + # If the php version used is not the default version for YunoHost + if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] + then + # Remove this specific version of php + ynh_remove_php + fi } # Install another version of php. # +# [internal] +# # usage: ynh_install_php --phpversion=phpversion [--package=packages] # | arg: -v, --phpversion - Version of php to install. # | arg: -p, --package - Additionnal php packages to install @@ -200,8 +225,15 @@ ynh_install_php () { ynh_die "Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION" fi - # Store the ID of this app and the version of php requested for it - echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version" + # Create the file if doesn't exist already + touch /etc/php/ynh_app_version + + # Do not add twice the same line + if ! grep --quiet "$YNH_APP_INSTANCE_NAME:" "/etc/php/ynh_app_version" + then + # Store the ID of this app and the version of php requested for it + echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version" + fi # Add an extra repository for those packages ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version @@ -216,7 +248,7 @@ ynh_install_php () { # Pin this extra repository after packages are installed to prevent sury of doing shit ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version - ynh_pin_repo --package="php${$YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append + ynh_pin_repo --package="php${YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append # Advertise service in admin panel yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" @@ -224,6 +256,8 @@ ynh_install_php () { # Remove the specific version of php used by the app. # +# [internal] +# # usage: ynh_install_php ynh_remove_php () { # Get the version of php used by this app @@ -233,27 +267,27 @@ ynh_remove_php () { then if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] then - ynh_print_err "Do not use ynh_remove_php to install php$YNH_DEFAULT_PHP_VERSION" + ynh_print_err "Do not use ynh_remove_php to remove php$YNH_DEFAULT_PHP_VERSION !" fi return 0 fi + # Create the file if doesn't exist already + touch /etc/php/ynh_app_version + # Remove the line for this app sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version" # If no other app uses this version of php, remove it. if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version" then - # Purge php dependences for this version. - ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common" # Remove the service from the admin panel - yunohost service remove php${phpversion}-fpm - fi + if ynh_package_is_installed --package="php${phpversion}-fpm"; then + yunohost service remove php${phpversion}-fpm + fi - # If no other app uses alternate php versions, remove the extra repo for php - if [ ! -s "/etc/php/ynh_app_version" ] - then - ynh_secure_remove /etc/php/ynh_app_version + # Purge php dependencies for this version. + ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common" fi } From 7154bca33c9de5377c9fb76b0429ddbe2035608e Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 11 Apr 2020 20:52:52 +0200 Subject: [PATCH 067/317] Fix php migration, integrate --package= to ynh_add_fpm_config --- data/helpers.d/php | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index bdd68e4bb..a72cae3b3 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -6,13 +6,14 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config # -# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] +# usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] [--package=packages] # | arg: -v, --phpversion - Version of php to use. # | arg: -t, --use_template - Use this helper in template mode. +# | arg: -p, --package - Additionnal php packages to install # # ----------------------------------------------------------------------------- # -# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint +# usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] # | arg: -v, --phpversion - Version of php to use. # | arg: -f, --footprint - Memory footprint of the service (low/medium/high). # low - Less than 20Mb of ram by pool. @@ -27,6 +28,8 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # medium - Low usage, few people or/and publicly accessible. # high - High usage, frequently visited website. # +# | arg: -p, --package - Additionnal php packages to install for a specific version of php +# # # The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. # So it will be used to defined 'pm.max_children' @@ -52,14 +55,16 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { # Declare an array to define the options of this helper. - local legacy_args=vtuf - declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= ) + local legacy_args=vtufp + declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= ) local phpversion local use_template local usage local footprint + local package # Manage arguments with getopts ynh_handle_getopts_args "$@" + package=${package:-} # The default behaviour is to use the template. use_template="${use_template:-1}" @@ -75,8 +80,18 @@ ynh_add_fpm_config () { # If the requested php version is not the default version for YunoHost if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] then + # If the argument --package is used, add the packages to ynh_install_php to install them from sury + if [ -n "$package" ]; then + local additionnal_packages="--package=$package" + else + local additionnal_packages="" + fi # Install this specific version of php. - ynh_install_php --phpversion=$phpversion + ynh_install_php --phpversion=$phpversion "$additionnal_packages" + elif [ -n "$package" ] + then + # Install the additionnal packages from the default repository + ynh_add_app_dependencies --package="$package" fi local fpm_config_dir="/etc/php/$phpversion/fpm" From 49d9832f0bc1ca4f2e27810a6439f8a921ac3b17 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 11 Apr 2020 20:53:16 +0200 Subject: [PATCH 068/317] Better apt logging --- data/helpers.d/apt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 9a038ac4d..bcce02dcb 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -189,7 +189,16 @@ ynh_package_install_from_equivs () { # If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies # Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell). # Be careful with the syntax : the semicolon + space at the end is important! - ynh_package_install -f || { apt-get check 2>&1; ynh_die --message="Unable to install dependencies"; } + + ynh_package_install -f || \ + { # If the installation failed + # Get the list of dependencies from the deb + local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ + sed 's/^ Depends: //' | sed 's/,//g')" + # Fake an install of those dependencies to see the errors + # The sed command here is, Print only from '--fix-broken' to the end. + ynh_package_install $dependencies --dry-run | sed -n '/--fix-broken/,$p' >&2 + ynh_die --message="Unable to install dependencies"; } [[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir. # check if the package is actually installed @@ -507,7 +516,7 @@ ynh_add_repo () { # | arg: -n, --name - Name for the files for this repo, $app as default value. # | arg: -a, --append - Do not overwrite existing files. # -# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html for information about pinning. +# See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning. # ynh_pin_repo () { # Declare an array to define the options of this helper. From bf291a0c506f076a951116a123ed7cb791db3147 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 23:25:51 +0200 Subject: [PATCH 069/317] Add 'yunohost tools versions' to have a simple way to fetch version from the webadmin --- data/actionsmap/yunohost.yml | 5 +++++ src/yunohost/tools.py | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index b0bb7f9dc..44419a342 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1459,6 +1459,11 @@ tools: help: List pending configuration files and exit action: store_true + ### tools_versions() + versions: + action_help: Display YunoHost's packages versions + api: GET /versions + subcategories: migrations: diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index e6d013894..3208bda60 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -43,7 +43,7 @@ from yunohost.dyndns import _dyndns_available, _dyndns_provides from yunohost.firewall import firewall_upnp from yunohost.service import service_start, service_enable from yunohost.regenconf import regen_conf -from yunohost.utils.packages import _dump_sources_list, _list_upgradable_apt_packages +from yunohost.utils.packages import _dump_sources_list, _list_upgradable_apt_packages, ynh_packages_version from yunohost.utils.error import YunohostError from yunohost.log import is_unit_operation, OperationLogger @@ -53,6 +53,8 @@ MIGRATIONS_STATE_PATH = "/etc/yunohost/migrations.yaml" logger = getActionLogger('yunohost.tools') +def tools_versions(): + return ynh_packages_version() def tools_ldapinit(): """ From 21c3cc4a5398dc435886e62e939a39ac3e8057e7 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 12 Apr 2020 00:29:47 +0200 Subject: [PATCH 070/317] Store fpm_footprint and fpm_usage --- data/helpers.d/php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/helpers.d/php b/data/helpers.d/php index a72cae3b3..dbb5f5930 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -119,6 +119,10 @@ ynh_add_fpm_config () { else # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm + # Store settings + ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint + ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage + # Define the values to use for the configuration of php. ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint From b0cd37aecad25bacd74c765101473d8ca8150d7d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 12 Apr 2020 01:57:56 +0200 Subject: [PATCH 071/317] Make sure we have at least the standard stuff in /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/snap/bin:/snap/bin:/var/lib/snapd/snap/bin:/snap/bin:/var/lib/snapd/snap/bin ~.~ --- bin/yunohost | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/yunohost b/bin/yunohost index 10a21a9da..b640c8c52 100755 --- a/bin/yunohost +++ b/bin/yunohost @@ -179,6 +179,10 @@ def _retrieve_namespaces(): ret.append(n) return ret +# Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ... +default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +if os.environ["PATH"] != default_path: + os.environ["PATH"] = default_path + ":" + os.environ["PATH"] # Main action ---------------------------------------------------------- From 240a7d76d8b36942cd9a5360f14ebb6b044928bd Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Fri, 10 Apr 2020 23:44:13 +0200 Subject: [PATCH 072/317] [fix] lxc uid number is limited to 65536 by default --- src/yunohost/user.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index af5ff77fb..3696272d0 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -170,7 +170,8 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, uid_guid_found = False while not uid_guid_found: - uid = str(random.randint(200, 99999)) + # LXC uid number is limited to 65536 by default + uid = str(random.randint(200, 65000)) uid_guid_found = uid not in all_uid and uid not in all_gid # Adapt values for LDAP From 2fcc93fcc80a7e8571b194ed9602c4198a9363a6 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sun, 12 Apr 2020 16:37:55 +0200 Subject: [PATCH 073/317] add YNH_DEFAULT_PHP_VERSION in backup.py --- src/yunohost/backup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 8408e7fa3..7ae6069e3 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -51,6 +51,7 @@ from yunohost.hook import ( from yunohost.tools import tools_postinstall from yunohost.regenconf import regen_conf from yunohost.log import OperationLogger +from yunohost.app import APPS_DEFAULT_PHP_VERSION from functools import reduce BACKUP_PATH = '/home/yunohost.backup' @@ -561,6 +562,7 @@ class BackupManager(): env_var["YNH_APP_ID"] = app_id env_var["YNH_APP_INSTANCE_NAME"] = app env_var["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_var["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION tmp_app_dir = os.path.join('apps/', app) tmp_app_bkp_dir = os.path.join(self.work_dir, tmp_app_dir, 'backup') env_var["YNH_APP_BACKUP_DIR"] = tmp_app_bkp_dir @@ -1411,6 +1413,7 @@ class RestoreManager(): env_dict_remove["YNH_APP_ID"] = app_id env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_dict_remove["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION operation_logger = OperationLogger('remove_on_failed_restore', [('app', app_instance_name)], @@ -1458,6 +1461,7 @@ class RestoreManager(): env_var["YNH_APP_ID"] = app_id env_var["YNH_APP_INSTANCE_NAME"] = app env_var["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) + env_var["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_var["YNH_APP_BACKUP_DIR"] = app_backup_in_archive return env_var From ef2f4b2a6ecb68557671710c1ef50d7b842d15f2 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sun, 12 Apr 2020 16:52:23 +0200 Subject: [PATCH 074/317] some hooks use helpers without php --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 56d35cee8..c099fd7a2 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,7 +2,7 @@ # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} +YNH_PHP_VERSION=${YNH_PHP_VERSION:-${YNH_DEFAULT_PHP_VERSION:-7.0}} # Create a dedicated php-fpm config # From 509190532933f27e72b8519db2be19361fbc096e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 12 Apr 2020 17:22:57 +0200 Subject: [PATCH 075/317] Update data/helpers.d/php Co-Authored-By: Kayou --- data/helpers.d/php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index c099fd7a2..4c711056d 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,7 +2,9 @@ # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -YNH_PHP_VERSION=${YNH_PHP_VERSION:-${YNH_DEFAULT_PHP_VERSION:-7.0}} +if [ -n "$YNH_DEFAULT_PHP_VERSION" ]; then + YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} +fi # Create a dedicated php-fpm config # From 6c9187e7e4d0458b9310ee1fed931e9e28385c56 Mon Sep 17 00:00:00 2001 From: Kayou Date: Sun, 12 Apr 2020 17:43:33 +0200 Subject: [PATCH 076/317] Update php --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 4c711056d..55c24ac57 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,7 +2,7 @@ # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -if [ -n "$YNH_DEFAULT_PHP_VERSION" ]; then +if [ -n "${YNH_DEFAULT_PHP_VERSION:-}" ]; then YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} fi From b20b7f3a852ed40ea20d74136c1ba0d010a01720 Mon Sep 17 00:00:00 2001 From: Kayou Date: Sun, 12 Apr 2020 20:03:09 +0200 Subject: [PATCH 077/317] Update php --- data/helpers.d/php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 55c24ac57..eaeee23ed 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,9 +2,8 @@ # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -if [ -n "${YNH_DEFAULT_PHP_VERSION:-}" ]; then - YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} -fi +YNH_DEFAULT_PHP_VERSION=${YNH_DEFAULT_PHP_VERSION:-7.0} +YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config # From aaabf8c75c993030ef3056f2aba7e87d55278a4b Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Thu, 9 Apr 2020 17:37:04 +0200 Subject: [PATCH 078/317] [fix] also invalidate group cache --- src/yunohost/user.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index 69baf4435..ee3504135 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -213,8 +213,9 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, except Exception as e: raise YunohostError('user_creation_failed', user=username, error=e) - # Invalidate passwd to take user creation into account + # Invalidate passwd and group to take user and group creation into account subprocess.call(['nscd', '-i', 'passwd']) + subprocess.call(['nscd', '-i', 'group']) try: # Attempt to create user home folder From f03bb82aadd1d16226cafdad9581390c0a866799 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 12 Apr 2020 01:57:56 +0200 Subject: [PATCH 079/317] Make sure we have at least the standard stuff in /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/snap/bin:/snap/bin:/var/lib/snapd/snap/bin:/snap/bin:/var/lib/snapd/snap/bin ~.~ --- bin/yunohost | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/yunohost b/bin/yunohost index 10a21a9da..b640c8c52 100755 --- a/bin/yunohost +++ b/bin/yunohost @@ -179,6 +179,10 @@ def _retrieve_namespaces(): ret.append(n) return ret +# Stupid PATH management because sometimes (e.g. some cron job) PATH is only /usr/bin:/bin ... +default_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +if os.environ["PATH"] != default_path: + os.environ["PATH"] = default_path + ":" + os.environ["PATH"] # Main action ---------------------------------------------------------- From 0c9a4509f765a60cc6f2840c243b8abb1c09a676 Mon Sep 17 00:00:00 2001 From: Laurent Peuch Date: Fri, 10 Apr 2020 23:44:13 +0200 Subject: [PATCH 080/317] [fix] lxc uid number is limited to 65536 by default --- src/yunohost/user.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yunohost/user.py b/src/yunohost/user.py index ee3504135..df0527655 100644 --- a/src/yunohost/user.py +++ b/src/yunohost/user.py @@ -170,7 +170,8 @@ def user_create(operation_logger, username, firstname, lastname, mail, password, uid_guid_found = False while not uid_guid_found: - uid = str(random.randint(200, 99999)) + # LXC uid number is limited to 65536 by default + uid = str(random.randint(200, 65000)) uid_guid_found = uid not in all_uid and uid not in all_gid # Adapt values for LDAP From 37fd69653a13e7cd90c61df8fbb52580d143f776 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 12 Apr 2020 23:14:07 +0200 Subject: [PATCH 081/317] Update changelog for 3.7.1.1 --- debian/changelog | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 018807b16..6245bb4b0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +yunohost (3.7.1.1) stable; urgency=low + + - [fix] lxc uid number is limited to 65536 by default (0c9a4509) + - [fix] also invalidate group cache when creating users (aaabf8c7) + - [fix] Make sure to have a path that include sbin for stupid cron jobs (f03bb82a) + + -- Alexandre Aubin Sun, 12 Apr 2020 23:15:00 +0000 + yunohost (3.7.1) stable; urgency=low - [enh] Add ynh_permission_has_user helper (#905) @@ -13,7 +21,7 @@ yunohost (3.7.1) stable; urgency=low Thanks to all contributors <3 ! (Bram, Kay0u, Maniack, Matthew D.) - -- Alexandre Aubin Thu, 9 April 2020 14:52:00 +0000 + -- Alexandre Aubin Thu, 9 Apr 2020 14:52:00 +0000 yunohost (3.7.0.12) stable; urgency=low From 23c6ca52364b549afda78a42f21cbf9a0e1405c2 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sun, 12 Apr 2020 23:43:39 +0200 Subject: [PATCH 082/317] Remove APPS_DEFAULT_PHP_VERSION from the core --- src/yunohost/app.py | 9 --------- src/yunohost/backup.py | 4 ---- 2 files changed, 13 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 5a0403af2..39793ec1a 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -59,7 +59,6 @@ APPS_CATALOG_CONF = '/etc/yunohost/apps_catalog.yml' APPS_CATALOG_CRON_PATH = "/etc/cron.daily/yunohost-fetch-apps-catalog" APPS_CATALOG_API_VERSION = 2 APPS_CATALOG_DEFAULT_URL = "https://app.yunohost.org/default" -APPS_DEFAULT_PHP_VERSION = "7.0" re_github_repo = re.compile( r'^(http[s]?://|git@)github.com[/:]' @@ -348,7 +347,6 @@ def app_change_url(operation_logger, app, domain, path): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_dict["YNH_APP_OLD_DOMAIN"] = old_domain env_dict["YNH_APP_OLD_PATH"] = old_path @@ -485,7 +483,6 @@ def app_upgrade(app=[], url=None, file=None): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Start register change on system related_to = [('app', app_instance_name)] @@ -698,7 +695,6 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) - env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Start register change on system operation_logger.extra.update({'env': env_dict}) @@ -807,7 +803,6 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu env_dict_remove["YNH_APP_ID"] = app_id env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number) - env_dict_remove["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION # Execute remove script operation_logger_remove = OperationLogger('remove_on_failed_install', @@ -985,7 +980,6 @@ def app_remove(operation_logger, app): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION operation_logger.extra.update({'env': env_dict}) operation_logger.flush() @@ -1410,7 +1404,6 @@ def app_action_run(operation_logger, app, action, args=None): env_dict["YNH_APP_ID"] = app_id env_dict["YNH_APP_INSTANCE_NAME"] = app env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_dict["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_dict["YNH_ACTION"] = action _, path = tempfile.mkstemp() @@ -1474,7 +1467,6 @@ def app_config_show_panel(operation_logger, app): "YNH_APP_ID": app_id, "YNH_APP_INSTANCE_NAME": app, "YNH_APP_INSTANCE_NUMBER": str(app_instance_nb), - "YNH_DEFAULT_PHP_VERSION": APPS_DEFAULT_PHP_VERSION, } return_code, parsed_values = hook_exec(config_script, @@ -1548,7 +1540,6 @@ def app_config_apply(operation_logger, app, args): "YNH_APP_ID": app_id, "YNH_APP_INSTANCE_NAME": app, "YNH_APP_INSTANCE_NUMBER": str(app_instance_nb), - "YNH_DEFAULT_PHP_VERSION": APPS_DEFAULT_PHP_VERSION, } args = dict(urlparse.parse_qsl(args, keep_blank_values=True)) if args else {} diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 7ae6069e3..8408e7fa3 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -51,7 +51,6 @@ from yunohost.hook import ( from yunohost.tools import tools_postinstall from yunohost.regenconf import regen_conf from yunohost.log import OperationLogger -from yunohost.app import APPS_DEFAULT_PHP_VERSION from functools import reduce BACKUP_PATH = '/home/yunohost.backup' @@ -562,7 +561,6 @@ class BackupManager(): env_var["YNH_APP_ID"] = app_id env_var["YNH_APP_INSTANCE_NAME"] = app env_var["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_var["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION tmp_app_dir = os.path.join('apps/', app) tmp_app_bkp_dir = os.path.join(self.work_dir, tmp_app_dir, 'backup') env_var["YNH_APP_BACKUP_DIR"] = tmp_app_bkp_dir @@ -1413,7 +1411,6 @@ class RestoreManager(): env_dict_remove["YNH_APP_ID"] = app_id env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_dict_remove["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION operation_logger = OperationLogger('remove_on_failed_restore', [('app', app_instance_name)], @@ -1461,7 +1458,6 @@ class RestoreManager(): env_var["YNH_APP_ID"] = app_id env_var["YNH_APP_INSTANCE_NAME"] = app env_var["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - env_var["YNH_DEFAULT_PHP_VERSION"] = APPS_DEFAULT_PHP_VERSION env_var["YNH_APP_BACKUP_DIR"] = app_backup_in_archive return env_var From 71743d211bc9e95f4bdaca77199aa9c891892495 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 10:44:56 +0200 Subject: [PATCH 083/317] Update data/helpers.d/php --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index eaeee23ed..beaa01f14 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,7 +2,7 @@ # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -YNH_DEFAULT_PHP_VERSION=${YNH_DEFAULT_PHP_VERSION:-7.0} +YNH_DEFAULT_PHP_VERSION=7.0 YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config From 4b3f7a1ddd13f0ce7a5f0c807d5069a692ed6024 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 10:45:42 +0200 Subject: [PATCH 084/317] Move YNH_DEFAULT_PHP_VERSION before the comment for YNH_DEFAULT_PHP_VERSION --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index beaa01f14..0bef2ad13 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -1,8 +1,8 @@ #!/bin/bash +YNH_DEFAULT_PHP_VERSION=7.0 # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -YNH_DEFAULT_PHP_VERSION=7.0 YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config From ab2f918a8c5d0eee66fefd852ca43b05b5c1ec6f Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 10:46:37 +0200 Subject: [PATCH 085/317] Missing $ --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 0bef2ad13..e70302912 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -3,7 +3,7 @@ YNH_DEFAULT_PHP_VERSION=7.0 # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. -YNH_PHP_VERSION=${YNH_PHP_VERSION:-YNH_DEFAULT_PHP_VERSION} +YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config # From 7f48631c3f4831f7f293f345865bee6e33d5dc11 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 13:36:33 +0200 Subject: [PATCH 086/317] Optionnal dedicated service --- data/helpers.d/php | 80 ++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 13036684b..14b107582 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -2,24 +2,35 @@ # Create a dedicated php-fpm config # -# usage: ynh_add_fpm_config [--phpversion=7.X] +# usage: ynh_add_fpm_config [--phpversion=7.X] [--dedicated_service] # | arg: -v, --phpversion - Version of php to use. +# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one. # # Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { # Declare an array to define the options of this helper. - local legacy_args=v - declare -Ar args_array=( [v]=phpversion= ) + local legacy_args=vd + declare -Ar args_array=( [v]=phpversion= [d]=dedicated_service ) local phpversion + local dedicated_service # Manage arguments with getopts ynh_handle_getopts_args "$@" # Configure PHP-FPM 7.0 by default phpversion="${phpversion:-7.0}" - local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" - local old_fpm_config_dir="/etc/php/$phpversion/fpm" - local fpm_service="php${phpversion}-fpm-$app" + # Do not use a dedicated service by default + dedicated_service=${dedicated_service:-0} + + if [ $dedicated_service -eq 1 ] + then + local fpm_service="php${phpversion}-fpm-$app" + local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" + local old_fpm_config_dir="/etc/php/$phpversion/fpm" + else + local fpm_service="php${phpversion}-fpm" + local fpm_config_dir="/etc/php/$phpversion/fpm" + fi # Configure PHP-FPM 5 on Debian Jessie if [ "$(ynh_get_debian_release)" == "jessie" ]; then fpm_config_dir="/etc/php5/fpm" @@ -31,22 +42,27 @@ ynh_add_fpm_config () { ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" + ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service" finalphpconf="$fpm_config_dir/pool.d/$app.conf" # Migrate from mutual php service to dedicated one. - if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] + if [ $dedicated_service -eq 1 ] then - ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." - # Create a backup of the old file before migration - ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" - # Remove the old php config file - ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" - # Reload php to release the socket and allow the dedicated service to use it - systemctl reload php${phpversion}-fpm - else - ynh_backup_if_checksum_is_different --file="$finalphpconf" + # If a config file exist in the common pool, move it. + if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] + then + ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." + # Create a backup of the old file before migration + ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" + # Remove the old php config file + ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" + # Reload php to release the socket and allow the dedicated service to use it + ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload + fi fi + ynh_backup_if_checksum_is_different --file="$finalphpconf" + cp ../conf/php-fpm.conf "$finalphpconf" ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" @@ -65,9 +81,10 @@ ynh_add_fpm_config () { ynh_store_file_checksum "$finalphpini" fi - # Create a config for a dedicated php-fpm service for the app - echo " -[Unit] + if [ $dedicated_service -eq 1 ] + then + # Create a config for a dedicated php-fpm service for the app + echo "[Unit] Description=PHP $phpversion FastCGI Process Manager for $app After=network.target @@ -81,10 +98,14 @@ ExecReload=/bin/kill -USR2 \$MAINPID WantedBy=multi-user.target " > ../conf/$fpm_service - # Create this dedicated php-fpm service - ynh_add_systemd_config --service=$fpm_service --template=$fpm_service - - ynh_systemd_action --service_name=$fpm_service --action=restart + # Create this dedicated php-fpm service + ynh_add_systemd_config --service=$fpm_service --template=$fpm_service + # Restart the service, as this service is either stopped or only for this app + ynh_systemd_action --service_name=$fpm_service --action=restart + else + # Reload php, to not impact other parts of the system using php + ynh_systemd_action --service_name=$fpm_service --action=reload + fi } # Remove the dedicated php-fpm config @@ -95,15 +116,20 @@ WantedBy=multi-user.target ynh_remove_fpm_config () { local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) - # Assume php version 7 if not set + local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service) + dedicated_service=${dedicated_service:-0} + # Assume php version 7.0 if not set if [ -z "$fpm_config_dir" ]; then fpm_config_dir="/etc/php/7.0/fpm" fpm_service="php7.0-fpm" fi - # Remove the dedicated service php-fpm service - ynh_remove_systemd_config --service=$fpm_service - yunohost service remove $fpm_service + if [ $dedicated_service -eq 1 ] + then + # Remove the dedicated service php-fpm service for the app + ynh_remove_systemd_config --service=$fpm_service + fi + ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 } From 613142c34290b422e8d130432bc251e1a258503b Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 13:37:00 +0200 Subject: [PATCH 087/317] Dedicate log for each php service --- data/helpers.d/php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 14b107582..7aefc697e 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -83,6 +83,15 @@ ynh_add_fpm_config () { if [ $dedicated_service -eq 1 ] then + # Create a dedicated php-fpm.conf for the service + local globalphpconf=$fpm_config_dir/php-fpm-$app.conf + cp /etc/php/${phpversion}/fpm/php-fpm.conf $globalphpconf + + ynh_replace_string --match_string="^[; ]*pid *=.*" --replace_string="pid = /run/php/php${phpversion}-fpm-$app.pid" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*error_log *=.*" --replace_string="error_log = /var/log/php/fpm-php.$app.log" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*syslog.ident *=.*" --replace_string="syslog.ident = php-fpm-$app" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*include *=.*" --replace_string="include = $finalphpconf" --target_file="$globalphpconf" + # Create a config for a dedicated php-fpm service for the app echo "[Unit] Description=PHP $phpversion FastCGI Process Manager for $app @@ -91,7 +100,7 @@ After=network.target [Service] Type=notify PIDFile=/run/php/php${phpversion}-fpm-$app.pid -ExecStart=/usr/sbin/php-fpm${phpversion} --nodaemonize --fpm-config $finalphpconf --pid /run/php/php${phpversion}-fpm-$app.pid +ExecStart=/usr/sbin/php-fpm$phpversion --nodaemonize --fpm-config $globalphpconf ExecReload=/bin/kill -USR2 \$MAINPID [Install] @@ -100,6 +109,10 @@ WantedBy=multi-user.target # Create this dedicated php-fpm service ynh_add_systemd_config --service=$fpm_service --template=$fpm_service + # Integrate the service in YunoHost admin panel + yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --log_type file --description "Php-fpm dedicated to $app" + # Configure log rotate + ynh_use_logrotate --logfile=/var/log/php # Restart the service, as this service is either stopped or only for this app ynh_systemd_action --service_name=$fpm_service --action=restart else @@ -128,6 +141,10 @@ ynh_remove_fpm_config () { then # Remove the dedicated service php-fpm service for the app ynh_remove_systemd_config --service=$fpm_service + # Remove the global php-fpm conf + ynh_secure_remove --file="$fpm_config_dir/php-fpm-$app.conf" + # Remove the service from the list of services known by Yunohost + yunohost service remove $fpm_service fi ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" From a62513b0b0bb24d83031a614f34d687b42a835f1 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 16:21:45 +0200 Subject: [PATCH 088/317] Clean after conflict --- data/helpers.d/php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index b479747c6..7a26824a4 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -77,6 +77,8 @@ ynh_add_fpm_config () { if [ -n "$usage" ] || [ -n "$footprint" ]; then use_template=0 fi + # Do not use a dedicated service by default + dedicated_service=${dedicated_service:-0} # Set the default PHP-FPM version by default phpversion="${phpversion:-$YNH_PHP_VERSION}" @@ -98,14 +100,10 @@ ynh_add_fpm_config () { ynh_add_app_dependencies --package="$package" fi - # Do not use a dedicated service by default - dedicated_service=${dedicated_service:-0} - if [ $dedicated_service -eq 1 ] then local fpm_service="php${phpversion}-fpm-$app" local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" - local old_fpm_config_dir="/etc/php/$phpversion/fpm" else local fpm_service="php${phpversion}-fpm" local fpm_config_dir="/etc/php/$phpversion/fpm" @@ -128,6 +126,7 @@ ynh_add_fpm_config () { # Migrate from mutual php service to dedicated one. if [ $dedicated_service -eq 1 ] then + local old_fpm_config_dir="/etc/php/$phpversion/fpm" # If a config file exist in the common pool, move it. if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] then @@ -163,7 +162,7 @@ ynh_add_fpm_config () { ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint # Copy the default file - cp "$fpm_config_dir/pool.d/www.conf" "$finalphpconf" + cp "/etc/php/$phpversion/fpm/pool.d/www.conf" "$finalphpconf" # Replace standard variables into the default file ynh_replace_string --match_string="^\[www\]" --replace_string="[$app]" --target_file="$finalphpconf" From 8005429dc489f856f579b3406629b43ffc45af86 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 13 Apr 2020 20:50:58 +0200 Subject: [PATCH 089/317] Update php --- data/helpers.d/php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 118477a0b..19e586b70 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -355,6 +355,18 @@ ynh_get_scalable_phpfpm () { footprint=50 fi + # Define the factor to determine min_spare_servers + # To not have not enough children ready to start for heavy apps. + if [ $footprint -le 20 ] + then + min_spare_servers_factor=8 + elif [ $footprint -le 35 ] + then + min_spare_servers_factor=5 + else + min_spare_servers_factor=3 + fi + # Define the way the process manager handle child processes. if [ "$usage" = "low" ] then @@ -405,7 +417,7 @@ ynh_get_scalable_phpfpm () { if [ "$php_pm" = "dynamic" ] then # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager - php_min_spare_servers=$(( $php_max_children / 8 )) + php_min_spare_servers=$(( $php_max_children / $min_spare_servers_factor )) php_min_spare_servers=$(at_least_one $php_min_spare_servers) php_max_spare_servers=$(( $php_max_children / 2 )) From df47040462983b65b0978f17960a6920279a712b Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 14 Apr 2020 12:47:29 +0200 Subject: [PATCH 090/317] Allow to overwrite pm.max_children --- data/helpers.d/php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/data/helpers.d/php b/data/helpers.d/php index 118477a0b..401c262b3 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -402,6 +402,12 @@ ynh_get_scalable_phpfpm () { php_max_children=$max_proc fi + # Get an potential forced value for php_max_children + local php_forced_max_children=$(ynh_app_setting_get --app=$app --key=php_forced_max_children) + if [ -n "$php_forced_max_children" ]; then + php_max_children=$php_forced_max_children + fi + if [ "$php_pm" = "dynamic" ] then # Define pm.start_servers, pm.min_spare_servers and pm.max_spare_servers for a dynamic process manager From f9429ea91a52c884a1ba496e525b5a1664f1f55f Mon Sep 17 00:00:00 2001 From: ericgaspar Date: Wed, 15 Apr 2020 11:41:24 +0200 Subject: [PATCH 091/317] Spelling and typo corrections --- locales/fr.json | 320 ++++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 770d59dde..1a55fbed9 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -17,9 +17,9 @@ "app_removed": "{app:s} supprimé", "app_requirements_checking": "Vérification des paquets requis pour {app} …", "app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}", - "app_sources_fetch_failed": "Impossible de récupérer les fichiers sources, l'URL est-elle correcte ?", + "app_sources_fetch_failed": "Impossible de récupérer les fichiers sources, l’URL est-elle correcte ?", "app_unknown": "Application inconnue", - "app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n'est pas supporté", + "app_unsupported_remote_type": "Ce type de commande à distance utilisé pour cette application n’est pas supporté", "app_upgrade_failed": "Impossible de mettre à jour {app:s} : {error}", "app_upgraded": "{app:s} mis à jour", "ask_email": "Adresse de courriel", @@ -35,14 +35,14 @@ "backup_archive_open_failed": "Impossible d’ouvrir l’archive de la sauvegarde", "backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde", "backup_created": "Sauvegarde terminée", - "backup_creation_failed": "Impossible de créer l'archive de la sauvegarde", + "backup_creation_failed": "Impossible de créer l’archive de la sauvegarde", "backup_delete_error": "Impossible de supprimer '{path:s}'", "backup_deleted": "La sauvegarde a été supprimée", "backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu", "backup_invalid_archive": "Archive de sauvegarde invalide", "backup_nothings_done": "Il n’y a rien à sauvegarder", "backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", - "backup_output_directory_not_empty": "Le répertoire de destination n'est pas vide", + "backup_output_directory_not_empty": "Le répertoire de destination n’est pas vide", "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde", "backup_running_hooks": "Exécution des scripts de sauvegarde …", "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}", @@ -59,11 +59,11 @@ "done": "Terminé", "downloading": "Téléchargement en cours …", "dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été créée", - "dyndns_cron_remove_failed": "Impossible de supprimer la tâche cron DynDNS parce que: {error}", + "dyndns_cron_remove_failed": "Impossible de supprimer la tâche cron DynDNS parce que : {error}", "dyndns_cron_removed": "La tâche cron pour le domaine DynDNS enlevée", "dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS", "dyndns_ip_updated": "Mise à jour de votre IP pour le domaine DynDNS", - "dyndns_key_generating": "Génération de la clé DNS ... , cela peut prendre un certain temps.", + "dyndns_key_generating": "Génération de la clé DNS …, cela peut prendre un certain temps.", "dyndns_key_not_found": "Clé DNS introuvable pour le domaine", "dyndns_no_domain_registered": "Aucun domaine enregistré avec DynDNS", "dyndns_registered": "Domaine DynDNS enregistré", @@ -75,18 +75,18 @@ "field_invalid": "Champ incorrect : '{:s}'", "firewall_reload_failed": "Impossible de recharger le pare-feu", "firewall_reloaded": "Pare-feu rechargé", - "firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Plus d'info dans le journal de log.", + "firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Plus d’info dans le journal de log.", "hook_exec_failed": "Échec de l’exécution du script : {path:s}", "hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement", "hook_list_by_invalid": "Propriété invalide pour lister les actions par celle-ci", - "hook_name_unknown": "Nom de l'action '{name:s}' inconnu", + "hook_name_unknown": "Nom de l’action '{name:s}' inconnu", "installation_complete": "Installation terminée", - "installation_failed": "Quelque chose s'est mal passé lors de l'installation", + "installation_failed": "Quelque chose s’est mal passé lors de l’installation", "ip6tables_unavailable": "Vous ne pouvez pas jouer avec ip6tables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge", "iptables_unavailable": "Vous ne pouvez pas jouer avec iptables ici. Vous êtes soit dans un conteneur, soit votre noyau ne le prend pas en charge", "ldap_initialized": "L’annuaire LDAP initialisé", "mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'", - "mail_domain_unknown": "Le domaine '{domain:s}' de cette adress de courriel n'est pas valide. Merci d'utiliser un domain administré par ce serveur.", + "mail_domain_unknown": "Le domaine '{domain:s}' de cette adresse de courriel n’est pas valide. Merci d’utiliser un domaine administré par ce serveur.", "mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'", "main_domain_change_failed": "Impossible de modifier le domaine principal", "main_domain_changed": "Le domaine principal modifié", @@ -112,13 +112,13 @@ "restore_complete": "Restauré", "restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]", "restore_failed": "Impossible de restaurer le système", - "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l'est pas non plus dans l’archive", + "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l’est pas non plus dans l’archive", "restore_nothings_done": "Rien n’a été restauré", - "restore_running_app_script": "Exécution du script de restauration de l'application '{app:s}' .…", + "restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}' …", "restore_running_hooks": "Exécution des scripts de restauration …", "service_add_failed": "Impossible d’ajouter le service '{service:s}'", "service_added": "Le service '{service:s}' a été ajouté", - "service_already_started": "Le service '{service:s}' est déjà en cours d'exécution", + "service_already_started": "Le service '{service:s}' est déjà en cours d’exécution", "service_already_stopped": "Le service '{service:s}' est déjà arrêté", "service_cmd_exec_failed": "Impossible d’exécuter la commande '{command:s}'", "service_disable_failed": "Impossible de ne pas lancer le service « {service:s} » au démarrage.\n\nJournaux récents du service : {logs:s}", @@ -152,46 +152,46 @@ "user_deleted": "L’utilisateur supprimé", "user_deletion_failed": "Impossible de supprimer l’utilisateur {user}: {error}", "user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur", - "user_unknown": "L'utilisateur {user:s} est inconnu", - "user_update_failed": "Impossible de mettre à jour l'utilisateur {user}: {error}", + "user_unknown": "L’utilisateur {user:s} est inconnu", + "user_update_failed": "Impossible de mettre à jour l’utilisateur {user}: {error}", "user_updated": "L’utilisateur a été modifié", "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", "yunohost_configured": "YunoHost est maintenant configuré", - "yunohost_installing": "L'installation de YunoHost est en cours …", - "yunohost_not_installed": "YunoHost n'est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", + "yunohost_installing": "L’installation de YunoHost est en cours …", + "yunohost_not_installed": "YunoHost n’est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)", "certmanager_domain_unknown": "Domaine {domain:s} inconnu", "certmanager_domain_cert_not_selfsigned": "Le certificat du domaine {domain:s} n’est pas auto-signé. Voulez-vous vraiment le remplacer ? (Utilisez --force pour cela)", "certmanager_certificate_fetching_or_enabling_failed": "Il semble que l’activation du nouveau certificat pour {domain:s} a échoué …", "certmanager_attempt_to_renew_nonLE_cert": "Le certificat pour le domaine {domain:s} n’est pas émis par Let’s Encrypt. Impossible de le renouveler automatiquement !", - "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} n'est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)", + "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} n’est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)", "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes", "certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", - "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", + "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateurs de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", "certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}", "certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »", "certmanager_cert_install_success": "Le certificat Let’s Encrypt est maintenant installé pour le domaine « {domain:s} »", - "certmanager_cert_renew_success": "Certificat Let's Encrypt renouvelé pour le domaine '{domain:s}'", + "certmanager_cert_renew_success": "Certificat Let’s Encrypt renouvelé pour le domaine '{domain:s}'", "certmanager_cert_signing_failed": "Impossible de signer le nouveau certificat", "certmanager_no_cert_file": "Impossible de lire le fichier du certificat pour le domaine {domain:s} (fichier : {file:s})", - "certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré", + "certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré", "certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations", - "ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin", - "domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s'agit du domaine principal. Vous devez d'abord définir un autre domaine comme domaine principal à l'aide de 'yunohost domain main-domain -n ', voici la liste des domaines candidats. : {other_domains:s}", + "ldap_init_failed_to_create_admin": "L’initialisation de l’annuaire LDAP n’a pas réussi à créer l’utilisateur admin", + "domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal. Vous devez d’abord définir un autre domaine comme domaine principal à l’aide de 'yunohost domain main-domain -n ', voici la liste des domaines candidats. : {other_domains:s}", "certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})", "certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})", "mailbox_used_space_dovecot_down": "Le service de courriel Dovecot doit être démarré si vous souhaitez voir l’espace disque occupé par la messagerie", "domains_available": "Domaines disponibles :", "backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path:s})", - "certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d'abord exécuter cert-install.", - "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l'adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.", + "certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d’abord exécuter cert-install.", + "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l’adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.", "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.", "domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).", "yunohost_ca_creation_success": "L’autorité de certification locale créée.", "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.", "app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}", - "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l'URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.", + "app_change_url_identical_domains": "L’ancien et le nouveau couple domaine/chemin_de_l’URL sont identiques pour ('{domain:s}{path:s}'), rien à faire.", "app_change_url_no_script": "L’application '{app_name:s}' ne prend pas encore en charge le changement d’URL. Vous devriez peut-être la mettre à jour.", "app_change_url_success": "L’URL de l’application {app:s} a été changée en {domain:s}{path:s}", "app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}", @@ -206,16 +206,16 @@ "global_settings_setting_example_int": "Exemple d’option de type entier", "global_settings_setting_example_string": "Exemple d’option de type chaîne", "global_settings_setting_example_enum": "Exemple d’option de type énumération", - "global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n'est pas pris en charge par le système.", + "global_settings_unknown_type": "Situation inattendue : la configuration {setting:s} semble avoir le type {unknown_type:s} mais celui-ci n’est pas pris en charge par le système.", "global_settings_unknown_setting_from_settings_file": "Clé inconnue dans les paramètres : '{setting_key:s}', rejet de cette clé et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json", "backup_abstract_method": "Cette méthode de sauvegarde reste à implémenter", - "backup_applying_method_tar": "Création de l’archive TAR de la sauvegarde…", + "backup_applying_method_tar": "Création de l’archive TAR de la sauvegarde …", "backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …", - "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup…", + "backup_applying_method_borg": "Envoi de tous les fichiers à sauvegarder dans le répertoire borg-backup …", "backup_applying_method_custom": "Appel de la méthode de sauvegarde personnalisée '{method:s}' …", "backup_archive_system_part_not_available": "La partie '{part:s}' du système n’est pas disponible dans cette sauvegarde", - "backup_archive_writing_error": "Impossible d'ajouter des fichiers '{source:s}' (nommés dans l'archive : '{dest:s}') à sauvegarder dans l'archive compressée '{archive:s}'", - "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size:s} temporairement? (Cette méthode est utilisée car certains fichiers n'ont pas pu être préparés avec une méthode plus efficace.)", + "backup_archive_writing_error": "Impossible d’ajouter des fichiers '{source:s}' (nommés dans l’archive : '{dest:s}') à sauvegarder dans l’archive compressée '{archive:s}'", + "backup_ask_for_copying_if_needed": "Voulez-vous effectuer la sauvegarde en utilisant {size:s} temporairement ? (Cette méthode est utilisée car certains fichiers n’ont pas pu être préparés avec une méthode plus efficace.)", "backup_borg_not_implemented": "La méthode de sauvegarde Borg n’est pas encore implémentée", "backup_cant_mount_uncompress_archive": "Impossible de monter en lecture seule le dossier de l’archive décompressée", "backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive", @@ -235,33 +235,33 @@ "global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}", "restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire", "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …", - "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)", - "restore_not_enough_disk_space": "Espace disponible insuffisant (L'espace libre est de {free_space:d} octets. Le besoin d'espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d'espace nécessaire est de {margin:d} octets)", + "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)", + "restore_not_enough_disk_space": "Espace disponible insuffisant (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)", "restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système", "backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.", "domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre fournisseur/registrar DNS avec cette recommandation.", - "migrations_cant_reach_migration_file": "Impossible d'accéder aux fichiers de migration via le chemin '%s'", + "migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migration via le chemin '%s'", "migrations_loading_migration": "Chargement de la migration {id} …", "migrations_migration_has_failed": "La migration {id} a échoué avec l’exception {exception} : annulation", "migrations_no_migrations_to_run": "Aucune migration à lancer", - "migrations_skip_migration": "Ignorer et passer la migration {id}…", - "server_shutdown": "Le serveur va éteindre", + "migrations_skip_migration": "Ignorer et passer la migration {id} …", + "server_shutdown": "Le serveur va s’éteindre", "server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]", "server_reboot": "Le serveur va redémarrer", "server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]", "app_upgrade_some_app_failed": "Certaines applications n’ont pas été mises à jour", "dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.", "dyndns_domain_not_provided": "Le fournisseur DynDNS {provider:s} ne peut pas fournir le domaine {domain:s}.", - "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l'application '{other_app}'", + "app_make_default_location_already_used": "Impossible de configurer l’application '{app}' par défaut pour le domaine '{domain}' car il est déjà utilisé par l’application '{other_app}'", "app_upgrade_app_name": "Mise à jour de l’application {app} …", - "backup_output_symlink_dir_broken": "Votre répertoire d'archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", + "backup_output_symlink_dir_broken": "Votre répertoire d’archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", "migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée", "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}", "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé", "migrate_tsig_wait": "Attendre trois minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …", "migrate_tsig_wait_2": "2 minutes …", "migrate_tsig_wait_3": "1 minute …", - "migrate_tsig_wait_4": "30 secondes …", + "migrate_tsig_wait_4": "30 secondes …", "migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire.", "migration_description_0001_change_cert_group_to_sslcert": "Changement des permissions de groupe des certificats de « metronome » à « ssl-cert »", "migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5", @@ -270,13 +270,13 @@ "migration_0003_patching_sources_list": "Modification du fichier sources.lists …", "migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …", "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …", - "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abords le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.", + "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abord le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.", "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.", "migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !", - "migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer à migration à Stretch.", + "migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer la migration à Stretch.", "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …", "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence.", - "migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n'ont pas été installées à partir d'un catalogue d'applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu'ils fonctionneront toujours après la mise à niveau: {problematic_apps}", + "migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n’ont pas été installées à partir d’un catalogue d’applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu’ils fonctionneront toujours après la mise à niveau: {problematic_apps}", "migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}", "migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.", "migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.", @@ -295,15 +295,15 @@ "service_description_slapd": "Stocke les utilisateurs, domaines et leurs informations liées", "service_description_ssh": "Vous permet de vous connecter à distance à votre serveur via un terminal (protocole SSH)", "service_description_yunohost-api": "Permet les interactions entre l’interface web de YunoHost et le système", - "service_description_yunohost-firewall": "Gère l'ouverture et la fermeture des ports de connexion aux services", + "service_description_yunohost-firewall": "Gère l’ouverture et la fermeture des ports de connexion aux services", "experimental_feature": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites.", "log_corrupted_md_file": "Le fichier YAML de métadonnées associé aux logs est corrompu : '{md_file}'\nErreur : {error}", "log_category_404": "Le journal de la catégorie '{category}' n’existe pas", "log_link_to_log": "Journal complet de cette opération : ' {desc} '", "log_help_to_get_log": "Pour voir le journal de cette opération '{desc}', utilisez la commande 'yunohost log display {name}'", - "log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour obtenir de l’aide, merci de partager le journal de l'opération en cliquant ici", + "log_link_to_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en cliquant ici", "backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})", - "log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour obtenir de l’aide, merci de partager le journal de l'opération en utilisant la commande 'yunohost log display {name} --share'", + "log_help_to_get_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en utilisant la commande 'yunohost log display {name} --share'", "log_does_exists": "Il n’existe pas de journal de l’opération ayant pour nom '{log}', utiliser 'yunohost log list' pour voir tous les fichiers de journaux disponibles", "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement", "log_app_change_url": "Changer l’URL de l’application '{}'", @@ -337,14 +337,14 @@ "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6", "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !", "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système… :(", - "migration_0005_not_enough_space": "Laissez suffisamment d'espace disponible dans {path} pour exécuter la migration.", + "migration_0005_not_enough_space": "Laissez suffisamment d’espace disponible dans {path} pour exécuter la migration.", "service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX", "users_available": "Liste des utilisateurs disponibles :", "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).", "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.", "migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root", - "migration_0006_disclaimer": "YunoHost s'attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.", - "password_listed": "Ce mot de passe est l'un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d'un peu plus singulier.", + "migration_0006_disclaimer": "YunoHost s’attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.", + "password_listed": "Ce mot de passe est l’un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d’un peu plus singulier.", "password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères", "password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules et des minuscules", "password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux", @@ -352,35 +352,35 @@ "root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager au mot de passe root !", "aborting": "Annulation.", "app_not_upgraded": "L’application {failed_app} n’a pas été mise à jour et par conséquence les applications suivantes n’ont pas été mises à jour : {apps}", - "app_start_install": "Installation de l'application {app} …", - "app_start_remove": "Suppression de l'application {app} …", - "app_start_backup": "Collecte des fichiers devant être sauvegardés pour l'application {app} …", - "app_start_restore": "Restauration de l'application {app} …", + "app_start_install": "Installation de l’application {app} …", + "app_start_remove": "Suppression de l’application {app} …", + "app_start_backup": "Collecte des fichiers devant être sauvegardés pour l’application {app} …", + "app_start_restore": "Restauration de l’application {app} …", "app_upgrade_several_apps": "Les applications suivantes seront mises à jour : {apps}", "ask_new_domain": "Nouveau domaine", "ask_new_path": "Nouveau chemin", - "backup_actually_backuping": "Création d'une archive de sauvegarde à partir des fichiers collectés …", - "backup_mount_archive_for_restore": "Préparation de l'archive pour restauration …", - "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n'est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l'authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L'installer quand même ? [{answers:s}] ", - "confirm_app_install_danger": "DANGER! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement)! Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", - "confirm_app_install_thirdparty": "DANGER! Cette application ne fait pas partie du catalogue d'applications de Yunohost. L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", + "backup_actually_backuping": "Création d’une archive de sauvegarde à partir des fichiers collectés …", + "backup_mount_archive_for_restore": "Préparation de l’archive pour restauration …", + "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n’est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l’authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L’installer quand même ? [{answers:s}] ", + "confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", + "confirm_app_install_thirdparty": "DANGER ! Cette application ne fait pas partie du catalogue d’applications de YunoHost. L’installation d’applications tierces peut compromettre l’intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", "dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.", "dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.", - "file_does_not_exist": "Le fichier dont le chemin est {path:s} n'existe pas.", + "file_does_not_exist": "Le fichier dont le chemin est {path:s} n’existe pas.", "global_settings_setting_security_password_admin_strength": "Qualité du mot de passe administrateur", - "global_settings_setting_security_password_user_strength": "Qualité du mot de passe de l'utilisateur", - "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Autoriser l'utilisation de la clé hôte DSA (obsolète) pour la configuration du service SSH", + "global_settings_setting_security_password_user_strength": "Qualité du mot de passe de l’utilisateur", + "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Autoriser l’utilisation de la clé hôte DSA (obsolète) pour la configuration du service SSH", "hook_json_return_error": "Échec de la lecture au retour du script {path:s}. Erreur : {msg:s}. Contenu brut : {raw_content}", "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuration SSH sera gérée par YunoHost (étape 1, automatique)", "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "La configuration SSH sera gérée par YunoHost (étape 2, manuelle)", - "migration_0007_cancelled": "Impossible d'améliorer la gestion de votre configuration SSH.", - "migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d'annuler la migration numéro 6.", + "migration_0007_cancelled": "Impossible d’améliorer la gestion de votre configuration SSH.", + "migration_0007_cannot_restart": "SSH ne peut pas être redémarré après avoir essayé d’annuler la migration numéro 6.", "migration_0008_general_disclaimer": "Pour améliorer la sécurité de votre serveur, il est recommandé de laisser YunoHost gérer la configuration SSH. Votre configuration SSH actuelle diffère de la configuration recommandée. Si vous laissez YunoHost la reconfigurer, la façon dont vous vous connectez à votre serveur via SSH changera comme suit :", - "migration_0008_port": "- Vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N'hésitez pas à le reconfigurer ;", - "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l'utilisateur admin ;", - "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d'invalider un avertissement effrayant de votre client SSH afin de revérifier l'empreinte de votre serveur ;", + "migration_0008_port": "- Vous devrez vous connecter en utilisant le port 22 au lieu de votre actuel port SSH personnalisé. N’hésitez pas à le reconfigurer ;", + "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l’utilisateur admin ;", + "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d’invalider un avertissement effrayant de votre client SSH afin de revérifier l’empreinte de votre serveur ;", "migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", - "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", "migrations_success": "Migration {number} {name} réussie !", "pattern_password_app": "Désolé, les mots de passe ne peuvent pas contenir les caractères suivants : {forbidden_chars}", "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.", @@ -391,10 +391,10 @@ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}", "service_reloaded_or_restarted": "Le service « {service:s} » a été rechargé ou redémarré", "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`.", - "app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d'exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).", + "app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d’exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).", "admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères", "log_regen_conf": "Régénérer les configurations du système '{}'", - "migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l'ignore.", + "migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l’ignore.", "regenconf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé sous '{backup}'", "regenconf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'", "regenconf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour", @@ -404,12 +404,12 @@ "regenconf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour", "regenconf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost (catégorie {category}).", "regenconf_up_to_date": "La configuration est déjà à jour pour la catégorie '{category}'", - "already_up_to_date": "Il n'y a rien à faire ! Tout est déjà à jour !", - "global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web nginx. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)", - "global_settings_setting_security_ssh_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur SSH. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)", - "global_settings_setting_security_postfix_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur Postfix. Affecte les cryptogrammes (et d'autres aspects liés à la sécurité)", + "already_up_to_date": "Il n’y a rien à faire ! Tout est déjà à jour !", + "global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web nginx. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", + "global_settings_setting_security_ssh_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur SSH. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", + "global_settings_setting_security_postfix_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur Postfix. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", "migration_description_0009_decouple_regenconf_from_services": "Dissocier le mécanisme « regen-conf » des services", - "migration_description_0010_migrate_to_apps_json": "Supprimer les catalogues d'applications obsolètes afin d'utiliser la nouvelle liste unifiée 'apps.json' à la place (les anciens catalogues seront remplacés durant la migration 13)", + "migration_description_0010_migrate_to_apps_json": "Supprimer les catalogues d’applications obsolètes afin d’utiliser la nouvelle liste unifiée 'apps.json' à la place (les anciens catalogues seront remplacés durant la migration 13)", "regenconf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par « regen-conf » (catégorie {category}) mais a été conservé.", "regenconf_updated": "La configuration a été mise à jour pour '{category}'", "regenconf_would_be_updated": "La configuration aurait dû être mise à jour pour la catégorie '{category}'", @@ -423,13 +423,13 @@ "tools_upgrade_regular_packages": "Mise à jour des paquets du système (non liés a YunoHost) …", "tools_upgrade_regular_packages_failed": "Impossible de mettre à jour les paquets suivants : {packages_list}", "tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost) …", - "tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie!\nPressez [Entrée] pour revenir à la ligne de commande", + "tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie !\nPressez [Entrée] pour revenir à la ligne de commande", "dpkg_lock_not_available": "Cette commande ne peut être exécutée actuellement car un autre programme semble utiliser le verrou de dpkg (gestionnaire de paquets)", "tools_upgrade_cant_unhold_critical_packages": "Impossible de conserver les paquets critiques…", "tools_upgrade_special_packages_explanation": "La mise à jour spéciale va continuer en arrière-plan. Veuillez ne pas lancer d’autres actions sur votre serveur pendant environ 10 minutes (en fonction de la vitesse du matériel). Après cela, il vous faudra peut-être vous reconnecter à la webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (dans la webadmin) ou via \"yunohost log list\" (en ligne de commande).", "update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", - "backup_permission": "Permission de sauvegarde pour l'application {app:s}", + "backup_permission": "Permission de sauvegarde pour l’application {app:s}", "group_created": "Le groupe '{group}' a été créé", "group_deleted": "Suppression du groupe '{group}'", "group_unknown": "Le groupe {group:s} est inconnu", @@ -439,121 +439,121 @@ "group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}", "log_user_group_delete": "Supprimer le groupe '{}'", "log_user_group_update": "Mettre à jour '{}' pour le groupe", - "mailbox_disabled": "La boîte aux lettres est désactivée pour l'utilisateur {user:s}", + "mailbox_disabled": "La boîte aux lettres est désactivée pour l’utilisateur {user:s}", "app_action_broke_system": "Cette action semble avoir cassé des services importants : {services}", "apps_already_up_to_date": "Toutes les applications sont déjà à jour", - "migration_0011_create_group": "Création d'un groupe pour chaque utilisateur…", - "migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d'utilisateurs.", + "migration_0011_create_group": "Création d’un groupe pour chaque utilisateur…", + "migration_0011_done": "Migration terminée. Vous êtes maintenant en mesure de gérer des groupes d’utilisateurs.", "migrations_must_provide_explicit_targets": "Vous devez fournir des cibles explicites lorsque vous utilisez '--skip' ou '--force-rerun'", - "migrations_no_such_migration": "Il n'y a pas de migration appelée '{id}'", - "migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau: {ids}", - "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l'authentification PostgreSQL à utiliser MD5 pour les connexions locales", + "migrations_no_such_migration": "Il n’y a pas de migration appelée '{id}'", + "migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau : {ids}", + "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l’authentification PostgreSQL à utiliser MD5 pour les connexions locales", "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}", - "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n'a pas pu être terminée avant l'échec de la migration. Erreur: {error:s}", - "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", - "migration_0011_migration_failed_trying_to_rollback": "La migration a échouée… Tentative de restauration du système.", + "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n’a pas pu être terminée avant l’échec de la migration. Erreur: {error:s}", + "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP …", + "migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… Tentative de restauration du système.", "migration_0011_rollback_success": "Système restauré.", "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", - "migration_0011_backup_before_migration": "Création d'une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", + "migration_0011_backup_before_migration": "Création d’une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", "permission_not_found": "Autorisation '{permission:s}' introuvable", - "permission_update_failed": "Impossible de mettre à jour la permission '{permission}': {error}", + "permission_update_failed": "Impossible de mettre à jour la permission '{permission}' : {error}", "permission_updated": "Permission '{permission:s}' mise à jour", "permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour", "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur DynDNS {provider}: votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", - "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP…", - "migrations_already_ran": "Ces migrations sont déjà effectuées: {ids}", - "migrations_dependencies_not_satisfied": "Exécutez ces migrations: '{dependencies_id}', avant migration {id}.", + "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP …", + "migrations_already_ran": "Ces migrations sont déjà effectuées : {ids}", + "migrations_dependencies_not_satisfied": "Exécutez ces migrations : '{dependencies_id}', avant migration {id}.", "migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}", - "migrations_running_forward": "Exécution de la migration {id}…", + "migrations_running_forward": "Exécution de la migration {id} …", "migrations_success_forward": "Migration {id} terminée", - "operation_interrupted": "L'opération a été interrompue manuellement ?", - "permission_already_exist": "L'autorisation '{permission}' existe déjà", + "operation_interrupted": "L’opération a été interrompue manuellement ?", + "permission_already_exist": "L’autorisation '{permission}' existe déjà", "permission_created": "Permission '{permission:s}' créée", - "permission_creation_failed": "Impossible de créer l'autorisation '{permission}': {error}", + "permission_creation_failed": "Impossible de créer l’autorisation '{permission}' : {error}", "permission_deleted": "Permission '{permission:s}' supprimée", - "permission_deletion_failed": "Impossible de supprimer la permission '{permission}': {error}", - "migration_description_0011_setup_group_permission": "Initialiser les groupes d'utilisateurs et autorisations pour les applications et les services", + "permission_deletion_failed": "Impossible de supprimer la permission '{permission}' : {error}", + "migration_description_0011_setup_group_permission": "Initialiser les groupes d’utilisateurs et autorisations pour les applications et les services", "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}", "group_already_exist": "Le groupe {group} existe déjà", "group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système", "group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.", - "group_user_already_in_group": "L'utilisateur {user} est déjà dans le groupe {group}", - "group_user_not_in_group": "L'utilisateur {user} n'est pas dans le groupe {group}", - "log_permission_create": "Créer permission '{}'", - "log_permission_delete": "supprimer permission '{}'", + "group_user_already_in_group": "L’utilisateur {user} est déjà dans le groupe {group}", + "group_user_not_in_group": "L’utilisateur {user} n’est pas dans le groupe {group}", + "log_permission_create": "Créer permission '{}'", + "log_permission_delete": "Supprimer permission '{}'", "log_user_group_create": "Créer '{}' groupe", "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", "log_user_permission_reset": "Réinitialiser la permission '{}'", "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", - "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée", - "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", - "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", - "user_already_exists": "L'utilisateur '{user}' existe déjà", - "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", - "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C'est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", - "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C'est un groupe spécial représentant les visiteurs anonymes", - "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.", - "log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'", + "permission_already_allowed": "Le groupe '{group}' a déjà l’autorisation '{permission}' activée", + "permission_already_disallowed": "Le groupe '{group}' a déjà l’autorisation '{permission}' désactivé '", + "permission_cannot_remove_main": "Supprimer une autorisation principale n’est pas autorisé", + "user_already_exists": "L’utilisateur '{user}' existe déjà", + "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d’autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", + "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C’est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", + "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C’est un groupe spécial représentant les visiteurs anonymes", + "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C’est le groupe principal destiné à ne contenir qu’un utilisateur spécifique.", + "log_permission_url": "Mise à jour de l’URL associée à l’autorisation '{}'", "migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.", - "permission_already_up_to_date": "L'autorisation n'a pas été mise à jour car les demandes d'ajout/suppression correspondent déjà à l'état actuel.", - "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l'autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", - "app_install_failed": "Impossible d'installer {app}: {error}", - "app_install_script_failed": "Une erreur est survenue dans le script d'installation de l'application", - "permission_require_account": "Permission {permission} n'a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs.", - "app_remove_after_failed_install": "Supprimer l'application après l'échec de l'installation…", - "diagnosis_display_tip_web": "Vous pouvez aller à la section Diagnostic (dans l'écran d'accueil) pour voir les problèmes rencontrés.", - "diagnosis_cant_run_because_of_dep": "Impossible d'exécuter le diagnostic pour {category} alors qu'il existe des problèmes importants liés à {dep}.", + "permission_already_up_to_date": "L’autorisation n’a pas été mise à jour car les demandes d’ajout/suppression correspondent déjà à l’état actuel.", + "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l’autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", + "app_install_failed": "Impossible d’installer {app}: {error}", + "app_install_script_failed": "Une erreur est survenue dans le script d’installation de l’application", + "permission_require_account": "Permission {permission} n’a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs.", + "app_remove_after_failed_install": "Supprimer l’application après l’échec de l’installation …", + "diagnosis_display_tip_web": "Vous pouvez aller à la section Diagnostic (dans l’écran d’accueil) pour voir les problèmes rencontrés.", + "diagnosis_cant_run_because_of_dep": "Impossible d’exécuter le diagnostic pour {category} alors qu’il existe des problèmes importants liés à {dep}.", "diagnosis_found_errors": "Trouvé {errors} problème(s) significatif(s) lié(s) à {category} !", "diagnosis_found_errors_and_warnings": "Trouvé {errors} problème(s) significatif(s) (et {warnings} (avertissement(s)) en relation avec {category} !", "diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?", "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.", - "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS de type {0}, nom {1} et valeur {2}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.", - "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free_abs_GB} Go ({free_percent}%) d'espace libre !", + "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS de type {0}, nom {1} et valeur {2}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d’informations.", + "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free_abs_GB} Go ({free_percent}%) d’espace libre !", "diagnosis_ram_ok": "Le système dispose encore de {available_abs_MB} MB ({available_percent}%) de RAM sur {total_abs_MB} MB.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", "diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}", "diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} version: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{0} version : {1} ({2})", "diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})", - "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... probablement à cause d'une mise à niveau partielle ou échouée.", + "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost … probablement à cause d’une mise à niveau partielle ou échouée.", "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", - "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}", - "diagnosis_cache_still_valid": "(Le cache est toujours valide pour le diagnostic {category}. Pas re-diagnostiquer pour le moment!)", + "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}' : {error}", + "diagnosis_cache_still_valid": "(Le cache est toujours valide pour le diagnostic {category}. Pas re-diagnostiquer pour le moment !)", "diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))", "diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.", "diagnosis_everything_ok": "Tout semble bien pour {category} !", - "diagnosis_failed": "Impossible d'extraire le résultat du diagnostic pour la catégorie '{category}': {error}", + "diagnosis_failed": "Impossible d’extraire le résultat du diagnostic pour la catégorie '{category}': {error}", "diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !", "diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d’une adresse IPv4.", "diagnosis_ip_connected_ipv6": "Le serveur est connecté à Internet en IPv6 !", - "diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d'une adresse IPv6.", + "diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d’une adresse IPv6.", "diagnosis_ip_dnsresolution_working": "La résolution de nom de domaine fonctionne !", - "diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque... Un pare-feu bloque-t-il les requêtes DNS ?", + "diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque … Un pare-feu bloque-t-il les requêtes DNS ?", "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.", "diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})", "diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})", - "diagnosis_dns_discrepancy": "L'enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.", + "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d’informations.", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d'espace.", + "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.", "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.", - "diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%)! (sur {total_abs_MB} Mo)", - "diagnosis_ram_low": "Le système n'a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.", - "diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d'avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", + "diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%) ! (sur {total_abs_MB} Mo)", + "diagnosis_ram_low": "Le système n’a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.", + "diagnosis_swap_none": "Le système n’a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.", + "diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d’avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_ok": "Le système dispose de {total_MB} Mo de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", - "diagnosis_regenconf_manually_modified_details": "C'est probablement OK tant que vous savez ce que vous faites;) !", - "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus ...", - "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n'a été trouvée.", - "apps_catalog_init_success": "Système de catalogue d'applications initialisé !", + "diagnosis_regenconf_manually_modified_details": "C’est probablement OK tant que vous savez ce que vous faites ;) !", + "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …", + "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n’a été trouvée.", + "apps_catalog_init_success": "Système de catalogue d’applications initialisé !", "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}", - "diagnosis_mail_ougoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d'autres serveurs.", - "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s'agit du domaine principal et de votre seul domaine. Vous devez d'abord ajouter un autre domaine à l'aide de 'yunohost domain add ', puis définir comme domaine principal à l'aide de ' yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l'aide de 'yunohost domain remove {domain:s}'.'", - "diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d'informations.", + "diagnosis_mail_ougoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d’autres serveurs.", + "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal et de votre seul domaine. Vous devez d’abord ajouter un autre domaine à l’aide de 'yunohost domain add ', puis définir comme domaine principal à l’aide de 'yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l’aide de 'yunohost domain remove {domain:s}'.'", + "diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d’informations.", "diagnosis_description_basesystem": "Système de base", "diagnosis_description_ip": "Connectivité Internet", "diagnosis_description_dnsrecords": "Enregistrements DNS", @@ -562,41 +562,41 @@ "diagnosis_description_ports": "Exposition des ports", "diagnosis_description_regenconf": "Configurations système", "diagnosis_description_security": "Contrôles de sécurité", - "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur. Erreur: {error}", - "apps_catalog_updating": "Mise à jour du catalogue d'applications...", - "apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.", + "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l’extérieur. Erreur : {error}", + "apps_catalog_updating": "Mise à jour du catalogue d’applications …", + "apps_catalog_obsolete_cache": "Le cache du catalogue d’applications est vide ou obsolète.", "apps_catalog_update_success": "Le catalogue des applications a été mis à jour !", - "diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n'est pas bloqué et le courrier électronique peut être envoyé à d'autres serveurs.", + "diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n’est pas bloqué et le courrier électronique peut être envoyé à d’autres serveurs.", "diagnosis_description_mail": "Email", - "diagnosis_ports_unreachable": "Le port {port} n'est pas accessible de l'extérieur.", - "diagnosis_ports_ok": "Le port {port} est accessible de l'extérieur.", - "diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l'extérieur. Erreur: {error}", - "diagnosis_http_ok": "Le domaine {domain} est accessible au travers de HTTP depuis l'extérieur.", - "diagnosis_http_unreachable": "Le domaine {domain} est inaccessible au travers de HTTP depuis l'extérieur.", - "diagnosis_unknown_categories": "Les catégories suivantes sont inconnues: {categories}", - "migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d'applications à l'épreuve du temps", - "app_upgrade_script_failed": "Une erreur s'est produite durant l’exécution du script de mise à niveau de l'application", - "migration_description_0014_remove_app_status_json": "Supprimer les fichiers d'application status.json hérités", - "diagnosis_services_running": "Le service {service} s'exécute correctement !", + "diagnosis_ports_unreachable": "Le port {port} n’est pas accessible de l’extérieur.", + "diagnosis_ports_ok": "Le port {port} est accessible de l’extérieur.", + "diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l’extérieur. Erreur : {error}", + "diagnosis_http_ok": "Le domaine {domain} est accessible au travers de HTTP depuis l’extérieur.", + "diagnosis_http_unreachable": "Le domaine {domain} est inaccessible au travers de HTTP depuis l’extérieur.", + "diagnosis_unknown_categories": "Les catégories suivantes sont inconnues : {categories}", + "migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d’applications à l’épreuve du temps", + "app_upgrade_script_failed": "Une erreur s’est produite durant l’exécution du script de mise à niveau de l’application", + "migration_description_0014_remove_app_status_json": "Supprimer les fichiers d’application status.json hérités", + "diagnosis_services_running": "Le service {service} s’exécute correctement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {1} (service {0})", "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", "diagnosis_http_unknown_error": "Une erreur est survenue en essayant de joindre votre domaine, il est probablement injoignable.", - "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l'interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l'administrateur: https://yunohost.org/admindoc.", - "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l'aide de 'yunohost service log {0}' ou de la section 'Services' de l'administrateur Web.", - "diagnosis_http_bad_status_code": "Le système de diagnostique n'a pas réussi à contacter votre serveur. Il se peut qu'une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", - "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", + "yunohost_postinstall_end_tip": "La post-installation terminée ! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l’interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de YunoHost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", + "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l’aide de 'yunohost service log {0}' ou de la section 'Services' de l’administrateur Web.", + "diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", + "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", "log_app_action_run": "Lancer l’action de l’application '{}'", "log_app_config_show_panel": "Montrer le panneau de configuration de l’application '{}'", "log_app_config_apply": "Appliquer la configuration à l’application '{}'", - "diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu'il n'y a pas encore eu de diagnostic. Vous devriez en lancer un depuis le webmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.", + "diagnosis_never_ran_yet": "Il apparaît que le serveur a été installé récemment et qu’il n’y a pas encore eu de diagnostic. Vous devriez en lancer un depuis le webmin ou en utilisant 'yunohost diagnosis run' depuis la ligne de commande.", "diagnosis_description_web": "Web", "diagnosis_basesystem_hardware_board": "Le modèle de carte du serveur est {model}", - "diagnosis_basesystem_hardware": "L'architecture du serveur est {virt} {arch}", - "group_already_exist_on_system_but_removing_it": "Le groupe {group} est déjà présent dans les groupes du système, mais Yuhonost va le supprimer…", + "diagnosis_basesystem_hardware": "L’architecture du serveur est {virt} {arch}", + "group_already_exist_on_system_but_removing_it": "Le groupe {group} est déjà présent dans les groupes du système, mais YunoHost va le supprimer…", "certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.", - "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans Yunohost." + "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost." } From 720e1daf8b4e31d5b79f4dbc0776951f05d29169 Mon Sep 17 00:00:00 2001 From: Kayou Date: Wed, 15 Apr 2020 15:21:10 +0200 Subject: [PATCH 092/317] Update en.json --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index f6aa35f67..64cca8713 100644 --- a/locales/en.json +++ b/locales/en.json @@ -462,7 +462,7 @@ "pattern_username": "Must be lower-case alphanumeric and underscore characters only", "pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}", "permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled", - "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled'", + "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled", "permission_already_exist": "Permission '{permission}' already exists", "permission_already_up_to_date": "The permission was not updated because the addition/removal requests already match the current state.", "permission_cannot_remove_main": "Removing a main permission is not allowed", From 369f945c779aa9d6990edc99cdaeed4c6c52f28d Mon Sep 17 00:00:00 2001 From: Weblate Admin Date: Wed, 15 Apr 2020 13:04:24 +0000 Subject: [PATCH 093/317] Translated using Weblate (French) Currently translated at 94.6% (566 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 770d59dde..738dc0807 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -563,7 +563,7 @@ "diagnosis_description_regenconf": "Configurations système", "diagnosis_description_security": "Contrôles de sécurité", "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur. Erreur: {error}", - "apps_catalog_updating": "Mise à jour du catalogue d'applications...", + "apps_catalog_updating": "Mise à jour du catalogue d'applications…", "apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.", "apps_catalog_update_success": "Le catalogue des applications a été mis à jour !", "diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n'est pas bloqué et le courrier électronique peut être envoyé à d'autres serveurs.", From 78167da5ca5537e37b48ca22213fc687b3f37ee7 Mon Sep 17 00:00:00 2001 From: Kayou Date: Wed, 15 Apr 2020 13:20:08 +0000 Subject: [PATCH 094/317] Translated using Weblate (French) Currently translated at 95.0% (568 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 738dc0807..688f884ab 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -487,7 +487,7 @@ "log_user_permission_reset": "Réinitialiser la permission '{}'", "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée", - "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé '", + "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé'", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", "user_already_exists": "L'utilisateur '{user}' existe déjà", "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", From 7cfd553c3f6b96e6862bc95f5eec93f6d058f613 Mon Sep 17 00:00:00 2001 From: Kayou Date: Wed, 15 Apr 2020 13:21:27 +0000 Subject: [PATCH 095/317] Translated using Weblate (French) Currently translated at 95.0% (568 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 688f884ab..9f7dd445b 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -487,7 +487,7 @@ "log_user_permission_reset": "Réinitialiser la permission '{}'", "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée", - "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé'", + "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé", "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", "user_already_exists": "L'utilisateur '{user}' existe déjà", "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", From f57b302299f9ea4b90d09db248329ce374de6980 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 17 Apr 2020 00:40:00 +0200 Subject: [PATCH 096/317] Update data/helpers.d/php Co-Authored-By: Kayou --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 7a26824a4..3509bdc3d 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -292,7 +292,7 @@ ynh_remove_fpm_config () { fi ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" - ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1 + ynh_exec_warn_less ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" # If the php version used is not the default version for YunoHost if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] From 05503d2f8ea5623831b809dd16a8ad6189ecdc21 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 17 Apr 2020 00:48:32 +0200 Subject: [PATCH 097/317] fpm_service name --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 3509bdc3d..4d3cdc480 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -102,7 +102,7 @@ ynh_add_fpm_config () { if [ $dedicated_service -eq 1 ] then - local fpm_service="php${phpversion}-fpm-$app" + local fpm_service="${app}-phpfpm" local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" else local fpm_service="php${phpversion}-fpm" From 8e83f8aa2904bae4a253b40d572b64ede5a326af Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 7 Apr 2020 00:16:18 +0200 Subject: [PATCH 098/317] Add a 'yunohost diagnosis get' to get one specific raw info --- data/actionsmap/yunohost.yml | 13 +++++- data/hooks/diagnosis/10-ip.py | 4 +- data/hooks/diagnosis/14-ports.py | 4 +- src/yunohost/diagnosis.py | 76 +++++++++++++++++++++++--------- 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 44419a342..48b1687d4 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1676,7 +1676,7 @@ diagnosis: action: store_true run: - action_help: Show most recents diagnosis results + action_help: Run diagnosis api: POST /diagnosis/run arguments: categories: @@ -1701,3 +1701,14 @@ diagnosis: --list: help: List active ignore filters action: store_true + + get: + action_help: Low-level command to fetch raw data and status about a specific diagnosis test + api: GET /diagnosis/item/ + arguments: + category: + help: Diagnosis category to fetch results from + item: + help: "List of criteria describing the test. Must correspond exactly to the 'meta' infos in 'yunohost diagnosis show'" + metavar: CRITERIA + nargs: "*" diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 552092fe3..32232457e 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -72,13 +72,13 @@ class IPDiagnoser(Diagnoser): ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None - yield dict(meta={"test": "ip", "version": 4}, + yield dict(meta={"test": "ip", "version": '4'}, data=ipv4, status="SUCCESS" if ipv4 else "ERROR", summary=("diagnosis_ip_connected_ipv4", {}) if ipv4 else ("diagnosis_ip_no_ipv4", {})) - yield dict(meta={"test": "ip", "version": 6}, + yield dict(meta={"test": "ip", "version": '6'}, data=ipv6, status="SUCCESS" if ipv6 else "WARNING", summary=("diagnosis_ip_connected_ipv6", {}) if ipv6 diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index 7730ddb57..712d0007b 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -46,12 +46,12 @@ class PortsDiagnoser(Diagnoser): for port, service in sorted(ports.items()): category = services[service].get("category", "[?]") if r["ports"].get(str(port), None) is not True: - yield dict(meta={"port": port, "needed_by": service}, + yield dict(meta={"port": str(port)}, status="ERROR", summary=("diagnosis_ports_unreachable", {"port": port}), details=[("diagnosis_ports_needed_by", (service, category)), ("diagnosis_ports_forwarding_tip", ())]) else: - yield dict(meta={"port": port, "needed_by": service}, + yield dict(meta={"port": str(port)}, status="SUCCESS", summary=("diagnosis_ports_ok", {"port": port}), details=[("diagnosis_ports_needed_by", (service, category))]) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index db791fcdf..7f488b6aa 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -44,6 +44,25 @@ def diagnosis_list(): return {"categories": all_categories_names} +def diagnosis_get(category, item): + + # Get all the categories + all_categories = _list_diagnosis_categories() + all_categories_names = [c for c, _ in all_categories] + + if category not in all_categories_names: + raise YunohostError('diagnosis_unknown_categories', categories=category) + + if isinstance(item, list): + if any("=" not in criteria for criteria in item): + raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)") + + # Convert the provided criteria into a nice dict + item = {c.split("=")[0]: c.split("=")[1] for c in item} + + return Diagnoser.get_cached_report(category, item=item) + + def diagnosis_show(categories=[], issues=False, full=False, share=False): # Get all the categories @@ -56,7 +75,7 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False): else: unknown_categories = [c for c in categories if c not in all_categories_names] if unknown_categories: - raise YunohostError('diagnosis_unknown_categories', categories=", ".join(categories)) + raise YunohostError('diagnosis_unknown_categories', categories=", ".join(unknown_categories)) if not os.path.exists(DIAGNOSIS_CACHE): logger.warning(m18n.n("diagnosis_never_ran_yet")) @@ -65,19 +84,14 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False): # Fetch all reports all_reports = [] for category in categories: - if not os.path.exists(Diagnoser.cache_file(category)): - logger.warning(m18n.n("diagnosis_no_cache", category=category)) - report = {"id": category, - "cached_for": -1, - "timestamp": -1, - "items": []} - Diagnoser.i18n(report) - else: - try: - report = Diagnoser.get_cached_report(category) - except Exception as e: - logger.error(m18n.n("diagnosis_failed", category=category, error=str(e))) - continue + + try: + report = Diagnoser.get_cached_report(category) + except Exception as e: + logger.error(m18n.n("diagnosis_failed", category=category, error=str(e))) + continue + + Diagnoser.i18n(report) add_ignore_flag_to_issues(report) if not full: @@ -221,7 +235,7 @@ def diagnosis_ignore(add_filter=None, remove_filter=None, list=False): if category not in all_categories_names: raise YunohostError("%s is not a diagnosis category" % category) if any("=" not in criteria for criteria in filter_[1:]): - raise YunohostError("Extra criterias should be of the form key=value (e.g. domain=yolo.test)") + raise YunohostError("Criterias should be of the form key=value (e.g. domain=yolo.test)") # Convert the provided criteria into a nice dict criterias = {c.split("=")[0]: c.split("=")[1] for c in filter_[1:]} @@ -356,7 +370,12 @@ class Diagnoser(): for dependency in self.dependencies: dep_report = Diagnoser.get_cached_report(dependency) - dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"] + + if dep_report["timestamp"] == -1: # No cache yet for this dep + dep_errors = True + else: + dep_errors = [item for item in dep_report["items"] if item["status"] == "ERROR"] + if dep_errors: logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency))) return 1, {} @@ -396,12 +415,25 @@ class Diagnoser(): return os.path.join(DIAGNOSIS_CACHE, "%s.json" % id_) @staticmethod - def get_cached_report(id_): - filename = Diagnoser.cache_file(id_) - report = read_json(filename) - report["timestamp"] = int(os.path.getmtime(filename)) - Diagnoser.i18n(report) - return report + def get_cached_report(id_, item=None): + cache_file = Diagnoser.cache_file(id_) + if not os.path.exists(cache_file): + logger.warning(m18n.n("diagnosis_no_cache", category=id_)) + report = {"id": category, + "cached_for": -1, + "timestamp": -1, + "items": []} + else: + report = read_json(cache_file) + report["timestamp"] = int(os.path.getmtime(cache_file)) + + if item: + for report_item in report["items"]: + if report_item.get("meta") == item: + return report_item + return {} + else: + return report @staticmethod def get_description(id_): From f0c0f63bb4da66e5e052dbe6efea433586fa8525 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 7 Apr 2020 02:21:33 +0200 Subject: [PATCH 099/317] Let's use dict for details data, much better for semantic when defining strings etc... --- data/hooks/diagnosis/00-basesystem.py | 10 +++++++--- data/hooks/diagnosis/10-ip.py | 2 +- data/hooks/diagnosis/12-dnsrecords.py | 14 ++++++++------ data/hooks/diagnosis/14-ports.py | 5 +++-- data/hooks/diagnosis/21-web.py | 2 +- data/hooks/diagnosis/30-services.py | 4 ++-- data/hooks/diagnosis/90-security.py | 2 +- locales/en.json | 11 ++++++----- src/yunohost/diagnosis.py | 2 +- 9 files changed, 30 insertions(+), 22 deletions(-) diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index bf7a27047..3c932b488 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -27,7 +27,7 @@ class BaseSystemDiagnoser(Diagnoser): if os.path.exists("/proc/device-tree/model"): model = read_file('/proc/device-tree/model').strip() hardware["data"]["board"] = model - hardware["details"] = [("diagnosis_basesystem_hardware_board", (model,))] + hardware["details"] = [("diagnosis_basesystem_hardware_board", {"model": model})] yield hardware @@ -51,8 +51,12 @@ class BaseSystemDiagnoser(Diagnoser): # Here, ynh_core_version is for example "3.5.4.12", so [:3] is "3.5" and we check it's the same for all packages ynh_core_version = ynh_packages["yunohost"]["version"] consistent_versions = all(infos["version"][:3] == ynh_core_version[:3] for infos in ynh_packages.values()) - ynh_version_details = [("diagnosis_basesystem_ynh_single_version", (package, infos["version"], infos["repo"])) - for package, infos in ynh_packages.items()] + ynh_version_details = [("diagnosis_basesystem_ynh_single_version", + {"package":package, + "version": infos["version"], + "repo": infos["repo"]} + ) + for package, infos in ynh_packages.items()] if consistent_versions: yield dict(meta={"test": "ynh_versions"}, diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 32232457e..7e96a7b56 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -58,7 +58,7 @@ class IPDiagnoser(Diagnoser): yield dict(meta={"test": "dnsresolv"}, status="WARNING", summary=("diagnosis_ip_weird_resolvconf", {}), - details=[("diagnosis_ip_weird_resolvconf_details", ())]) + details=[("diagnosis_ip_weird_resolvconf_details", {})]) else: yield dict(meta={"test": "dnsresolv"}, status="SUCCESS", diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index a889201b9..5d8a12ebb 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -52,15 +52,17 @@ class DNSRecordsDiagnoser(Diagnoser): discrepancies = [] for r in records: - current_value = self.get_current_record(domain, r["name"], r["type"]) or "None" - expected_value = r["value"] if r["value"] != "@" else domain + "." + r["current"] = self.get_current_record(domain, r["name"], r["type"]) or "None" + if r["value"] == "@": + r["value"] = domain + "." - if current_value == "None": - discrepancies.append(("diagnosis_dns_missing_record", (r["type"], r["name"], expected_value))) - elif current_value != expected_value: - discrepancies.append(("diagnosis_dns_discrepancy", (r["type"], r["name"], expected_value, current_value))) + if r["current"] == "None": + discrepancies.append(("diagnosis_dns_missing_record", r)) + elif r["current"] != r["value"]: + discrepancies.append(("diagnosis_dns_discrepancy", r)) if discrepancies: + discrepancies = [("diagnosis_dns_point_to_doc", {})] + discrepancies status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING" summary = ("diagnosis_dns_bad_conf", {"domain": domain, "category": category}) else: diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index 712d0007b..fe7c9003d 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -49,12 +49,13 @@ class PortsDiagnoser(Diagnoser): yield dict(meta={"port": str(port)}, status="ERROR", summary=("diagnosis_ports_unreachable", {"port": port}), - details=[("diagnosis_ports_needed_by", (service, category)), ("diagnosis_ports_forwarding_tip", ())]) + details=[("diagnosis_ports_needed_by", {"service": service, "category": category}), + ("diagnosis_ports_forwarding_tip", {})]) else: yield dict(meta={"port": str(port)}, status="SUCCESS", summary=("diagnosis_ports_ok", {"port": port}), - details=[("diagnosis_ports_needed_by", (service, category))]) + details=[("diagnosis_ports_needed_by", {"service": service, "category": category})]) def main(args, env, loggers): diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 2a3afba88..6b65b8da3 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -51,7 +51,7 @@ class WebDiagnoser(Diagnoser): yield dict(meta={"domain": domain}, status="ERROR", summary=("diagnosis_http_unreachable", {"domain": domain}), - details=[(detail,())]) + details=[(detail,{})]) # In there or idk where else ... # try to diagnose hairpinning situation by crafting a request for the diff --git a/data/hooks/diagnosis/30-services.py b/data/hooks/diagnosis/30-services.py index a46fa735d..9d6879933 100644 --- a/data/hooks/diagnosis/30-services.py +++ b/data/hooks/diagnosis/30-services.py @@ -22,12 +22,12 @@ class ServicesDiagnoser(Diagnoser): if result["status"] != "running": item["status"] = "ERROR" item["summary"] = ("diagnosis_services_bad_status", {"service": service, "status": result["status"]}) - item["details"] = [("diagnosis_services_bad_status_tip", (service,))] + item["details"] = [("diagnosis_services_bad_status_tip", {"service":service})] elif result["configuration"] == "broken": item["status"] = "WARNING" item["summary"] = ("diagnosis_services_conf_broken", {"service": service}) - item["details"] = [(d, tuple()) for d in result["configuration-details"]] + item["details"] = [(d, {}) for d in result["configuration-details"]] else: item["status"] = "SUCCESS" diff --git a/data/hooks/diagnosis/90-security.py b/data/hooks/diagnosis/90-security.py index 0b1b61226..1eedcc8ca 100644 --- a/data/hooks/diagnosis/90-security.py +++ b/data/hooks/diagnosis/90-security.py @@ -22,7 +22,7 @@ class SecurityDiagnoser(Diagnoser): yield dict(meta={"test": "meltdown"}, status="ERROR", summary=("diagnosis_security_vulnerable_to_meltdown", {}), - details=[("diagnosis_security_vulnerable_to_meltdown_details", ())] + details=[("diagnosis_security_vulnerable_to_meltdown_details", {})] ) else: yield dict(meta={}, diff --git a/locales/en.json b/locales/en.json index 64cca8713..3318e762a 100644 --- a/locales/en.json +++ b/locales/en.json @@ -140,7 +140,7 @@ "diagnosis_basesystem_hardware_board": "Server board model is {model}", "diagnosis_basesystem_host": "Server is running Debian {debian_version}", "diagnosis_basesystem_kernel": "Server is running Linux kernel {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} version: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server is running YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.", "diagnosis_display_tip_web": "You can go to the Diagnosis section (in the home screen) to see the issues found.", @@ -167,12 +167,13 @@ "diagnosis_ip_weird_resolvconf_details": "Instead, this file should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). The actual resolvers should be configured in /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Good DNS configuration for domain {domain} (category {category})", "diagnosis_dns_bad_conf": "Bad or missing DNS configuration for domain {domain} (category {category})", - "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with type {0}, name {1} and value {2}. You can check https://yunohost.org/dns_config for more info.", - "diagnosis_dns_discrepancy": "The DNS record with type {0} and name {1} does not match the recommended configuration. Current value: {2}. Excepted value: {3}. You can check https://yunohost.org/dns_config for more info.", + "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with type: {type}, name: {name}, and value: {value}", + "diagnosis_dns_discrepancy": "The DNS record with type {type} and name {name} does not match the recommended configuration. Current value: {current}. Excepted value: {value}", + "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", - "diagnosis_services_bad_status_tip": "You can try to restart the service, and if it doesn't work, have a look at the service logs using 'yunohost service log {0}' or through the 'Services' section of the webadmin.", + "diagnosis_services_bad_status_tip": "You can try to restart the service, and if it doesn't work, have a look at the service logs using 'yunohost service log {service}' or through the 'Services' section of the webadmin.", "diagnosis_diskusage_verylow": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. You should really consider cleaning up some space.", "diagnosis_diskusage_low": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. Be careful.", "diagnosis_diskusage_ok": "Storage {mountpoint} (on device {device}) still has {free_abs_GB} GB ({free_percent}%) space left!", @@ -205,7 +206,7 @@ "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", - "diagnosis_ports_needed_by": "Exposing this port is needed for {1} features (service {0})", + "diagnosis_ports_needed_by": "Exposing this port is needed for {category} features (service {service})", "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 7f488b6aa..7f93f7c0d 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -458,7 +458,7 @@ class Diagnoser(): item["summary"] = m18n.n(summary_key, **summary_args) if "details" in item: - item["details"] = [m18n.n(key, *values) for key, values in item["details"]] + item["details"] = [m18n.n(key, **values) for key, values in item["details"]] def _list_diagnosis_categories(): From 587a07a6e6da1ee12c0f8cf013126c74cd1a5272 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 03:00:10 +0200 Subject: [PATCH 100/317] Propagate change in string format to other locales --- locales/ar.json | 2 +- locales/ca.json | 12 ++++++------ locales/de.json | 2 +- locales/en.json | 4 ++-- locales/eo.json | 10 +++++----- locales/es.json | 10 +++++----- locales/fr.json | 10 +++++----- locales/oc.json | 10 +++++----- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/locales/ar.json b/locales/ar.json index a1349fde7..9c1e67fe0 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -162,7 +162,7 @@ "app_action_broke_system": "يبدو أنّ هذا الإجراء أدّى إلى تحطيم هذه الخدمات المهمة: {services}", "diagnosis_basesystem_host": "هذا الخادم يُشغّل ديبيان {debian_version}", "diagnosis_basesystem_kernel": "هذا الخادم يُشغّل نواة لينكس {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} الإصدار: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} الإصدار: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "هذا الخادم يُشغّل YunoHost {main_version} ({repo})", "diagnosis_everything_ok": "كل شيء على ما يرام في {category}!", "diagnosis_ip_connected_ipv4": "الخادم مُتّصل بالإنترنت عبر IPv4!", diff --git a/locales/ca.json b/locales/ca.json index 175543a13..4c31e4a6c 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -510,7 +510,7 @@ "domain_cannot_remove_main_add_new_one": "No es pot eliminar «{domain:s}» ja que és el domini principal i únic domini, primer s'ha d'afegir un altre domini utilitzant «yunohost domain add », i després fer-lo el domini principal amb «yunohost domain main-domain -n » i després es pot eliminar el domini «{domain:s}» utilitzant «yunohost domain remove {domain:s}».", "diagnosis_basesystem_host": "El servidor funciona amb Debian {debian_version}", "diagnosis_basesystem_kernel": "El servidor funciona amb el nucli de Linux {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} versió: {1}({2})", + "diagnosis_basesystem_ynh_single_version": "{package} versió: {version}({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Esteu utilitzant versions inconsistents dels paquets de YunoHost… probablement a causa d'una actualització fallida o parcial.", "diagnosis_display_tip_web": "Podeu anar a la secció de Diagnòstics (en la pantalla principal) per veure els errors que s'han trobat.", "diagnosis_failed_for_category": "Ha fallat el diagnòstic per la categoria «{category}»: {error}", @@ -535,8 +535,8 @@ "diagnosis_ip_weird_resolvconf_details": "En canvi, aquest fitxer hauria de ser un enllaç simbòlic cap a /etc/resolvconf/run/resolv.conf i que aquest apunti cap a 127.0.0.1 (dnsmasq). La configuració del «resolver» real s'hauria de fer a /etc/resolv.dnsmaq.conf.", "diagnosis_dns_good_conf": "Bona configuració DNS pel domini {domain} (categoria {category})", "diagnosis_dns_bad_conf": "Configuració DNS incorrecta o inexistent pel domini {domain} (categoria {category})", - "diagnosis_dns_missing_record": "Segons la configuració DNS recomanada, hauríeu d'afegir un registre DNS de tipus {0}, nom {1} i valor {2}. Hi ha més informació a https://yunohost.org/dns_config.", - "diagnosis_dns_discrepancy": "El registre DNS de tipus {0} i nom {1} no concorda amb la configuració recomanada. Valor actual: {2}. Valor esperat: {3}. Més informació a https://yunohost.org/dns_config.", + "diagnosis_dns_missing_record": "Segons la configuració DNS recomanada, hauríeu d'afegir un registre DNS\ntipus: {type}\nnom: {name}\nvalor: {value}.", + "diagnosis_dns_discrepancy": "El registre DNS de tipus {type} i nom {name} no concorda amb la configuració recomanada.\nValor actual: {current}\nValor esperat: {value}", "diagnosis_services_bad_status": "El servei {service} està {status} :(", "diagnosis_diskusage_verylow": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Hauríeu de considerar alliberar una mica d'espai.", "diagnosis_diskusage_low": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Aneu amb compte.", @@ -575,7 +575,7 @@ "diagnosis_description_mail": "Correu electrònic", "migration_description_0013_futureproof_apps_catalog_system": "Migrar al nou sistema de catàleg d'aplicacions resistent al pas del temps", "app_upgrade_script_failed": "Hi ha hagut un error en el script d'actualització de l'aplicació", - "diagnosis_services_bad_status_tip": "Podeu intentar reiniciar el servei, i si no funciona, podeu mirar els registres del servei utilitzant «yunohost service log {0}» o a través de «Serveis» a la secció de la pàgina web d'administració.", + "diagnosis_services_bad_status_tip": "Podeu intentar reiniciar el servei, i si no funciona, podeu mirar els registres del servei utilitzant «yunohost service log {service}» o a través de «Serveis» a la secció de la pàgina web d'administració.", "diagnosis_ports_forwarding_tip": "Per arreglar aquest problema, segurament s'ha de configurar el reenviament de ports en el router tal i com s'explica a https://yunohost.org/isp_box_config", "diagnosis_http_bad_status_code": "El sistema de diagnòstic no ha pogut connectar amb el servidor. Podria ser que una altra màquina hagi contestat en lloc del servidor. S'hauria de comprovar que el reenviament del port 80 sigui correcte, que la configuració NGINX està actualitzada i que el reverse-proxy no està interferint.", "diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»", @@ -586,7 +586,7 @@ "migration_description_0014_remove_app_status_json": "Eliminar els fitxers d'aplicació status.json heretats", "diagnosis_services_running": "El servei {service} s'està executant!", "diagnosis_services_conf_broken": "La configuració pel servei {service} està trencada!", - "diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {1} (servei {0})", + "diagnosis_ports_needed_by": "És necessari exposar aquest port per a les funcions {category} (servei {service})", "global_settings_setting_pop3_enabled": "Activa el protocol POP3 per al servidor de correu", "log_app_action_run": "Executa l'acció de l'aplicació «{}»", "log_app_config_show_panel": "Mostra el taulell de configuració de l'aplicació «{}»", @@ -596,4 +596,4 @@ "diagnosis_basesystem_hardware_board": "El model de la targeta del servidor és {model}", "diagnosis_basesystem_hardware": "L'arquitectura del maquinari del servidor és {virt} {arch}", "group_already_exist_on_system_but_removing_it": "El grup {group} ja existeix en els grups del sistema, però YunoHost l'eliminarà…" -} \ No newline at end of file +} diff --git a/locales/de.json b/locales/de.json index d250a22fd..2369e3bdc 100644 --- a/locales/de.json +++ b/locales/de.json @@ -304,7 +304,7 @@ "app_upgrade_script_failed": "Es ist ein Fehler im App-Upgrade-Skript aufgetreten", "diagnosis_basesystem_host": "Server läuft unter Debian {debian_version}.", "diagnosis_basesystem_kernel": "Server läuft unter Linux-Kernel {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} Version: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} Version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.", "diagnosis_display_tip_web": "Sie können den Abschnitt Diagnose (im Startbildschirm) aufrufen, um die gefundenen Probleme anzuzeigen.", diff --git a/locales/en.json b/locales/en.json index 3318e762a..cec219ee6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -167,8 +167,8 @@ "diagnosis_ip_weird_resolvconf_details": "Instead, this file should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). The actual resolvers should be configured in /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Good DNS configuration for domain {domain} (category {category})", "diagnosis_dns_bad_conf": "Bad or missing DNS configuration for domain {domain} (category {category})", - "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with type: {type}, name: {name}, and value: {value}", - "diagnosis_dns_discrepancy": "The DNS record with type {type} and name {name} does not match the recommended configuration. Current value: {current}. Excepted value: {value}", + "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.\nType: {type}\nName: {name}\nValue: {value}", + "diagnosis_dns_discrepancy": "The DNS record with type {type} and name {name} does not match the recommended configuration.\nCurrent value: {current}\nExcepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", diff --git a/locales/eo.json b/locales/eo.json index 7142d9f72..127e7df39 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -504,7 +504,7 @@ "apps_catalog_obsolete_cache": "La kaŝmemoro de la katalogo de programoj estas malplena aŭ malaktuala.", "apps_catalog_update_success": "La aplika katalogo estis ĝisdatigita!", "diagnosis_basesystem_kernel": "Servilo funkcias Linuksan kernon {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} versio: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} versio: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Servilo funkcias YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Vi prizorgas malkonsekvencajn versiojn de la YunoHost-pakoj... plej probable pro malsukcesa aŭ parta ĝisdatigo.", "diagnosis_display_tip_web": "Vi povas iri al la sekcio Diagnozo (en la hejmekrano) por vidi la trovitajn problemojn.", @@ -541,8 +541,8 @@ "diagnosis_no_cache": "Neniu diagnoza kaŝmemoro por kategorio '{category}'", "diagnosis_ip_broken_dnsresolution": "Rezolucio pri domajna nomo rompiĝas pro iu kialo ... Ĉu fajroŝirmilo blokas DNS-petojn ?", "diagnosis_ip_broken_resolvconf": "Rezolucio pri domajna nomo ŝajnas esti rompita en via servilo, kiu ŝajnas rilata al /etc/resolv.conf ne notante 127.0.0.1.", - "diagnosis_dns_missing_record": "Laŭ la rekomendita DNS-agordo, vi devas aldoni DNS-registron kun tipo {0}, nomo {1} kaj valoro {2}. Vi povas kontroli https://yunohost.org/dns_config por pliaj informoj.", - "diagnosis_dns_discrepancy": "La DNS-registro kun tipo {0} kaj nomo {1} ne kongruas kun la rekomendita agordo. Nuna valoro: {2}. Esceptita valoro: {3}. Vi povas kontroli https://yunohost.org/dns_config por pliaj informoj.", + "diagnosis_dns_missing_record": "Laŭ la rekomendita DNS-agordo, vi devas aldoni DNS-registron kun\ntipo: {type}\nnomo: {name}\nvaloro: {value}", + "diagnosis_dns_discrepancy": "La DNS-registro kun tipo {type} kaj nomo {name} ne kongruas kun la rekomendita agordo.\nNuna valoro: {current}\nEsceptita valoro: {value}", "diagnosis_services_conf_broken": "Agordo estas rompita por servo {service} !", "diagnosis_services_bad_status": "Servo {service} estas {status} :(", "diagnosis_ram_low": "La sistemo havas {available_abs_MB} MB ({available_percent}%) RAM forlasita de {total_abs_MB} MB. Estu zorgema.", @@ -556,7 +556,7 @@ "diagnosis_description_systemresources": "Rimedaj sistemoj", "diagnosis_description_security": "Sekurecaj kontroloj", "diagnosis_ports_could_not_diagnose": "Ne povis diagnozi, ĉu haveblaj havenoj de ekstere. Eraro: {error}", - "diagnosis_services_bad_status_tip": "Vi povas provi rekomenci la servon, kaj se ĝi ne funkcias, trarigardu la servajn protokolojn uzante 'yunohost service log {0}' aŭ tra la sekcio 'Servoj' de la retadreso.", + "diagnosis_services_bad_status_tip": "Vi povas provi rekomenci la servon, kaj se ĝi ne funkcias, trarigardu la servajn protokolojn uzante 'yunohost service log {service}' aŭ tra la sekcio 'Servoj' de la retadreso.", "diagnosis_security_vulnerable_to_meltdown_details": "Por ripari tion, vi devas ĝisdatigi vian sistemon kaj rekomenci por ŝarĝi la novan linux-kernon (aŭ kontaktu vian servilan provizanton se ĉi tio ne funkcias). Vidu https://meltdownattack.com/ por pliaj informoj.", "diagnosis_description_basesystem": "Baza sistemo", "diagnosis_description_regenconf": "Sistemaj agordoj", @@ -576,7 +576,7 @@ "diagnosis_services_running": "Servo {service} funkcias!", "diagnosis_ports_unreachable": "Haveno {port} ne atingeblas de ekstere.", "diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.", - "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {0}", + "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {service}", "diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, plej probable vi devas agordi la plusendon de haveno en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config", "diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere. Eraro: {error}", "diagnosis_http_ok": "Domajno {domain} atingeblas de ekstere.", diff --git a/locales/es.json b/locales/es.json index 5a00ab6dc..b72665066 100644 --- a/locales/es.json +++ b/locales/es.json @@ -505,7 +505,7 @@ "app_remove_after_failed_install": "Eliminando la aplicación tras el fallo de instalación…", "diagnosis_basesystem_host": "El servidor está ejecutando Debian {debian_version}.", "diagnosis_basesystem_kernel": "El servidor está ejecutando el núcleo de Linux {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} versión: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} versión: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "El servidor está ejecutando YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Está ejecutando versiones incoherentes de los paquetes de YunoHost... probablemente por una actualización errónea o parcial.", "diagnosis_failed_for_category": "Diagnóstico fallido para la categoría «{category}» : {error}", @@ -528,9 +528,9 @@ "diagnosis_ip_no_ipv4": "El servidor no cuenta con ipv4 funcional.", "diagnosis_ip_not_connected_at_all": "¿¡Está conectado el servidor a internet!?", "diagnosis_ip_broken_resolvconf": "DNS parece no funcionar en tu servidor, lo que parece estar relacionado con /etc/resolv.conf no apuntando a 127.0.0.1.", - "diagnosis_dns_missing_record": "Según la configuración DNS recomendada, deberías añadir un registro DNS de tipo {0}, nombre {1} y valor {2}. Puedes consultar https://yunohost.org/dns_config para más información.", + "diagnosis_dns_missing_record": "Según la configuración DNS recomendada, deberías añadir un registro DNS\ntipo: {type}\nnombre: {name}\nvalor: {value}", "diagnosis_diskusage_low": "El almacenamiento {mountpoint} (en dispositivo {device}) solo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Ten cuidado.", - "diagnosis_services_bad_status_tip": "Puedes intentar reiniciar el servicio, y si no funciona, echar un vistazo a los logs del servicio usando 'yunohost service log {0}' o a través de la sección 'Servicios' en webadmin.", + "diagnosis_services_bad_status_tip": "Puedes intentar reiniciar el servicio, y si no funciona, echar un vistazo a los logs del servicio usando 'yunohost service log {service}' o a través de la sección 'Servicios' en webadmin.", "diagnosis_ip_connected_ipv6": "¡El servidor está conectado a internet a través de IPv6!", "diagnosis_ip_no_ipv6": "El servidor no cuenta con IPv6 funcional.", "diagnosis_ip_dnsresolution_working": "¡DNS no está funcionando!", @@ -539,7 +539,7 @@ "diagnosis_ip_weird_resolvconf_details": "En su lugar, este fichero debería ser un enlace simbólico a /etc/resolvconf/run/resolv.conf apuntando a 127.0.0.1 (dnsmasq). Los servidores de nombre de domino deben configurarse a través de /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Buena configuración DNS para el dominio {domain} (categoría {category})", "diagnosis_dns_bad_conf": "Configuración mala o faltante de los DNS para el dominio {domain} (categoría {category})", - "diagnosis_dns_discrepancy": "El registro DNS con tipo {0} y nombre {1} no se corresponde a la configuración recomendada. Valor actual: {2}. Valor esperado: {3}. Puedes consultar https://yunohost.org/dns_config para más información.", + "diagnosis_dns_discrepancy": "El registro DNS con tipo {type} y nombre {name} no se corresponde a la configuración recomendada.\nValor actual: {current}\nValor esperado: {value}", "diagnosis_services_bad_status": "El servicio {service} está {status} :(", "diagnosis_diskusage_verylow": "El almacenamiento {mountpoint} (en el dispositivo {device}) sólo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Deberías considerar la posibilidad de limpiar algo de espacio.", "diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free_abs_GB} GB ({free_percent}%) de espacio libre!", @@ -569,7 +569,7 @@ "diagnosis_description_ports": "Exposición de puertos", "diagnosis_description_systemresources": "Recursos del sistema", "diagnosis_swap_ok": "El sistema tiene {total_MB} MB de espacio de intercambio!", - "diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {1} (service {0})", + "diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {category} (service {service})", "diagnosis_ports_ok": "El puerto {port} es accesible desde internet.", "diagnosis_ports_unreachable": "El puerto {port} no es accesible desde internet.", "diagnosis_ports_could_not_diagnose": "No se puede comprobar si los puertos están accesibles desde el exterior. Error: {error}", diff --git a/locales/fr.json b/locales/fr.json index 9f7dd445b..c8dfd12a9 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -509,14 +509,14 @@ "diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?", "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.", - "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS de type {0}, nom {1} et valeur {2}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.", + "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType: {type}\nNom: {name}\nValeur {value}", "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free_abs_GB} Go ({free_percent}%) d'espace libre !", "diagnosis_ram_ok": "Le système dispose encore de {available_abs_MB} MB ({available_percent}%) de RAM sur {total_abs_MB} MB.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", "diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}", "diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} version: {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... probablement à cause d'une mise à niveau partielle ou échouée.", "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", @@ -535,7 +535,7 @@ "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.", "diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})", "diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})", - "diagnosis_dns_discrepancy": "L'enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d'informations.", + "diagnosis_dns_discrepancy": "L'enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d'espace.", "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.", @@ -579,13 +579,13 @@ "migration_description_0014_remove_app_status_json": "Supprimer les fichiers d'application status.json hérités", "diagnosis_services_running": "Le service {service} s'exécute correctement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", - "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {1} (service {0})", + "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})", "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", "diagnosis_http_unknown_error": "Une erreur est survenue en essayant de joindre votre domaine, il est probablement injoignable.", "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l'interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l'administrateur: https://yunohost.org/admindoc.", - "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l'aide de 'yunohost service log {0}' ou de la section 'Services' de l'administrateur Web.", + "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l'aide de 'yunohost service log {service}' ou de la section 'Services' de l'administrateur Web.", "diagnosis_http_bad_status_code": "Le système de diagnostique n'a pas réussi à contacter votre serveur. Il se peut qu'une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l'extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", diff --git a/locales/oc.json b/locales/oc.json index 5472c97e8..a452b72bb 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -497,7 +497,7 @@ "user_already_exists": "L’utilizaire {user} existís ja", "diagnosis_basesystem_host": "Lo servidor fonciona amb Debian {debian_version}.", "diagnosis_basesystem_kernel": "Lo servidor fonciona amb lo nuclèu Linuxl {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{0} version : {1} ({2})", + "diagnosis_basesystem_ynh_single_version": "{package} version : {version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Utilizatz de versions inconsistentas dels paquets de YunoHost… probablament a causa d'una actualizacion fracassada o parciala.", "diagnosis_display_tip_cli": "Podètz executar « yunohost diagnosis show --issues » per mostrar las errors trobadas.", "diagnosis_ignored_issues": "(+ {nb_ignored} problèma(es) ignorat(s))", @@ -536,8 +536,8 @@ "operation_interrupted": "L’operacion es estada interrompuda manualament ?", "group_cannot_be_deleted": "Lo grop « {group} » pòt pas èsser suprimit manualament.", "diagnosis_found_warnings": "Trobat {warnings} element(s) que se poirián melhorar per {category}.", - "diagnosis_dns_missing_record": "Segon la configuracion DNS recomandada, vos calriá ajustar un enregistrament DNS de tipe {0}, nom {1} e valor {2}. Podètz consultar https://yunohost.org/dns_config per mai d’informacions.", - "diagnosis_dns_discrepancy": "Segon la configuracion DNS recomandada, la valor per l’enregistrament DNS de tipe {0} e nom {1} deuriá èsser {2} allòc de {3}.", + "diagnosis_dns_missing_record": "Segon la configuracion DNS recomandada, vos calriá ajustar un enregistrament DNS\ntipe: {type}\nnom: {name}\nvalor: {value}", + "diagnosis_dns_discrepancy": "Segon la configuracion DNS recomandada, la valor per l’enregistrament DNS\ntipe: {type}\nnom: {name}\ndeuriá èsser: {current}\nallòc de: {value}", "diagnosis_regenconf_manually_modified_debian_details": "Es pas problematic, mas car téner d’agacher...", "diagnosis_ports_could_not_diagnose": "Impossible de diagnosticar se los pòrts son accessibles de l’exterior. Error : {error}", "diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior. Error : {error}", @@ -556,11 +556,11 @@ "apps_catalog_init_success": "Sistèma de catalòg d’aplicacion iniciat !", "diagnosis_services_running": "Lo servici {service} es lançat !", "diagnosis_services_conf_broken": "La configuracion es copada pel servici {service} !", - "diagnosis_ports_needed_by": "Es necessari qu’aqueste pòrt siá accessible pel servici {0}", + "diagnosis_ports_needed_by": "Es necessari qu’aqueste pòrt siá accessible pel servici {service}", "diagnosis_diskusage_low": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free_abs_GB} Go ({free_percent}%). Siatz prudent.", "migration_description_0014_remove_app_status_json": "Suprimir los fichièrs d’aplicacion status.json eretats", "dyndns_provider_unreachable": "Impossible d’atenher lo provesidor Dyndns : siá vòstre YunoHost es pas corrèctament connectat a Internet siá lo servidor dynette es copat.", - "diagnosis_services_bad_status_tip": "Podètz ensajar de reaviar lo servici, e se non fonciona pas, podètz agachar los jornals en utilizant « yunohost service log {0} » o via la seccion « Servicis » de pas la pagina web d’administracion.", + "diagnosis_services_bad_status_tip": "Podètz ensajar de reaviar lo servici, e se non fonciona pas, podètz agachar los jornals en utilizant « yunohost service log {service} » o via la seccion « Servicis » de pas la pagina web d’administracion.", "diagnosis_http_connection_error": "Error de connexion : connexion impossibla al domeni demandat, benlèu qu’es pas accessible.", "diagnosis_http_unknown_error": "Una error s’es producha en ensajar de se connectar a vòstre domeni, es benlèu pas accessible.", "group_user_already_in_group": "L’utilizaire {user} es ja dins lo grop « {group} »", From 3cff370c62f2150b0a306871b2258c42f01b29d1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 01:55:25 +0200 Subject: [PATCH 101/317] Add some bits of magic to simplify the way we yield test items --- data/hooks/diagnosis/00-basesystem.py | 37 +++++++++------------- data/hooks/diagnosis/10-ip.py | 26 +++++++-------- data/hooks/diagnosis/12-dnsrecords.py | 7 ++-- data/hooks/diagnosis/14-ports.py | 11 ++++--- data/hooks/diagnosis/21-web.py | 6 ++-- data/hooks/diagnosis/24-mail.py | 4 +-- data/hooks/diagnosis/30-services.py | 13 ++++---- data/hooks/diagnosis/50-systemresources.py | 34 +++++++++++--------- data/hooks/diagnosis/70-regenconf.py | 6 ++-- data/hooks/diagnosis/90-security.py | 6 ++-- src/yunohost/diagnosis.py | 21 ++++++++++++ 11 files changed, 94 insertions(+), 77 deletions(-) diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index 3c932b488..97f77cc1d 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -23,55 +23,48 @@ class BaseSystemDiagnoser(Diagnoser): hardware = dict(meta={"test": "hardware"}, status="INFO", data={"virt": virt, "arch": arch}, - summary=("diagnosis_basesystem_hardware", {"virt": virt, "arch": arch})) + summary="diagnosis_basesystem_hardware") if os.path.exists("/proc/device-tree/model"): model = read_file('/proc/device-tree/model').strip() - hardware["data"]["board"] = model - hardware["details"] = [("diagnosis_basesystem_hardware_board", {"model": model})] + hardware["data"]["model"] = model + hardware["details"] = ["diagnosis_basesystem_hardware_board"] yield hardware # Kernel version kernel_version = read_file('/proc/sys/kernel/osrelease').strip() yield dict(meta={"test": "kernel"}, + data={"kernel_version": kernel_version}, status="INFO", - summary=("diagnosis_basesystem_kernel", {"kernel_version": kernel_version})) + summary="diagnosis_basesystem_kernel") # Debian release debian_version = read_file("/etc/debian_version").strip() yield dict(meta={"test": "host"}, + data={"debian_version": debian_version}, status="INFO", - summary=("diagnosis_basesystem_host", {"debian_version": debian_version})) + summary="diagnosis_basesystem_host") # Yunohost packages versions - ynh_packages = ynh_packages_version() # We check if versions are consistent (e.g. all 3.6 and not 3 packages with 3.6 and the other with 3.5) # This is a classical issue for upgrades that failed in the middle # (or people upgrading half of the package because they did 'apt upgrade' instead of 'dist-upgrade') # Here, ynh_core_version is for example "3.5.4.12", so [:3] is "3.5" and we check it's the same for all packages + ynh_packages = ynh_packages_version() ynh_core_version = ynh_packages["yunohost"]["version"] consistent_versions = all(infos["version"][:3] == ynh_core_version[:3] for infos in ynh_packages.values()) ynh_version_details = [("diagnosis_basesystem_ynh_single_version", {"package":package, "version": infos["version"], "repo": infos["repo"]} - ) - for package, infos in ynh_packages.items()] + ) + for package, infos in ynh_packages.items()] - if consistent_versions: - yield dict(meta={"test": "ynh_versions"}, - data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, - status="INFO", - summary=("diagnosis_basesystem_ynh_main_version", - {"main_version": ynh_core_version, - "repo": ynh_packages["yunohost"]["repo"]}), - details=ynh_version_details) - else: - yield dict(meta={"test": "ynh_versions"}, - data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, - status="ERROR", - summary=("diagnosis_basesystem_ynh_inconsistent_versions", {}), - details=ynh_version_details) + yield dict(meta={"test": "ynh_versions"}, + data={"main_version": ynh_core_version, "repo": ynh_packages["yunohost"]["repo"]}, + status="INFO" if consistent_versions else "ERROR", + summary="diagnosis_basesystem_ynh_main_version" if consistent_versions else "diagnosis_basesystem_ynh_inconsistent_versions", + details=ynh_version_details) def main(args, env, loggers): diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 7e96a7b56..3f197a7bc 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -28,7 +28,7 @@ class IPDiagnoser(Diagnoser): if not can_ping_ipv4 and not can_ping_ipv6: yield dict(meta={"test": "ping"}, status="ERROR", - summary=("diagnosis_ip_not_connected_at_all", {})) + summary="diagnosis_ip_not_connected_at_all") # Not much else we can do if there's no internet at all return @@ -49,20 +49,19 @@ class IPDiagnoser(Diagnoser): if not can_resolve_dns: yield dict(meta={"test": "dnsresolv"}, status="ERROR", - summary=("diagnosis_ip_broken_dnsresolution", {}) if good_resolvconf - else ("diagnosis_ip_broken_resolvconf", {})) + summary="diagnosis_ip_broken_dnsresolution" if good_resolvconf else "diagnosis_ip_broken_resolvconf") return # Otherwise, if the resolv conf is bad but we were able to resolve domain name, # still warn that we're using a weird resolv conf ... elif not good_resolvconf: yield dict(meta={"test": "dnsresolv"}, status="WARNING", - summary=("diagnosis_ip_weird_resolvconf", {}), - details=[("diagnosis_ip_weird_resolvconf_details", {})]) + summary="diagnosis_ip_weird_resolvconf", + details=["diagnosis_ip_weird_resolvconf_details"]) else: yield dict(meta={"test": "dnsresolv"}, status="SUCCESS", - summary=("diagnosis_ip_dnsresolution_working", {})) + summary="diagnosis_ip_dnsresolution_working") # ##################################################### # # IP DIAGNOSIS : Check that we're actually able to talk # @@ -72,17 +71,16 @@ class IPDiagnoser(Diagnoser): ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None - yield dict(meta={"test": "ip", "version": '4'}, - data=ipv4, + yield dict(meta={"test": "ipv4"}, + data={"global": ipv4}, status="SUCCESS" if ipv4 else "ERROR", - summary=("diagnosis_ip_connected_ipv4", {}) if ipv4 - else ("diagnosis_ip_no_ipv4", {})) + summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4") - yield dict(meta={"test": "ip", "version": '6'}, - data=ipv6, + yield dict(meta={"test": "ipv6"}, + data={"global": ipv6}, status="SUCCESS" if ipv6 else "WARNING", - summary=("diagnosis_ip_connected_ipv6", {}) if ipv6 - else ("diagnosis_ip_no_ipv6", {})) + summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6") + # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 5d8a12ebb..d653b044c 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -62,19 +62,18 @@ class DNSRecordsDiagnoser(Diagnoser): discrepancies.append(("diagnosis_dns_discrepancy", r)) if discrepancies: - discrepancies = [("diagnosis_dns_point_to_doc", {})] + discrepancies status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING" - summary = ("diagnosis_dns_bad_conf", {"domain": domain, "category": category}) + summary = "diagnosis_dns_bad_conf" else: status = "SUCCESS" - summary = ("diagnosis_dns_good_conf", {"domain": domain, "category": category}) + summary = "diagnosis_dns_good_conf" output = dict(meta={"domain": domain, "category": category}, status=status, summary=summary) if discrepancies: - output["details"] = discrepancies + output["details"] = ["diagnosis_dns_point_to_doc"] + discrepancies yield output diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index fe7c9003d..f973a3275 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -47,15 +47,16 @@ class PortsDiagnoser(Diagnoser): category = services[service].get("category", "[?]") if r["ports"].get(str(port), None) is not True: yield dict(meta={"port": str(port)}, + data={"service": service, "category": category}, status="ERROR", - summary=("diagnosis_ports_unreachable", {"port": port}), - details=[("diagnosis_ports_needed_by", {"service": service, "category": category}), - ("diagnosis_ports_forwarding_tip", {})]) + summary="diagnosis_ports_unreachable", + details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) else: yield dict(meta={"port": str(port)}, + data={"service": service, "category": category}, status="SUCCESS", - summary=("diagnosis_ports_ok", {"port": port}), - details=[("diagnosis_ports_needed_by", {"service": service, "category": category})]) + summary="diagnosis_ports_ok", + details=["diagnosis_ports_needed_by"]) def main(args, env, loggers): diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 6b65b8da3..5008f0360 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -45,13 +45,13 @@ class WebDiagnoser(Diagnoser): if r["status"] == "ok": yield dict(meta={"domain": domain}, status="SUCCESS", - summary=("diagnosis_http_ok", {"domain": domain})) + summary="diagnosis_http_ok") else: detail = r["code"].replace("error_http_check", "diagnosis_http") if "code" in r else "diagnosis_http_unknown_error" yield dict(meta={"domain": domain}, status="ERROR", - summary=("diagnosis_http_unreachable", {"domain": domain}), - details=[(detail,{})]) + summary="diagnosis_http_unreachable", + details=[detail]) # In there or idk where else ... # try to diagnose hairpinning situation by crafting a request for the diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index f0060df52..0a3a97102 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -17,11 +17,11 @@ class MailDiagnoser(Diagnoser): if os.system('/bin/nc -z -w2 yunohost.org 25') == 0: yield dict(meta={"test": "ougoing_port_25"}, status="SUCCESS", - summary=("diagnosis_mail_ougoing_port_25_ok",{})) + summary="diagnosis_mail_ougoing_port_25_ok") else: yield dict(meta={"test": "outgoing_port_25"}, status="ERROR", - summary=("diagnosis_mail_ougoing_port_25_blocked",{})) + summary="diagnosis_mail_ougoing_port_25_blocked") diff --git a/data/hooks/diagnosis/30-services.py b/data/hooks/diagnosis/30-services.py index 9d6879933..6217d89d3 100644 --- a/data/hooks/diagnosis/30-services.py +++ b/data/hooks/diagnosis/30-services.py @@ -17,21 +17,22 @@ class ServicesDiagnoser(Diagnoser): for service, result in sorted(all_result.items()): - item = dict(meta={"service": service}) + item = dict(meta={"service": service}, + data={"status": result["status"], "configuration": result["configuration"]}) if result["status"] != "running": item["status"] = "ERROR" - item["summary"] = ("diagnosis_services_bad_status", {"service": service, "status": result["status"]}) - item["details"] = [("diagnosis_services_bad_status_tip", {"service":service})] + item["summary"] = "diagnosis_services_bad_status" + item["details"] = ["diagnosis_services_bad_status_tip"] elif result["configuration"] == "broken": item["status"] = "WARNING" - item["summary"] = ("diagnosis_services_conf_broken", {"service": service}) - item["details"] = [(d, {}) for d in result["configuration-details"]] + item["summary"] = "diagnosis_services_conf_broken" + item["details"] = result["configuration-details"] else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_services_running", {"service": service, "status": result["status"]}) + item["summary"] = "diagnosis_services_running" yield item diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index 95f58ddb7..1f0c07f47 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -20,17 +20,19 @@ class SystemResourcesDiagnoser(Diagnoser): ram_total_abs_MB = ram.total / (1024**2) ram_available_abs_MB = ram.available / (1024**2) ram_available_percent = round(100 * ram.available / ram.total) - item = dict(meta={"test": "ram"}) - infos = {"total_abs_MB": ram_total_abs_MB, "available_abs_MB": ram_available_abs_MB, "available_percent": ram_available_percent} + item = dict(meta={"test": "ram"}, + data={"total_abs_MB": ram_total_abs_MB, + "available_abs_MB": ram_available_abs_MB, + "available_percent": ram_available_percent}) if ram_available_abs_MB < 100 or ram_available_percent < 5: item["status"] = "ERROR" - item["summary"] = ("diagnosis_ram_verylow", infos) + item["summary"] = "diagnosis_ram_verylow" elif ram_available_abs_MB < 200 or ram_available_percent < 10: item["status"] = "WARNING" - item["summary"] = ("diagnosis_ram_low", infos) + item["summary"] = "diagnosis_ram_low" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_ram_ok", infos) + item["summary"] = "diagnosis_ram_ok" yield item # @@ -39,19 +41,21 @@ class SystemResourcesDiagnoser(Diagnoser): swap = psutil.swap_memory() swap_total_abs_MB = swap.total / (1024*1024) - item = dict(meta={"test": "swap"}) - infos = {"total_MB": swap_total_abs_MB} + item = dict(meta={"test": "swap"}, + data={"total_MB": swap_total_abs_MB}) if swap_total_abs_MB <= 0: item["status"] = "ERROR" - item["summary"] = ("diagnosis_swap_none", infos) + item["summary"] = "diagnosis_swap_none" elif swap_total_abs_MB <= 256: item["status"] = "WARNING" - item["summary"] = ("diagnosis_swap_notsomuch", infos) + item["summary"] = "diagnosis_swap_notsomuch" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_swap_ok", infos) + item["summary"] = "diagnosis_swap_ok" yield item + # FIXME : add a check that swapiness is low if swap is on a sdcard... + # # Disks usage # @@ -66,17 +70,17 @@ class SystemResourcesDiagnoser(Diagnoser): free_abs_GB = usage.free / (1024 ** 3) free_percent = 100 - usage.percent - item = dict(meta={"test": "diskusage", "mountpoint": mountpoint}) - infos = {"mountpoint": mountpoint, "device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent} + item = dict(meta={"test": "diskusage", "mountpoint": mountpoint}, + data={"device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent}) if free_abs_GB < 1 or free_percent < 5: item["status"] = "ERROR" - item["summary"] = ("diagnosis_diskusage_verylow", infos) + item["summary"] = "diagnosis_diskusage_verylow" elif free_abs_GB < 2 or free_percent < 10: item["status"] = "WARNING" - item["summary"] = ("diagnosis_diskusage_low", infos) + item["summary"] = "diagnosis_diskusage_low" else: item["status"] = "SUCCESS" - item["summary"] = ("diagnosis_diskusage_ok", infos) + item["summary"] = "diagnosis_diskusage_ok" yield item diff --git a/data/hooks/diagnosis/70-regenconf.py b/data/hooks/diagnosis/70-regenconf.py index a3e284f90..75db146ab 100644 --- a/data/hooks/diagnosis/70-regenconf.py +++ b/data/hooks/diagnosis/70-regenconf.py @@ -22,14 +22,14 @@ class RegenconfDiagnoser(Diagnoser): if regenconf_modified_files == []: yield dict(meta={"test": "regenconf"}, status="SUCCESS", - summary=("diagnosis_regenconf_allgood", {}) + summary="diagnosis_regenconf_allgood" ) else: for f in regenconf_modified_files: yield dict(meta={"test": "regenconf", "file": f}, status="WARNING", - summary=("diagnosis_regenconf_manually_modified", {"file": f}), - details=[("diagnosis_regenconf_manually_modified_details", {})] + summary="diagnosis_regenconf_manually_modified", + details=["diagnosis_regenconf_manually_modified_details"] ) #for f in debian_modified_files: diff --git a/data/hooks/diagnosis/90-security.py b/data/hooks/diagnosis/90-security.py index 1eedcc8ca..d281042b0 100644 --- a/data/hooks/diagnosis/90-security.py +++ b/data/hooks/diagnosis/90-security.py @@ -21,13 +21,13 @@ class SecurityDiagnoser(Diagnoser): if self.is_vulnerable_to_meltdown(): yield dict(meta={"test": "meltdown"}, status="ERROR", - summary=("diagnosis_security_vulnerable_to_meltdown", {}), - details=[("diagnosis_security_vulnerable_to_meltdown_details", {})] + summary="diagnosis_security_vulnerable_to_meltdown", + details=["diagnosis_security_vulnerable_to_meltdown_details"] ) else: yield dict(meta={}, status="SUCCESS", - summary=("diagnosis_security_all_good", {}) + summary="diagnosis_security_all_good" ) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 7f93f7c0d..effd610cc 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -453,11 +453,32 @@ class Diagnoser(): report["description"] = Diagnoser.get_description(report["id"]) + def is_tuple_or_list(stuff): + return isinstance(stuff, tuple) or isinstance(stuff, list) + for item in report["items"]: + + # For the summary and each details, we want to call + # m18n() on the string, with the appropriate data for string + # formatting which can come from : + # - infos super-specific to the summary/details (if it's a tuple(key,dict_with_info) and not just a string) + # - 'meta' info = parameters of the test (e.g. which domain/category for DNS conf record) + # - actual 'data' retrieved from the test (e.g. actual global IP, ...) + + meta_data = item.get("meta", {}).copy() + meta_data.update(item.get("data", {})) + + if not is_tuple_or_list(item["summary"]): + item["summary"] = (item["summary"], {}) summary_key, summary_args = item["summary"] + summary_args.update(meta_data) + item["summary"] = m18n.n(summary_key, **summary_args) if "details" in item: + item["details"] = [(d[0], d[1]) if is_tuple_or_list(d) else (d, {}) for d in item["details"]] + for d in item["details"]: + d[1].update(meta_data) item["details"] = [m18n.n(key, **values) for key, values in item["details"]] From 7c3cce6bf97937aeb09282c229fcf3e10d63d120 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 02:26:47 +0200 Subject: [PATCH 102/317] Try to diagnose and add details about global and local IPs --- data/hooks/diagnosis/10-ip.py | 24 ++++++++++++++++++------ locales/en.json | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 3f197a7bc..70a5c9594 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -8,7 +8,7 @@ from moulinette.utils.process import check_output from moulinette.utils.filesystem import read_file from yunohost.diagnosis import Diagnoser - +from yunohost.utils.network import get_network_interfaces class IPDiagnoser(Diagnoser): @@ -71,16 +71,28 @@ class IPDiagnoser(Diagnoser): ipv4 = self.get_public_ip(4) if can_ping_ipv4 else None ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None + network_interfaces = get_network_interfaces() + def get_local_ip(version): + local_ip = {iface:addr[version].split("/")[0] + for iface, addr in network_interfaces.items() if version in addr} + if not local_ip: + return None + elif len(local_ip): + return next(iter(local_ip.values())) + else: + return local_ip + yield dict(meta={"test": "ipv4"}, - data={"global": ipv4}, + data={"global": ipv4, "local": get_local_ip("ipv4")}, status="SUCCESS" if ipv4 else "ERROR", - summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4") + summary="diagnosis_ip_connected_ipv4" if ipv4 else "diagnosis_ip_no_ipv4", + details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv4 else None) yield dict(meta={"test": "ipv6"}, - data={"global": ipv6}, + data={"global": ipv6, "local": get_local_ip("ipv6")}, status="SUCCESS" if ipv6 else "WARNING", - summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6") - + summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", + details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 else None) # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? diff --git a/locales/en.json b/locales/en.json index cec219ee6..c02c6890e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -159,6 +159,8 @@ "diagnosis_ip_no_ipv4": "The server does not have working IPv4.", "diagnosis_ip_connected_ipv6": "The server is connected to the Internet through IPv6 !", "diagnosis_ip_no_ipv6": "The server does not have working IPv6.", + "diagnosis_ip_global": "Global IP: {global}", + "diagnosis_ip_local": "Local IP: {local}", "diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?", "diagnosis_ip_dnsresolution_working": "Domain name resolution is working!", "diagnosis_ip_broken_dnsresolution": "Domain name resolution seems to be broken for some reason... Is a firewall blocking DNS requests ?", From 9ebb3102cdc0a1d4d2f259f7495663a7025acfbf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 02:27:09 +0200 Subject: [PATCH 103/317] Remove details key if it's empty --- src/yunohost/diagnosis.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index effd610cc..31518c257 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -384,6 +384,10 @@ class Diagnoser(): items = list(self.run()) + for item in items: + if "details" in item and not item["details"]: + del item["details"] + new_report = {"id": self.id_, "cached_for": self.cache_duration, "items": items} From 8cb2640872a49d780d01029758e601caaaa03338 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 10 Apr 2020 20:43:11 +0200 Subject: [PATCH 104/317] Fix usage of systemd-detect-virt on baremetal --- data/hooks/diagnosis/00-basesystem.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index 97f77cc1d..68a9570ce 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -17,13 +17,20 @@ class BaseSystemDiagnoser(Diagnoser): def run(self): # Detect virt technology (if not bare metal) and arch - # Also possibly the board name - virt = check_output("systemd-detect-virt").strip() or "bare-metal" + # Gotta have this "|| true" because it systemd-detect-virt return 'none' + # with an error code on bare metal ~.~ + virt = check_output("systemd-detect-virt || true", shell=True).strip() + if virt.lower() == "none": + virt = "bare-metal" + + # Detect arch arch = check_output("dpkg --print-architecture").strip() hardware = dict(meta={"test": "hardware"}, status="INFO", data={"virt": virt, "arch": arch}, summary="diagnosis_basesystem_hardware") + + # Also possibly the board name if os.path.exists("/proc/device-tree/model"): model = read_file('/proc/device-tree/model').strip() hardware["data"]["model"] = model From f9dd634ebeace1983d3dce9ce9a9048269369391 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 00:18:45 +0200 Subject: [PATCH 105/317] Detect if nginx conf does not include well-known diagnosis location --- data/hooks/diagnosis/21-web.py | 9 +++++++++ locales/en.json | 2 ++ 2 files changed, 11 insertions(+) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 5008f0360..add192685 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -22,6 +22,15 @@ class WebDiagnoser(Diagnoser): all_domains = domain_list()["domains"] for domain in all_domains: + # If the diagnosis location ain't defined, can't do diagnosis, + # probably because nginx conf manually modified... + nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain + if os.system("grep -q '^.*location .*/.well-known/ynh-diagnosis/' %s" % nginx_conf) != 0: + yield dict(meta={"domain": domain}, + status="WARNING", + summary="diagnosis_http_nginx_conf_not_up_to_date", + details=["diagnosis_http_nginx_conf_not_up_to_date_details"]) + nonce = ''.join(random.choice(nonce_digits) for i in range(16)) os.system("rm -rf /tmp/.well-known/ynh-diagnosis/") os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/") diff --git a/locales/en.json b/locales/en.json index c02c6890e..5032bb4f3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -217,6 +217,8 @@ "diagnosis_http_unknown_error": "An error happened while trying to reach your domain, it's very likely unreachable.", "diagnosis_http_bad_status_code": "The diagnosis system could not reach your server. It might be that another machine answered instead of your server. You should check that you're correctly forwarding port 80, that your nginx configuration is up to date, and that a reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", + "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", + "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the different with the command line using 'yunohost tools regen-conf nginx --dry-run --with-diff' and if you're ok, apply the changes with 'yunohost tools regen-conf nginx --force'.", "diagnosis_unknown_categories": "The following categories are unknown: {categories}", "diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.", "domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n '; here is the list of candidate domains: {other_domains:s}", From 3869c2f68e02f1fe170484213a46c312575764b9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 02:28:40 +0200 Subject: [PATCH 106/317] Add html tags to improve readability of some results (in particular DNS records stuff) on webadmin --- locales/en.json | 20 +++++++++++--------- src/yunohost/diagnosis.py | 25 +++++++++++++------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/locales/en.json b/locales/en.json index 5032bb4f3..d3261a2cf 100644 --- a/locales/en.json +++ b/locales/en.json @@ -159,19 +159,19 @@ "diagnosis_ip_no_ipv4": "The server does not have working IPv4.", "diagnosis_ip_connected_ipv6": "The server is connected to the Internet through IPv6 !", "diagnosis_ip_no_ipv6": "The server does not have working IPv6.", - "diagnosis_ip_global": "Global IP: {global}", - "diagnosis_ip_local": "Local IP: {local}", + "diagnosis_ip_global": "Global IP: {global}", + "diagnosis_ip_local": "Local IP: {local}", "diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?", "diagnosis_ip_dnsresolution_working": "Domain name resolution is working!", "diagnosis_ip_broken_dnsresolution": "Domain name resolution seems to be broken for some reason... Is a firewall blocking DNS requests ?", - "diagnosis_ip_broken_resolvconf": "Domain name resolution seems to be broken on your server, which seems related to /etc/resolv.conf not pointing to 127.0.0.1.", - "diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but be careful that you seem to be using a custom /etc/resolv.conf.", - "diagnosis_ip_weird_resolvconf_details": "Instead, this file should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). The actual resolvers should be configured in /etc/resolv.dnsmasq.conf.", + "diagnosis_ip_broken_resolvconf": "Domain name resolution seems to be broken on your server, which seems related to /etc/resolv.conf not pointing to 127.0.0.1.", + "diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but it looks like you're using a custom /etc/resolv.conf.", + "diagnosis_ip_weird_resolvconf_details": "The file /etc/resolv.conf should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). If you want to manually configure DNS resolvers, please edit /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Good DNS configuration for domain {domain} (category {category})", "diagnosis_dns_bad_conf": "Bad or missing DNS configuration for domain {domain} (category {category})", - "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.\nType: {type}\nName: {name}\nValue: {value}", - "diagnosis_dns_discrepancy": "The DNS record with type {type} and name {name} does not match the recommended configuration.\nCurrent value: {current}\nExcepted value: {value}", - "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records", + "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.
Type: {type}
Name: {name}
Value: {value}", + "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", + "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", @@ -209,7 +209,9 @@ "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", "diagnosis_ports_needed_by": "Exposing this port is needed for {category} features (service {service})", - "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", + "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", + "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", + "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable. You should check that you're correctly forwarding port 80, that nginx is running, and that a firewall is not interfering.", diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 31518c257..369554bd4 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -24,6 +24,7 @@ Look for possible issues on the server """ +import re import os import time @@ -457,9 +458,6 @@ class Diagnoser(): report["description"] = Diagnoser.get_description(report["id"]) - def is_tuple_or_list(stuff): - return isinstance(stuff, tuple) or isinstance(stuff, list) - for item in report["items"]: # For the summary and each details, we want to call @@ -472,18 +470,21 @@ class Diagnoser(): meta_data = item.get("meta", {}).copy() meta_data.update(item.get("data", {})) - if not is_tuple_or_list(item["summary"]): - item["summary"] = (item["summary"], {}) - summary_key, summary_args = item["summary"] - summary_args.update(meta_data) + html_tags = re.compile(r'<[^>]+>') + def m18n_(info): + if not isinstance(info, tuple) and not isinstance(info, list): + info = (info, {}) + info[1].update(meta_data) + s = m18n.n(info[0], **(info[1])) + # In cli, we remove the html tags + if msettings.get("interface") != "api": + s = html_tags.sub('', s.replace("
","\n")) + return s - item["summary"] = m18n.n(summary_key, **summary_args) + item["summary"] = m18n_(item["summary"]) if "details" in item: - item["details"] = [(d[0], d[1]) if is_tuple_or_list(d) else (d, {}) for d in item["details"]] - for d in item["details"]: - d[1].update(meta_data) - item["details"] = [m18n.n(key, **values) for key, values in item["details"]] + item["details"] = [m18n_(info) for info in item["details"]] def _list_diagnosis_categories(): From 2f0a95645ae58f273e55667cb266d16e4d329f11 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 03:25:03 +0200 Subject: [PATCH 107/317] Hmpf boring resolvconf shit --- data/hooks/conf_regen/43-dnsmasq | 15 +++++++++++++++ data/hooks/diagnosis/10-ip.py | 15 +++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/data/hooks/conf_regen/43-dnsmasq b/data/hooks/conf_regen/43-dnsmasq index 90e96a04c..d6ab8648c 100755 --- a/data/hooks/conf_regen/43-dnsmasq +++ b/data/hooks/conf_regen/43-dnsmasq @@ -50,6 +50,21 @@ do_pre_regen() { do_post_regen() { regen_conf_files=$1 + # Fuck it, those domain/search entries from dhclient are usually annoying + # lying shit from the ISP trying to MiTM + if grep -q -E "^ *(domain|search)" /run/resolvconf/resolv.conf + then + if grep -q -E "^ *(domain|search)" /run/resolvconf/interface/*.dhclient 2>/dev/null + then + sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient + fi + + grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede domain-name "";' >> /etc/dhcp/dhclient.conf + grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede domain-search "";' >> /etc/dhcp/dhclient.conf + grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede name "";' >> /etc/dhcp/dhclient.conf + systemctl restart resolvconf + fi + [[ -z "$regen_conf_files" ]] \ || service dnsmasq restart } diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 70a5c9594..7d0aa8da2 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -41,7 +41,7 @@ class IPDiagnoser(Diagnoser): # In every case, we can check that resolvconf seems to be okay # (symlink managed by resolvconf service + pointing to dnsmasq) - good_resolvconf = self.resolvconf_is_symlink() and self.resolvconf_points_to_localhost() + good_resolvconf = self.good_resolvconf() # If we can't resolve domain names at all, that's a pretty big issue ... # If it turns out that at the same time, resolvconf is bad, that's probably @@ -131,13 +131,12 @@ class IPDiagnoser(Diagnoser): def can_resolve_dns(self): return os.system("dig +short ip.yunohost.org >/dev/null 2>/dev/null") == 0 - def resolvconf_is_symlink(self): - return os.path.realpath("/etc/resolv.conf") == "/run/resolvconf/resolv.conf" - - def resolvconf_points_to_localhost(self): - file_ = "/etc/resolv.conf" - resolvers = [r.split(" ")[1] for r in read_file(file_).split("\n") if r.startswith("nameserver")] - return resolvers == ["127.0.0.1"] + def good_resolvconf(self): + content = read_file(file_).strip().split("\n") + # Ignore comments and empty lines + content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#")] + # We should only find a "nameserver 127.0.0.1" + return len(content) == 1 and content.split() == ["nameserver", "127.0.0.1"] def get_public_ip(self, protocol=4): From 42293fcce38792e10623777542011dd10224cde0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 9 Apr 2020 13:53:31 +0200 Subject: [PATCH 108/317] Attempt to detect hairpinning --- data/hooks/diagnosis/21-web.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index add192685..56b054e53 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -19,6 +19,7 @@ class WebDiagnoser(Diagnoser): nonce_digits = "0123456789abcedf" + at_least_one_domain_ok = False all_domains = domain_list()["domains"] for domain in all_domains: @@ -52,6 +53,7 @@ class WebDiagnoser(Diagnoser): raise YunohostError("diagnosis_http_could_not_diagnose", error=e) if r["status"] == "ok": + at_least_one_domain_ok = True yield dict(meta={"domain": domain}, status="SUCCESS", summary="diagnosis_http_ok") @@ -62,9 +64,28 @@ class WebDiagnoser(Diagnoser): summary="diagnosis_http_unreachable", details=[detail]) - # In there or idk where else ... - # try to diagnose hairpinning situation by crafting a request for the - # global ip (from within local network) and seeing if we're getting the right page ? + # If at least one domain is correctly exposed to the outside, + # attempt to diagnose hairpinning situations. On network with + # hairpinning issues, the server may be correctly exposed on the + # outside, but from the outside, it will be as if the port forwarding + # was not configured... Hence, calling for example + # "curl --head the.global.ip" will simply timeout... + if at_least_one_domain_ok: + ipv4 = Diagnoser.get_cached_report_item("ip", {"test": "ipv4"}) + global_ipv4 = ipv4.get("data", {}).get("global", {}) + if global_ipv4: + try: + requests.head("http://" + ipv4, timeout=5) + except requests.exceptions.Timeout as e: + yield dict(meta={"test": "hairpinning"}, + status="WARNING", + summary="diagnosis_http_hairpinning_issue", + details=["diagnosis_http_hairpinning_issue_details"]) + except: + # Well I dunno what to do if that's another exception + # type... That'll most probably *not* be an hairpinning + # issue but something else super weird ... + pass def main(args, env, loggers): From ad4c13887862fbaec774619f34d41cf6de5ef4d0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 17:20:24 +0200 Subject: [PATCH 109/317] Better debugging info when miserably failing to run diagnosis --- src/yunohost/diagnosis.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 369554bd4..d8c6b5f57 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -167,7 +167,8 @@ def diagnosis_run(categories=[], force=False): try: code, report = hook_exec(path, args={"force": force}, env=None) except Exception as e: - logger.error(m18n.n("diagnosis_failed_for_category", category=category, error=str(e)), exc_info=True) + import traceback + logger.error(m18n.n("diagnosis_failed_for_category", category=category, error='\n'+traceback.format_exc())) else: diagnosed_categories.append(category) if report != {}: @@ -424,7 +425,7 @@ class Diagnoser(): cache_file = Diagnoser.cache_file(id_) if not os.path.exists(cache_file): logger.warning(m18n.n("diagnosis_no_cache", category=id_)) - report = {"id": category, + report = {"id": id_, "cached_for": -1, "timestamp": -1, "items": []} From f47352df8896ec39a26338048eb552491cd32528 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 18:10:21 +0200 Subject: [PATCH 110/317] Improve message about server unreachable on http --- locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index d3261a2cf..be479efca 100644 --- a/locales/en.json +++ b/locales/en.json @@ -214,10 +214,10 @@ "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", - "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable. You should check that you're correctly forwarding port 80, that nginx is running, and that a firewall is not interfering.", + "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", "diagnosis_http_unknown_error": "An error happened while trying to reach your domain, it's very likely unreachable.", - "diagnosis_http_bad_status_code": "The diagnosis system could not reach your server. It might be that another machine answered instead of your server. You should check that you're correctly forwarding port 80, that your nginx configuration is up to date, and that a reverse-proxy is not interfering.", + "diagnosis_http_bad_status_code": "Timed-out while trying to contact your server from outside. It might be that another machine answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the different with the command line using 'yunohost tools regen-conf nginx --dry-run --with-diff' and if you're ok, apply the changes with 'yunohost tools regen-conf nginx --force'.", From b443caf63a0877d63fca26f34010e47cd4a58452 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 18:10:46 +0200 Subject: [PATCH 111/317] Open links in new tab in the webadmin --- src/yunohost/diagnosis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index d8c6b5f57..9a8962ac4 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -480,6 +480,9 @@ class Diagnoser(): # In cli, we remove the html tags if msettings.get("interface") != "api": s = html_tags.sub('', s.replace("
","\n")) + else: + # Make it so that links open in new tabs + s = s.replace(" Date: Sat, 11 Apr 2020 19:21:29 +0200 Subject: [PATCH 112/317] Uhoh typo --- data/hooks/diagnosis/10-ip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 7d0aa8da2..42b52eb07 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -132,7 +132,7 @@ class IPDiagnoser(Diagnoser): return os.system("dig +short ip.yunohost.org >/dev/null 2>/dev/null") == 0 def good_resolvconf(self): - content = read_file(file_).strip().split("\n") + content = read_file("/etc/resolv.conf").strip().split("\n") # Ignore comments and empty lines content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#")] # We should only find a "nameserver 127.0.0.1" From ae82fe3693cb51d0c19b0817a7093ed8980e5129 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 19:52:57 +0200 Subject: [PATCH 113/317] Improve the way we check DNS records to avoid false negative on TXT or MX --- data/hooks/diagnosis/12-dnsrecords.py | 45 +++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index d653b044c..f5d779118 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -52,14 +52,15 @@ class DNSRecordsDiagnoser(Diagnoser): discrepancies = [] for r in records: - r["current"] = self.get_current_record(domain, r["name"], r["type"]) or "None" + r["current"] = self.get_current_record(domain, r["name"], r["type"]) if r["value"] == "@": r["value"] = domain + "." - if r["current"] == "None": - discrepancies.append(("diagnosis_dns_missing_record", r)) - elif r["current"] != r["value"]: - discrepancies.append(("diagnosis_dns_discrepancy", r)) + if not self.current_record_match_expected(r): + if r["current"] is None: + discrepancies.append(("diagnosis_dns_missing_record", r)) + else: + discrepancies.append(("diagnosis_dns_discrepancy", r)) if discrepancies: status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING" @@ -85,10 +86,36 @@ class DNSRecordsDiagnoser(Diagnoser): # FIXME : gotta handle case where this command fails ... # e.g. no internet connectivity (dependency mechanism to good result from 'ip' diagosis ?) # or the resolver is unavailable for some reason - output = check_output(command).strip() - if output.startswith('"') and output.endswith('"'): - output = '"' + ' '.join(output.replace('"', ' ').split()) + '"' - return output + output = check_output(command).strip().split("\n") + if len(output) == 0 or not output[0]: + return None + elif len(output) == 1: + return output[0] + else: + return output + + def current_record_match_expected(self, r): + if r["value"] is not None and r["current"] is None: + return False + if r["value"] is None and r["current"] is not None: + return False + elif isinstance(r["current"], list): + return False + + if r["type"] == "TXT": + # Split expected/current + # from "v=DKIM1; k=rsa; p=hugekey;" + # to a set like {'v=DKIM1', 'k=rsa', 'p=...'} + expected = set(r["value"].strip(' "').strip(";").replace(" ", "").split()) + current = set(r["current"].strip(' "').strip(";").replace(" ", "").split()) + return expected == current + elif r["type"] == "MX": + # For MX, we want to ignore the priority + expected = r["value"].split()[-1] + current = r["current"].split()[-1] + return expected == current + else: + return r["current"] == r["value"] def main(args, env, loggers): From 093ccd8020f509845a81df31c43f9843914defd7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 20:02:47 +0200 Subject: [PATCH 114/317] Make sure that there's no AAAA records when no ipv6 --- data/hooks/diagnosis/12-dnsrecords.py | 2 +- src/yunohost/domain.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index f5d779118..7ea92e3f7 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -38,7 +38,7 @@ class DNSRecordsDiagnoser(Diagnoser): def check_domain(self, domain, is_main_domain, is_subdomain): - expected_configuration = _build_dns_conf(domain) + expected_configuration = _build_dns_conf(domain, include_empty_AAAA_if_no_ipv6=True) # FIXME: Here if there are no AAAA record, we should add something to expect "no" AAAA record # to properly diagnose situations where people have a AAAA record but no IPv6 diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 23b5a4179..7910147a3 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -395,7 +395,7 @@ def _normalize_domain_path(domain, path): return domain, path -def _build_dns_conf(domain, ttl=3600): +def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): """ Internal function that will returns a data structure containing the needed information to generate/adapt the dns configuration @@ -448,6 +448,8 @@ def _build_dns_conf(domain, ttl=3600): if ipv6: basic.append(["@", ttl, "AAAA", ipv6]) + elif include_empty_AAAA_if_no_ipv6: + basic.append(["@", ttl, "AAAA", None]) ######### # Email # @@ -495,8 +497,11 @@ def _build_dns_conf(domain, ttl=3600): if ipv4: extra.append(["*", ttl, "A", ipv4]) + if ipv6: extra.append(["*", ttl, "AAAA", ipv6]) + elif include_empty_AAAA_if_no_ipv6: + extra.append(["*", ttl, "AAAA", None]) extra.append(["@", ttl, "CAA", '128 issue "letsencrypt.org"']) From 16b234044137bbf24a757482a8e8f0e2820beed0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 20:04:03 +0200 Subject: [PATCH 115/317] Uhoh typo again --- data/hooks/diagnosis/21-web.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 56b054e53..2d0344abe 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -75,7 +75,7 @@ class WebDiagnoser(Diagnoser): global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: try: - requests.head("http://" + ipv4, timeout=5) + requests.head("http://" + global_ipv4, timeout=5) except requests.exceptions.Timeout as e: yield dict(meta={"test": "hairpinning"}, status="WARNING", From bfe3f415cacbea9fff7746c456128911d4d6a98a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 11 Apr 2020 20:06:14 +0200 Subject: [PATCH 116/317] Report bad XMPP DNS records as warning for now --- data/hooks/diagnosis/12-dnsrecords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 7ea92e3f7..3132cf45f 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -63,7 +63,7 @@ class DNSRecordsDiagnoser(Diagnoser): discrepancies.append(("diagnosis_dns_discrepancy", r)) if discrepancies: - status = "ERROR" if (category == "basic" or (is_main_domain and category != "extra")) else "WARNING" + status = "ERROR" if (category == "basic" or (is_main_domain and category == "mail")) else "WARNING" summary = "diagnosis_dns_bad_conf" else: status = "SUCCESS" From 92d9d49a05aa2d68cf78d4e7d4bfd8f4a55087d3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 13 Apr 2020 18:50:37 +0200 Subject: [PATCH 117/317] Fix resolvconf check --- data/hooks/diagnosis/10-ip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 42b52eb07..36e04b5c1 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -136,7 +136,7 @@ class IPDiagnoser(Diagnoser): # Ignore comments and empty lines content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#")] # We should only find a "nameserver 127.0.0.1" - return len(content) == 1 and content.split() == ["nameserver", "127.0.0.1"] + return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"] def get_public_ip(self, protocol=4): From efb45d4ece1c870736882eebf09470198e0fa4af Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 14 Apr 2020 16:01:59 +0200 Subject: [PATCH 118/317] Add special behavior for tags for diagnosis messages... --- src/yunohost/diagnosis.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index 9a8962ac4..c11cde566 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -479,8 +479,10 @@ class Diagnoser(): s = m18n.n(info[0], **(info[1])) # In cli, we remove the html tags if msettings.get("interface") != "api": + s = s.replace("", "'").replace("", "'") s = html_tags.sub('', s.replace("
","\n")) else: + s = s.replace("", "").replace("", "") # Make it so that links open in new tabs s = s.replace("
yunohost service log {service} or through the 'Services' section of the webadmin.", "diagnosis_diskusage_verylow": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. You should really consider cleaning up some space.", "diagnosis_diskusage_low": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. Be careful.", "diagnosis_diskusage_ok": "Storage {mountpoint} (on device {device}) still has {free_abs_GB} GB ({free_percent}%) space left!", @@ -188,10 +188,8 @@ "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", - "diagnosis_regenconf_manually_modified": "Configuration file {file} was manually modified.", - "diagnosis_regenconf_manually_modified_details": "This is probably OK as long as you know what you're doing ;) !", - "diagnosis_regenconf_manually_modified_debian": "Configuration file {file} was manually modified compared to Debian's default.", - "diagnosis_regenconf_manually_modified_debian_details": "This may probably be OK, but gotta keep an eye on it...", + "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", + "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! Though YunoHost will stop updating this file automatically, beware that YunoHost upgrades may contain important recommended changes. You can inspect the difference with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", "diagnosis_security_all_good": "No critical security vulnerability was found.", "diagnosis_security_vulnerable_to_meltdown": "You appear vulnerable to the Meltdown criticial security vulnerability", "diagnosis_security_vulnerable_to_meltdown_details": "To fix this, you should upgrade your system and reboot to load the new linux kernel (or contact your server provider if this doesn't work). See https://meltdownattack.com/ for more infos.", @@ -220,7 +218,7 @@ "diagnosis_http_bad_status_code": "Timed-out while trying to contact your server from outside. It might be that another machine answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", - "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the different with the command line using 'yunohost tools regen-conf nginx --dry-run --with-diff' and if you're ok, apply the changes with 'yunohost tools regen-conf nginx --force'.", + "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using yunohost tools regen-conf nginx --dry-run --with-diff and if you're ok, apply the changes with yunohost tools regen-conf nginx --force.", "diagnosis_unknown_categories": "The following categories are unknown: {categories}", "diagnosis_never_ran_yet": "It looks like this server was setup recently and there's no diagnosis report to show yet. You should start by running a full diagnosis, either from the webadmin or using 'yunohost diagnosis run' from the command line.", "domain_cannot_remove_main": "You cannot remove '{domain:s}' since it's the main domain, you first need to set another domain as the main domain using 'yunohost domain main-domain -n '; here is the list of candidate domains: {other_domains:s}", From a03ee5b912dd6aaf3e6c514ee266e01cee8d3402 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 14 Apr 2020 18:47:58 +0200 Subject: [PATCH 120/317] Be able to restart services from the webadmin --- data/actionsmap/yunohost.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 48b1687d4..ded56a7c1 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1041,6 +1041,7 @@ service: ### service_restart() restart: action_help: Restart one or more services. If the services are not running yet, they will be started. + api: PUT /services//restart arguments: names: help: Service name to restart From 4787f0ce042f8eaace1440c95e1d3cf9dabe73dc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 14 Apr 2020 23:48:59 +0200 Subject: [PATCH 121/317] Rework diagnosis of system resources --- data/hooks/diagnosis/50-systemresources.py | 78 +++++++++++++++------- locales/en.json | 20 +++--- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index 1f0c07f47..491c5b665 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -12,22 +12,24 @@ class SystemResourcesDiagnoser(Diagnoser): def run(self): + MB = 1024**2 + GB = 1024**2 + # # RAM # ram = psutil.virtual_memory() - ram_total_abs_MB = ram.total / (1024**2) - ram_available_abs_MB = ram.available / (1024**2) - ram_available_percent = round(100 * ram.available / ram.total) + ram_available_percent = 100 * ram.available / ram.total item = dict(meta={"test": "ram"}, - data={"total_abs_MB": ram_total_abs_MB, - "available_abs_MB": ram_available_abs_MB, - "available_percent": ram_available_percent}) - if ram_available_abs_MB < 100 or ram_available_percent < 5: + data={"total": human_size(ram.total), + "available": human_size(ram.available), + "available_percent": round_(ram_available_percent)}) + + if ram.available < 100 * MB or ram_available_percent < 5: item["status"] = "ERROR" item["summary"] = "diagnosis_ram_verylow" - elif ram_available_abs_MB < 200 or ram_available_percent < 10: + elif ram.available < 200 * MB or ram_available_percent < 10: item["status"] = "WARNING" item["summary"] = "diagnosis_ram_low" else: @@ -40,13 +42,12 @@ class SystemResourcesDiagnoser(Diagnoser): # swap = psutil.swap_memory() - swap_total_abs_MB = swap.total / (1024*1024) item = dict(meta={"test": "swap"}, - data={"total_MB": swap_total_abs_MB}) - if swap_total_abs_MB <= 0: + data={"total": human_size(swap.total)}) + if swap.total <= 1 * MB: item["status"] = "ERROR" item["summary"] = "diagnosis_swap_none" - elif swap_total_abs_MB <= 256: + elif swap.total <= 256 * MB: item["status"] = "WARNING" item["summary"] = "diagnosis_swap_notsomuch" else: @@ -67,23 +68,54 @@ class SystemResourcesDiagnoser(Diagnoser): mountpoint = disk_partition.mountpoint usage = psutil.disk_usage(mountpoint) - free_abs_GB = usage.free / (1024 ** 3) - free_percent = 100 - usage.percent + free_percent = round_(100 - usage.percent) item = dict(meta={"test": "diskusage", "mountpoint": mountpoint}, - data={"device": device, "free_abs_GB": free_abs_GB, "free_percent": free_percent}) - if free_abs_GB < 1 or free_percent < 5: - item["status"] = "ERROR" - item["summary"] = "diagnosis_diskusage_verylow" - elif free_abs_GB < 2 or free_percent < 10: - item["status"] = "WARNING" - item["summary"] = "diagnosis_diskusage_low" + data={"device": device, "total": human_size(usage.total), "free": human_size(usage.free), "free_percent": free_percent}) + + # Special checks for /boot partition because they sometimes are + # pretty small and that's kind of okay... (for example on RPi) + if mountpoint.startswith("/boot"): + if usage.free < 10 * MB or free_percent < 10: + item["status"] = "ERROR" + item["summary"] = "diagnosis_diskusage_verylow" + elif usage.free < 20 * MB or free_percent < 20: + item["status"] = "WARNING" + item["summary"] = "diagnosis_diskusage_low" + else: + item["status"] = "SUCCESS" + item["summary"] = "diagnosis_diskusage_ok" else: - item["status"] = "SUCCESS" - item["summary"] = "diagnosis_diskusage_ok" + if usage.free < 1 * GB or free_percent < 5: + item["status"] = "ERROR" + item["summary"] = "diagnosis_diskusage_verylow" + elif usage.free < 2 * GB or free_percent < 10: + item["status"] = "WARNING" + item["summary"] = "diagnosis_diskusage_low" + else: + item["status"] = "SUCCESS" + item["summary"] = "diagnosis_diskusage_ok" + yield item +def human_size(bytes_): + # Adapted from https://stackoverflow.com/a/1094933 + for unit in ['','ki','Mi','Gi','Ti','Pi','Ei','Zi']: + if abs(bytes_) < 1024.0: + return "%s %sB" % (round_(bytes_), unit) + bytes_ /= 1024.0 + return "%s %sB" % (round_(bytes_), 'Yi') + + +def round_(n): + # round_(22.124) -> 22 + # round_(9.45) -> 9.4 + n = round(n, 1) + if n > 10: + n = int(round(n)) + return n + def main(args, env, loggers): return SystemResourcesDiagnoser(args, env, loggers).diagnose() diff --git a/locales/en.json b/locales/en.json index 4b1fdaa05..71804af97 100644 --- a/locales/en.json +++ b/locales/en.json @@ -175,21 +175,21 @@ "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", - "diagnosis_services_bad_status_tip": "You can try to restart the service, and if it doesn't work, have a look at the service logs using yunohost service log {service} or through the 'Services' section of the webadmin.", - "diagnosis_diskusage_verylow": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. You should really consider cleaning up some space.", - "diagnosis_diskusage_low": "Storage {mountpoint} (on device {device}) has only {free_abs_GB} GB ({free_percent}%) space remaining. Be careful.", - "diagnosis_diskusage_ok": "Storage {mountpoint} (on device {device}) still has {free_abs_GB} GB ({free_percent}%) space left!", - "diagnosis_ram_verylow": "The system has only {available_abs_MB} MB ({available_percent}%) RAM left! (out of {total_abs_MB} MB)", - "diagnosis_ram_low": "The system has {available_abs_MB} MB ({available_percent}%) RAM left out of {total_abs_MB} MB. Be careful.", - "diagnosis_ram_ok": "The system still has {available_abs_MB} MB ({available_percent}%) RAM left out of {total_abs_MB} MB.", + "diagnosis_services_bad_status_tip": "You can try to restart the service, and if it doesn't work, have a look at the service logs in the webadmin (from the command line, you can do this with yunohost service restart {service} and yunohost service log {service}).", + "diagnosis_diskusage_verylow": "Storage {mountpoint} (on device {device}) has only {free} ({free_percent}%) space remaining (out of {total}). You should really consider cleaning up some space!", + "diagnosis_diskusage_low": "Storage {mountpoint} (on device {device}) has only {free} ({free_percent}%) space remaining (out of {total}). Be careful.", + "diagnosis_diskusage_ok": "Storage {mountpoint} (on device {device}) still has {free} ({free_percent}%) space left (out of {total})!", + "diagnosis_ram_verylow": "The system has only {available} ({available_percent}%) RAM available! (out of {total})", + "diagnosis_ram_low": "The system has {available} ({available_percent}%) RAM available (out of {total}). Be careful.", + "diagnosis_ram_ok": "The system still has {available} ({available_percent}%) RAM available out of {total}.", "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least 256 MB of swap to avoid situations where the system runs out of memory.", - "diagnosis_swap_notsomuch": "The system has only {total_MB} MB swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", - "diagnosis_swap_ok": "The system has {total_MB} MB of swap!", + "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", + "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", - "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! Though YunoHost will stop updating this file automatically, beware that YunoHost upgrades may contain important recommended changes. You can inspect the difference with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", + "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", "diagnosis_security_all_good": "No critical security vulnerability was found.", "diagnosis_security_vulnerable_to_meltdown": "You appear vulnerable to the Meltdown criticial security vulnerability", "diagnosis_security_vulnerable_to_meltdown_details": "To fix this, you should upgrade your system and reboot to load the new linux kernel (or contact your server provider if this doesn't work). See https://meltdownattack.com/ for more infos.", From a85c15dd0bf58d8bc1a75fb2adac61db7a6a9cca Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 15 Apr 2020 01:07:40 +0200 Subject: [PATCH 122/317] Update data/hooks/diagnosis/50-systemresources.py Co-Authored-By: Kayou --- data/hooks/diagnosis/50-systemresources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index 491c5b665..b4e50ccf1 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -13,7 +13,7 @@ class SystemResourcesDiagnoser(Diagnoser): def run(self): MB = 1024**2 - GB = 1024**2 + GB = MB*1024 # # RAM From 8e46b536dc9089cd2db934354dacca497036c926 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 15 Apr 2020 03:48:14 +0200 Subject: [PATCH 123/317] Somewhat cleaner hack to check the status of those damn services that aren't the real services... --- data/templates/yunohost/services.yml | 4 +- src/yunohost/service.py | 55 +++++++++++++++------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/data/templates/yunohost/services.yml b/data/templates/yunohost/services.yml index fdf278fcf..e1dd57e55 100644 --- a/data/templates/yunohost/services.yml +++ b/data/templates/yunohost/services.yml @@ -13,7 +13,7 @@ metronome: category: xmpp mysql: log: [/var/log/mysql.log,/var/log/mysql.err,/var/log/mysql/error.log] - alternates: ['mariadb'] + actual_systemd_service: mariadb category: database nginx: log: /var/log/nginx @@ -27,7 +27,7 @@ php7.0-fpm: category: web postfix: log: [/var/log/mail.log,/var/log/mail.err] - test_status: systemctl show postfix@- | grep -q "^SubState=running" + actual_systemd_service: postfix@- needs_exposed_ports: [25, 587] category: email redis-server: diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 748037df6..b6c93b5ae 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -80,7 +80,7 @@ def service_add(name, description=None, log=None, log_type="file", test_status=N services[name]['description'] = description else: # Try to get the description from systemd service - out = subprocess.check_output("systemctl show %s | grep '^Description='" % name, shell=True) + out = subprocess.check_output("systemctl show %s | grep '^Description='" % name, shell=True).strip() out = out.replace("Description=", "") # If the service does not yet exists or if the description is empty, # systemd will anyway return foo.service as default value, so we wanna @@ -295,16 +295,11 @@ def service_status(names=[]): if services[name].get("status", "") is None: continue - status = _get_service_information_from_systemd(name) - - # try to get status using alternative version if they exists - # this is for mariadb/mysql but is generic in case of - alternates = services[name].get("alternates", []) - while status is None and alternates: - status = _get_service_information_from_systemd(alternates.pop()) + systemd_service = services[name].get("actual_systemd_service", name) + status = _get_service_information_from_systemd(systemd_service) if status is None: - logger.error("Failed to get status information via dbus for service %s, systemctl didn't recognize this service ('NoSuchUnit')." % name) + logger.error("Failed to get status information via dbus for service %s, systemctl didn't recognize this service ('NoSuchUnit')." % systemd_service) result[name] = { 'status': "unknown", 'start_on_boot': "unknown", @@ -338,6 +333,8 @@ def service_status(names=[]): # gotta do this ... cf code of /lib/systemd/systemd-sysv-install if result[name]["start_on_boot"] == "generated": result[name]["start_on_boot"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled" + elif os.path.exists("/etc/systemd/system/multi-user.target.wants/%s.service" % name): + result[name]["start_on_boot"] = "enabled" if "StateChangeTimestamp" in status: result[name]['last_state_change'] = datetime.utcfromtimestamp(status["StateChangeTimestamp"] / 1000000) @@ -408,6 +405,7 @@ def service_log(name, number=50): """ services = _get_services() + number = int(number) if name not in services.keys(): raise YunohostError('service_unknown', service=name) @@ -423,11 +421,7 @@ def service_log(name, number=50): result = {} # First we always add the logs from journalctl / systemd - result["journalctl"] = _get_journalctl_logs(name, int(number)).splitlines() - - # Mysql and journalctl are fucking annoying, we gotta explictly fetch mariadb ... - if name == "mysql": - result["journalctl"] = _get_journalctl_logs("mariadb", int(number)).splitlines() + result["journalctl"] = _get_journalctl_logs(name, number).splitlines() for index, log_path in enumerate(log_list): log_type = log_type_list[index] @@ -435,7 +429,7 @@ def service_log(name, number=50): if log_type == "file": # log is a file, read it if not os.path.isdir(log_path): - result[log_path] = _tail(log_path, int(number)) if os.path.exists(log_path) else [] + result[log_path] = _tail(log_path, number) if os.path.exists(log_path) else [] continue for log_file in os.listdir(log_path): @@ -447,10 +441,11 @@ def service_log(name, number=50): if not log_file.endswith(".log"): continue - result[log_file_path] = _tail(log_file_path, int(number)) if os.path.exists(log_file_path) else [] + result[log_file_path] = _tail(log_file_path, number) if os.path.exists(log_file_path) else [] else: + # N.B. : this is legacy code that can probably be removed ... to be confirmed # get log with journalctl - result[log_path] = _get_journalctl_logs(log_path, int(number)).splitlines() + result[log_path] = _get_journalctl_logs(log_path, number).splitlines() return result @@ -572,14 +567,22 @@ def _get_services(): services = yaml.load(f) except: return {} - else: - # some services are marked as None to remove them from YunoHost - # filter this - for key, value in services.items(): - if value is None: - del services[key] - return services + # some services are marked as None to remove them from YunoHost + # filter this + for key, value in services.items(): + if value is None: + del services[key] + + # Stupid hack for postgresql which ain't an official service ... Can't + # really inject that info otherwise. Real service we want to check for + # status and log is in fact postgresql@x.y-main (x.y being the version) + if "postgresql" in services: + if "description" in services["postgresql"]: + del services["postgresql"]["description"] + services["postgresql"]["actual_systemd_service"] = "postgresql@9.6-main" + + return services def _save_services(services): @@ -674,8 +677,10 @@ def _find_previous_log_file(file): def _get_journalctl_logs(service, number="all"): + services = _get_services() + systemd_service = services.get(service, {}).get("actual_systemd_service", service) try: - return subprocess.check_output("journalctl -xn -u {0} -n{1}".format(service, number), shell=True) + return subprocess.check_output("journalctl -xn -u {0} -n{1}".format(systemd_service, number), shell=True) except: import traceback return "error while get services logs from journalctl:\n%s" % traceback.format_exc() From 7f3cc334873d693e13667de7b6ae3d34eca0217f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 02:51:29 +0200 Subject: [PATCH 124/317] Add a static method to call remote diagnosis and supports ipv4-only or ipv6-only check --- data/hooks/diagnosis/14-ports.py | 20 ++----- data/hooks/diagnosis/21-web.py | 98 +++++++++++++++++++------------- src/yunohost/diagnosis.py | 46 +++++++++++++++ 3 files changed, 110 insertions(+), 54 deletions(-) diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index f973a3275..05c28e8dc 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import requests from yunohost.diagnosis import Diagnoser from yunohost.utils.error import YunohostError @@ -27,25 +26,16 @@ class PortsDiagnoser(Diagnoser): ports[port] = service try: - r = requests.post('https://diagnosis.yunohost.org/check-ports', json={'ports': ports.keys()}, timeout=30) - if r.status_code not in [200, 400, 418]: - raise Exception("Bad response from the server https://diagnosis.yunohost.org/check-ports : %s - %s" % (str(r.status_code), r.content)) - r = r.json() - if "status" not in r.keys(): - raise Exception("Bad syntax for response ? Raw json: %s" % str(r)) - elif r["status"] == "error": - if "content" in r.keys(): - raise Exception(r["content"]) - else: - raise Exception("Bad syntax for response ? Raw json: %s" % str(r)) - elif r["status"] != "ok" or "ports" not in r.keys() or not isinstance(r["ports"], dict): - raise Exception("Bad syntax for response ? Raw json: %s" % str(r)) + r = Diagnoser.remote_diagnosis('check-ports', + data={'ports': ports.keys()}, + ipversion=4) + results = r["ports"] except Exception as e: raise YunohostError("diagnosis_ports_could_not_diagnose", error=e) for port, service in sorted(ports.items()): category = services[service].get("category", "[?]") - if r["ports"].get(str(port), None) is not True: + if results.get(str(port), None) is not True: yield dict(meta={"port": str(port)}, data={"service": service, "category": category}, status="ERROR", diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 2d0344abe..270c566cc 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -4,10 +4,14 @@ import os import random import requests +from moulinette.utils.filesystem import read_file + from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list from yunohost.utils.error import YunohostError +DIAGNOSIS_SERVER = "diagnosis.yunohost.org" + class WebDiagnoser(Diagnoser): @@ -17,52 +21,42 @@ class WebDiagnoser(Diagnoser): def run(self): - nonce_digits = "0123456789abcedf" - - at_least_one_domain_ok = False all_domains = domain_list()["domains"] + domains_to_check = [] for domain in all_domains: # If the diagnosis location ain't defined, can't do diagnosis, # probably because nginx conf manually modified... nginx_conf = "/etc/nginx/conf.d/%s.conf" % domain - if os.system("grep -q '^.*location .*/.well-known/ynh-diagnosis/' %s" % nginx_conf) != 0: + if ".well-known/ynh-diagnosis/" not in read_file(nginx_conf): yield dict(meta={"domain": domain}, status="WARNING", summary="diagnosis_http_nginx_conf_not_up_to_date", details=["diagnosis_http_nginx_conf_not_up_to_date_details"]) - - nonce = ''.join(random.choice(nonce_digits) for i in range(16)) - os.system("rm -rf /tmp/.well-known/ynh-diagnosis/") - os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/") - os.system("touch /tmp/.well-known/ynh-diagnosis/%s" % nonce) - - try: - r = requests.post('https://diagnosis.yunohost.org/check-http', json={'domain': domain, "nonce": nonce}, timeout=30) - if r.status_code not in [200, 400, 418]: - raise Exception("Bad response from the server https://diagnosis.yunohost.org/check-http : %s - %s" % (str(r.status_code), r.content)) - r = r.json() - if "status" not in r.keys(): - raise Exception("Bad syntax for response ? Raw json: %s" % str(r)) - elif r["status"] == "error" and ("code" not in r.keys() or not r["code"].startswith("error_http_check_")): - if "content" in r.keys(): - raise Exception(r["content"]) - else: - raise Exception("Bad syntax for response ? Raw json: %s" % str(r)) - except Exception as e: - raise YunohostError("diagnosis_http_could_not_diagnose", error=e) - - if r["status"] == "ok": - at_least_one_domain_ok = True - yield dict(meta={"domain": domain}, - status="SUCCESS", - summary="diagnosis_http_ok") else: - detail = r["code"].replace("error_http_check", "diagnosis_http") if "code" in r else "diagnosis_http_unknown_error" - yield dict(meta={"domain": domain}, - status="ERROR", - summary="diagnosis_http_unreachable", - details=[detail]) + domains_to_check.append(domain) + + self.nonce = ''.join(random.choice("0123456789abcedf") for i in range(16)) + os.system("rm -rf /tmp/.well-known/ynh-diagnosis/") + os.system("mkdir -p /tmp/.well-known/ynh-diagnosis/") + os.system("touch /tmp/.well-known/ynh-diagnosis/%s" % self.nonce) + + if not domains_to_check: + return + + # To perform hairpinning test, we gotta make sure that port forwarding + # is working and therefore we'll do it only if at least one ipv4 domain + # works. + self.do_hairpinning_test = False + ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} + if ipv4.get("status") == "SUCCESS": + for item in self.test_http(domains_to_check, ipversion=4): + yield item + + ipv6 = Diagnoser.get_cached_report("ip", item={"test": "ipv6"}) or {} + if ipv6.get("status") == "SUCCESS": + for item in self.test_http(domains_to_check, ipversion=6): + yield item # If at least one domain is correctly exposed to the outside, # attempt to diagnose hairpinning situations. On network with @@ -70,13 +64,12 @@ class WebDiagnoser(Diagnoser): # outside, but from the outside, it will be as if the port forwarding # was not configured... Hence, calling for example # "curl --head the.global.ip" will simply timeout... - if at_least_one_domain_ok: - ipv4 = Diagnoser.get_cached_report_item("ip", {"test": "ipv4"}) - global_ipv4 = ipv4.get("data", {}).get("global", {}) + if self.do_hairpinning_test: + global_ipv4 = ipv4.get("data", {}).get("global", None) if global_ipv4: try: requests.head("http://" + global_ipv4, timeout=5) - except requests.exceptions.Timeout as e: + except requests.exceptions.Timeout: yield dict(meta={"test": "hairpinning"}, status="WARNING", summary="diagnosis_http_hairpinning_issue", @@ -87,6 +80,33 @@ class WebDiagnoser(Diagnoser): # issue but something else super weird ... pass + def test_http(self, domains, ipversion): + + try: + r = Diagnoser.remote_diagnosis('check-http', + data={'domains': domains, + "nonce": self.nonce}, + ipversion=ipversion) + results = r["http"] + except Exception as e: + raise YunohostError("diagnosis_http_could_not_diagnose", error=e) + + assert set(results.keys()) == set(domains) + + for domain, result in results.items(): + + if result["status"] == "ok": + if ipversion == 4: + self.do_hairpinning_test = True + yield dict(meta={"domain": domain}, + status="SUCCESS", + summary="diagnosis_http_ok") + else: + yield dict(meta={"domain": domain}, + status="ERROR", + summary="diagnosis_http_unreachable", + details=[result["status"].replace("error_http_check", "diagnosis_http")]) + def main(args, env, loggers): return WebDiagnoser(args, env, loggers).diagnose() diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index c11cde566..fd7a37480 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -27,6 +27,8 @@ import re import os import time +import requests +import socket from moulinette import m18n, msettings from moulinette.utils import log @@ -39,6 +41,7 @@ logger = log.getActionLogger('yunohost.diagnosis') DIAGNOSIS_CACHE = "/var/cache/yunohost/diagnosis/" DIAGNOSIS_CONFIG_FILE = '/etc/yunohost/diagnosis.yml' +DIAGNOSIS_SERVER = "diagnosis.yunohost.org" def diagnosis_list(): all_categories_names = [h for h, _ in _list_diagnosis_categories()] @@ -492,6 +495,49 @@ class Diagnoser(): if "details" in item: item["details"] = [m18n_(info) for info in item["details"]] + @staticmethod + def remote_diagnosis(uri, data, ipversion, timeout=30): + + # Monkey patch socket.getaddrinfo to force request() to happen in ipv4 + # or 6 ... + # Inspired by https://stackoverflow.com/a/50044152 + old_getaddrinfo = socket.getaddrinfo + + def getaddrinfo_ipv4_only(*args, **kwargs): + responses = old_getaddrinfo(*args, **kwargs) + return [response + for response in responses + if response[0] == socket.AF_INET] + + def getaddrinfo_ipv6_only(*args, **kwargs): + responses = old_getaddrinfo(*args, **kwargs) + return [response + for response in responses + if response[0] == socket.AF_INET6] + + if ipversion == 4: + socket.getaddrinfo = getaddrinfo_ipv4_only + elif ipversion == 6: + socket.getaddrinfo = getaddrinfo_ipv6_only + + url = 'https://%s/%s' % (DIAGNOSIS_SERVER, uri) + try: + r = requests.post(url, json=data, timeout=timeout) + finally: + socket.getaddrinfo = old_getaddrinfo + + if r.status_code not in [200, 400]: + raise Exception("Bad response from diagnosis server.\nURL: %s\nStatus code: %s\nMessage: %s" % (url, r.status_code, r.content)) + if r.status_code == 400: + raise Exception("Diagnosis request was refused: %s" % r.content) + + try: + r = r.json() + except Exception as e: + raise Exception("Failed to parse json from diagnosis server response.\nError: %s\nOriginal content: %s" % (e, r.content)) + + return r + def _list_diagnosis_categories(): hooks_raw = hook_list("diagnosis", list_by="priority", show_info=True)["hooks"] From e8730ad92b4abe2f27e22b090b1693773d3d1eec Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 03:21:01 +0200 Subject: [PATCH 125/317] Correctly handle cases where domain works in IPv4 but not IPv6 or viceversa --- data/hooks/diagnosis/21-web.py | 57 ++++++++++++++++++++++------------ locales/en.json | 1 + 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 270c566cc..c54544aa0 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -48,15 +48,20 @@ class WebDiagnoser(Diagnoser): # is working and therefore we'll do it only if at least one ipv4 domain # works. self.do_hairpinning_test = False + + ipversions = [] ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} if ipv4.get("status") == "SUCCESS": - for item in self.test_http(domains_to_check, ipversion=4): - yield item + ipversions.append(4) + # To be discussed: we could also make this check dependent on the + # existence of an AAAA record... ipv6 = Diagnoser.get_cached_report("ip", item={"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": - for item in self.test_http(domains_to_check, ipversion=6): - yield item + ipversions.append(6) + + for item in self.test_http(domains_to_check, ipversions): + yield item # If at least one domain is correctly exposed to the outside, # attempt to diagnose hairpinning situations. On network with @@ -80,32 +85,44 @@ class WebDiagnoser(Diagnoser): # issue but something else super weird ... pass - def test_http(self, domains, ipversion): + def test_http(self, domains, ipversions): - try: - r = Diagnoser.remote_diagnosis('check-http', - data={'domains': domains, - "nonce": self.nonce}, - ipversion=ipversion) - results = r["http"] - except Exception as e: - raise YunohostError("diagnosis_http_could_not_diagnose", error=e) + results = {} + for ipversion in ipversions: + try: + r = Diagnoser.remote_diagnosis('check-http', + data={'domains': domains, + "nonce": self.nonce}, + ipversion=ipversion) + results[ipversion] = r["http"] + except Exception as e: + raise YunohostError("diagnosis_http_could_not_diagnose", error=e) - assert set(results.keys()) == set(domains) + for domain in domains: - for domain, result in results.items(): - - if result["status"] == "ok": - if ipversion == 4: + # If both IPv4 and IPv6 (if applicable) are good + if all(results[ipversion][domain]["status"] == "ok" for ipversion in ipversions): + if 4 in ipversions: self.do_hairpinning_test = True yield dict(meta={"domain": domain}, status="SUCCESS", summary="diagnosis_http_ok") - else: + # If both IPv4 and IPv6 (if applicable) are failed + elif all(results[ipversion][domain]["status"] != "ok" for ipversion in ipversions): + detail = results[4 if 4 in ipversions else 6][domain]["status"] yield dict(meta={"domain": domain}, status="ERROR", summary="diagnosis_http_unreachable", - details=[result["status"].replace("error_http_check", "diagnosis_http")]) + details=[detail.replace("error_http_check", "diagnosis_http")]) + # If only IPv4 is failed or only IPv6 is failed (if applicable) + else: + passed, failed = (4, 6) if results[4][domain]["status"] == "ok" else (6, 4) + detail = results[failed][domain]["status"] + yield dict(meta={"domain": domain}, + data={"passed": passed, "failed": failed}, + status="ERROR", + summary="diagnosis_http_partially_unreachable", + details=[detail.replace("error_http_check", "diagnosis_http")]) def main(args, env, loggers): diff --git a/locales/en.json b/locales/en.json index 71804af97..96a1f4658 100644 --- a/locales/en.json +++ b/locales/en.json @@ -217,6 +217,7 @@ "diagnosis_http_unknown_error": "An error happened while trying to reach your domain, it's very likely unreachable.", "diagnosis_http_bad_status_code": "Timed-out while trying to contact your server from outside. It might be that another machine answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", + "diagnosis_http_partiallu_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using yunohost tools regen-conf nginx --dry-run --with-diff and if you're ok, apply the changes with yunohost tools regen-conf nginx --force.", "diagnosis_unknown_categories": "The following categories are unknown: {categories}", From 1552c6472bbd375071edb146c4be91ecd2b0fd06 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 18:57:52 +0200 Subject: [PATCH 126/317] Try to improve wording of DNS reports --- locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index 96a1f4658..cf1b8d552 100644 --- a/locales/en.json +++ b/locales/en.json @@ -167,8 +167,8 @@ "diagnosis_ip_broken_resolvconf": "Domain name resolution seems to be broken on your server, which seems related to /etc/resolv.conf not pointing to 127.0.0.1.", "diagnosis_ip_weird_resolvconf": "DNS resolution seems to be working, but it looks like you're using a custom /etc/resolv.conf.", "diagnosis_ip_weird_resolvconf_details": "The file /etc/resolv.conf should be a symlink to /etc/resolvconf/run/resolv.conf itself pointing to 127.0.0.1 (dnsmasq). If you want to manually configure DNS resolvers, please edit /etc/resolv.dnsmasq.conf.", - "diagnosis_dns_good_conf": "Good DNS configuration for domain {domain} (category {category})", - "diagnosis_dns_bad_conf": "Bad or missing DNS configuration for domain {domain} (category {category})", + "diagnosis_dns_good_conf": "DNS records are correctly configured for domain {domain} (category {category})", + "diagnosis_dns_bad_conf": "Some DNS records are missing or incorrect for domain {domain} (category {category})", "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.
Type: {type}
Name: {name}
Value: {value}", "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", From 4e64e2ccfda6374b6c8e3eb1412afa7855f30c2f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 19:03:44 +0200 Subject: [PATCH 127/317] Save a per-record result for DNS diagnosis and report missing AAAA as warning only --- data/hooks/diagnosis/12-dnsrecords.py | 29 +++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 3132cf45f..c4996de38 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -40,9 +40,8 @@ class DNSRecordsDiagnoser(Diagnoser): expected_configuration = _build_dns_conf(domain, include_empty_AAAA_if_no_ipv6=True) - # FIXME: Here if there are no AAAA record, we should add something to expect "no" AAAA record - # to properly diagnose situations where people have a AAAA record but no IPv6 categories = ["basic", "mail", "xmpp", "extra"] + # For subdomains, we only diagnosis A and AAAA records if is_subdomain: categories = ["basic"] @@ -50,26 +49,48 @@ class DNSRecordsDiagnoser(Diagnoser): records = expected_configuration[category] discrepancies = [] + results = {} for r in records: + id_ = r["type"] + ":" + r["name"] r["current"] = self.get_current_record(domain, r["name"], r["type"]) if r["value"] == "@": r["value"] = domain + "." - if not self.current_record_match_expected(r): + if self.current_record_match_expected(r): + results[id_] = "OK" + else: if r["current"] is None: + results[id_] = "MISSING" discrepancies.append(("diagnosis_dns_missing_record", r)) else: + results[id_] = "WRONG" discrepancies.append(("diagnosis_dns_discrepancy", r)) + + def its_important(): + # Every mail DNS records are important for main domain + # For other domain, we only report it as a warning for now... + if is_main_domain and category == "mail": + return True + elif category == "basic": + # A bad or missing A record is critical ... + # And so is a wrong AAAA record + # (However, a missing AAAA record is acceptable) + if results["A:@"] != "OK" or results["AAAA:@"] == "WRONG": + return True + + return False + if discrepancies: - status = "ERROR" if (category == "basic" or (is_main_domain and category == "mail")) else "WARNING" + status = "ERROR" if its_important() else "WARNING" summary = "diagnosis_dns_bad_conf" else: status = "SUCCESS" summary = "diagnosis_dns_good_conf" output = dict(meta={"domain": domain, "category": category}, + data=results, status=status, summary=summary) From be0da3b9dcd10bbb528ff674d8536a787c571168 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 20:48:25 +0200 Subject: [PATCH 128/317] Only report an INFO is domain ain't accessible in IPv6 and there's in fact no AAAA record set yet --- data/hooks/diagnosis/21-web.py | 40 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index c54544aa0..10deea28d 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -17,7 +17,7 @@ class WebDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 3600 - dependencies = ["ip"] + dependencies = ["ip", "dnsrecords"] def run(self): @@ -118,11 +118,39 @@ class WebDiagnoser(Diagnoser): else: passed, failed = (4, 6) if results[4][domain]["status"] == "ok" else (6, 4) detail = results[failed][domain]["status"] - yield dict(meta={"domain": domain}, - data={"passed": passed, "failed": failed}, - status="ERROR", - summary="diagnosis_http_partially_unreachable", - details=[detail.replace("error_http_check", "diagnosis_http")]) + + # Failing in ipv4 is critical. + # If we failed in IPv6 but there's in fact no AAAA record + # It's an acceptable situation and we shall not report an + # error + def ipv6_is_important_for_this_domain(): + dnsrecords = Diagnoser.get_cached_report("dnsrecords", item={"domain": domain, "category": "basic"}) or {} + AAAA_status = dnsrecords.get("data", {}).get("AAAA:@") + + return AAAA_status in ["OK", "WRONG"] + + if failed == 4 or ipv6_is_important_for_this_domain(): + yield dict(meta={"domain": domain}, + data={"passed": passed, "failed": failed}, + status="ERROR", + summary="diagnosis_http_partially_unreachable", + details=[detail.replace("error_http_check", "diagnosis_http")]) + # So otherwise we report a success (note that this info is + # later used to know that ACME challenge is doable) + # + # And in addition we report an info about the failure in IPv6 + # *with a different meta* (important to avoid conflicts when + # fetching the other info...) + else: + self.do_hairpinning_test = True + yield dict(meta={"domain": domain}, + status="SUCCESS", + summary="diagnosis_http_ok") + yield dict(meta={"test": "ipv6", "domain": domain}, + data={"passed": passed, "failed": failed}, + status="INFO", + summary="diagnosis_http_partially_unreachable", + details=[detail.replace("error_http_check", "diagnosis_http")]) def main(args, env, loggers): From dd7b42d3e8c2878da2bb67e6a7ba442f8d8149ff Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 23:38:05 +0200 Subject: [PATCH 129/317] Add ipv6 check for ports --- data/hooks/diagnosis/14-ports.py | 87 ++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index 05c28e8dc..809407be3 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -10,10 +10,12 @@ class PortsDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 3600 - dependencies = ["ip"] + dependencies = ["ip", "dnsrecords"] def run(self): + # TODO: report a warning if port 53 or 5353 is exposed to the outside world... + # This dict is something like : # { 80: "nginx", # 25: "postfix", @@ -25,28 +27,81 @@ class PortsDiagnoser(Diagnoser): for port in infos.get("needs_exposed_ports", []): ports[port] = service - try: - r = Diagnoser.remote_diagnosis('check-ports', - data={'ports': ports.keys()}, - ipversion=4) - results = r["ports"] - except Exception as e: - raise YunohostError("diagnosis_ports_could_not_diagnose", error=e) + ipversions = [] + ipv4 = Diagnoser.get_cached_report("ip", item={"test": "ipv4"}) or {} + if ipv4.get("status") == "SUCCESS": + ipversions.append(4) + + # To be discussed: we could also make this check dependent on the + # existence of an AAAA record... + ipv6 = Diagnoser.get_cached_report("ip", item={"test": "ipv6"}) or {} + if ipv6.get("status") == "SUCCESS": + ipversions.append(6) + + # Fetch test result for each relevant IP version + results = {} + for ipversion in ipversions: + try: + r = Diagnoser.remote_diagnosis('check-ports', + data={'ports': ports.keys()}, + ipversion=ipversion) + results[ipversion] = r["ports"] + except Exception as e: + raise YunohostError("diagnosis_http_could_not_diagnose", error=e) + for port, service in sorted(ports.items()): + port = str(port) category = services[service].get("category", "[?]") - if results.get(str(port), None) is not True: - yield dict(meta={"port": str(port)}, - data={"service": service, "category": category}, - status="ERROR", - summary="diagnosis_ports_unreachable", - details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) - else: - yield dict(meta={"port": str(port)}, + + # If both IPv4 and IPv6 (if applicable) are good + if all(results[ipversion].get(port) is True for ipversion in ipversions): + yield dict(meta={"port": port}, data={"service": service, "category": category}, status="SUCCESS", summary="diagnosis_ports_ok", details=["diagnosis_ports_needed_by"]) + # If both IPv4 and IPv6 (if applicable) are failed + elif all(results[ipversion].get(port) is not True for ipversion in ipversions): + yield dict(meta={"port": port}, + data={"service": service, "category": category}, + status="ERROR", + summary="diagnosis_ports_unreachable", + details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) + # If only IPv4 is failed or only IPv6 is failed (if applicable) + else: + passed, failed = (4, 6) if results[4].get(port) is True else (6, 4) + + # Failing in ipv4 is critical. + # If we failed in IPv6 but there's in fact no AAAA record + # It's an acceptable situation and we shall not report an + # error + # If any AAAA record is set, IPv6 is important... + def ipv6_is_important(): + dnsrecords = Diagnoser.get_cached_report("dnsrecords") or {} + return any(record["data"]["AAAA:@"] in ["OK", "WRONG"] for record in dnsrecords.get("items", [])) + + if failed == 4 or ipv6_is_important(): + yield dict(meta={"port": port}, + data={"service": service, "category": category, "passed": passed, "failed": failed}, + status="ERROR", + summary="diagnosis_ports_partially_unreachable", + details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) + # So otherwise we report a success + # And in addition we report an info about the failure in IPv6 + # *with a different meta* (important to avoid conflicts when + # fetching the other info...) + else: + yield dict(meta={"port": port}, + data={"service": service, "category": category}, + status="SUCCESS", + summary="diagnosis_ports_ok", + details=["diagnosis_ports_needed_by"]) + yield dict(meta={"test": "ipv6", "port": port}, + data={"service": service, "category": category, "passed": passed, "failed": failed}, + status="INFO", + summary="diagnosis_ports_partially_unreachable", + details=["diagnosis_ports_needed_by", "diagnosis_ports_forwarding_tip"]) def main(args, env, loggers): From 4306db7cf1a8ee89ee7a3090f53ea4cb81d213c4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 16 Apr 2020 23:59:42 +0200 Subject: [PATCH 130/317] Be more flexible about SPF record: just 'a mx -all' is enough, no need to specify IP. (also fix TXT record validation in diagnosis) --- data/hooks/diagnosis/12-dnsrecords.py | 8 ++++++-- src/yunohost/domain.py | 9 +-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index c4996de38..3853350bd 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -127,8 +127,12 @@ class DNSRecordsDiagnoser(Diagnoser): # Split expected/current # from "v=DKIM1; k=rsa; p=hugekey;" # to a set like {'v=DKIM1', 'k=rsa', 'p=...'} - expected = set(r["value"].strip(' "').strip(";").replace(" ", "").split()) - current = set(r["current"].strip(' "').strip(";").replace(" ", "").split()) + expected = set(r["value"].strip(';" ').replace(";", " ").split()) + current = set(r["current"].strip(';" ').replace(";", " ").split()) + + # For SPF, ignore parts starting by ip4: or ip6: + if r["name"] == "@": + current = {part for part in current if not part.startswith("ip4:") and not part.startswith("ip6:")} return expected == current elif r["type"] == "MX": # For MX, we want to ignore the priority diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 7910147a3..1d1e10da1 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -455,16 +455,9 @@ def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): # Email # ######### - spf_record = '"v=spf1 a mx' - if ipv4: - spf_record += ' ip4:{ip4}'.format(ip4=ipv4) - if ipv6: - spf_record += ' ip6:{ip6}'.format(ip6=ipv6) - spf_record += ' -all"' - mail = [ ["@", ttl, "MX", "10 %s." % domain], - ["@", ttl, "TXT", spf_record], + ["@", ttl, "TXT", "v=spf1 a mx -all"], ] # DKIM/DMARC record From 2c269613142032cbca8bb0a2376c5614876b8da6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 17 Apr 2020 02:17:15 +0200 Subject: [PATCH 131/317] Fix bad copy pasta for string key --- data/hooks/diagnosis/14-ports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index 809407be3..b63971b71 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -47,7 +47,7 @@ class PortsDiagnoser(Diagnoser): ipversion=ipversion) results[ipversion] = r["ports"] except Exception as e: - raise YunohostError("diagnosis_http_could_not_diagnose", error=e) + raise YunohostError("diagnosis_ports_could_not_diagnose", error=e) for port, service in sorted(ports.items()): From 040bc1d09fd5c6ba89ab87ccfaeb99d954b32265 Mon Sep 17 00:00:00 2001 From: Kayou Date: Fri, 17 Apr 2020 03:20:02 +0200 Subject: [PATCH 132/317] Yolo fix locales (#936) * Yolo fix locales * Fix bad copy pasta for string key * Yolo fix locales * Add diagnosis_ports_could_not_diagnose back Co-authored-by: Alexandre Aubin --- locales/ca.json | 17 ++++++++--------- locales/en.json | 4 ++-- locales/eo.json | 17 ++++++++--------- locales/es.json | 17 ++++++++--------- locales/fr.json | 17 ++++++++--------- locales/oc.json | 17 ++++++++--------- 6 files changed, 42 insertions(+), 47 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index 4c31e4a6c..0ea0d91f6 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -502,7 +502,7 @@ "permission_require_account": "El permís {permission} només té sentit per als usuaris que tenen un compte, i per tant no es pot activar per als visitants.", "app_remove_after_failed_install": "Eliminant l'aplicació després que hagi fallat la instal·lació…", "diagnosis_basesystem_ynh_main_version": "El servidor funciona amb YunoHost {main_version} ({repo})", - "diagnosis_ram_low": "El sistema només té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles d'un total de {total_abs_MB} MB. Aneu amb compte.", + "diagnosis_ram_low": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}. Aneu amb compte.", "diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de 256 MB de swap per evitar situacions en les que el sistema es queda sense memòria.", "diagnosis_regenconf_manually_modified": "El fitxer de configuració {file} ha estat modificat manualment.", "diagnosis_security_vulnerable_to_meltdown_details": "Per arreglar-ho, hauríeu d'actualitzar i reiniciar el sistema per tal de carregar el nou nucli de linux (o contactar amb el proveïdor del servidor si no funciona). Vegeu https://meltdownattack.com/ per a més informació.", @@ -538,13 +538,13 @@ "diagnosis_dns_missing_record": "Segons la configuració DNS recomanada, hauríeu d'afegir un registre DNS\ntipus: {type}\nnom: {name}\nvalor: {value}.", "diagnosis_dns_discrepancy": "El registre DNS de tipus {type} i nom {name} no concorda amb la configuració recomanada.\nValor actual: {current}\nValor esperat: {value}", "diagnosis_services_bad_status": "El servei {service} està {status} :(", - "diagnosis_diskusage_verylow": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Hauríeu de considerar alliberar una mica d'espai.", - "diagnosis_diskusage_low": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free_abs_GB} GB ({free_percent}%). Aneu amb compte.", - "diagnosis_diskusage_ok": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) encara té {free_abs_GB} GB ({free_percent}%) lliures!", - "diagnosis_ram_verylow": "El sistema només té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles! (d'un total de {total_abs_MB} MB)", - "diagnosis_ram_ok": "El sistema encara té {available_abs_MB} MB ({available_percent}%) de memòria RAM disponibles d'un total de {total_abs_MB} MB.", - "diagnosis_swap_notsomuch": "El sistema només té {total_MB} MB de swap. Hauríeu de considerar tenir un mínim de 256 MB per evitar situacions en les que el sistema es queda sense memòria.", - "diagnosis_swap_ok": "El sistema té {total_MB} MB de swap!", + "diagnosis_diskusage_verylow": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free} ({free_percent}%). Hauríeu de considerar alliberar una mica d'espai.", + "diagnosis_diskusage_low": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) només té disponibles {free} ({free_percent}%). Aneu amb compte.", + "diagnosis_diskusage_ok": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) encara té {free} ({free_percent}%) lliures!", + "diagnosis_ram_verylow": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles! (d'un total de {total})", + "diagnosis_ram_ok": "El sistema encara té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}.", + "diagnosis_swap_notsomuch": "El sistema només té {total} de swap. Hauríeu de considerar tenir un mínim de 256 MB per evitar situacions en les que el sistema es queda sense memòria.", + "diagnosis_swap_ok": "El sistema té {total} de swap!", "diagnosis_regenconf_allgood": "Tots els fitxers de configuració estan en acord amb la configuració recomanada!", "diagnosis_regenconf_manually_modified_details": "No hauria de ser cap problema sempre i quan sapigueu el que esteu fent ;) !", "diagnosis_regenconf_manually_modified_debian": "El fitxer de configuració {file} ha estat modificat manualment respecte al fitxer per defecte de Debian.", @@ -581,7 +581,6 @@ "diagnosis_no_cache": "Encara no hi ha memòria cau pel diagnòstic de la categoria «{category}»", "diagnosis_http_timeout": "S'ha exhaurit el temps d'esperar intentant connectar amb el servidor des de l'exterior. Sembla que no s'hi pot accedir. S'hauria de comprovar que el reenviament del port 80 és correcte, que NGINX funciona, i que el tallafocs no està interferint.", "diagnosis_http_connection_error": "Error de connexió: no s'ha pogut connectar amb el domini demanat, segurament és inaccessible.", - "diagnosis_http_unknown_error": "Hi ha hagut un error intentant accedir al domini, segurament és inaccessible.", "yunohost_postinstall_end_tip": "S'ha completat la post-instal·lació. Per acabar la configuració, considereu:\n - afegir un primer usuari a través de la secció «Usuaris» a la pàgina web d'administració (o emprant «yunohost user create » a la línia d'ordres);\n - diagnosticar possibles problemes a través de la secció «Diagnòstics» a la pàgina web d'administració (o emprant «yunohost diagnosis run» a la línia d'ordres);\n - llegir les seccions «Finalizing your setup» i «Getting to know Yunohost» a la documentació per administradors: https://yunohost.org/admindoc.", "migration_description_0014_remove_app_status_json": "Eliminar els fitxers d'aplicació status.json heretats", "diagnosis_services_running": "El servei {service} s'està executant!", diff --git a/locales/en.json b/locales/en.json index cf1b8d552..27fb19444 100644 --- a/locales/en.json +++ b/locales/en.json @@ -205,6 +205,7 @@ "diagnosis_description_security": "Security checks", "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", + "diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", "diagnosis_ports_needed_by": "Exposing this port is needed for {category} features (service {service})", "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", @@ -214,10 +215,9 @@ "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", - "diagnosis_http_unknown_error": "An error happened while trying to reach your domain, it's very likely unreachable.", "diagnosis_http_bad_status_code": "Timed-out while trying to contact your server from outside. It might be that another machine answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", - "diagnosis_http_partiallu_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.", + "diagnosis_http_partially_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", "diagnosis_http_nginx_conf_not_up_to_date_details": "To fix the situation, inspect the difference with the command line using yunohost tools regen-conf nginx --dry-run --with-diff and if you're ok, apply the changes with yunohost tools regen-conf nginx --force.", "diagnosis_unknown_categories": "The following categories are unknown: {categories}", diff --git a/locales/eo.json b/locales/eo.json index 127e7df39..87e062ea2 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -513,8 +513,8 @@ "diagnosis_display_tip_cli": "Vi povas aranĝi 'yunohost diagnosis show --issues' por aperigi la trovitajn problemojn.", "diagnosis_failed_for_category": "Diagnozo malsukcesis por kategorio '{category}': {error}", "app_upgrade_script_failed": "Eraro okazis en la skripto pri ĝisdatiga programo", - "diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free_abs_GB} GB ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.", - "diagnosis_ram_verylow": "La sistemo nur restas {available_abs_MB} MB ({available_percent}%) RAM! (el {total_abs_MB} MB)", + "diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.", + "diagnosis_ram_verylow": "La sistemo nur restas {available} ({available_percent}%) RAM! (el {total})", "diagnosis_mail_ougoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.", "diagnosis_http_bad_status_code": "Ne povis atingi vian servilon kiel atendite, ĝi redonis malbonan statuskodon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via nginx-agordo ĝisdatigas kaj ke reverso-prokuro ne interbatalas.", "main_domain_changed": "La ĉefa domajno estis ŝanĝita", @@ -530,9 +530,9 @@ "diagnosis_ip_weird_resolvconf_details": "Anstataŭe, ĉi tiu dosiero estu ligilo kun /etc/resolvconf/run/resolv.conf mem montrante al 127.0.0.1 (dnsmasq). La efektivaj solvantoj devas agordi per /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Bona DNS-agordo por domajno {domain} (kategorio {category})", "diagnosis_dns_bad_conf": "Malbona / mankas DNS-agordo por domajno {domain} (kategorio {category})", - "diagnosis_ram_ok": "La sistemo ankoraŭ havas {available_abs_MB} MB ({available_percent}%) RAM forlasita de {total_abs_MB} MB.", + "diagnosis_ram_ok": "La sistemo ankoraŭ havas {available} ({available_percent}%) RAM forlasita de {total}.", "diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ 256 MB da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.", - "diagnosis_swap_notsomuch": "La sistemo havas nur {total_MB} MB-interŝanĝon. Vi konsideru havi almenaŭ 256 MB por eviti situaciojn en kiuj la sistemo restas sen memoro.", + "diagnosis_swap_notsomuch": "La sistemo havas nur {total}-interŝanĝon. Vi konsideru havi almenaŭ 256 MB por eviti situaciojn en kiuj la sistemo restas sen memoro.", "diagnosis_regenconf_manually_modified_details": "Ĉi tio probable estas bona tiel longe kiel vi scias kion vi faras;)!", "diagnosis_regenconf_manually_modified_debian": "Agordodosiero {file} estis modifita permane kompare kun la defaŭlta Debian.", "diagnosis_regenconf_manually_modified_debian_details": "Ĉi tio probable estas bona, sed devas observi ĝin...", @@ -545,8 +545,8 @@ "diagnosis_dns_discrepancy": "La DNS-registro kun tipo {type} kaj nomo {name} ne kongruas kun la rekomendita agordo.\nNuna valoro: {current}\nEsceptita valoro: {value}", "diagnosis_services_conf_broken": "Agordo estas rompita por servo {service} !", "diagnosis_services_bad_status": "Servo {service} estas {status} :(", - "diagnosis_ram_low": "La sistemo havas {available_abs_MB} MB ({available_percent}%) RAM forlasita de {total_abs_MB} MB. Estu zorgema.", - "diagnosis_swap_ok": "La sistemo havas {total_MB} MB da interŝanĝoj!", + "diagnosis_ram_low": "La sistemo havas {available} ({available_percent}%) RAM forlasita de {total}. Estu zorgema.", + "diagnosis_swap_ok": "La sistemo havas {total} da interŝanĝoj!", "diagnosis_mail_ougoing_port_25_ok": "Eliranta haveno 25 ne estas blokita kaj retpoŝto povas esti sendita al aliaj serviloj.", "diagnosis_regenconf_allgood": "Ĉiuj agordaj dosieroj kongruas kun la rekomendita agordo!", "diagnosis_regenconf_manually_modified": "Agordodosiero {file} estis permane modifita.", @@ -564,13 +564,12 @@ "log_domain_main_domain": "Faru '{}' kiel ĉefa domajno", "diagnosis_http_timeout": "Tempolimigita dum provado kontakti vian servilon de ekstere. Ĝi ŝajnas esti neatingebla. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke nginx funkcias kaj ke fajroŝirmilo ne interbatalas.", "diagnosis_http_connection_error": "Rilata eraro: ne povis konektiĝi al la petita domajno, tre probable ĝi estas neatingebla.", - "diagnosis_http_unknown_error": "Eraro okazis dum provado atingi vian domajnon, tre probable ĝi estas neatingebla.", "migration_description_0013_futureproof_apps_catalog_system": "Migru al la nova katalogosistemo pri estontecaj programoj", "diagnosis_ignored_issues": "(+ {nb_ignored} ignorataj aferoj))", "diagnosis_found_errors": "Trovis {errors} signifa(j) afero(j) rilata al {category}!", "diagnosis_found_errors_and_warnings": "Trovis {errors} signifaj problemo (j) (kaj {warnings} averto) rilataj al {category}!", - "diagnosis_diskusage_low": "Stokado {mountpoint} (sur aparato {device)) restas nur {free_abs_GB} GB ({free_percent}%) spaco. Estu zorgema.", - "diagnosis_diskusage_ok": "Stokado {mountpoint} (sur aparato {device) ankoraŭ restas {free_abs_GB} GB ({free_percent}%) spaco!", + "diagnosis_diskusage_low": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Estu zorgema.", + "diagnosis_diskusage_ok": "Stokado {mountpoint} (sur aparato {device) ankoraŭ restas {free} ({free_percent}%) spaco!", "global_settings_setting_pop3_enabled": "Ebligu la protokolon POP3 por la poŝta servilo", "diagnosis_unknown_categories": "La jenaj kategorioj estas nekonataj: {categories}", "diagnosis_services_running": "Servo {service} funkcias!", diff --git a/locales/es.json b/locales/es.json index b72665066..6a55378da 100644 --- a/locales/es.json +++ b/locales/es.json @@ -529,7 +529,7 @@ "diagnosis_ip_not_connected_at_all": "¿¡Está conectado el servidor a internet!?", "diagnosis_ip_broken_resolvconf": "DNS parece no funcionar en tu servidor, lo que parece estar relacionado con /etc/resolv.conf no apuntando a 127.0.0.1.", "diagnosis_dns_missing_record": "Según la configuración DNS recomendada, deberías añadir un registro DNS\ntipo: {type}\nnombre: {name}\nvalor: {value}", - "diagnosis_diskusage_low": "El almacenamiento {mountpoint} (en dispositivo {device}) solo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Ten cuidado.", + "diagnosis_diskusage_low": "El almacenamiento {mountpoint} (en dispositivo {device}) solo tiene {free} ({free_percent}%) de espacio disponible. Ten cuidado.", "diagnosis_services_bad_status_tip": "Puedes intentar reiniciar el servicio, y si no funciona, echar un vistazo a los logs del servicio usando 'yunohost service log {service}' o a través de la sección 'Servicios' en webadmin.", "diagnosis_ip_connected_ipv6": "¡El servidor está conectado a internet a través de IPv6!", "diagnosis_ip_no_ipv6": "El servidor no cuenta con IPv6 funcional.", @@ -541,18 +541,18 @@ "diagnosis_dns_bad_conf": "Configuración mala o faltante de los DNS para el dominio {domain} (categoría {category})", "diagnosis_dns_discrepancy": "El registro DNS con tipo {type} y nombre {name} no se corresponde a la configuración recomendada.\nValor actual: {current}\nValor esperado: {value}", "diagnosis_services_bad_status": "El servicio {service} está {status} :(", - "diagnosis_diskusage_verylow": "El almacenamiento {mountpoint} (en el dispositivo {device}) sólo tiene {free_abs_GB} GB ({free_percent}%) de espacio disponible. Deberías considerar la posibilidad de limpiar algo de espacio.", - "diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free_abs_GB} GB ({free_percent}%) de espacio libre!", + "diagnosis_diskusage_verylow": "El almacenamiento {mountpoint} (en el dispositivo {device}) sólo tiene {free} ({free_percent}%) de espacio disponible. Deberías considerar la posibilidad de limpiar algo de espacio.", + "diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free} ({free_percent}%) de espacio libre!", "diagnosis_services_conf_broken": "¡Mala configuración para el servicio {service}!", "diagnosis_services_running": "¡El servicio {service} está en ejecución!", "diagnosis_failed": "No se ha podido obtener el resultado del diagnóstico para la categoría '{category}': {error}", "diagnosis_ip_connected_ipv4": "¡El servidor está conectado a internet a través de IPv4!", "diagnosis_security_vulnerable_to_meltdown_details": "Para corregir esto, debieras actualizar y reiniciar tu sistema para cargar el nuevo kernel de Linux (o contacta tu proveedor si esto no funciona). Mas información en https://meltdownattack.com/", - "diagnosis_ram_verylow": "Al sistema le queda solamente {available_abs_MB} MB ({available_percent}%) de RAM! (De un total de {total_abs_MB} MB)", - "diagnosis_ram_low": "Al sistema le queda {available_abs_MB} MB ({available_percent}%) de RAM de un total de {total_abs_MB} MB. Cuidado.", - "diagnosis_ram_ok": "El sistema aun tiene {available_abs_MB} MB ({available_percent}%) de RAM de un total de {total_abs_MB} MB.", + "diagnosis_ram_verylow": "Al sistema le queda solamente {available} ({available_percent}%) de RAM! (De un total de {total})", + "diagnosis_ram_low": "Al sistema le queda {available} ({available_percent}%) de RAM de un total de {total}. Cuidado.", + "diagnosis_ram_ok": "El sistema aun tiene {available} ({available_percent}%) de RAM de un total de {total}.", "diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos 256 MB de espacio de intercambio para evitar que el sistema se quede sin memoria.", - "diagnosis_swap_notsomuch": "Al sistema le queda solamente {total_MB} MB de espacio de intercambio. Considera agregar al menos 256 MB para evitar que el sistema se quede sin memoria.", + "diagnosis_swap_notsomuch": "Al sistema le queda solamente {total} de espacio de intercambio. Considera agregar al menos 256 MB para evitar que el sistema se quede sin memoria.", "diagnosis_mail_ougoing_port_25_ok": "El puerto de salida 25 no esta bloqueado y los correos electrónicos pueden ser enviados a otros servidores.", "diagnosis_mail_ougoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.", "diagnosis_regenconf_allgood": "Todos los archivos de configuración están en linea con la configuración recomendada!", @@ -568,7 +568,7 @@ "diagnosis_description_services": "Comprobación del estado de los servicios", "diagnosis_description_ports": "Exposición de puertos", "diagnosis_description_systemresources": "Recursos del sistema", - "diagnosis_swap_ok": "El sistema tiene {total_MB} MB de espacio de intercambio!", + "diagnosis_swap_ok": "El sistema tiene {total} de espacio de intercambio!", "diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {category} (service {service})", "diagnosis_ports_ok": "El puerto {port} es accesible desde internet.", "diagnosis_ports_unreachable": "El puerto {port} no es accesible desde internet.", @@ -592,7 +592,6 @@ "diagnosis_unknown_categories": "Las siguientes categorías están desconocidas: {categories}", "diagnosis_http_unreachable": "El dominio {domain} esta fuera de alcance desde internet y a través de HTTP.", "diagnosis_http_bad_status_code": "El sistema de diagnostico no pudo comunicarse con su servidor. Puede ser otra maquina que contesto en lugar del servidor. Debería verificar en su firewall que el re-direccionamiento del puerto 80 esta correcto.", - "diagnosis_http_unknown_error": "Hubo un error durante la búsqueda de su dominio, parece inalcanzable.", "diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado,", "diagnosis_http_timeout": "El intento de contactar a su servidor desde internet corrió fuera de tiempo. Al parece esta incomunicado. Debería verificar que nginx corre en el puerto 80, y que la redireción del puerto 80 no interfiere con en el firewall.", "diagnosis_http_ok": "El Dominio {domain} es accesible desde internet a través de HTTP.", diff --git a/locales/fr.json b/locales/fr.json index c8dfd12a9..f029a1d13 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -510,8 +510,8 @@ "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.", "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType: {type}\nNom: {name}\nValeur {value}", - "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free_abs_GB} Go ({free_percent}%) d'espace libre !", - "diagnosis_ram_ok": "Le système dispose encore de {available_abs_MB} MB ({available_percent}%) de RAM sur {total_abs_MB} MB.", + "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free} ({free_percent}%) d'espace libre !", + "diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", "diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}", @@ -537,13 +537,13 @@ "diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})", "diagnosis_dns_discrepancy": "L'enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d'espace.", - "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.", - "diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%)! (sur {total_abs_MB} Mo)", - "diagnosis_ram_low": "Le système n'a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.", + "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d'espace.", + "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Faites attention.", + "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", + "diagnosis_ram_low": "Le système n'a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", "diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d'avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_ok": "Le système dispose de {total_MB} Mo de swap !", + "diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d'avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", + "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", "diagnosis_regenconf_manually_modified_details": "C'est probablement OK tant que vous savez ce que vous faites;) !", @@ -583,7 +583,6 @@ "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", - "diagnosis_http_unknown_error": "Une erreur est survenue en essayant de joindre votre domaine, il est probablement injoignable.", "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l'interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l'administrateur: https://yunohost.org/admindoc.", "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l'aide de 'yunohost service log {service}' ou de la section 'Services' de l'administrateur Web.", "diagnosis_http_bad_status_code": "Le système de diagnostique n'a pas réussi à contacter votre serveur. Il se peut qu'une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", diff --git a/locales/oc.json b/locales/oc.json index a452b72bb..eebfaac64 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -479,8 +479,8 @@ "diagnosis_http_ok": "Lo domeni {domain} accessible de l’exterior.", "app_full_domain_unavailable": "Aquesta aplicacion a d’èsser installada sul seu pròpri domeni, mas i a d’autras aplicacions installadas sus aqueste domeni « {domain} ». Podètz utilizar allòc un josdomeni dedicat a aquesta aplicacion.", "diagnosis_dns_bad_conf": "Configuracion DNS incorrècta o inexistenta pel domeni {domain} (categoria {category})", - "diagnosis_ram_verylow": "Lo sistèma a solament {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla ! (d’un total de {total_abs_MB} MB)", - "diagnosis_ram_ok": "Lo sistèma a encara {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla d’un total de {total_abs_MB} MB).", + "diagnosis_ram_verylow": "Lo sistèma a solament {available} ({available_percent}%) de memòria RAM disponibla ! (d’un total de {total})", + "diagnosis_ram_ok": "Lo sistèma a encara {available} ({available_percent}%) de memòria RAM disponibla d’un total de {total}).", "permission_already_allowed": "Lo grop « {group} » a ja la permission « {permission} » activada", "permission_already_disallowed": "Lo grop « {group} » a ja la permission « {permission} » desactivada", "permission_cannot_remove_main": "La supression d’una permission màger es pas autorizada", @@ -511,7 +511,7 @@ "diagnosis_cache_still_valid": "(Memòria cache totjorn valida pel diagnostic {category}. Cap d’autre diagnostic pel moment !)", "diagnosis_found_errors": "{errors} errors importantas trobadas ligadas a {category} !", "diagnosis_services_bad_status": "Lo servici {service} es {status} :(", - "diagnosis_swap_ok": "Lo sistèma a {total_MB} MB d’escambi !", + "diagnosis_swap_ok": "Lo sistèma a {total} d’escambi !", "diagnosis_regenconf_allgood": "Totes los fichièrs de configuracion son confòrmes a la configuracion recomandada !", "diagnosis_regenconf_manually_modified": "Lo fichièr de configuracion {file} foguèt modificat manualament.", "diagnosis_regenconf_manually_modified_details": "Es probablament bon tan que sabètz çò que fasètz ;) !", @@ -527,7 +527,7 @@ "diagnosis_ports_ok": "Lo pòrt {port} es accessible de l’exterior.", "diagnosis_http_unreachable": "Lo domeni {domain} es pas accessible via HTTP de l’exterior.", "diagnosis_unknown_categories": "La categorias seguentas son desconegudas : {categories}", - "diagnosis_ram_low": "Lo sistèma a {available_abs_MB} Mo ({available_percent}%) de memòria RAM disponibla d’un total de {total_abs_MB} MB). Atencion.", + "diagnosis_ram_low": "Lo sistèma a {available} ({available_percent}%) de memòria RAM disponibla d’un total de {total}). Atencion.", "diagnosis_regenconf_manually_modified_debian": "Lo fichier de configuracion {file} foguèt modificat manualament respècte al fichièr per defaut de Debian.", "log_permission_create": "Crear la permission « {} »", "log_permission_delete": "Suprimir la permission « {} »", @@ -557,18 +557,17 @@ "diagnosis_services_running": "Lo servici {service} es lançat !", "diagnosis_services_conf_broken": "La configuracion es copada pel servici {service} !", "diagnosis_ports_needed_by": "Es necessari qu’aqueste pòrt siá accessible pel servici {service}", - "diagnosis_diskusage_low": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free_abs_GB} Go ({free_percent}%). Siatz prudent.", + "diagnosis_diskusage_low": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free} ({free_percent}%). Siatz prudent.", "migration_description_0014_remove_app_status_json": "Suprimir los fichièrs d’aplicacion status.json eretats", "dyndns_provider_unreachable": "Impossible d’atenher lo provesidor Dyndns : siá vòstre YunoHost es pas corrèctament connectat a Internet siá lo servidor dynette es copat.", "diagnosis_services_bad_status_tip": "Podètz ensajar de reaviar lo servici, e se non fonciona pas, podètz agachar los jornals en utilizant « yunohost service log {service} » o via la seccion « Servicis » de pas la pagina web d’administracion.", "diagnosis_http_connection_error": "Error de connexion : connexion impossibla al domeni demandat, benlèu qu’es pas accessible.", - "diagnosis_http_unknown_error": "Una error s’es producha en ensajar de se connectar a vòstre domeni, es benlèu pas accessible.", "group_user_already_in_group": "L’utilizaire {user} es ja dins lo grop « {group} »", "diagnosis_ip_broken_resolvconf": "La resolucion del nom de domeni sembla copada sul servidor, poiriá èsser ligada al fait que /etc/resolv.conf manda pas a 127.0.0.1.", "diagnosis_ip_weird_resolvconf": "La resolucion del nom de domeni sembla foncionar, mas siatz prudent en utilizant un fichièr /etc/resolv.con personalizat.", - "diagnosis_diskusage_verylow": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free_abs_GB} Go ({free_percent}%). Deuriatz considerar de liberar un pauc d’espaci.", + "diagnosis_diskusage_verylow": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free} ({free_percent}%). Deuriatz considerar de liberar un pauc d’espaci.", "global_settings_setting_pop3_enabled": "Activar lo protocòl POP3 pel servidor de corrièr", - "diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free_abs_GB} Go ({free_percent}%) de liure !", + "diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free} ({free_percent}%) de liure !", "diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria.", - "diagnosis_swap_notsomuch": "Lo sistèma a solament {total_MB} de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria." + "diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria." } From 0a3e7aa88b04c58c1795b52443c9eb8953768d85 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 17 Apr 2020 12:01:50 +0200 Subject: [PATCH 133/317] Update data/helpers.d/php Co-Authored-By: JimboJoe --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 19e586b70..532e3ba1a 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -356,7 +356,7 @@ ynh_get_scalable_phpfpm () { fi # Define the factor to determine min_spare_servers - # To not have not enough children ready to start for heavy apps. + # to avoid having too few children ready to start for heavy apps if [ $footprint -le 20 ] then min_spare_servers_factor=8 From f90a238973dc4c9687492ec696f3922977076a74 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 17 Apr 2020 12:02:11 +0200 Subject: [PATCH 134/317] Update data/helpers.d/php Co-Authored-By: JimboJoe --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 401c262b3..0bfbd2c29 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -402,7 +402,7 @@ ynh_get_scalable_phpfpm () { php_max_children=$max_proc fi - # Get an potential forced value for php_max_children + # Get a potential forced value for php_max_children local php_forced_max_children=$(ynh_app_setting_get --app=$app --key=php_forced_max_children) if [ -n "$php_forced_max_children" ]; then php_max_children=$php_forced_max_children From 7061c4c3fe489ffb4e5d5b4b230bef887e911ca1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 17 Apr 2020 14:40:53 +0200 Subject: [PATCH 135/317] Improve systemd settings for slapd (#933) --- data/hooks/conf_regen/06-slapd | 10 ++++++++++ data/templates/slapd/systemd-override.conf | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 data/templates/slapd/systemd-override.conf diff --git a/data/hooks/conf_regen/06-slapd b/data/hooks/conf_regen/06-slapd index 2fa108baa..9b2c20138 100755 --- a/data/hooks/conf_regen/06-slapd +++ b/data/hooks/conf_regen/06-slapd @@ -63,6 +63,9 @@ do_pre_regen() { cp -a ldap.conf slapd.conf "$ldap_dir" cp -a sudo.schema mailserver.schema yunohost.schema "$schema_dir" + mkdir -p ${pending_dir}/etc/systemd/system/slapd.service.d/ + cp systemd-override.conf ${pending_dir}/etc/systemd/system/slapd.service.d/ynh-override.conf + install -D -m 644 slapd.default "${pending_dir}/etc/default/slapd" } @@ -83,6 +86,13 @@ do_post_regen() { chmod o-rwx /etc/yunohost/certs/yunohost.org/ chmod -R g+rx /etc/yunohost/certs/yunohost.org/ + # If we changed the systemd ynh-override conf + if echo "$regen_conf_files" | sed 's/,/\n/g' | grep -q "^/etc/systemd/system/slapd.service.d/ynh-override.conf$" + then + systemctl daemon-reload + systemctl restart slapd + fi + [ -z "$regen_conf_files" ] && exit 0 # check the slapd config file at first diff --git a/data/templates/slapd/systemd-override.conf b/data/templates/slapd/systemd-override.conf new file mode 100644 index 000000000..afa821bd4 --- /dev/null +++ b/data/templates/slapd/systemd-override.conf @@ -0,0 +1,9 @@ +[Service] +# Prevent slapd from getting killed by oom reaper as much as possible +OOMScoreAdjust=-1000 +# If slapd exited (for instance if got killed) the service should not be +# considered as active anymore... +RemainAfterExit=no +# Automatically restart the service if the service gets down +Restart=always +RestartSec=3 From 61ef67252e37c436b2efa346d9c8312a03c1b077 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 17 Apr 2020 19:38:46 +0200 Subject: [PATCH 136/317] Don't contact ip6.yunohost if we can know right away that there's no IPv6 at all on the system --- data/hooks/diagnosis/10-ip.py | 2 +- src/yunohost/utils/network.py | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 36e04b5c1..0cb608b48 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -106,7 +106,7 @@ class IPDiagnoser(Diagnoser): # If we are indeed connected in ipv4 or ipv6, we should find a default route routes = check_output("ip -%s route" % protocol).split("\n") - if not [r for r in routes if r.startswith("default")]: + if not any(r.startswith("default") for r in routes): return False # We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index 4e23516c3..3ae1ba910 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -18,10 +18,12 @@ along with this program; if not, see http://www.gnu.org/licenses """ -import logging +import os import re -import subprocess +import logging + from moulinette.utils.network import download_text +from moulinette.utils.process import check_output logger = logging.getLogger('yunohost.utils.network') @@ -36,6 +38,17 @@ def get_public_ip(protocol=4): else: raise ValueError("invalid protocol version") + # We can know that ipv6 is not available directly if this file does not exists + if protocol == 6 and not os.path.exists("/proc/net/if_inet6"): + logger.debug("IPv6 appears not at all available on the system, so assuming there's no IP address for that version") + return None + + # If we are indeed connected in ipv4 or ipv6, we should find a default route + routes = check_output("ip -%s route" % protocol).split("\n") + if not any(r.startswith("default") for r in routes): + logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) + return None + try: return download_text(url, timeout=30).strip() except Exception as e: @@ -47,7 +60,7 @@ def get_network_interfaces(): # Get network devices and their addresses (raw infos from 'ip addr') devices_raw = {} - output = subprocess.check_output('ip addr show'.split()) + output = check_output('ip addr show') for d in re.split(r'^(?:[0-9]+: )', output, flags=re.MULTILINE): # Extract device name (1) and its addresses (2) m = re.match(r'([^\s@]+)(?:@[\S]+)?: (.*)', d, flags=re.DOTALL) @@ -62,7 +75,7 @@ def get_network_interfaces(): def get_gateway(): - output = subprocess.check_output('ip route show'.split()) + output = check_output('ip route show') m = re.search(r'default via (.*) dev ([a-z]+[0-9]?)', output) if not m: return None From 485de92b50c8f826beb764225083cdc0ade5fc51 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 17 Apr 2020 21:22:02 +0200 Subject: [PATCH 137/317] Redundant message --- src/yunohost/diagnosis.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index fd7a37480..f8e3f36cc 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -385,8 +385,6 @@ class Diagnoser(): logger.error(m18n.n("diagnosis_cant_run_because_of_dep", category=self.description, dep=Diagnoser.get_description(dependency))) return 1, {} - self.logger_debug("Running diagnostic for %s" % self.id_) - items = list(self.run()) for item in items: From 08f9091257feb7423ffb9e06f72845dcd4533131 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 02:40:40 +0200 Subject: [PATCH 138/317] Handle stupid weird case where the manifest file disappeared yet the app folder is still there ... --- src/yunohost/app.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 39793ec1a..ed7747b29 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -116,7 +116,11 @@ def app_list(full=False): """ out = [] for app_id in sorted(_installed_apps()): - app_info_dict = app_info(app_id, full=full) + try: + app_info_dict = app_info(app_id, full=full) + except Exception as e: + logger.error("Failed to read info for %s : %s" % (app_id, e)) + continue app_info_dict["id"] = app_id out.append(app_info_dict) @@ -131,6 +135,7 @@ def app_info(app, full=False): raise YunohostError('app_not_installed', app=app, all_apps=_get_all_installed_apps_id()) local_manifest = _get_manifest_of_app(os.path.join(APPS_SETTING_PATH, app)) + settings = _get_app_settings(app) ret = { @@ -2026,7 +2031,7 @@ def _get_manifest_of_app(path): elif os.path.exists(os.path.join(path, "manifest.json")): return read_json(os.path.join(path, "manifest.json")) else: - return None + raise YunohostError("There doesn't seem to be any manifest file in %s ... It looks like an app was not correctly installed/removed." % path, raw_msg=True) def _get_git_last_commit_hash(repository, reference='HEAD'): From 749ca54a34f05a9751f0bbf17d84c9b067c5a592 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 02:53:15 +0200 Subject: [PATCH 139/317] More sensible cache_duration for diagnosis categories --- data/hooks/diagnosis/00-basesystem.py | 2 +- data/hooks/diagnosis/10-ip.py | 2 +- data/hooks/diagnosis/12-dnsrecords.py | 2 +- data/hooks/diagnosis/14-ports.py | 2 +- data/hooks/diagnosis/21-web.py | 2 +- data/hooks/diagnosis/24-mail.py | 2 +- data/hooks/diagnosis/50-systemresources.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/hooks/diagnosis/00-basesystem.py b/data/hooks/diagnosis/00-basesystem.py index 68a9570ce..51926924a 100644 --- a/data/hooks/diagnosis/00-basesystem.py +++ b/data/hooks/diagnosis/00-basesystem.py @@ -11,7 +11,7 @@ from yunohost.utils.packages import ynh_packages_version class BaseSystemDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 * 24 + cache_duration = 600 dependencies = [] def run(self): diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 0cb608b48..6571ca556 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -13,7 +13,7 @@ from yunohost.utils.network import get_network_interfaces class IPDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 60 + cache_duration = 600 dependencies = [] def run(self): diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 3853350bd..5ed7fc737 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -12,7 +12,7 @@ from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain class DNSRecordsDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 * 24 + cache_duration = 600 dependencies = ["ip"] def run(self): diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index b63971b71..6f4c808bd 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -9,7 +9,7 @@ from yunohost.service import _get_services class PortsDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 + cache_duration = 600 dependencies = ["ip", "dnsrecords"] def run(self): diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 10deea28d..6e9dd6b79 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -16,7 +16,7 @@ DIAGNOSIS_SERVER = "diagnosis.yunohost.org" class WebDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 + cache_duration = 600 dependencies = ["ip", "dnsrecords"] def run(self): diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 0a3a97102..3f9517bb0 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -8,7 +8,7 @@ from yunohost.diagnosis import Diagnoser class MailDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 + cache_duration = 600 dependencies = ["ip"] def run(self): diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index b4e50ccf1..ab9ead7bb 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -7,7 +7,7 @@ from yunohost.diagnosis import Diagnoser class SystemResourcesDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 3600 * 24 + cache_duration = 300 dependencies = [] def run(self): From 301ced9d6ebbd350a734da40572c5312068fbb35 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 02:54:16 +0200 Subject: [PATCH 140/317] Hmf I dunno let's have this weird option if we really want to have a special case for first-run ... --- data/actionsmap/yunohost.yml | 3 +++ src/yunohost/diagnosis.py | 13 ++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index ded56a7c1..e1229352c 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1686,6 +1686,9 @@ diagnosis: --force: help: Ignore the cached report even if it is still 'fresh' action: store_true + --except-if-never-ran-yet: + help: Don't run anything if diagnosis never ran yet ... (this is meant to be used by the webadmin) + action: store_true ignore: action_help: Configure some diagnosis results to be ignored and therefore not considered as actual issues diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index f8e3f36cc..f40687989 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -69,6 +69,10 @@ def diagnosis_get(category, item): def diagnosis_show(categories=[], issues=False, full=False, share=False): + if not os.path.exists(DIAGNOSIS_CACHE): + logger.warning(m18n.n("diagnosis_never_ran_yet")) + return + # Get all the categories all_categories = _list_diagnosis_categories() all_categories_names = [category for category, _ in all_categories] @@ -81,10 +85,6 @@ def diagnosis_show(categories=[], issues=False, full=False, share=False): if unknown_categories: raise YunohostError('diagnosis_unknown_categories', categories=", ".join(unknown_categories)) - if not os.path.exists(DIAGNOSIS_CACHE): - logger.warning(m18n.n("diagnosis_never_ran_yet")) - return - # Fetch all reports all_reports = [] for category in categories: @@ -146,7 +146,10 @@ def _dump_human_readable_reports(reports): return(output) -def diagnosis_run(categories=[], force=False): +def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False): + + if except_if_never_ran_yet and not os.path.exists(DIAGNOSIS_CACHE): + return # Get all the categories all_categories = _list_diagnosis_categories() From e880e775c15f730d7a9a23ecd88a425cf02bbef6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 03:09:43 +0200 Subject: [PATCH 141/317] No need to display this message in webadmin (we're already on the diagnosis script when this happens ...) + in CLI we want to have it as a warning so that it's displayed in cron email --- locales/en.json | 3 +-- src/yunohost/diagnosis.py | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/locales/en.json b/locales/en.json index 27fb19444..f0189f8fe 100644 --- a/locales/en.json +++ b/locales/en.json @@ -143,8 +143,7 @@ "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server is running YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.", - "diagnosis_display_tip_web": "You can go to the Diagnosis section (in the home screen) to see the issues found.", - "diagnosis_display_tip_cli": "You can run 'yunohost diagnosis show --issues' to display the issues found.", + "diagnosis_display_tip": "To see the issues found, you can go to the Diagnosis section of the webadmin, or run 'yunohost diagnosis show --issues' from the command-line.", "diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}", "diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Not re-diagnosing yet!)", "diagnosis_cant_run_because_of_dep": "Can't run diagnosis for {category} while there are important issues related to {dep}.", diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index f40687989..aba65a619 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -180,11 +180,8 @@ def diagnosis_run(categories=[], force=False, except_if_never_ran_yet=False): if report != {}: issues.extend([item for item in report["items"] if item["status"] in ["WARNING", "ERROR"]]) - if issues: - if msettings.get("interface") == "api": - logger.info(m18n.n("diagnosis_display_tip_web")) - else: - logger.info(m18n.n("diagnosis_display_tip_cli")) + if issues and msettings.get("interface") == "cli": + logger.warning(m18n.n("diagnosis_display_tip")) return From db347115fcc69c45705e505b150eed36bdab9e1e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 03:24:31 +0200 Subject: [PATCH 142/317] In fact we can't have a hard dependency on dnsrecords here, otherwise no check are performed until the dnsrecords have no important issue ... --- data/hooks/diagnosis/14-ports.py | 2 +- data/hooks/diagnosis/21-web.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index 6f4c808bd..a4459d92f 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -10,7 +10,7 @@ class PortsDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 - dependencies = ["ip", "dnsrecords"] + dependencies = ["ip"] def run(self): diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 6e9dd6b79..09f5b2b73 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -17,7 +17,7 @@ class WebDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] cache_duration = 600 - dependencies = ["ip", "dnsrecords"] + dependencies = ["ip"] def run(self): From fc5047838213f67db2bb3cdf76d83e15d2440f82 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 03:28:52 +0200 Subject: [PATCH 143/317] Another attempt to improve messages... --- locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index f0189f8fe..800a1d696 100644 --- a/locales/en.json +++ b/locales/en.json @@ -212,9 +212,9 @@ "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", - "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", + "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", - "diagnosis_http_bad_status_code": "Timed-out while trying to contact your server from outside. It might be that another machine answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", + "diagnosis_http_bad_status_code": "It looks like another machine (maybe your internet router) answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", "diagnosis_http_partially_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", From 9bd6d39a79ced84d0cb6b3f939aa86ef568754b6 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sat, 18 Apr 2020 10:53:22 +0200 Subject: [PATCH 144/317] [enh] add dynamic variables to systemd helper --- data/helpers.d/systemd | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 47e905f0f..5b1e3eaa8 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -2,9 +2,10 @@ # Create a dedicated systemd config # -# usage: ynh_add_systemd_config [--service=service] [--template=template] -# | arg: -s, --service - Service name (optionnal, $app by default) -# | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) +# usage: ynh_add_systemd_config [--service=service] [--template=template] "list of others variables to replace" +# | arg: -s, --service - Service name (optional, $app by default) +# | arg: -t, --template - Name of template file (optional, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) +# | arg: -v, --others_var= - List of others variables to replace separeted by a space. For example : 'var_1 var_2 ...' # # This will use the template ../conf/.service # to generate a systemd config, by replacing the following keywords @@ -14,17 +15,22 @@ # __APP__ by $app # __FINALPATH__ by $final_path # +# And dynamic variables (from the last example) : +# __PATH_2__ by $path_2 +# __PORT_2__ by $port_2 +# # Requires YunoHost version 2.7.2 or higher. ynh_add_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=st - declare -Ar args_array=( [s]=service= [t]=template= ) + declare -Ar args_array=( [s]=service= [t]=template= [v]=others_var=) local service local template # Manage arguments with getopts ynh_handle_getopts_args "$@" local service="${service:-$app}" local template="${template:-systemd.service}" + local others_var="${others_var:-}" finalsystemdconf="/etc/systemd/system/$service.service" ynh_backup_if_checksum_is_different --file="$finalsystemdconf" @@ -38,6 +44,15 @@ ynh_add_systemd_config () { if test -n "${app:-}"; then ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf" fi + + # Replace all other variable given as arguments + for var_to_replace in $others_var + do + # ${var_to_replace^^} make the content of the variable on upper-cases + # ${!var_to_replace} get the content of the variable named $var_to_replace + ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf" + done + ynh_store_file_checksum --file="$finalsystemdconf" chown root: "$finalsystemdconf" From 34a12c142776a6b558a87ae1793ed34f63ba5798 Mon Sep 17 00:00:00 2001 From: tituspijean Date: Sat, 18 Apr 2020 11:07:20 +0200 Subject: [PATCH 145/317] [enh] ynh_add_systemd_config comments Some typos fixes should be propagated to the fail2ban helper too. --- data/helpers.d/systemd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 5b1e3eaa8..6b46dc875 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -2,10 +2,10 @@ # Create a dedicated systemd config # -# usage: ynh_add_systemd_config [--service=service] [--template=template] "list of others variables to replace" +# usage: ynh_add_systemd_config [--service=service] [--template=template] [--others_var="list of others variables to replace"] # | arg: -s, --service - Service name (optional, $app by default) # | arg: -t, --template - Name of template file (optional, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) -# | arg: -v, --others_var= - List of others variables to replace separeted by a space. For example : 'var_1 var_2 ...' +# | arg: -v, --others_var - List of others variables to replace separated by a space. For example: 'var_1 var_2 ...' # # This will use the template ../conf/.service # to generate a systemd config, by replacing the following keywords From 5777a266a2150fa4490f73fedc25b5e4c4ed38ed Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 18 Apr 2020 12:22:32 +0200 Subject: [PATCH 146/317] Update systemd --- data/helpers.d/systemd | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 6b46dc875..4f731f5db 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -16,21 +16,22 @@ # __FINALPATH__ by $final_path # # And dynamic variables (from the last example) : -# __PATH_2__ by $path_2 -# __PORT_2__ by $port_2 +# __VAR_1__ by $var_1 +# __VAR_2__ by $var_2 # # Requires YunoHost version 2.7.2 or higher. ynh_add_systemd_config () { # Declare an array to define the options of this helper. - local legacy_args=st - declare -Ar args_array=( [s]=service= [t]=template= [v]=others_var=) + local legacy_args=stv + declare -Ar args_array=( [s]=service= [t]=template= [v]=others_var= ) local service local template + local others_var # Manage arguments with getopts ynh_handle_getopts_args "$@" - local service="${service:-$app}" - local template="${template:-systemd.service}" - local others_var="${others_var:-}" + service="${service:-$app}" + template="${template:-systemd.service}" + others_var="${others_var:-}" finalsystemdconf="/etc/systemd/system/$service.service" ynh_backup_if_checksum_is_different --file="$finalsystemdconf" @@ -44,15 +45,15 @@ ynh_add_systemd_config () { if test -n "${app:-}"; then ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf" fi - - # Replace all other variable given as arguments + + # Replace all other variables given as arguments for var_to_replace in $others_var do # ${var_to_replace^^} make the content of the variable on upper-cases # ${!var_to_replace} get the content of the variable named $var_to_replace - ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf" + ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalsystemdconf" done - + ynh_store_file_checksum --file="$finalsystemdconf" chown root: "$finalsystemdconf" From d8feb1b72ae605100e8656f39e874209fa43172f Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 7 Apr 2020 01:53:05 +0200 Subject: [PATCH 147/317] [enh] Add RBL check --- data/hooks/diagnosis/24-mail.py | 89 ++++++++++++++++++++++++++++++++- locales/en.json | 3 ++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 3f9517bb0..731267593 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -1,9 +1,42 @@ #!/usr/bin/env python import os +import dns.resolver + +from moulinette.utils.network import download_text from yunohost.diagnosis import Diagnoser +DEFAULT_BLACKLIST = [ + ('zen.spamhaus.org' , 'Spamhaus SBL, XBL and PBL' ), + ('dnsbl.sorbs.net' , 'SORBS aggregated' ), + ('safe.dnsbl.sorbs.net' , "'safe' subset of SORBS aggregated"), + ('ix.dnsbl.manitu.net' , 'Heise iX NiX Spam' ), + ('babl.rbl.webiron.net' , 'Bad Abuse' ), + ('cabl.rbl.webiron.net' , 'Chronicly Bad Abuse' ), + ('truncate.gbudb.net' , 'Exclusively Spam/Malware' ), + ('dnsbl-1.uceprotect.net' , 'Trapserver Cluster' ), + ('cbl.abuseat.org' , 'Net of traps' ), + ('dnsbl.cobion.com' , 'used in IBM products' ), + ('psbl.surriel.com' , 'passive list, easy to unlist' ), + ('dnsrbl.org' , 'Real-time black list' ), + ('db.wpbl.info' , 'Weighted private' ), + ('bl.spamcop.net' , 'Based on spamcop users' ), + ('dyna.spamrats.com' , 'Dynamic IP addresses' ), + ('spam.spamrats.com' , 'Manual submissions' ), + ('auth.spamrats.com' , 'Suspicious authentications' ), + ('dnsbl.inps.de' , 'automated and reported' ), + ('bl.blocklist.de' , 'fail2ban reports etc.' ), + ('srnblack.surgate.net' , 'feeders' ), + ('all.s5h.net' , 'traps' ), + ('rbl.realtimeblacklist.com' , 'lists ip ranges' ), + ('b.barracudacentral.org' , 'traps' ), + ('hostkarma.junkemailfilter.com', 'Autotected Virus Senders' ), + ('rbl.megarbl.net' , 'Curated Spamtraps' ), + ('ubl.unsubscore.com' , 'Collected Opt-Out Addresses' ), + ('0spam.fusionzero.com' , 'Spam Trap' ), +] + class MailDiagnoser(Diagnoser): @@ -14,6 +47,7 @@ class MailDiagnoser(Diagnoser): def run(self): # Is outgoing port 25 filtered somehow ? + self.logger_debug("Running outgoing 25 port check") if os.system('/bin/nc -z -w2 yunohost.org 25') == 0: yield dict(meta={"test": "ougoing_port_25"}, status="SUCCESS", @@ -23,9 +57,22 @@ class MailDiagnoser(Diagnoser): status="ERROR", summary="diagnosis_mail_ougoing_port_25_blocked") + # Is Reverse DNS well configured ? - # Mail blacklist using dig requests (c.f. ljf's code) + # Are IPs blacklisted ? + self.logger_debug("Running RBL detection") + blacklisted_details = tuple(self.check_blacklisted(self.get_public_ip(4))) + blacklisted_details += tuple(self.check_blacklisted(self.get_public_ip(6))) + if blacklisted_details: + yield dict(meta={}, + status="ERROR", + summary=("diagnosis_mail_blacklist_nok", {}), + details=blacklisted_details) + else: + yield dict(meta={}, + status="SUCCESS", + summary=("diagnosis_mail_blacklist_ok", {})) # SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser) @@ -37,6 +84,46 @@ class MailDiagnoser(Diagnoser): # check for unusual failed sending attempt being refused in the logs ? + def check_blacklisted(self, ip): + """ Check with dig onto blacklist DNS server + """ + if ip is None: + return + + for blacklist, description in DEFAULT_BLACKLIST: + + # Determine if we are listed on this RBL + try: + rev = dns.reversename.from_address(ip) + query = str(rev.split(3)[0]) + '.' + blacklist + # TODO add timeout lifetime + dns.resolver.query(query, "A") + except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, + dns.exception.Timeout): + continue + + # Try to get the reason + reason = "not explained" + try: + reason = str(dns.resolver.query(query, "TXT")[0]) + except Exception: + pass + + yield ('diagnosis_mail_blacklisted_by', + (ip, blacklist, reason)) + + def get_public_ip(self, protocol=4): + # TODO we might call this function from another side + assert protocol in [4, 6], "Invalid protocol version, it should be either 4 or 6 and was '%s'" % repr(protocol) + + url = 'https://ip%s.yunohost.org' % ('6' if protocol == 6 else '') + + try: + return download_text(url, timeout=30).strip() + except Exception as e: + self.logger_debug("Could not get public IPv%s : %s" % (str(protocol), str(e))) + return None + def main(args, env, loggers): return MailDiagnoser(args, env, loggers).diagnose() diff --git a/locales/en.json b/locales/en.json index 800a1d696..dbce8f367 100644 --- a/locales/en.json +++ b/locales/en.json @@ -186,6 +186,9 @@ "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", + "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklist.", + "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklist.", + "diagnosis_mail_blacklisted_by": "{0} is listed on {1}. Reason: {2}", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From bb162662c6007d729c6105c7e40352fba8500015 Mon Sep 17 00:00:00 2001 From: ljf Date: Sat, 11 Apr 2020 19:34:34 +0200 Subject: [PATCH 148/317] [enh] Use named var in i18n --- data/hooks/diagnosis/24-mail.py | 20 ++++++++++++-------- locales/en.json | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 731267593..25d0ff984 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -62,17 +62,21 @@ class MailDiagnoser(Diagnoser): # Are IPs blacklisted ? self.logger_debug("Running RBL detection") - blacklisted_details = tuple(self.check_blacklisted(self.get_public_ip(4))) - blacklisted_details += tuple(self.check_blacklisted(self.get_public_ip(6))) + ipv4 = Diagnoser.get_cached_report_item("ip", {"test": "ipv4"}) + global_ipv4 = ipv4.get("data", {}).get("global", {}) + ipv6 = Diagnoser.get_cached_report_item("ip", {"test": "ipv6"}) + global_ipv6 = ipv6.get("data", {}).get("global", {}) + blacklisted_details = tuple(self.check_blacklisted(global_ipv4)) + blacklisted_details += tuple(self.check_blacklisted(global_ipv6)) if blacklisted_details: - yield dict(meta={}, + yield dict(meta={"test": "mail_blacklist"}, status="ERROR", - summary=("diagnosis_mail_blacklist_nok", {}), - details=blacklisted_details) + summary="diagnosis_mail_blacklist_nok", + details=list(blacklisted_details)) else: - yield dict(meta={}, + yield dict(meta={"test": "mail_blacklist"}, status="SUCCESS", - summary=("diagnosis_mail_blacklist_ok", {})) + summary="diagnosis_mail_blacklist_ok") # SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser) @@ -110,7 +114,7 @@ class MailDiagnoser(Diagnoser): pass yield ('diagnosis_mail_blacklisted_by', - (ip, blacklist, reason)) + {'ip': ip, 'blacklist': blacklist, 'reason': reason}) def get_public_ip(self, protocol=4): # TODO we might call this function from another side diff --git a/locales/en.json b/locales/en.json index dbce8f367..26c51d253 100644 --- a/locales/en.json +++ b/locales/en.json @@ -188,7 +188,7 @@ "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklist.", "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklist.", - "diagnosis_mail_blacklisted_by": "{0} is listed on {1}. Reason: {2}", + "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist}. Reason: {reason}", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From 0b7984adf117a413b63d8604d6b54cea22bc3c87 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 12 Apr 2020 04:14:49 +0200 Subject: [PATCH 149/317] [enh] Improve DNSBL check --- data/hooks/diagnosis/24-mail.py | 120 +++++++++------------ data/other/dnsbl_list.yml | 184 ++++++++++++++++++++++++++++++++ debian/install | 1 + locales/en.json | 6 +- 4 files changed, 237 insertions(+), 74 deletions(-) create mode 100644 data/other/dnsbl_list.yml diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 25d0ff984..333d98c8a 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -4,38 +4,11 @@ import os import dns.resolver from moulinette.utils.network import download_text +from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser -DEFAULT_BLACKLIST = [ - ('zen.spamhaus.org' , 'Spamhaus SBL, XBL and PBL' ), - ('dnsbl.sorbs.net' , 'SORBS aggregated' ), - ('safe.dnsbl.sorbs.net' , "'safe' subset of SORBS aggregated"), - ('ix.dnsbl.manitu.net' , 'Heise iX NiX Spam' ), - ('babl.rbl.webiron.net' , 'Bad Abuse' ), - ('cabl.rbl.webiron.net' , 'Chronicly Bad Abuse' ), - ('truncate.gbudb.net' , 'Exclusively Spam/Malware' ), - ('dnsbl-1.uceprotect.net' , 'Trapserver Cluster' ), - ('cbl.abuseat.org' , 'Net of traps' ), - ('dnsbl.cobion.com' , 'used in IBM products' ), - ('psbl.surriel.com' , 'passive list, easy to unlist' ), - ('dnsrbl.org' , 'Real-time black list' ), - ('db.wpbl.info' , 'Weighted private' ), - ('bl.spamcop.net' , 'Based on spamcop users' ), - ('dyna.spamrats.com' , 'Dynamic IP addresses' ), - ('spam.spamrats.com' , 'Manual submissions' ), - ('auth.spamrats.com' , 'Suspicious authentications' ), - ('dnsbl.inps.de' , 'automated and reported' ), - ('bl.blocklist.de' , 'fail2ban reports etc.' ), - ('srnblack.surgate.net' , 'feeders' ), - ('all.s5h.net' , 'traps' ), - ('rbl.realtimeblacklist.com' , 'lists ip ranges' ), - ('b.barracudacentral.org' , 'traps' ), - ('hostkarma.junkemailfilter.com', 'Autotected Virus Senders' ), - ('rbl.megarbl.net' , 'Curated Spamtraps' ), - ('ubl.unsubscore.com' , 'Collected Opt-Out Addresses' ), - ('0spam.fusionzero.com' , 'Spam Trap' ), -] +DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" class MailDiagnoser(Diagnoser): @@ -57,17 +30,13 @@ class MailDiagnoser(Diagnoser): status="ERROR", summary="diagnosis_mail_ougoing_port_25_blocked") - # Is Reverse DNS well configured ? + # Forward-confirmed reverse DNS (FCrDNS) verification - # Are IPs blacklisted ? - self.logger_debug("Running RBL detection") - ipv4 = Diagnoser.get_cached_report_item("ip", {"test": "ipv4"}) - global_ipv4 = ipv4.get("data", {}).get("global", {}) - ipv6 = Diagnoser.get_cached_report_item("ip", {"test": "ipv6"}) - global_ipv6 = ipv6.get("data", {}).get("global", {}) - blacklisted_details = tuple(self.check_blacklisted(global_ipv4)) - blacklisted_details += tuple(self.check_blacklisted(global_ipv6)) + # Are IPs listed on a DNSBL ? + self.logger_debug("Running DNSBL detection") + + blacklisted_details = self.check_ip_dnsbl() if blacklisted_details: yield dict(meta={"test": "mail_blacklist"}, status="ERROR", @@ -88,45 +57,54 @@ class MailDiagnoser(Diagnoser): # check for unusual failed sending attempt being refused in the logs ? - def check_blacklisted(self, ip): + def check_blacklisted(self): """ Check with dig onto blacklist DNS server """ - if ip is None: - return + dns_blacklists = read_yaml(DEFAULT_DNS_BLACKLIST) + for ip in self.get_public_ips(): + for blacklist in dns_blacklists: + + if "." in ip and not blacklist.ipv4: + continue - for blacklist, description in DEFAULT_BLACKLIST: + if ":" in ip and not blacklist.ipv6: + continue + + # Determine if we are listed on this RBL + try: + rev = dns.reversename.from_address(ip) + query = str(rev.split(3)[0]) + '.' + blacklist.dns_server + # TODO add timeout lifetime + dns.resolver.query(query, "A") + except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, + dns.exception.Timeout): + continue - # Determine if we are listed on this RBL - try: - rev = dns.reversename.from_address(ip) - query = str(rev.split(3)[0]) + '.' + blacklist - # TODO add timeout lifetime - dns.resolver.query(query, "A") - except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, - dns.exception.Timeout): - continue + # Try to get the reason + reason = "not explained" + try: + reason = str(dns.resolver.query(query, "TXT")[0]) + except Exception: + pass - # Try to get the reason - reason = "not explained" - try: - reason = str(dns.resolver.query(query, "TXT")[0]) - except Exception: - pass + yield ('diagnosis_mail_blacklisted_by', { + 'ip': ip, + 'blacklist': blacklist, + 'reason': reason}) - yield ('diagnosis_mail_blacklisted_by', - {'ip': ip, 'blacklist': blacklist, 'reason': reason}) - - def get_public_ip(self, protocol=4): - # TODO we might call this function from another side - assert protocol in [4, 6], "Invalid protocol version, it should be either 4 or 6 and was '%s'" % repr(protocol) - - url = 'https://ip%s.yunohost.org' % ('6' if protocol == 6 else '') - - try: - return download_text(url, timeout=30).strip() - except Exception as e: - self.logger_debug("Could not get public IPv%s : %s" % (str(protocol), str(e))) - return None + def get_public_ips(self): + # Todo code a better way to access a data + ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) + if ipv4: + global_ipv4 = ipv4.get("data", {}).get("global", {}) + if global_ipv4: + yield global_ipv4 + + ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) + if ipv6: + global_ipv6 = ipv6.get("data", {}).get("global", {}) + if global_ipv6: + yield global_ipv6 def main(args, env, loggers): diff --git a/data/other/dnsbl_list.yml b/data/other/dnsbl_list.yml new file mode 100644 index 000000000..839aeaab6 --- /dev/null +++ b/data/other/dnsbl_list.yml @@ -0,0 +1,184 @@ +# Used by GAFAM +- name: Spamhaus ZEN + dns_server: zen.spamhaus.org + website: https://www.spamhaus.org/zen/ + ipv4: true + ipv6: true + domain: false +- name: Barracuda Reputation Block List + dns_server: b.barracudacentral.org + website: https://barracudacentral.org/rbl/ + ipv4: true + ipv6: false + domain: false +- name: Hostkarma + dns_server: hostkarma.junkemailfilter.com + website: https://ipadmin.junkemailfilter.com/remove.php + ipv4: true + ipv6: false + domain: false +- name: ImproWare IP based spamlist + dns_server: spamrbl.imp.ch + website: https://antispam.imp.ch/ + ipv4: true + ipv6: false + domain: false +- name: ImproWare IP based wormlist + dns_server: wormrbl.imp.ch + website: https://antispam.imp.ch/ + ipv4: true + ipv6: false + domain: false +- name: Backscatterer.org + dns_server: ips.backscatterer.org + website: http://www.backscatterer.org/ + ipv4: true + ipv6: false + domain: false +- name: inps.de + dns_server: dnsbl.inps.de + website: http://dnsbl.inps.de/ + ipv4: true + ipv6: false + domain: false +- name: LASHBACK + dns_server: ubl.unsubscore.com + website: https://blacklist.lashback.com/ + ipv4: true + ipv6: false + domain: false +- name: Mailspike.org + dns_server: bl.mailspike.net + website: http://www.mailspike.net/ + ipv4: true + ipv6: false + domain: false +- name: NiX Spam + dns_server: ix.dnsbl.manitu.net + website: http://www.dnsbl.manitu.net/ + ipv4: true + ipv6: false + domain: false +- name: REDHAWK + dns_server: access.redhawk.org + website: https://www.redhawk.org/SpamHawk/query.php + ipv4: true + ipv6: false + domain: false +- name: SORBS Open SMTP relays + dns_server: smtp.dnsbl.sorbs.net + website: http://www.sorbs.net/ + ipv4: true + ipv6: false + domain: false +- name: SORBS Spamhost (last 28 days) + dns_server: recent.spam.dnsbl.sorbs.net + website: http://www.sorbs.net/ + ipv4: true + ipv6: false + domain: false +- name: SORBS Spamhost (last 48 hours) + dns_server: new.spam.dnsbl.sorbs.net + website: http://www.sorbs.net/ + ipv4: true + ipv6: false + domain: false +- name: SpamCop Blocking List + dns_server: bl.spamcop.net + website: https://www.spamcop.net/bl.shtml + ipv4: true + ipv6: false + domain: false +- name: Spam Eating Monkey SEM-BACKSCATTER + dns_server: backscatter.spameatingmonkey.net + website: https://spameatingmonkey.com/services + ipv4: true + ipv6: false + domain: false +- name: Spam Eating Monkey SEM-BLACK + dns_server: bl.spameatingmonkey.net + website: https://spameatingmonkey.com/services + ipv4: true + ipv6: false + domain: false +- name: Spam Eating Monkey SEM-IPV6BL + dns_server: bl.ipv6.spameatingmonkey.net + website: https://spameatingmonkey.com/services + ipv4: false + ipv6: true + domain: false +- name: SpamRATS! all + dns_server: all.spamrats.com + website: http://www.spamrats.com/ + ipv4: true + ipv6: false + domain: false +- name: PSBL (Passive Spam Block List) + dns_server: psbl.surriel.com + website: http://psbl.surriel.com/ + ipv4: true + ipv6: false + domain: false +- name: SWINOG + dns_server: dnsrbl.swinog.ch + website: https://antispam.imp.ch/ + ipv4: true + ipv6: false + domain: false +- name: GBUdb Truncate + dns_server: truncate.gbudb.net + website: http://www.gbudb.com/truncate/index.jsp + ipv4: true + ipv6: false + domain: false +- name: Weighted Private Block List + dns_server: db.wpbl.info + website: http://www.wpbl.info/ + ipv4: true + ipv6: false + domain: false +# Used by GAFAM +- name: Composite Blocking List + dns_server: cbl.abuseat.org + website: cbl.abuseat.org + ipv4: true + ipv6: false + domain: false +# Used by GAFAM +- name: SenderScore Blacklist + dns_server: bl.score.senderscore.com + website: https://senderscore.com + ipv4: true + ipv6: false + domain: false +- name: Invaluement + dns_server: sip.invaluement.com + website: https://www.invaluement.com/ + ipv4: true + ipv6: false + domain: false +# Added cause it supports IPv6 +- name: AntiCaptcha.NET IPv6 + dns_server: dnsbl6.anticaptcha.net + website: http://anticaptcha.net/ + ipv4: false + ipv6: true + domain: false +- name: SPFBL.net RBL + dns_server: dnsbl.spfbl.net + website: https://spfbl.net/en/dnsbl/ + ipv4: true + ipv6: true + domain: true +- name: Suomispam Blacklist + dns_server: bl.suomispam.net + website: http://suomispam.net/ + ipv4: true + ipv6: true + domain: false +- name: NordSpam + dns_server: bl.nordspam.com + website: https://www.nordspam.com/ + ipv4: true + ipv6: true + domain: false diff --git a/debian/install b/debian/install index e0743cdd1..cf682d958 100644 --- a/debian/install +++ b/debian/install @@ -7,6 +7,7 @@ data/hooks/* /usr/share/yunohost/hooks/ data/other/yunoprompt.service /etc/systemd/system/ data/other/password/* /usr/share/yunohost/other/password/ data/other/dpkg-origins/yunohost /etc/dpkg/origins +data/other/dnsbl_list.yml /usr/share/yunohost/other/dnsbl_list.yml data/other/* /usr/share/yunohost/yunohost-config/moulinette/ data/templates/* /usr/share/yunohost/templates/ data/helpers /usr/share/yunohost/ diff --git a/locales/en.json b/locales/en.json index 26c51d253..37ae2a34f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -186,9 +186,9 @@ "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", - "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklist.", - "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklist.", - "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist}. Reason: {reason}", + "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklists.", + "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklists.", + "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist.name}. Reason: {reason}. See {blacklist.website}", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From 5b0698e798421c1a3d71147c279b326b4b2726a6 Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 13 Apr 2020 16:41:27 +0200 Subject: [PATCH 150/317] [fix] Bad call to dict --- data/hooks/diagnosis/24-mail.py | 19 ++++++++++--------- locales/en.json | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 333d98c8a..f4f897e28 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -36,12 +36,13 @@ class MailDiagnoser(Diagnoser): # Are IPs listed on a DNSBL ? self.logger_debug("Running DNSBL detection") - blacklisted_details = self.check_ip_dnsbl() + blacklisted_details = list(self.check_dnsbl(self.get_public_ips())) + print(blacklisted_details) if blacklisted_details: yield dict(meta={"test": "mail_blacklist"}, status="ERROR", summary="diagnosis_mail_blacklist_nok", - details=list(blacklisted_details)) + details=blacklisted_details) else: yield dict(meta={"test": "mail_blacklist"}, status="SUCCESS", @@ -57,23 +58,22 @@ class MailDiagnoser(Diagnoser): # check for unusual failed sending attempt being refused in the logs ? - def check_blacklisted(self): + def check_dnsbl(self, ips): """ Check with dig onto blacklist DNS server """ dns_blacklists = read_yaml(DEFAULT_DNS_BLACKLIST) - for ip in self.get_public_ips(): + for ip in ips: for blacklist in dns_blacklists: - - if "." in ip and not blacklist.ipv4: + if "." in ip and not blacklist['ipv4']: continue - if ":" in ip and not blacklist.ipv6: + if ":" in ip and not blacklist['ipv6']: continue # Determine if we are listed on this RBL try: rev = dns.reversename.from_address(ip) - query = str(rev.split(3)[0]) + '.' + blacklist.dns_server + query = str(rev.split(3)[0]) + '.' + blacklist['dns_server'] # TODO add timeout lifetime dns.resolver.query(query, "A") except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, @@ -89,7 +89,8 @@ class MailDiagnoser(Diagnoser): yield ('diagnosis_mail_blacklisted_by', { 'ip': ip, - 'blacklist': blacklist, + 'blacklist_name': blacklist['name'], + 'blacklist_website': blacklist['website'], 'reason': reason}) def get_public_ips(self): diff --git a/locales/en.json b/locales/en.json index 37ae2a34f..93f7680bf 100644 --- a/locales/en.json +++ b/locales/en.json @@ -188,7 +188,7 @@ "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklists.", "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklists.", - "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist.name}. Reason: {reason}. See {blacklist.website}", + "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist_name}. Reason: {reason}. See {blacklist_website}", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From 027a0ed73c9281fd35582d9e683348483f12f7bd Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 14 Apr 2020 03:56:35 +0200 Subject: [PATCH 151/317] [wip] Add rDNS and mailqueue check --- data/hooks/diagnosis/24-mail.py | 78 ++++++++++++++++++++++++++++++--- locales/en.json | 12 ++++- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index f4f897e28..b91bfec85 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -2,11 +2,15 @@ import os import dns.resolver +import smtplib +import socket +from moulinette.utils.process import check_output from moulinette.utils.network import download_text from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser +from yunohost.domain import _get_maindomain DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" @@ -18,6 +22,8 @@ class MailDiagnoser(Diagnoser): dependencies = ["ip"] def run(self): + + ips = self.get_public_ips() # Is outgoing port 25 filtered somehow ? self.logger_debug("Running outgoing 25 port check") @@ -30,14 +36,56 @@ class MailDiagnoser(Diagnoser): status="ERROR", summary="diagnosis_mail_ougoing_port_25_blocked") - # Forward-confirmed reverse DNS (FCrDNS) verification + # Get HELO and be sure postfix is running + # TODO SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser) + server = None + result = dict(meta={"test": "mail_ehlo"}, + status="SUCCESS", + summary="diagnosis_mail_service_working") + try: + server = smtplib.SMTP("127.0.0.1", 25, timeout=10) + ehlo = server.ehlo() + ehlo_domain = ehlo[1].decode("utf-8").split("\n")[0] + except OSError: + result = dict(meta={"test": "mail_ehlo"}, + status="ERROR", + summary="diagnosis_mail_service_not_working") + ehlo_domain = _get_maindomain() + if server: + server.quit() + yield result + # Forward-confirmed reverse DNS (FCrDNS) verification + self.logger_debug("Running Forward-confirmed reverse DNS check") + for ip in ips: + try: + rdns_domain, _, _ = socket.gethostbyaddr(ip) + except socket.herror as e: + yield dict(meta={"test": "mail_fcrdns"}, + data={"ip": ip, "ehlo_domain": ehlo_domain}, + status="ERROR", + summary="diagnosis_mail_reverse_dns_missing") + continue + else: + if rdns_domain != ehlo_domain: + yield dict(meta={"test": "mail_fcrdns"}, + data={"ip": ip, "ehlo_domain": ehlo_domain, + "rdns_domain": rdns_domain}, + status="ERROR", + summary="diagnosis_mail_rdns_different_from_ehlo_domain") + else: + yield dict(meta={"test": "mail_fcrdns"}, + data={"ip": ip, "ehlo_domain": ehlo_domain}, + status="SUCCESS", + summary="diagnosis_mail_rdns_equal_to_ehlo_domain") + + # TODO Is a A/AAAA and MX Record ? # Are IPs listed on a DNSBL ? - self.logger_debug("Running DNSBL detection") + self.logger_debug("Running DNS Blacklist detection") + # TODO Test if domain are blacklisted too blacklisted_details = list(self.check_dnsbl(self.get_public_ips())) - print(blacklisted_details) if blacklisted_details: yield dict(meta={"test": "mail_blacklist"}, status="ERROR", @@ -48,11 +96,29 @@ class MailDiagnoser(Diagnoser): status="SUCCESS", summary="diagnosis_mail_blacklist_ok") - # SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser) + # TODO Are outgoing public IPs authorized to send mail by SPF ? + + # TODO Validate DKIM and dmarc ? - # ideally, SPF / DMARC / DKIM validation ... (c.f. https://github.com/alexAubin/yunoScripts/blob/master/yunoDKIM.py possibly though that looks horrible) - # check that the mail queue is not filled with hundreds of email pending + # Is mail queue filled with hundreds of email pending ? + command = 'postqueue -p | grep -c "^[A-Z0-9]"' + output = check_output(command).strip() + try: + pending_emails = int(output) + except ValueError: + yield dict(meta={"test": "mail_queue"}, + status="ERROR", + summary="diagnosis_mail_cannot_get_queue") + else: + if pending_emails > 300: + yield dict(meta={"test": "mail_queue"}, + status="WARNING", + summary="diagnosis_mail_queue_too_many_pending_emails") + else: + yield dict(meta={"test": "mail_queue"}, + status="INFO", + summary="diagnosis_mail_queue_ok") # check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) diff --git a/locales/en.json b/locales/en.json index 93f7680bf..978ceb831 100644 --- a/locales/en.json +++ b/locales/en.json @@ -186,9 +186,17 @@ "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", - "diagnosis_mail_blacklist_ok": "Your server public IP are not listed on email blacklists.", - "diagnosis_mail_blacklist_nok": "Your server public IPs are listed on email blacklists.", + "diagnosis_mail_blacklist_ok": "The public IPs of this instance are not listed on email blacklists.", + "diagnosis_mail_blacklist_nok": "Some of the public IPs of this instance are listed on email blacklists.", "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist_name}. Reason: {reason}. See {blacklist_website}", + "diagnosis_mail_service_working": "Postfix mail service answer correctly.", + "diagnosis_mail_service_not_working": "Postfix mail service don't answer to EHLO request.", + "diagnosis_mail_reverse_dns_missing": "No reverse DNS defined for the ip {ip}.", + "diagnosis_mail_rdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}.", + "diagnosis_mail_rdns_equal_to_ehlo_domain": "Your reverse DNS is equal to your EHLO domain {ehlo_domain} on {ip}.", + "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", + "diagnosis_mail_queue_too_big": "The mail queue has {nb_pending} pending emails in the mail queue. It seems abnormal.", + "diagnosis_mail_queue_unavailable": "The mail queue has {nb_pending} pending emails in the mail queue.", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From da6ae405dd426fabb72d9673bfc2b5ac02accbe2 Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 14 Apr 2020 03:59:33 +0200 Subject: [PATCH 152/317] [fix] Missing pending number args --- data/hooks/diagnosis/24-mail.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index b91bfec85..f1a267641 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -113,10 +113,12 @@ class MailDiagnoser(Diagnoser): else: if pending_emails > 300: yield dict(meta={"test": "mail_queue"}, + data={'nb_pending': pending_emails}, status="WARNING", summary="diagnosis_mail_queue_too_many_pending_emails") else: yield dict(meta={"test": "mail_queue"}, + data={'nb_pending': pending_emails}, status="INFO", summary="diagnosis_mail_queue_ok") From a17adc274c90517b42bdcdf31d9a12b58f43d7d9 Mon Sep 17 00:00:00 2001 From: ljf Date: Sat, 18 Apr 2020 17:08:09 +0200 Subject: [PATCH 153/317] [wip] Small refactoring for mail diagnoser --- data/hooks/diagnosis/24-mail.py | 279 ++++++++++++++++++-------------- locales/en.json | 15 +- 2 files changed, 165 insertions(+), 129 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index f1a267641..1336e8c2b 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -2,15 +2,21 @@ import os import dns.resolver -import smtplib import socket +import re + +from subprocess import CalledProcessError +from types import FunctionType from moulinette.utils.process import check_output from moulinette.utils.network import download_text from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser -from yunohost.domain import _get_maindomain +from yunohost.domain import _get_maindomain, domain_list +from yunohost.utils.error import YunohostError + +DIAGNOSIS_SERVER = "diagnosis.yunohost.org" DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" @@ -22,126 +28,124 @@ class MailDiagnoser(Diagnoser): dependencies = ["ip"] def run(self): - - ips = self.get_public_ips() - # Is outgoing port 25 filtered somehow ? - self.logger_debug("Running outgoing 25 port check") - if os.system('/bin/nc -z -w2 yunohost.org 25') == 0: - yield dict(meta={"test": "ougoing_port_25"}, - status="SUCCESS", - summary="diagnosis_mail_ougoing_port_25_ok") - else: - yield dict(meta={"test": "outgoing_port_25"}, - status="ERROR", - summary="diagnosis_mail_ougoing_port_25_blocked") + self.ehlo_domain = _get_maindomain() + self.mail_domains = domain_list()["domains"] + self.ipversions, self.ips = self.get_ips_checked() - # Get HELO and be sure postfix is running - # TODO SMTP reachability (c.f. check-smtp to be implemented on yunohost's remote diagnoser) - server = None - result = dict(meta={"test": "mail_ehlo"}, - status="SUCCESS", - summary="diagnosis_mail_service_working") - try: - server = smtplib.SMTP("127.0.0.1", 25, timeout=10) - ehlo = server.ehlo() - ehlo_domain = ehlo[1].decode("utf-8").split("\n")[0] - except OSError: - result = dict(meta={"test": "mail_ehlo"}, - status="ERROR", - summary="diagnosis_mail_service_not_working") - ehlo_domain = _get_maindomain() - if server: - server.quit() - yield result + # TODO Is a A/AAAA and MX Record ? + # TODO Are outgoing public IPs authorized to send mail by SPF ? + # TODO Validate DKIM and dmarc ? + # TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) + # TODO check for unusual failed sending attempt being refused in the logs ? + checks = [name for name, value in MailDiagnoser.__dict__.items() + if type(value) == FunctionType and name.startswith("check_")] + for check in checks: + self.logger_debug("Running " + check) + for report in getattr(self, check): + yield report + else: + name = checks[6:] + yield dict(meta={"test": "mail_" + name}, + status="SUCCESS", + summary="diagnosis_mail_" + name + "_ok") - # Forward-confirmed reverse DNS (FCrDNS) verification - self.logger_debug("Running Forward-confirmed reverse DNS check") - for ip in ips: + + def check_outgoing_port_25(self): + """ + Check outgoing port 25 is open and not blocked by router + This check is ran on IPs we could used to send mail. + """ + + for ipversion in self.ipversions: + cmd = '/bin/nc -{ipversion} -z -w2 yunohost.org 25'.format({ + 'ipversion': ipversion}) + if os.system(cmd) != 0: + yield dict(meta={"test": "outgoing_port_25", "ipversion": ipversion}, + data={}, + status="ERROR", + summary="diagnosis_mail_ougoing_port_25_blocked") + + + def check_ehlo(self): + """ + Check the server is reachable from outside and it's the good one + This check is ran on IPs we could used to send mail. + """ + + for ipversion in self.ipversions: + try: + r = Diagnoser.remote_diagnosis('check-smtp', + data={}, + ipversion=ipversion) + except Exception as e: + yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, + data={"error": e}, + status="WARNING", + summary="diagnosis_mail_ehlo_could_not_diagnose") + continue + + if r["status"] == "error_smtp_unreachable": + yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, + data={}, + status="ERROR", + summary="diagnosis_mail_ehlo_unavailable") + elif r["helo"] != self.ehlo_domain: + yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, + data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain}, + status="ERROR", + summary="diagnosis_mail_ehlo_wrong") + + + def check_fcrdns(self): + """ + Check the reverse DNS is well defined by doing a Forward-confirmed + reverse DNS check + This check is ran on IPs we could used to send mail. + """ + + for ip in self.ips: try: rdns_domain, _, _ = socket.gethostbyaddr(ip) - except socket.herror as e: - yield dict(meta={"test": "mail_fcrdns"}, - data={"ip": ip, "ehlo_domain": ehlo_domain}, + except socket.herror: + yield dict(meta={"test": "mail_fcrdns", "ip": ip}, + data={"ehlo_domain": self.ehlo_domain}, status="ERROR", summary="diagnosis_mail_reverse_dns_missing") continue - else: - if rdns_domain != ehlo_domain: - yield dict(meta={"test": "mail_fcrdns"}, - data={"ip": ip, "ehlo_domain": ehlo_domain, - "rdns_domain": rdns_domain}, - status="ERROR", - summary="diagnosis_mail_rdns_different_from_ehlo_domain") - else: - yield dict(meta={"test": "mail_fcrdns"}, - data={"ip": ip, "ehlo_domain": ehlo_domain}, - status="SUCCESS", - summary="diagnosis_mail_rdns_equal_to_ehlo_domain") - - # TODO Is a A/AAAA and MX Record ? - - # Are IPs listed on a DNSBL ? - self.logger_debug("Running DNS Blacklist detection") - # TODO Test if domain are blacklisted too - - blacklisted_details = list(self.check_dnsbl(self.get_public_ips())) - if blacklisted_details: - yield dict(meta={"test": "mail_blacklist"}, - status="ERROR", - summary="diagnosis_mail_blacklist_nok", - details=blacklisted_details) - else: - yield dict(meta={"test": "mail_blacklist"}, - status="SUCCESS", - summary="diagnosis_mail_blacklist_ok") - - # TODO Are outgoing public IPs authorized to send mail by SPF ? - - # TODO Validate DKIM and dmarc ? + if rdns_domain != self.ehlo_domain: + yield dict(meta={"test": "mail_fcrdns", "ip": ip}, + data={"ehlo_domain": self.ehlo_domain, + "rdns_domain": rdns_domain}, + status="ERROR", + summary="diagnosis_mail_rdns_different_from_ehlo_domain") - # Is mail queue filled with hundreds of email pending ? - command = 'postqueue -p | grep -c "^[A-Z0-9]"' - output = check_output(command).strip() - try: - pending_emails = int(output) - except ValueError: - yield dict(meta={"test": "mail_queue"}, - status="ERROR", - summary="diagnosis_mail_cannot_get_queue") - else: - if pending_emails > 300: - yield dict(meta={"test": "mail_queue"}, - data={'nb_pending': pending_emails}, - status="WARNING", - summary="diagnosis_mail_queue_too_many_pending_emails") - else: - yield dict(meta={"test": "mail_queue"}, - data={'nb_pending': pending_emails}, - status="INFO", - summary="diagnosis_mail_queue_ok") - - # check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) - - # check for unusual failed sending attempt being refused in the logs ? - - def check_dnsbl(self, ips): - """ Check with dig onto blacklist DNS server + def check_blacklist(self): """ + Check with dig onto blacklist DNS server + This check is ran on IPs and domains we could used to send mail. + """ + dns_blacklists = read_yaml(DEFAULT_DNS_BLACKLIST) - for ip in ips: + for item in self.ips + self.mail_domains: for blacklist in dns_blacklists: - if "." in ip and not blacklist['ipv4']: + item_type = "domain" + if ":" in item: + item_type = 'ipv6' + elif re.match(r'^\d+\.\d+\.\d+\.\d+$', item): + item_type = 'ipv4' + + if not blacklist[item_type]: continue - if ":" in ip and not blacklist['ipv6']: - continue - # Determine if we are listed on this RBL try: - rev = dns.reversename.from_address(ip) - query = str(rev.split(3)[0]) + '.' + blacklist['dns_server'] + subdomain = item + if item_type != "domain": + rev = dns.reversename.from_address(item) + subdomain = str(rev.split(3)[0]) + query = subdomain + '.' + blacklist['dns_server'] # TODO add timeout lifetime dns.resolver.query(query, "A") except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, @@ -149,32 +153,63 @@ class MailDiagnoser(Diagnoser): continue # Try to get the reason - reason = "not explained" try: reason = str(dns.resolver.query(query, "TXT")[0]) except Exception: - pass + reason = "-" - yield ('diagnosis_mail_blacklisted_by', { - 'ip': ip, - 'blacklist_name': blacklist['name'], - 'blacklist_website': blacklist['website'], - 'reason': reason}) + yield dict(meta={"test": "mail_blacklist", "item": item, + "blacklist": blacklist["dns_server"]}, + data={'blacklist_name': blacklist['name'], + 'blacklist_website': blacklist['website'], + 'reason': reason}, + status="ERROR", + summary='diagnosis_mail_blacklist_listed_by') - def get_public_ips(self): - # Todo code a better way to access a data - ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) - if ipv4: + def check_queue(self): + """ + Check mail queue is not filled with hundreds of email pending + """ + + command = 'postqueue -p | grep -v "Mail queue is empty" | grep -c "^[A-Z0-9]"' + try: + output = check_output(command).strip() + pending_emails = int(output) + except (ValueError, CalledProcessError) as e: + yield dict(meta={"test": "mail_queue"}, + data={"error": e}, + status="ERROR", + summary="diagnosis_mail_cannot_get_queue") + else: + if pending_emails > 100: + yield dict(meta={"test": "mail_queue"}, + data={'nb_pending': pending_emails}, + status="WARNING", + summary="diagnosis_mail_queue_too_many_pending_emails") + else: + yield dict(meta={"test": "mail_queue"}, + data={'nb_pending': pending_emails}, + status="SUCCESS", + summary="diagnosis_mail_queue_ok") + + + def get_ips_checked(self): + outgoing_ipversions = [] + outgoing_ips = [] + ipv4 = Diagnoser.get_cached_report("ip", {"test": "ipv4"}) or {} + if ipv4.get("status") == "SUCCESS": + outgoing_ipversions.append(4) global_ipv4 = ipv4.get("data", {}).get("global", {}) if global_ipv4: - yield global_ipv4 - - ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) - if ipv6: + outgoing_ips.append(global_ipv4) + + ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} + if ipv6.get("status") == "SUCCESS": + outgoing_ipversions.append(6) global_ipv6 = ipv6.get("data", {}).get("global", {}) if global_ipv6: - yield global_ipv6 - + outgoing_ips.append(global_ipv6) + return (outgoing_ipversions, outgoing_ips) def main(args, env, loggers): return MailDiagnoser(args, env, loggers).diagnose() diff --git a/locales/en.json b/locales/en.json index 978ceb831..1a17c484f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -185,18 +185,19 @@ "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", - "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", - "diagnosis_mail_blacklist_ok": "The public IPs of this instance are not listed on email blacklists.", - "diagnosis_mail_blacklist_nok": "Some of the public IPs of this instance are listed on email blacklists.", - "diagnosis_mail_blacklisted_by": "{ip} is listed on {blacklist_name}. Reason: {reason}. See {blacklist_website}", - "diagnosis_mail_service_working": "Postfix mail service answer correctly.", - "diagnosis_mail_service_not_working": "Postfix mail service don't answer to EHLO request.", + "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", + "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", + "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}.", + "diagnosis_mail_ehlo_wrong": "A mail server answer {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}.", + "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside. Error: {error}", "diagnosis_mail_reverse_dns_missing": "No reverse DNS defined for the ip {ip}.", "diagnosis_mail_rdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}.", "diagnosis_mail_rdns_equal_to_ehlo_domain": "Your reverse DNS is equal to your EHLO domain {ehlo_domain} on {ip}.", + "diagnosis_mail_blacklist_ok": "The public IPs of this instance are not listed on email blacklists.", + "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}. Reason: {reason}. See {blacklist_website}", "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", "diagnosis_mail_queue_too_big": "The mail queue has {nb_pending} pending emails in the mail queue. It seems abnormal.", - "diagnosis_mail_queue_unavailable": "The mail queue has {nb_pending} pending emails in the mail queue.", + "diagnosis_mail_queue_ok": "The mail queue has {nb_pending} pending emails in the mail queue.", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From b1124b7080aae3c1750503b430cfc4c067184f7c Mon Sep 17 00:00:00 2001 From: ljf Date: Sat, 18 Apr 2020 19:06:45 +0200 Subject: [PATCH 154/317] [fix] Maildiagnoser typo --- data/hooks/diagnosis/24-mail.py | 22 +++++++++++----------- locales/en.json | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 1336e8c2b..4c36d7ca0 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -24,7 +24,7 @@ DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" class MailDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 600 + cache_duration = 0 dependencies = ["ip"] def run(self): @@ -42,10 +42,11 @@ class MailDiagnoser(Diagnoser): if type(value) == FunctionType and name.startswith("check_")] for check in checks: self.logger_debug("Running " + check) - for report in getattr(self, check): + reports = list(getattr(self, check)()) + for report in reports: yield report - else: - name = checks[6:] + if not reports: + name = check[6:] yield dict(meta={"test": "mail_" + name}, status="SUCCESS", summary="diagnosis_mail_" + name + "_ok") @@ -58,8 +59,7 @@ class MailDiagnoser(Diagnoser): """ for ipversion in self.ipversions: - cmd = '/bin/nc -{ipversion} -z -w2 yunohost.org 25'.format({ - 'ipversion': ipversion}) + cmd = '/bin/nc -{ipversion} -z -w2 yunohost.org 25'.format(ipversion=ipversion) if os.system(cmd) != 0: yield dict(meta={"test": "outgoing_port_25", "ipversion": ipversion}, data={}, @@ -80,7 +80,7 @@ class MailDiagnoser(Diagnoser): ipversion=ipversion) except Exception as e: yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, - data={"error": e}, + data={"error": str(e)}, status="WARNING", summary="diagnosis_mail_ehlo_could_not_diagnose") continue @@ -111,14 +111,14 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "mail_fcrdns", "ip": ip}, data={"ehlo_domain": self.ehlo_domain}, status="ERROR", - summary="diagnosis_mail_reverse_dns_missing") + summary="diagnosis_mail_fcrdns_dns_missing") continue if rdns_domain != self.ehlo_domain: yield dict(meta={"test": "mail_fcrdns", "ip": ip}, data={"ehlo_domain": self.ehlo_domain, "rdns_domain": rdns_domain}, status="ERROR", - summary="diagnosis_mail_rdns_different_from_ehlo_domain") + summary="diagnosis_mail_fcrdns_different_from_ehlo_domain") def check_blacklist(self): @@ -177,9 +177,9 @@ class MailDiagnoser(Diagnoser): pending_emails = int(output) except (ValueError, CalledProcessError) as e: yield dict(meta={"test": "mail_queue"}, - data={"error": e}, + data={"error": str(e)}, status="ERROR", - summary="diagnosis_mail_cannot_get_queue") + summary="diagnosis_mail_queue_unavailable") else: if pending_emails > 100: yield dict(meta={"test": "mail_queue"}, diff --git a/locales/en.json b/locales/en.json index 1a17c484f..327dba2a9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -184,15 +184,15 @@ "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least 256 MB of swap to avoid situations where the system runs out of memory.", "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", - "diagnosis_mail_ougoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", - "diagnosis_mail_ougoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", + "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", + "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}.", "diagnosis_mail_ehlo_wrong": "A mail server answer {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}.", "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside. Error: {error}", - "diagnosis_mail_reverse_dns_missing": "No reverse DNS defined for the ip {ip}.", - "diagnosis_mail_rdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}.", - "diagnosis_mail_rdns_equal_to_ehlo_domain": "Your reverse DNS is equal to your EHLO domain {ehlo_domain} on {ip}.", + "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}.", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}.", + "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured.", "diagnosis_mail_blacklist_ok": "The public IPs of this instance are not listed on email blacklists.", "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}. Reason: {reason}. See {blacklist_website}", "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", From a30ed783da379f4085ec24309002aaa23b8b60e8 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 18 Apr 2020 20:33:30 +0200 Subject: [PATCH 155/317] Improve message about error 500 --- src/yunohost/diagnosis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index aba65a619..f7d2830b6 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -525,7 +525,7 @@ class Diagnoser(): socket.getaddrinfo = old_getaddrinfo if r.status_code not in [200, 400]: - raise Exception("Bad response from diagnosis server.\nURL: %s\nStatus code: %s\nMessage: %s" % (url, r.status_code, r.content)) + raise Exception("The remote diagnosis server failed miserably while trying to diagnose your server. This is most likely an error on Yunohost's infrastructure and not on your side. Please contact the YunoHost team an provide them with the following information.\nURL:
%s
\nStatus code:
%s
" % (url, r.status_code)) if r.status_code == 400: raise Exception("Diagnosis request was refused: %s" % r.content) From 0014fe29033c6eeb2e4238b7283ea342ff72fc34 Mon Sep 17 00:00:00 2001 From: ljf Date: Sat, 18 Apr 2020 20:40:18 +0200 Subject: [PATCH 156/317] [fix] Order of mail checks and mail queue --- data/hooks/diagnosis/24-mail.py | 26 ++++++++++++++++---------- locales/en.json | 30 ++++++++++++++++++------------ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 4c36d7ca0..b122e876a 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -6,15 +6,12 @@ import socket import re from subprocess import CalledProcessError -from types import FunctionType from moulinette.utils.process import check_output -from moulinette.utils.network import download_text from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser from yunohost.domain import _get_maindomain, domain_list -from yunohost.utils.error import YunohostError DIAGNOSIS_SERVER = "diagnosis.yunohost.org" @@ -38,8 +35,8 @@ class MailDiagnoser(Diagnoser): # TODO Validate DKIM and dmarc ? # TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) # TODO check for unusual failed sending attempt being refused in the logs ? - checks = [name for name, value in MailDiagnoser.__dict__.items() - if type(value) == FunctionType and name.startswith("check_")] + checks = ["check_outgoing_port_25", "check_ehlo", "check_fcrdns", + "check_blacklist", "check_queue"] for check in checks: self.logger_debug("Running " + check) reports = list(getattr(self, check)()) @@ -64,7 +61,9 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "outgoing_port_25", "ipversion": ipversion}, data={}, status="ERROR", - summary="diagnosis_mail_ougoing_port_25_blocked") + summary="diagnosis_mail_ougoing_port_25_blocked", + details=["diagnosis_mail_ougoing_port_25_blocked_details", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn"]) def check_ehlo(self): @@ -82,7 +81,8 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, data={"error": str(e)}, status="WARNING", - summary="diagnosis_mail_ehlo_could_not_diagnose") + summary="diagnosis_mail_ehlo_could_not_diagnose", + details=["diagnosis_mail_ehlo_could_not_diagnose_details"]) continue if r["status"] == "error_smtp_unreachable": @@ -153,25 +153,30 @@ class MailDiagnoser(Diagnoser): continue # Try to get the reason + details = [] try: reason = str(dns.resolver.query(query, "TXT")[0]) + details.append("diagnosis_mail_blacklist_reason") except Exception: reason = "-" + details.append("diagnosis_mail_blacklist_website") + yield dict(meta={"test": "mail_blacklist", "item": item, "blacklist": blacklist["dns_server"]}, data={'blacklist_name': blacklist['name'], 'blacklist_website': blacklist['website'], 'reason': reason}, status="ERROR", - summary='diagnosis_mail_blacklist_listed_by') + summary='diagnosis_mail_blacklist_listed_by', + details=details) def check_queue(self): """ Check mail queue is not filled with hundreds of email pending """ - command = 'postqueue -p | grep -v "Mail queue is empty" | grep -c "^[A-Z0-9]"' + command = 'postqueue -p | grep -v "Mail queue is empty" | grep -c "^[A-Z0-9]" || true' try: output = check_output(command).strip() pending_emails = int(output) @@ -179,7 +184,8 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "mail_queue"}, data={"error": str(e)}, status="ERROR", - summary="diagnosis_mail_queue_unavailable") + summary="diagnosis_mail_queue_unavailable", + details="diagnosis_mail_queue_unavailable_details") else: if pending_emails > 100: yield dict(meta={"test": "mail_queue"}, diff --git a/locales/en.json b/locales/en.json index 327dba2a9..d2f4a925b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -184,20 +184,26 @@ "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least 256 MB of swap to avoid situations where the system runs out of memory.", "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", - "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is not blocked and email can be sent to other servers.", - "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. You should try to unblock it in your internet service provider (or hosting provider) configuration panel. Meanwhile, the server won't be able to send emails to other servers.", + "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent", + "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be bloecked in IPv{ipversion}", + "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock it in your internet service provider (or hosting provider) configuration panel or by sending a ticket to your hosting provider. Meanwhile, the server won't be able to send emails to other servers.", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", - "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}.", - "diagnosis_mail_ehlo_wrong": "A mail server answer {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}.", - "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside. Error: {error}", - "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}.", - "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}.", - "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured.", - "diagnosis_mail_blacklist_ok": "The public IPs of this instance are not listed on email blacklists.", - "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}. Reason: {reason}. See {blacklist_website}", + "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}", + "diagnosis_mail_ehlo_wrong": "A mail server answers {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}", + "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", + "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", + "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}", + "diagnosis_mail_blacklist_ok": "IPs and domains used by this server to send mail are not on most used email blacklists", + "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}", + "diagnosis_mail_blacklist_reason": "The blacklist explains: {reason}", + "diagnosis_mail_blacklist_website": "After identifying why you are listed and fixed it, feel free to ask for delisting on {blacklist_website}", + "diagnosis_mail_queue_ok": "{nb_pending} pending emails in the mail queues", "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", - "diagnosis_mail_queue_too_big": "The mail queue has {nb_pending} pending emails in the mail queue. It seems abnormal.", - "diagnosis_mail_queue_ok": "The mail queue has {nb_pending} pending emails in the mail queue.", + "diagnosis_mail_queue_unavailable_details": "Error: {error}", + "diagnosis_mail_queue_too_big": "Too many pending emails in mail queue ({nb_pending} emails)", "diagnosis_regenconf_allgood": "All configurations files are in line with the recommended configuration!", "diagnosis_regenconf_manually_modified": "Configuration file {file} appears to have been manually modified.", "diagnosis_regenconf_manually_modified_details": "This is probably OK if you know what you're doing! YunoHost will stop updating this file automatically... But beware that YunoHost upgrades could contain important recommended changes. If you want to, you can inspect the differences with yunohost tools regen-conf {category} --dry-run --with-diff and force the reset to the recommended configuration with yunohost tools regen-conf {category} --force", From 7818eb39464846bbfb1c65aea7d6326520b48c86 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 00:26:33 +0200 Subject: [PATCH 157/317] Better handling of failure to use the remote-diagnosis --- data/hooks/diagnosis/14-ports.py | 10 +++++++++- data/hooks/diagnosis/21-web.py | 11 ++++++++++- data/hooks/diagnosis/24-mail.py | 2 -- locales/en.json | 10 ++++++---- src/yunohost/diagnosis.py | 2 +- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/data/hooks/diagnosis/14-ports.py b/data/hooks/diagnosis/14-ports.py index a4459d92f..bd68c60d6 100644 --- a/data/hooks/diagnosis/14-ports.py +++ b/data/hooks/diagnosis/14-ports.py @@ -47,8 +47,16 @@ class PortsDiagnoser(Diagnoser): ipversion=ipversion) results[ipversion] = r["ports"] except Exception as e: - raise YunohostError("diagnosis_ports_could_not_diagnose", error=e) + yield dict(meta={"reason": "remote_diagnosis_failed", "ipversion": ipversion}, + data={"error": str(e)}, + status="WARNING", + summary="diagnosis_ports_could_not_diagnose", + details=["diagnosis_ports_could_not_diagnose_details"]) + continue + ipversions = results.keys() + if not ipversions: + return for port, service in sorted(ports.items()): port = str(port) diff --git a/data/hooks/diagnosis/21-web.py b/data/hooks/diagnosis/21-web.py index 09f5b2b73..c1f6d912a 100644 --- a/data/hooks/diagnosis/21-web.py +++ b/data/hooks/diagnosis/21-web.py @@ -96,7 +96,16 @@ class WebDiagnoser(Diagnoser): ipversion=ipversion) results[ipversion] = r["http"] except Exception as e: - raise YunohostError("diagnosis_http_could_not_diagnose", error=e) + yield dict(meta={"reason": "remote_diagnosis_failed", "ipversion": ipversion}, + data={"error": str(e)}, + status="WARNING", + summary="diagnosis_http_could_not_diagnose", + details=["diagnosis_http_could_not_diagnose_details"]) + continue + + ipversions = results.keys() + if not ipversions: + return for domain in domains: diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index b122e876a..0ce1f3f25 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -13,8 +13,6 @@ from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser from yunohost.domain import _get_maindomain, domain_list -DIAGNOSIS_SERVER = "diagnosis.yunohost.org" - DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" diff --git a/locales/en.json b/locales/en.json index d2f4a925b..4a0aefca8 100644 --- a/locales/en.json +++ b/locales/en.json @@ -191,8 +191,8 @@ "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}", "diagnosis_mail_ehlo_wrong": "A mail server answers {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}", - "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside", - "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", + "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", + "diagnosis_mail_ehlo_could_not_diagnose_details": "{error}", "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}", @@ -220,7 +220,8 @@ "diagnosis_description_mail": "Email", "diagnosis_description_regenconf": "System configurations", "diagnosis_description_security": "Security checks", - "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}", + "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.", + "diagnosis_ports_could_not_diagnose_details": "Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", @@ -228,7 +229,8 @@ "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", - "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", + "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", + "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index f7d2830b6..bd52f57f8 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -525,7 +525,7 @@ class Diagnoser(): socket.getaddrinfo = old_getaddrinfo if r.status_code not in [200, 400]: - raise Exception("The remote diagnosis server failed miserably while trying to diagnose your server. This is most likely an error on Yunohost's infrastructure and not on your side. Please contact the YunoHost team an provide them with the following information.\nURL:
%s
\nStatus code:
%s
" % (url, r.status_code)) + raise Exception("The remote diagnosis server failed miserably while trying to diagnose your server. This is most likely an error on Yunohost's infrastructure and not on your side. Please contact the YunoHost team an provide them with the following information.
URL: %s
Status code: %s" % (url, r.status_code)) if r.status_code == 400: raise Exception("Diagnosis request was refused: %s" % r.content) From 3c174389b64581dd91581c424f7299f637e1f00c Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 00:48:54 +0200 Subject: [PATCH 158/317] [enh] Add some details --- data/hooks/diagnosis/24-mail.py | 13 ++++++++----- locales/ca.json | 2 +- locales/en.json | 19 +++++++++++-------- locales/eo.json | 2 +- locales/es.json | 2 +- locales/fr.json | 2 +- tests/test_i18n_keys.py | 7 +++++++ 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 0ce1f3f25..27903c9e9 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -59,8 +59,8 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "outgoing_port_25", "ipversion": ipversion}, data={}, status="ERROR", - summary="diagnosis_mail_ougoing_port_25_blocked", - details=["diagnosis_mail_ougoing_port_25_blocked_details", + summary="diagnosis_mail_outgoing_port_25_blocked", + details=["diagnosis_mail_outgoing_port_25_blocked_details", "diagnosis_mail_outgoing_port_25_blocked_relay_vpn"]) @@ -76,18 +76,21 @@ class MailDiagnoser(Diagnoser): data={}, ipversion=ipversion) except Exception as e: - yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, + yield dict(meta={"test": "mail_ehlo", "reason": "remote_server_failed", + "ipversion": ipversion}, data={"error": str(e)}, status="WARNING", summary="diagnosis_mail_ehlo_could_not_diagnose", details=["diagnosis_mail_ehlo_could_not_diagnose_details"]) continue - if r["status"] == "error_smtp_unreachable": + if r["status"] != "ok": + summary = r["status"].replace("error_smtp_", "diagnosis_mail_ehlo_") yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, data={}, status="ERROR", - summary="diagnosis_mail_ehlo_unavailable") + summary=summary, + details=[summary + "_details"]) elif r["helo"] != self.ehlo_domain: yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain}, diff --git a/locales/ca.json b/locales/ca.json index 0ea0d91f6..c20b94d6e 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -571,7 +571,7 @@ "apps_catalog_obsolete_cache": "La memòria cau del catàleg d'aplicacions és buida o obsoleta.", "apps_catalog_update_success": "S'ha actualitzat el catàleg d'aplicacions!", "diagnosis_mail_ougoing_port_25_ok": "El port de sortida 25 no està bloquejat i els correus es poden enviar a altres servidors.", - "diagnosis_mail_ougoing_port_25_blocked": "Sembla que el port de sortida 25 està bloquejat. Hauríeu d'intentar desbloquejar-lo al panell de configuració del proveïdor d'accés a internet (o allotjador). Mentrestant, el servidor no podrà enviar correus a altres servidors.", + "diagnosis_mail_outgoing_port_25_blocked": "Sembla que el port de sortida 25 està bloquejat. Hauríeu d'intentar desbloquejar-lo al panell de configuració del proveïdor d'accés a internet (o allotjador). Mentrestant, el servidor no podrà enviar correus a altres servidors.", "diagnosis_description_mail": "Correu electrònic", "migration_description_0013_futureproof_apps_catalog_system": "Migrar al nou sistema de catàleg d'aplicacions resistent al pas del temps", "app_upgrade_script_failed": "Hi ha hagut un error en el script d'actualització de l'aplicació", diff --git a/locales/en.json b/locales/en.json index 4a0aefca8..63cef236b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -189,12 +189,17 @@ "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock it in your internet service provider (or hosting provider) configuration panel or by sending a ticket to your hosting provider. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", - "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}", - "diagnosis_mail_ehlo_wrong": "A mail server answers {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}", - "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", - "diagnosis_mail_ehlo_could_not_diagnose_details": "{error}", + "diagnosis_mail_ehlo_unreachable": "SMTP server unreachable on IPv{ipversion}", + "diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 through IPv{ipversion}, probably because of a firewall, port forwarding issue or postfix service down", + "diagnosis_mail_ehlo_bad_answer": "A non-SMTP service answered on port 25 on IPv{ipversion}", + "diagnosis_mail_ehlo_bad_answer_details": "It could be due to an other machine answering instead of your server.", + "diagnosis_mail_ehlo_wrong": "An other SMTP server answers on IPv{ipversion}", + "diagnosis_mail_ehlo_wrong_details": "The remote diagnoser return a wrong EHLO answer from your IPv{ipversion}.
Received: {wrong_ehlo}
Expected: {right_ehlo}
You probably have a port forwarding issue or a reverse proxy server unconfigured for mail.", + "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", + "diagnosis_mail_fcrdns_dns_missing_details": "You can configure it on ", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}", "diagnosis_mail_blacklist_ok": "IPs and domains used by this server to send mail are not on most used email blacklists", "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}", @@ -220,8 +225,7 @@ "diagnosis_description_mail": "Email", "diagnosis_description_regenconf": "System configurations", "diagnosis_description_security": "Security checks", - "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.", - "diagnosis_ports_could_not_diagnose_details": "Error: {error}", + "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", @@ -229,8 +233,7 @@ "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", - "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", - "diagnosis_http_could_not_diagnose_details": "Error: {error}", + "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", diff --git a/locales/eo.json b/locales/eo.json index 87e062ea2..9c1aed008 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -515,7 +515,7 @@ "app_upgrade_script_failed": "Eraro okazis en la skripto pri ĝisdatiga programo", "diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.", "diagnosis_ram_verylow": "La sistemo nur restas {available} ({available_percent}%) RAM! (el {total})", - "diagnosis_mail_ougoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.", + "diagnosis_mail_outgoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.", "diagnosis_http_bad_status_code": "Ne povis atingi vian servilon kiel atendite, ĝi redonis malbonan statuskodon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via nginx-agordo ĝisdatigas kaj ke reverso-prokuro ne interbatalas.", "main_domain_changed": "La ĉefa domajno estis ŝanĝita", "yunohost_postinstall_end_tip": "La post-instalado finiĝis! Por fini vian agordon, bonvolu konsideri:\n - aldonado de unua uzanto tra la sekcio 'Uzantoj' de la retadreso (aŭ 'yunohost user create ' en komandlinio);\n - diagnozi problemojn atendantajn solvi por ke via servilo funkciu kiel eble plej glate tra la sekcio 'Diagnosis' de la retadministrado (aŭ 'yunohost diagnosis run' en komandlinio);\n - legante la partojn 'Finigi vian agordon' kaj 'Ekkoni Yunohost' en la administra dokumentado: https://yunohost.org/admindoc.", diff --git a/locales/es.json b/locales/es.json index 6a55378da..de9eb91c6 100644 --- a/locales/es.json +++ b/locales/es.json @@ -554,7 +554,7 @@ "diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos 256 MB de espacio de intercambio para evitar que el sistema se quede sin memoria.", "diagnosis_swap_notsomuch": "Al sistema le queda solamente {total} de espacio de intercambio. Considera agregar al menos 256 MB para evitar que el sistema se quede sin memoria.", "diagnosis_mail_ougoing_port_25_ok": "El puerto de salida 25 no esta bloqueado y los correos electrónicos pueden ser enviados a otros servidores.", - "diagnosis_mail_ougoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.", + "diagnosis_mail_outgoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.", "diagnosis_regenconf_allgood": "Todos los archivos de configuración están en linea con la configuración recomendada!", "diagnosis_regenconf_manually_modified": "El archivo de configuración {file} fue modificado manualmente.", "diagnosis_regenconf_manually_modified_details": "Esto este probablemente BIEN siempre y cuando sepas lo que estas haciendo ;) !", diff --git a/locales/fr.json b/locales/fr.json index f029a1d13..faf2837a3 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -551,7 +551,7 @@ "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n'a été trouvée.", "apps_catalog_init_success": "Système de catalogue d'applications initialisé !", "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}", - "diagnosis_mail_ougoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d'autres serveurs.", + "diagnosis_mail_outgoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d'autres serveurs.", "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s'agit du domaine principal et de votre seul domaine. Vous devez d'abord ajouter un autre domaine à l'aide de 'yunohost domain add ', puis définir comme domaine principal à l'aide de ' yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l'aide de 'yunohost domain remove {domain:s}'.'", "diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d'informations.", "diagnosis_description_basesystem": "Système de base", diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 0d5af33f6..20e9dd8a0 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -122,6 +122,13 @@ def find_expected_string_keys(): yield "password_listed" for i in [1, 2, 3, 4]: yield "password_too_simple_%s" % i + + checks = ["outgoing_port_25_ok", "ehlo_ok", "fcrdns_ok", + "blacklist_ok", "queue_ok", "ehlo_bad_answer", + "ehlo_unreachable", "ehlo_bad_answer_details", + "ehlo_unreachable_details", ] + for check in checks: + yield "diagnosis_mail_%" ############################################################################### # Load en locale json keys # From 55957d77b09386c48362590702a306029983fe9d Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 00:52:28 +0200 Subject: [PATCH 159/317] [fix] Key queue_to_big --- data/hooks/diagnosis/24-mail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 27903c9e9..608bfd931 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -192,7 +192,7 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "mail_queue"}, data={'nb_pending': pending_emails}, status="WARNING", - summary="diagnosis_mail_queue_too_many_pending_emails") + summary="diagnosis_mail_queue_too_big") else: yield dict(meta={"test": "mail_queue"}, data={'nb_pending': pending_emails}, From dae8adff4b21aaa74657ae317c9caf2b717ae42f Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 01:02:30 +0200 Subject: [PATCH 160/317] [fix] rebase issue --- locales/en.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index 63cef236b..3be85fd35 100644 --- a/locales/en.json +++ b/locales/en.json @@ -225,7 +225,8 @@ "diagnosis_description_mail": "Email", "diagnosis_description_regenconf": "System configurations", "diagnosis_description_security": "Security checks", - "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside. Error: {error}", + "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside.", + "diagnosis_ports_could_not_diagnose_details": "Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.", "diagnosis_ports_ok": "Port {port} is reachable from outside.", @@ -233,7 +234,8 @@ "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", - "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside. Error: {error}", + "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside.", + "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", From 0ac1cfb31aea189c44671f3b889057c2e6c4c1cc Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 01:04:02 +0200 Subject: [PATCH 161/317] [fix] rebase issue --- locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index 3be85fd35..92067229f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -225,7 +225,7 @@ "diagnosis_description_mail": "Email", "diagnosis_description_regenconf": "System configurations", "diagnosis_description_security": "Security checks", - "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside.", + "diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.", "diagnosis_ports_could_not_diagnose_details": "Error: {error}", "diagnosis_ports_unreachable": "Port {port} is not reachable from outside.", "diagnosis_ports_partially_unreachable": "Port {port} is not reachable from outside in IPv{failed}.", @@ -234,7 +234,7 @@ "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", - "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside.", + "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside in IPv{ipversion}.", "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", From a7a0f93102b617f7a344498a496c3fbc5d84b09a Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 01:05:36 +0200 Subject: [PATCH 162/317] [fix] rebase issue --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 92067229f..8272fc86c 100644 --- a/locales/en.json +++ b/locales/en.json @@ -234,7 +234,7 @@ "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", - "diagnosis_http_could_not_diagnose": "Could not diagnose if domain is reachable from outside in IPv{ipversion}.", + "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", From 91a07bdf08ee4eecdcb1734493fed31fccb7ecd3 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 01:07:06 +0200 Subject: [PATCH 163/317] [fix] tests i18n key --- tests/test_i18n_keys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 20e9dd8a0..c845a2e3e 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -128,7 +128,7 @@ def find_expected_string_keys(): "ehlo_unreachable", "ehlo_bad_answer_details", "ehlo_unreachable_details", ] for check in checks: - yield "diagnosis_mail_%" + yield "diagnosis_mail_%" % check ############################################################################### # Load en locale json keys # From 9d0074d71bb53f9a0ac6a6d28acf1a74aef7b521 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 01:15:21 +0200 Subject: [PATCH 164/317] [fix] tests i18n key --- tests/test_i18n_keys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index c845a2e3e..7546f51aa 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -128,7 +128,7 @@ def find_expected_string_keys(): "ehlo_unreachable", "ehlo_bad_answer_details", "ehlo_unreachable_details", ] for check in checks: - yield "diagnosis_mail_%" % check + yield "diagnosis_mail_%s" % check ############################################################################### # Load en locale json keys # From 8aced5b4ce2e7b55da7681d602085eec3d78a861 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 01:30:22 +0200 Subject: [PATCH 165/317] Let's cache mail diagnosis with a duration similar to other checks... --- data/hooks/diagnosis/24-mail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 0ce1f3f25..c2f898e65 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -19,7 +19,7 @@ DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" class MailDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 0 + cache_duration = 600 dependencies = ["ip"] def run(self): From 3cb47a226f948af74d8625b7e9197cf5bd9bf67c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 01:43:27 +0200 Subject: [PATCH 166/317] More flexible warning about swap size... Move it to 512 MiB 'cause 256 MiB really aint much I think --- data/hooks/diagnosis/50-systemresources.py | 4 ++-- locales/ca.json | 4 ++-- locales/en.json | 4 ++-- locales/eo.json | 4 ++-- locales/es.json | 4 ++-- locales/fr.json | 4 ++-- locales/oc.json | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index ab9ead7bb..417b88ae7 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -43,11 +43,11 @@ class SystemResourcesDiagnoser(Diagnoser): swap = psutil.swap_memory() item = dict(meta={"test": "swap"}, - data={"total": human_size(swap.total)}) + data={"total": human_size(swap.total), "recommended": "512 MiB"}) if swap.total <= 1 * MB: item["status"] = "ERROR" item["summary"] = "diagnosis_swap_none" - elif swap.total <= 256 * MB: + elif swap.total <= 512 * MB: item["status"] = "WARNING" item["summary"] = "diagnosis_swap_notsomuch" else: diff --git a/locales/ca.json b/locales/ca.json index 0ea0d91f6..07e2c6f27 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -503,7 +503,7 @@ "app_remove_after_failed_install": "Eliminant l'aplicació després que hagi fallat la instal·lació…", "diagnosis_basesystem_ynh_main_version": "El servidor funciona amb YunoHost {main_version} ({repo})", "diagnosis_ram_low": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}. Aneu amb compte.", - "diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de 256 MB de swap per evitar situacions en les que el sistema es queda sense memòria.", + "diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de {recommended} de swap per evitar situacions en les que el sistema es queda sense memòria.", "diagnosis_regenconf_manually_modified": "El fitxer de configuració {file} ha estat modificat manualment.", "diagnosis_security_vulnerable_to_meltdown_details": "Per arreglar-ho, hauríeu d'actualitzar i reiniciar el sistema per tal de carregar el nou nucli de linux (o contactar amb el proveïdor del servidor si no funciona). Vegeu https://meltdownattack.com/ per a més informació.", "diagnosis_http_could_not_diagnose": "No s'ha pogut diagnosticar si el domini és accessible des de l'exterior. Error: {error}", @@ -543,7 +543,7 @@ "diagnosis_diskusage_ok": "El lloc d'emmagatzematge {mountpoint} (en l'aparell {device}) encara té {free} ({free_percent}%) lliures!", "diagnosis_ram_verylow": "El sistema només té {available} ({available_percent}%) de memòria RAM disponibles! (d'un total de {total})", "diagnosis_ram_ok": "El sistema encara té {available} ({available_percent}%) de memòria RAM disponibles d'un total de {total}.", - "diagnosis_swap_notsomuch": "El sistema només té {total} de swap. Hauríeu de considerar tenir un mínim de 256 MB per evitar situacions en les que el sistema es queda sense memòria.", + "diagnosis_swap_notsomuch": "El sistema només té {total} de swap. Hauríeu de considerar tenir un mínim de {recommended} per evitar situacions en les que el sistema es queda sense memòria.", "diagnosis_swap_ok": "El sistema té {total} de swap!", "diagnosis_regenconf_allgood": "Tots els fitxers de configuració estan en acord amb la configuració recomanada!", "diagnosis_regenconf_manually_modified_details": "No hauria de ser cap problema sempre i quan sapigueu el que esteu fent ;) !", diff --git a/locales/en.json b/locales/en.json index 4a0aefca8..a5048b8c9 100644 --- a/locales/en.json +++ b/locales/en.json @@ -181,8 +181,8 @@ "diagnosis_ram_verylow": "The system has only {available} ({available_percent}%) RAM available! (out of {total})", "diagnosis_ram_low": "The system has {available} ({available_percent}%) RAM available (out of {total}). Be careful.", "diagnosis_ram_ok": "The system still has {available} ({available_percent}%) RAM available out of {total}.", - "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least 256 MB of swap to avoid situations where the system runs out of memory.", - "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", + "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least {recommended} of swap to avoid situations where the system runs out of memory.", + "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least {recommended} to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent", "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be bloecked in IPv{ipversion}", diff --git a/locales/eo.json b/locales/eo.json index 87e062ea2..36396d6f1 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -531,8 +531,8 @@ "diagnosis_dns_good_conf": "Bona DNS-agordo por domajno {domain} (kategorio {category})", "diagnosis_dns_bad_conf": "Malbona / mankas DNS-agordo por domajno {domain} (kategorio {category})", "diagnosis_ram_ok": "La sistemo ankoraŭ havas {available} ({available_percent}%) RAM forlasita de {total}.", - "diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ 256 MB da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.", - "diagnosis_swap_notsomuch": "La sistemo havas nur {total}-interŝanĝon. Vi konsideru havi almenaŭ 256 MB por eviti situaciojn en kiuj la sistemo restas sen memoro.", + "diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ {recommended} da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.", + "diagnosis_swap_notsomuch": "La sistemo havas nur {total}-interŝanĝon. Vi konsideru havi almenaŭ {recommended} por eviti situaciojn en kiuj la sistemo restas sen memoro.", "diagnosis_regenconf_manually_modified_details": "Ĉi tio probable estas bona tiel longe kiel vi scias kion vi faras;)!", "diagnosis_regenconf_manually_modified_debian": "Agordodosiero {file} estis modifita permane kompare kun la defaŭlta Debian.", "diagnosis_regenconf_manually_modified_debian_details": "Ĉi tio probable estas bona, sed devas observi ĝin...", diff --git a/locales/es.json b/locales/es.json index 6a55378da..c21585e7b 100644 --- a/locales/es.json +++ b/locales/es.json @@ -551,8 +551,8 @@ "diagnosis_ram_verylow": "Al sistema le queda solamente {available} ({available_percent}%) de RAM! (De un total de {total})", "diagnosis_ram_low": "Al sistema le queda {available} ({available_percent}%) de RAM de un total de {total}. Cuidado.", "diagnosis_ram_ok": "El sistema aun tiene {available} ({available_percent}%) de RAM de un total de {total}.", - "diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos 256 MB de espacio de intercambio para evitar que el sistema se quede sin memoria.", - "diagnosis_swap_notsomuch": "Al sistema le queda solamente {total} de espacio de intercambio. Considera agregar al menos 256 MB para evitar que el sistema se quede sin memoria.", + "diagnosis_swap_none": "El sistema no tiene mas espacio de intercambio. Considera agregar por lo menos {recommended} de espacio de intercambio para evitar que el sistema se quede sin memoria.", + "diagnosis_swap_notsomuch": "Al sistema le queda solamente {total} de espacio de intercambio. Considera agregar al menos {recommended} para evitar que el sistema se quede sin memoria.", "diagnosis_mail_ougoing_port_25_ok": "El puerto de salida 25 no esta bloqueado y los correos electrónicos pueden ser enviados a otros servidores.", "diagnosis_mail_ougoing_port_25_blocked": "El puerto de salida 25 parece estar bloqueado. Intenta desbloquearlo con el panel de configuración de tu proveedor de servicios de Internet (o proveedor de halbergue). Mientras tanto, el servidor no podrá enviar correos electrónicos a otros servidores.", "diagnosis_regenconf_allgood": "Todos los archivos de configuración están en linea con la configuración recomendada!", diff --git a/locales/fr.json b/locales/fr.json index f029a1d13..7e77cdc7a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -541,8 +541,8 @@ "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Faites attention.", "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", "diagnosis_ram_low": "Le système n'a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", - "diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d'avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", + "diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins {recommended} de swap pour éviter les situations où le système manque de mémoire.", + "diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d'avoir au moins {recommended} pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", diff --git a/locales/oc.json b/locales/oc.json index eebfaac64..97978bb18 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -568,6 +568,6 @@ "diagnosis_diskusage_verylow": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a solament {free} ({free_percent}%). Deuriatz considerar de liberar un pauc d’espaci.", "global_settings_setting_pop3_enabled": "Activar lo protocòl POP3 pel servidor de corrièr", "diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free} ({free_percent}%) de liure !", - "diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria.", - "diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens 256 Mo d’escambi per evitar las situacions ont lo sistèma manca de memòria." + "diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria.", + "diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria." } From 97ab8c91f86c43dcec728253a2e3bd6a8304208c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 02:03:35 +0200 Subject: [PATCH 167/317] Fix the fix for stupid 'search' stuff in resolvconf ... + let's in fact ignore it if it does exists in /etc/resolv.conf >.> --- data/hooks/conf_regen/43-dnsmasq | 6 +++--- data/hooks/diagnosis/10-ip.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/hooks/conf_regen/43-dnsmasq b/data/hooks/conf_regen/43-dnsmasq index d6ab8648c..59a1f8a06 100755 --- a/data/hooks/conf_regen/43-dnsmasq +++ b/data/hooks/conf_regen/43-dnsmasq @@ -59,9 +59,9 @@ do_post_regen() { sed -E "s/^(domain|search)/#\1/g" -i /run/resolvconf/interface/*.dhclient fi - grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede domain-name "";' >> /etc/dhcp/dhclient.conf - grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede domain-search "";' >> /etc/dhcp/dhclient.conf - grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo '^supersede name "";' >> /etc/dhcp/dhclient.conf + grep -q '^supersede domain-name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-name "";' >> /etc/dhcp/dhclient.conf + grep -q '^supersede domain-search "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede domain-search "";' >> /etc/dhcp/dhclient.conf + grep -q '^supersede name "";' /etc/dhcp/dhclient.conf 2>/dev/null || echo 'supersede name "";' >> /etc/dhcp/dhclient.conf systemctl restart resolvconf fi diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index 6571ca556..c0d35278c 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -134,7 +134,7 @@ class IPDiagnoser(Diagnoser): def good_resolvconf(self): content = read_file("/etc/resolv.conf").strip().split("\n") # Ignore comments and empty lines - content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#")] + content = [l.strip() for l in content if l.strip() and not l.strip().startswith("#") and not l.strip().startswith("search")] # We should only find a "nameserver 127.0.0.1" return len(content) == 1 and content[0].split() == ["nameserver", "127.0.0.1"] From 4686673bb52c6181cbed60105917cb32d9c43a3d Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 02:30:23 +0200 Subject: [PATCH 168/317] [enh] Be able to disable ipv6 for smtp --- data/hooks/conf_regen/19-postfix | 3 ++- data/hooks/diagnosis/24-mail.py | 31 ++++++++++++++++++++++--------- locales/en.json | 9 ++++++--- src/yunohost/settings.py | 1 + 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 0f09f0299..172438f37 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -35,7 +35,8 @@ do_pre_regen() { > "${default_dir}/postsrsd" # adapt it for IPv4-only hosts - if [ ! -f /proc/net/if_inet6 ]; then + ipv6="$(yunohost settings get 'smtp.ipv6')" + if [ "$ipv6" == "False" ] || [ ! -f /proc/net/if_inet6 ]; then sed -i \ 's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \ "${postfix_dir}/main.cf" diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 608bfd931..022b24114 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -12,6 +12,7 @@ from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser from yunohost.domain import _get_maindomain, domain_list +from yunohost.settings import settings_get DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" @@ -95,7 +96,8 @@ class MailDiagnoser(Diagnoser): yield dict(meta={"test": "mail_ehlo", "ipversion": ipversion}, data={"wrong_ehlo": r["helo"], "right_ehlo": self.ehlo_domain}, status="ERROR", - summary="diagnosis_mail_ehlo_wrong") + summary="diagnosis_mail_ehlo_wrong", + details=["diagnosis_mail_ehlo_wrong_details"]) def check_fcrdns(self): @@ -106,20 +108,30 @@ class MailDiagnoser(Diagnoser): """ for ip in self.ips: + if ":" in ip: + details = ["diagnosis_mail_fcrdns_nok_details", + "diagnosis_mail_fcrdns_nok_alternatives_6"] + else: + details = ["diagnosis_mail_fcrdns_nok_details", + "diagnosis_mail_fcrdns_nok_alternatives_4"] + try: rdns_domain, _, _ = socket.gethostbyaddr(ip) except socket.herror: yield dict(meta={"test": "mail_fcrdns", "ip": ip}, data={"ehlo_domain": self.ehlo_domain}, status="ERROR", - summary="diagnosis_mail_fcrdns_dns_missing") + summary="diagnosis_mail_fcrdns_dns_missing", + details=details) continue if rdns_domain != self.ehlo_domain: + details = ["diagnosis_mail_fcrdns_different_from_ehlo_domain_details"] + details yield dict(meta={"test": "mail_fcrdns", "ip": ip}, data={"ehlo_domain": self.ehlo_domain, "rdns_domain": rdns_domain}, status="ERROR", - summary="diagnosis_mail_fcrdns_different_from_ehlo_domain") + summary="diagnosis_mail_fcrdns_different_from_ehlo_domain", + details=details) def check_blacklist(self): @@ -210,12 +222,13 @@ class MailDiagnoser(Diagnoser): if global_ipv4: outgoing_ips.append(global_ipv4) - ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} - if ipv6.get("status") == "SUCCESS": - outgoing_ipversions.append(6) - global_ipv6 = ipv6.get("data", {}).get("global", {}) - if global_ipv6: - outgoing_ips.append(global_ipv6) + if settings_get("smtp.ipv6"): + ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} + if ipv6.get("status") == "SUCCESS": + outgoing_ipversions.append(6) + global_ipv6 = ipv6.get("data", {}).get("global", {}) + if global_ipv6: + outgoing_ips.append(global_ipv6) return (outgoing_ipversions, outgoing_ips) def main(args, env, loggers): diff --git a/locales/en.json b/locales/en.json index 8272fc86c..0fc9ca777 100644 --- a/locales/en.json +++ b/locales/en.json @@ -185,7 +185,7 @@ "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least 256 MB to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent", - "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be bloecked in IPv{ipversion}", + "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}", "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock it in your internet service provider (or hosting provider) configuration panel or by sending a ticket to your hosting provider. Meanwhile, the server won't be able to send emails to other servers.", "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", @@ -199,8 +199,11 @@ "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", - "diagnosis_mail_fcrdns_dns_missing_details": "You can configure it on ", - "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}", + "diagnosis_mail_fcrdns_nok_details": "You should first try to configure the reverse DNS with {ehlo_domain} on your internet service provider (or hosting provider) config panel or by sending a ticket to your hosting provider. Meanwhile, some outgoing mails won't be delivered.", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure it or the feature is broken on their config panel. If you are experiencing some server refusing your email for this reason, you could try those solutions:
- Some ISP provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", + "diagnosis_mail_fcrdns_nok_alternatives_6": "Some providers won't let you configure it or the feature is broken on their config panel in IPv6. If your reverse DNS is ok in IPv4, you can try to disable the use of IPv6 to send mail by running yunohost settings set smtp.ipv6 -v off ; yunohost tools regen-conf postfix. Note: with this last solution you won't be able to send or received emails from the rare ipv6 only servers.", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "The reverse DNS is different from your EHLO domain on {ip}", + "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Current reverse DNS: {rdns_domain}
Expected value: {ehlo_domain}", "diagnosis_mail_blacklist_ok": "IPs and domains used by this server to send mail are not on most used email blacklists", "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}", "diagnosis_mail_blacklist_reason": "The blacklist explains: {reason}", diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index 72477e4de..c016e0809 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -70,6 +70,7 @@ DEFAULTS = OrderedDict([ ("security.postfix.compatibility", {"type": "enum", "default": "intermediate", "choices": ["intermediate", "modern"]}), ("pop3.enabled", {"type": "bool", "default": False}), + ("smtp.ipv6", {"type": "bool", "default": True}), ]) From ed75108142840090b7dd6f249ad4e39ffac6000c Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 02:32:15 +0200 Subject: [PATCH 169/317] [fix] Cache duration --- data/hooks/diagnosis/24-mail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 022b24114..0c89fd7e0 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -20,7 +20,7 @@ DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" class MailDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] - cache_duration = 0 + cache_duration = 12 * 3600 dependencies = ["ip"] def run(self): From a33ae634c3d78245791585959c9326b0c492e3ad Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 02:39:36 +0200 Subject: [PATCH 170/317] We need those quotes around spf --- src/yunohost/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 1d1e10da1..c725b58c9 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -457,7 +457,7 @@ def _build_dns_conf(domain, ttl=3600, include_empty_AAAA_if_no_ipv6=False): mail = [ ["@", ttl, "MX", "10 %s." % domain], - ["@", ttl, "TXT", "v=spf1 a mx -all"], + ["@", ttl, "TXT", '"v=spf1 a mx -all"'], ] # DKIM/DMARC record From da112a3668df850d007fba9cadc8f4d284c02fe1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 02:44:39 +0200 Subject: [PATCH 171/317] Let's push also CAA for nohost.me ... Assuming dynette will eventually allow it .. --- src/yunohost/dyndns.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/yunohost/dyndns.py b/src/yunohost/dyndns.py index 6e597fbbf..efa25f23f 100644 --- a/src/yunohost/dyndns.py +++ b/src/yunohost/dyndns.py @@ -259,11 +259,6 @@ def dyndns_update(operation_logger, dyn_host="dyndns.yunohost.org", domain=None, dns_conf = _build_dns_conf(domain) - for i, record in enumerate(dns_conf["extra"]): - # Ignore CAA record ... not sure why, we could probably enforce it... - if record[3] == "CAA": - del dns_conf["extra"][i] - # Delete custom DNS records, we don't support them (have to explicitly # authorize them on dynette) for category in dns_conf.keys(): From f78af06a355ad4590e7b27937bec897a01d75720 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 02:59:16 +0200 Subject: [PATCH 172/317] Lazy loading for performance, possibly --- src/yunohost/diagnosis.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/yunohost/diagnosis.py b/src/yunohost/diagnosis.py index bd52f57f8..bfb2619eb 100644 --- a/src/yunohost/diagnosis.py +++ b/src/yunohost/diagnosis.py @@ -27,8 +27,6 @@ import re import os import time -import requests -import socket from moulinette import m18n, msettings from moulinette.utils import log @@ -496,6 +494,10 @@ class Diagnoser(): @staticmethod def remote_diagnosis(uri, data, ipversion, timeout=30): + # Lazy loading for performance + import requests + import socket + # Monkey patch socket.getaddrinfo to force request() to happen in ipv4 # or 6 ... # Inspired by https://stackoverflow.com/a/50044152 From b53695af2743a300fe3dc3dc4ff6ef478dabe200 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 03:08:34 +0200 Subject: [PATCH 173/317] Fix _could_not_diagnose string consistency --- locales/ca.json | 6 ++++-- locales/en.json | 2 +- locales/eo.json | 6 ++++-- locales/es.json | 6 ++++-- locales/fr.json | 6 ++++-- locales/oc.json | 6 ++++-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index 07e2c6f27..6416307f6 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -506,7 +506,8 @@ "diagnosis_swap_none": "El sistema no té swap. Hauríeu de considerar afegir un mínim de {recommended} de swap per evitar situacions en les que el sistema es queda sense memòria.", "diagnosis_regenconf_manually_modified": "El fitxer de configuració {file} ha estat modificat manualment.", "diagnosis_security_vulnerable_to_meltdown_details": "Per arreglar-ho, hauríeu d'actualitzar i reiniciar el sistema per tal de carregar el nou nucli de linux (o contactar amb el proveïdor del servidor si no funciona). Vegeu https://meltdownattack.com/ per a més informació.", - "diagnosis_http_could_not_diagnose": "No s'ha pogut diagnosticar si el domini és accessible des de l'exterior. Error: {error}", + "diagnosis_http_could_not_diagnose": "No s'ha pogut diagnosticar si el domini és accessible des de l'exterior.", + "diagnosis_http_could_not_diagnose_details": "Error: {error}", "domain_cannot_remove_main_add_new_one": "No es pot eliminar «{domain:s}» ja que és el domini principal i únic domini, primer s'ha d'afegir un altre domini utilitzant «yunohost domain add », i després fer-lo el domini principal amb «yunohost domain main-domain -n » i després es pot eliminar el domini «{domain:s}» utilitzant «yunohost domain remove {domain:s}».", "diagnosis_basesystem_host": "El servidor funciona amb Debian {debian_version}", "diagnosis_basesystem_kernel": "El servidor funciona amb el nucli de Linux {kernel_version}", @@ -559,7 +560,8 @@ "diagnosis_description_ports": "Exposició dels ports", "diagnosis_description_regenconf": "Configuració del sistema", "diagnosis_description_security": "Verificacions de seguretat", - "diagnosis_ports_could_not_diagnose": "No s'ha pogut diagnosticar si els ports són accessibles des de l'exterior. Error: {error}", + "diagnosis_ports_could_not_diagnose": "No s'ha pogut diagnosticar si els ports són accessibles des de l'exterior.", + "diagnosis_ports_could_not_diagnose_details": "Error: {error}", "diagnosis_ports_unreachable": "El port {port} no és accessible des de l'exterior.", "diagnosis_ports_ok": "El port {port} és accessible des de l'exterior.", "diagnosis_http_ok": "El domini {domain} és accessible per mitjà de HTTP des de fora de la xarxa local.", diff --git a/locales/en.json b/locales/en.json index a5048b8c9..b850b5b41 100644 --- a/locales/en.json +++ b/locales/en.json @@ -192,7 +192,7 @@ "diagnosis_mail_ehlo_unavailable": "Postfix mail service don't answer to EHLO request on IPv{ipversion}", "diagnosis_mail_ehlo_wrong": "A mail server answers {wrong_ehlo} instead {right_ehlo} on IPv{ipversion}", "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", - "diagnosis_mail_ehlo_could_not_diagnose_details": "{error}", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Your reverse DNS {rdns_domain} is different from your EHLO domain {ehlo_domain} on {ip}", diff --git a/locales/eo.json b/locales/eo.json index 36396d6f1..64571e7e7 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -555,7 +555,8 @@ "diagnosis_description_services": "Servo kontrolas staton", "diagnosis_description_systemresources": "Rimedaj sistemoj", "diagnosis_description_security": "Sekurecaj kontroloj", - "diagnosis_ports_could_not_diagnose": "Ne povis diagnozi, ĉu haveblaj havenoj de ekstere. Eraro: {error}", + "diagnosis_ports_could_not_diagnose": "Ne povis diagnozi, ĉu haveblaj havenoj de ekstere.", + "diagnosis_ports_could_not_diagnose_details": "Eraro: {error}", "diagnosis_services_bad_status_tip": "Vi povas provi rekomenci la servon, kaj se ĝi ne funkcias, trarigardu la servajn protokolojn uzante 'yunohost service log {service}' aŭ tra la sekcio 'Servoj' de la retadreso.", "diagnosis_security_vulnerable_to_meltdown_details": "Por ripari tion, vi devas ĝisdatigi vian sistemon kaj rekomenci por ŝarĝi la novan linux-kernon (aŭ kontaktu vian servilan provizanton se ĉi tio ne funkcias). Vidu https://meltdownattack.com/ por pliaj informoj.", "diagnosis_description_basesystem": "Baza sistemo", @@ -577,7 +578,8 @@ "diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.", "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {service}", "diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, plej probable vi devas agordi la plusendon de haveno en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config", - "diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere. Eraro: {error}", + "diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere.", + "diagnosis_http_could_not_diagnose_details": "Eraro: {error}", "diagnosis_http_ok": "Domajno {domain} atingeblas de ekstere.", "diagnosis_http_unreachable": "Domajno {domain} estas atingebla per HTTP de ekstere.", "domain_cannot_remove_main_add_new_one": "Vi ne povas forigi '{domain:s}' ĉar ĝi estas la ĉefa domajno kaj via sola domajno, vi devas unue aldoni alian domajnon uzante ''yunohost domain add ', tiam agordi kiel ĉefan domajnon uzante 'yunohost domain main-domain -n ' kaj tiam vi povas forigi la domajnon' {domain:s} 'uzante' yunohost domain remove {domain:s} '.'", diff --git a/locales/es.json b/locales/es.json index c21585e7b..beefb838c 100644 --- a/locales/es.json +++ b/locales/es.json @@ -572,7 +572,8 @@ "diagnosis_ports_needed_by": "La apertura de este puerto es requerida para la funcionalidad {category} (service {service})", "diagnosis_ports_ok": "El puerto {port} es accesible desde internet.", "diagnosis_ports_unreachable": "El puerto {port} no es accesible desde internet.", - "diagnosis_ports_could_not_diagnose": "No se puede comprobar si los puertos están accesibles desde el exterior. Error: {error}", + "diagnosis_ports_could_not_diagnose": "No se puede comprobar si los puertos están accesibles desde el exterior.", + "diagnosis_ports_could_not_diagnose_details": "Error: {error}", "diagnosis_description_security": "Validación de seguridad", "diagnosis_description_regenconf": "Configuraciones de sistema", "diagnosis_description_mail": "Correo electrónico", @@ -595,6 +596,7 @@ "diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado,", "diagnosis_http_timeout": "El intento de contactar a su servidor desde internet corrió fuera de tiempo. Al parece esta incomunicado. Debería verificar que nginx corre en el puerto 80, y que la redireción del puerto 80 no interfiere con en el firewall.", "diagnosis_http_ok": "El Dominio {domain} es accesible desde internet a través de HTTP.", - "diagnosis_http_could_not_diagnose": "No se pudo verificar si el dominio es accesible desde internet. Error: {error}", + "diagnosis_http_could_not_diagnose": "No se pudo verificar si el dominio es accesible desde internet.", + "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_ports_forwarding_tip": "Para solucionar este incidente, debería configurar el \"port forwading\" en su router como especificado en https://yunohost.org/isp_box_config" } diff --git a/locales/fr.json b/locales/fr.json index 7e77cdc7a..94cb76a5a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -562,7 +562,8 @@ "diagnosis_description_ports": "Exposition des ports", "diagnosis_description_regenconf": "Configurations système", "diagnosis_description_security": "Contrôles de sécurité", - "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur. Erreur: {error}", + "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur.", + "diagnosis_ports_could_not_diagnose_details": "Erreur: {error}", "apps_catalog_updating": "Mise à jour du catalogue d'applications…", "apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.", "apps_catalog_update_success": "Le catalogue des applications a été mis à jour !", @@ -570,7 +571,8 @@ "diagnosis_description_mail": "Email", "diagnosis_ports_unreachable": "Le port {port} n'est pas accessible de l'extérieur.", "diagnosis_ports_ok": "Le port {port} est accessible de l'extérieur.", - "diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l'extérieur. Erreur: {error}", + "diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l'extérieur.", + "diagnosis_http_could_not_diagnose_details": "Erreur: {error}", "diagnosis_http_ok": "Le domaine {domain} est accessible au travers de HTTP depuis l'extérieur.", "diagnosis_http_unreachable": "Le domaine {domain} est inaccessible au travers de HTTP depuis l'extérieur.", "diagnosis_unknown_categories": "Les catégories suivantes sont inconnues: {categories}", diff --git a/locales/oc.json b/locales/oc.json index 97978bb18..95f581851 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -539,8 +539,10 @@ "diagnosis_dns_missing_record": "Segon la configuracion DNS recomandada, vos calriá ajustar un enregistrament DNS\ntipe: {type}\nnom: {name}\nvalor: {value}", "diagnosis_dns_discrepancy": "Segon la configuracion DNS recomandada, la valor per l’enregistrament DNS\ntipe: {type}\nnom: {name}\ndeuriá èsser: {current}\nallòc de: {value}", "diagnosis_regenconf_manually_modified_debian_details": "Es pas problematic, mas car téner d’agacher...", - "diagnosis_ports_could_not_diagnose": "Impossible de diagnosticar se los pòrts son accessibles de l’exterior. Error : {error}", - "diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior. Error : {error}", + "diagnosis_ports_could_not_diagnose": "Impossible de diagnosticar se los pòrts son accessibles de l’exterior.", + "diagnosis_ports_could_not_diagnose_details": "Error : {error}", + "diagnosis_http_could_not_diagnose": "Impossible de diagnosticar se lo domeni es accessible de l’exterior.", + "diagnosis_http_could_not_diagnose_details": "Error : {error}", "apps_catalog_updating": "Actualizacion del catalòg d’aplicacion…", "apps_catalog_failed_to_download": "Telecargament impossible del catalòg d’aplicacions {apps_catalog} : {error}", "apps_catalog_obsolete_cache": "La memòria cache del catalòg d’aplicacion es voida o obsolèta.", From 70566b70220d427ec0215c6da310db19f9eaef22 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 03:19:34 +0200 Subject: [PATCH 174/317] Ignore some string keys which are only fragments concatenated with other stuff --- tests/test_i18n_keys.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 0d5af33f6..d6df56452 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -49,6 +49,9 @@ def find_expected_string_keys(): for python_file in glob.glob("data/hooks/diagnosis/*.py"): content = open(python_file).read() for m in p3.findall(content): + if m.endswith("_"): + # Ignore some name fragments which are actually concatenated with other stuff.. + continue yield m yield "diagnosis_description_" + os.path.basename(python_file)[:-3].split("-")[-1] From e6f0091f59b37be9bc6c365da98b26e5c50d59f5 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 03:45:59 +0200 Subject: [PATCH 175/317] [fix] Rename ipv6 mail settings + desc --- data/hooks/conf_regen/19-postfix | 2 +- locales/en.json | 1 + src/yunohost/settings.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 172438f37..10076b680 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -35,7 +35,7 @@ do_pre_regen() { > "${default_dir}/postsrsd" # adapt it for IPv4-only hosts - ipv6="$(yunohost settings get 'smtp.ipv6')" + ipv6="$(yunohost settings get 'smtp.allow_ipv6')" if [ "$ipv6" == "False" ] || [ ! -f /proc/net/if_inet6 ]; then sed -i \ 's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \ diff --git a/locales/en.json b/locales/en.json index 0fc9ca777..fc4726aed 100644 --- a/locales/en.json +++ b/locales/en.json @@ -312,6 +312,7 @@ "global_settings_setting_security_postfix_compatibility": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)", "global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discard it and save it in /etc/yunohost/settings-unknown.json", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration", + "global_settings_setting_smtp_allow_ipv6": "Allow the use of IPv6 to receive and send mail", "global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it is not a type supported by the system.", "good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to use a variation of characters (uppercase, lowercase, digits and special characters).", "good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters long—though it is good practice to use a longer password (i.e. a passphrase) and/or to a variation of characters (uppercase, lowercase, digits and special characters).", diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index c016e0809..db94e7429 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -70,7 +70,7 @@ DEFAULTS = OrderedDict([ ("security.postfix.compatibility", {"type": "enum", "default": "intermediate", "choices": ["intermediate", "modern"]}), ("pop3.enabled", {"type": "bool", "default": False}), - ("smtp.ipv6", {"type": "bool", "default": True}), + ("smtp.allow_ipv6", {"type": "bool", "default": True}), ]) From 40141c84f39b1f17a387ca55aa4505046a729e3c Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 03:55:50 +0200 Subject: [PATCH 176/317] [enh] Auto update postfix on smtp.allow_ipv6 change --- src/yunohost/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/yunohost/settings.py b/src/yunohost/settings.py index db94e7429..c1edadb93 100644 --- a/src/yunohost/settings.py +++ b/src/yunohost/settings.py @@ -321,6 +321,7 @@ def reconfigure_ssh(setting_name, old_value, new_value): if old_value != new_value: service_regen_conf(names=['ssh']) +@post_change_hook("smtp.allow_ipv6") @post_change_hook("security.postfix.compatibility") def reconfigure_postfix(setting_name, old_value, new_value): if old_value != new_value: From 6e334eba955439f30a1511ef0ceeb02f170fd93d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 04:14:48 +0200 Subject: [PATCH 177/317] Wording / weird translation.. --- locales/en.json | 2 +- locales/fr.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/en.json b/locales/en.json index b59b53325..5c97c01fc 100644 --- a/locales/en.json +++ b/locales/en.json @@ -145,7 +145,7 @@ "diagnosis_basesystem_ynh_inconsistent_versions": "You are running inconsistent versions of the YunoHost packages... most probably because of a failed or partial upgrade.", "diagnosis_display_tip": "To see the issues found, you can go to the Diagnosis section of the webadmin, or run 'yunohost diagnosis show --issues' from the command-line.", "diagnosis_failed_for_category": "Diagnosis failed for category '{category}': {error}", - "diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Not re-diagnosing yet!)", + "diagnosis_cache_still_valid": "(Cache still valid for {category} diagnosis. Won't re-diagnose it yet!)", "diagnosis_cant_run_because_of_dep": "Can't run diagnosis for {category} while there are important issues related to {dep}.", "diagnosis_ignored_issues": "(+ {nb_ignored} ignored issue(s))", "diagnosis_found_errors": "Found {errors} significant issue(s) related to {category}!", diff --git a/locales/fr.json b/locales/fr.json index 2431af8da..6b8ddcabe 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -521,7 +521,7 @@ "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... probablement à cause d'une mise à niveau partielle ou échouée.", "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}", - "diagnosis_cache_still_valid": "(Le cache est toujours valide pour le diagnostic {category}. Pas re-diagnostiquer pour le moment!)", + "diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment!)", "diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))", "diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.", "diagnosis_everything_ok": "Tout semble bien pour {category} !", From 39f0aa3ef32d54c5c45a4621d052e51cb4586061 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 04:44:09 +0200 Subject: [PATCH 178/317] Improve wording --- data/hooks/diagnosis/24-mail.py | 13 ++++++----- locales/en.json | 40 ++++++++++++++++----------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 5457c5890..4ced72959 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -109,25 +109,28 @@ class MailDiagnoser(Diagnoser): for ip in self.ips: if ":" in ip: + ipversion = 6 details = ["diagnosis_mail_fcrdns_nok_details", "diagnosis_mail_fcrdns_nok_alternatives_6"] else: + ipversion = 4 details = ["diagnosis_mail_fcrdns_nok_details", "diagnosis_mail_fcrdns_nok_alternatives_4"] try: rdns_domain, _, _ = socket.gethostbyaddr(ip) except socket.herror: - yield dict(meta={"test": "mail_fcrdns", "ip": ip}, - data={"ehlo_domain": self.ehlo_domain}, + yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion}, + data={"ip": ip, "ehlo_domain": self.ehlo_domain}, status="ERROR", summary="diagnosis_mail_fcrdns_dns_missing", details=details) continue if rdns_domain != self.ehlo_domain: details = ["diagnosis_mail_fcrdns_different_from_ehlo_domain_details"] + details - yield dict(meta={"test": "mail_fcrdns", "ip": ip}, - data={"ehlo_domain": self.ehlo_domain, + yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion}, + data={"ip": ip, + "ehlo_domain": self.ehlo_domain, "rdns_domain": rdns_domain}, status="ERROR", summary="diagnosis_mail_fcrdns_different_from_ehlo_domain", @@ -222,7 +225,7 @@ class MailDiagnoser(Diagnoser): if global_ipv4: outgoing_ips.append(global_ipv4) - if settings_get("smtp.ipv6"): + if settings_get("smtp.allow_ipv6"): ipv6 = Diagnoser.get_cached_report("ip", {"test": "ipv6"}) or {} if ipv6.get("status") == "SUCCESS": outgoing_ipversions.append(6) diff --git a/locales/en.json b/locales/en.json index 5c97c01fc..400413e3d 100644 --- a/locales/en.json +++ b/locales/en.json @@ -184,29 +184,29 @@ "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least {recommended} of swap to avoid situations where the system runs out of memory.", "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least {recommended} to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", - "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent", - "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}", - "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock it in your internet service provider (or hosting provider) configuration panel or by sending a ticket to your hosting provider. Meanwhile, the server won't be able to send emails to other servers.", - "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", - "diagnosis_mail_ehlo_ok": "Postfix mail service answer correctly from outside", - "diagnosis_mail_ehlo_unreachable": "SMTP server unreachable on IPv{ipversion}", - "diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 through IPv{ipversion}, probably because of a firewall, port forwarding issue or postfix service down", + "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent!", + "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. This prevent emails from being sent to other servers.", + "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock outgoing port 25 in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- You can also consider switching to a more net neutrality-friendly provider", + "diagnosis_mail_ehlo_ok": "The SMTP mail server is reachable from the outside, which allows to receive email.", + "diagnosis_mail_ehlo_unreachable": "The SMTP mail server is unreachable from the outside on IPv{ipversion}. It won't be able to receive emails.", + "diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 to your server in IPv{ipversion}. It appears to be unreachable.
1. The most common cause for this issue is that port 25 is not correctly forwarded to your server.
2. You should also make sure that service postfix is running.
3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_bad_answer": "A non-SMTP service answered on port 25 on IPv{ipversion}", "diagnosis_mail_ehlo_bad_answer_details": "It could be due to an other machine answering instead of your server.", - "diagnosis_mail_ehlo_wrong": "An other SMTP server answers on IPv{ipversion}", - "diagnosis_mail_ehlo_wrong_details": "The remote diagnoser return a wrong EHLO answer from your IPv{ipversion}.
Received: {wrong_ehlo}
Expected: {right_ehlo}
You probably have a port forwarding issue or a reverse proxy server unconfigured for mail.", + "diagnosis_mail_ehlo_wrong": "A different SMTP server answers on IPv{ipversion}. It will probably not be able to receive emails.", + "diagnosis_mail_ehlo_wrong_details": "The EHLO received by the remote diagnoser in IPv{ipversion} is different from your server's domain.
Received EHLO: {wrong_ehlo}
Expected: {right_ehlo}
The most common cause for this issue is that port 25 is not correctly forwarded to your server. Alternatively, make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", - "diagnosis_mail_fcrdns_ok": "Your reverse DNS is well configured", - "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS defined for the ip {ip}", - "diagnosis_mail_fcrdns_nok_details": "You should first try to configure the reverse DNS with {ehlo_domain} on your internet service provider (or hosting provider) config panel or by sending a ticket to your hosting provider. Meanwhile, some outgoing mails won't be delivered.", - "diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure it or the feature is broken on their config panel. If you are experiencing some server refusing your email for this reason, you could try those solutions:
- Some ISP provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", - "diagnosis_mail_fcrdns_nok_alternatives_6": "Some providers won't let you configure it or the feature is broken on their config panel in IPv6. If your reverse DNS is ok in IPv4, you can try to disable the use of IPv6 to send mail by running yunohost settings set smtp.ipv6 -v off ; yunohost tools regen-conf postfix. Note: with this last solution you won't be able to send or received emails from the rare ipv6 only servers.", - "diagnosis_mail_fcrdns_different_from_ehlo_domain": "The reverse DNS is different from your EHLO domain on {ip}", + "diagnosis_mail_fcrdns_ok": "Your reverse DNS is correctly configured!", + "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS is defined in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.", + "diagnosis_mail_fcrdns_nok_details": "You should first try to configure the reverse DNS with {ehlo_domain} in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If you are experiencing issues because of this, consider the following solutions:
- Some ISP provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", + "diagnosis_mail_fcrdns_nok_alternatives_6": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If your reverse DNS is correctly configured for IPv4, you can try disabling the use of IPv6 when sending emails by running yunohost settings set smtp.allow_ipv6 -v off. Note: this last solution means that you won't be able to send or receive emails from the few IPv6-only servers out there.", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "The reverse DNS is not correctly configured in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.", "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Current reverse DNS: {rdns_domain}
Expected value: {ehlo_domain}", - "diagnosis_mail_blacklist_ok": "IPs and domains used by this server to send mail are not on most used email blacklists", - "diagnosis_mail_blacklist_listed_by": "{item} is blacklisted on {blacklist_name}", - "diagnosis_mail_blacklist_reason": "The blacklist explains: {reason}", + "diagnosis_mail_blacklist_ok": "The IPs and domains used by this server do not appear to be blacklisted", + "diagnosis_mail_blacklist_listed_by": "Your IP or domain {item} is blacklisted on {blacklist_name}", + "diagnosis_mail_blacklist_reason": "The blacklist reason is: {reason}", "diagnosis_mail_blacklist_website": "After identifying why you are listed and fixed it, feel free to ask for delisting on {blacklist_website}", "diagnosis_mail_queue_ok": "{nb_pending} pending emails in the mail queues", "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", @@ -240,9 +240,9 @@ "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", - "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. Also make sure that the web server nginx is running
3. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", + "diagnosis_http_timeout": "Timed-out while trying to contact your server from outside. It appears to be unreachable.
1. The most common cause for this issue is that port 80 (and 443) are not correctly forwarded to your server.
2. You should also make sure that the service nginx is running
3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_http_connection_error": "Connection error: could not connect to the requested domain, it's very likely unreachable.", - "diagnosis_http_bad_status_code": "It looks like another machine (maybe your internet router) answered instead of your server.
1. The most common cause for this issue is that you did not correctly configure port forwarding for port 80.
2. On more complex setups: make sure that a firewall or reverse-proxy is not interfering.", + "diagnosis_http_bad_status_code": "It looks like another machine (maybe your internet router) answered instead of your server.
1. The most common cause for this issue is that port 80 (and 443) are not correctly forwarded to your server.
2. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_http_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network.", "diagnosis_http_partially_unreachable": "Domain {domain} appears unreachable through HTTP from outside the local network in IPv{failed}, though it works in IPv{passed}.", "diagnosis_http_nginx_conf_not_up_to_date": "This domain's nginx configuration appears to have been modified manually, and prevents YunoHost from diagnosing if it's reachable on HTTP.", From 878bb82d9df14cb14fc40dec3b775a9a6e9fd5c0 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 05:10:32 +0200 Subject: [PATCH 179/317] Hmgn bad fr translation --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 6b8ddcabe..3f7776009 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -541,7 +541,7 @@ "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Faites attention.", "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", "diagnosis_ram_low": "Le système n'a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", - "diagnosis_swap_none": "Le système n'a aucun échange. Vous devez envisager d’ajouter au moins {recommended} de swap pour éviter les situations où le système manque de mémoire.", + "diagnosis_swap_none": "Le système n'a aucun espace de swap. Vous devriez envisager d’ajouter au moins {recommended} de swap pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d'avoir au moins {recommended} pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", From 4c95d52c37864fc2ff5d5c632e3e8fd390af4d77 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 05:29:32 +0200 Subject: [PATCH 180/317] More small wording/translation improvement.. --- locales/en.json | 8 ++++---- locales/fr.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/locales/en.json b/locales/en.json index 400413e3d..c2c087031 100644 --- a/locales/en.json +++ b/locales/en.json @@ -184,16 +184,16 @@ "diagnosis_swap_none": "The system has no swap at all. You should consider adding at least {recommended} of swap to avoid situations where the system runs out of memory.", "diagnosis_swap_notsomuch": "The system has only {total} swap. You should consider having at least {recommended} to avoid situations where the system runs out of memory.", "diagnosis_swap_ok": "The system has {total} of swap!", - "diagnosis_mail_outgoing_port_25_ok": "Outgoing port 25 is open, emails can be sent!", - "diagnosis_mail_outgoing_port_25_blocked": "Outgoing port 25 appears to be blocked in IPv{ipversion}. This prevent emails from being sent to other servers.", + "diagnosis_mail_outgoing_port_25_ok": "The SMTP mail server is able to send emails (outgoing port 25 is not blocked).", + "diagnosis_mail_outgoing_port_25_blocked": "The SMTP mail server cannot send emails to other servers because outgoing port 25 is blocked in IPv{ipversion}.", "diagnosis_mail_outgoing_port_25_blocked_details": "You should first try to unblock outgoing port 25 in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).", "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Some providers won't let you unblock outgoing port 25 because they don't care about Net Neutrality.
- Some of them provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- You can also consider switching to a more net neutrality-friendly provider", - "diagnosis_mail_ehlo_ok": "The SMTP mail server is reachable from the outside, which allows to receive email.", + "diagnosis_mail_ehlo_ok": "The SMTP mail server is reachable from the outside and therefore is able to receive emails!", "diagnosis_mail_ehlo_unreachable": "The SMTP mail server is unreachable from the outside on IPv{ipversion}. It won't be able to receive emails.", "diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 to your server in IPv{ipversion}. It appears to be unreachable.
1. The most common cause for this issue is that port 25 is not correctly forwarded to your server.
2. You should also make sure that service postfix is running.
3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_bad_answer": "A non-SMTP service answered on port 25 on IPv{ipversion}", "diagnosis_mail_ehlo_bad_answer_details": "It could be due to an other machine answering instead of your server.", - "diagnosis_mail_ehlo_wrong": "A different SMTP server answers on IPv{ipversion}. It will probably not be able to receive emails.", + "diagnosis_mail_ehlo_wrong": "A different SMTP mail server answers on IPv{ipversion}. It will probably not be able to receive emails.", "diagnosis_mail_ehlo_wrong_details": "The EHLO received by the remote diagnoser in IPv{ipversion} is different from your server's domain.
Received EHLO: {wrong_ehlo}
Expected: {right_ehlo}
The most common cause for this issue is that port 25 is not correctly forwarded to your server. Alternatively, make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", diff --git a/locales/fr.json b/locales/fr.json index 3f7776009..c86ed244c 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -579,7 +579,7 @@ "migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d'applications à l'épreuve du temps", "app_upgrade_script_failed": "Une erreur s'est produite durant l’exécution du script de mise à niveau de l'application", "migration_description_0014_remove_app_status_json": "Supprimer les fichiers d'application status.json hérités", - "diagnosis_services_running": "Le service {service} s'exécute correctement !", + "diagnosis_services_running": "Le service {service} est en cours de fonctionnement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})", "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config", From 8bd4ada50a455cf1264bf83968e64e914952fbe5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 06:19:08 +0200 Subject: [PATCH 181/317] Update changelog for 3.8.1 --- debian/changelog | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 83c310d67..eb925ab31 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,26 @@ +yunohost (3.8.1) testing; urgency=low + + ## Helpers (PHP, apt) + + - New helpers for extra apt repo, PHP version install, and PHP fpm (#881, #928, #929) + - Pave the way to migration to php7.3 and future ones (#880, #926) + - Option in PHP helper to use a dedicated php service (#915) + + ## Diagnosis + + - Many improvements in diagnosis mechanism (#923, #921, #940) + + ## Misc fixes, improvements + - custom_portal and custom_overlay redirect (#925) + - Improve systemd settings for slapd (#933) + - Spelling and typo corrections (#931) + - Improve translations for French, German, Catalan + + Thanks to all contributors <3 ! (Kay0u, Maniack Crudelis, ljf, E.Gaspar, + xaloc33) + + -- Alexandre Aubin Sun, 19 Apr 2020 06:20:00 +0000 + yunohost (3.8.0) testing; urgency=low # Major stuff @@ -50,7 +73,7 @@ yunohost (3.7.1.1) stable; urgency=low - [fix] lxc uid number is limited to 65536 by default (0c9a4509) - [fix] also invalidate group cache when creating users (aaabf8c7) - [fix] Make sure to have a path that include sbin for stupid cron jobs (f03bb82a) - + -- Alexandre Aubin Sun, 12 Apr 2020 23:15:00 +0000 yunohost (3.7.1) stable; urgency=low @@ -73,7 +96,7 @@ yunohost (3.7.1) stable; urgency=low yunohost (3.7.0.12) stable; urgency=low - Fix previous buggy hotfix about deleting existing primary groups ... - + -- Alexandre Aubin Sat, 28 Mar 2020 14:52:00 +0000 yunohost (3.7.0.11) stable; urgency=low @@ -85,7 +108,7 @@ yunohost (3.7.0.11) stable; urgency=low yunohost (3.7.0.10) stable; urgency=low - [fix] On some weird setup, this folder and content ain't readable by group ... gotta make sure to make rx for group other slapd will explode - + -- Alexandre Aubin Fri, 27 Mar 2020 21:45:00 +0000 yunohost (3.7.0.9) stable; urgency=low From f6837b17906fcc6f9dd0d5a9af22246ac31ed87e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 07:03:21 +0200 Subject: [PATCH 182/317] Right side gotta be a folder path ... -_- --- debian/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/install b/debian/install index cf682d958..a814d1617 100644 --- a/debian/install +++ b/debian/install @@ -7,7 +7,7 @@ data/hooks/* /usr/share/yunohost/hooks/ data/other/yunoprompt.service /etc/systemd/system/ data/other/password/* /usr/share/yunohost/other/password/ data/other/dpkg-origins/yunohost /etc/dpkg/origins -data/other/dnsbl_list.yml /usr/share/yunohost/other/dnsbl_list.yml +data/other/dnsbl_list.yml /usr/share/yunohost/other/ data/other/* /usr/share/yunohost/yunohost-config/moulinette/ data/templates/* /usr/share/yunohost/templates/ data/helpers /usr/share/yunohost/ From 7cc04f51715ccfaea387a4ebb88ad58d2413b474 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 19 Apr 2020 07:04:32 +0200 Subject: [PATCH 183/317] Update changelog for 3.8.1.1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index eb925ab31..fbeba2dcc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.8.1.1) testing; urgency=low + + - [fix] Stupid issue about path in debian/install ... + + -- Alexandre Aubin Sun, 19 Apr 2020 07:04:00 +0000 + yunohost (3.8.1) testing; urgency=low ## Helpers (PHP, apt) From 23664c5036e5eb59699cb1ceb06f50bec792762b Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 19 Apr 2020 18:15:58 +0200 Subject: [PATCH 184/317] Wait for fail2ban to reload --- data/helpers.d/fail2ban | 2 +- data/helpers.d/systemd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 58af9ec0b..40f435ecd 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -130,7 +130,7 @@ EOF ynh_store_file_checksum "$finalfail2banjailconf" ynh_store_file_checksum "$finalfail2banfilterconf" - ynh_systemd_action --service_name=fail2ban --action=reload + ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")" if [[ -n "$fail2ban_error" ]]; then diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 47e905f0f..4a9eac7e7 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -133,7 +133,7 @@ ynh_systemd_action() { for i in $(seq 1 $timeout) do # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout - if grep --quiet "$line_match" "$templog" + if grep --extended-regexp --quiet "$line_match" "$templog" then ynh_print_info --message="The service $service_name has correctly executed the action ${action}." break From 1dd4a73e1720bbc1bc1e43443ee7804c0d908e71 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 19 Apr 2020 19:10:39 +0200 Subject: [PATCH 185/317] Replace declare -Ar by local A for args_array --- data/helpers.d/apt | 16 ++++++++-------- data/helpers.d/backup | 10 +++++----- data/helpers.d/fail2ban | 2 +- data/helpers.d/getopts | 6 +++--- data/helpers.d/hardware | 4 ++-- data/helpers.d/logging | 12 ++++++------ data/helpers.d/logrotate | 2 +- data/helpers.d/mysql | 14 +++++++------- data/helpers.d/network | 10 +++++----- data/helpers.d/nodejs | 2 +- data/helpers.d/php | 6 +++--- data/helpers.d/postgresql | 16 ++++++++-------- data/helpers.d/setting | 22 +++++++++++----------- data/helpers.d/string | 10 +++++----- data/helpers.d/systemd | 6 +++--- data/helpers.d/user | 12 ++++++------ data/helpers.d/utils | 10 +++++----- 17 files changed, 80 insertions(+), 80 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index bcce02dcb..44d5c9c38 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -51,7 +51,7 @@ ynh_wait_dpkg_free() { ynh_package_is_installed() { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=package= ) + local -A args_array=( [p]=package= ) local package # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -73,7 +73,7 @@ ynh_package_is_installed() { ynh_package_version() { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=package= ) + local -A args_array=( [p]=package= ) local package # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -295,7 +295,7 @@ EOF ynh_add_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=pr - declare -Ar args_array=( [p]=package= [r]=replace) + local -A args_array=( [p]=package= [r]=replace) local package local replace # Manage arguments with getopts @@ -341,7 +341,7 @@ ynh_remove_app_dependencies () { ynh_install_extra_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=rpkn - declare -Ar args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) + local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) local repo local package local key @@ -379,7 +379,7 @@ ynh_install_extra_app_dependencies () { ynh_install_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=rkpna - declare -Ar args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) + local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) local repo local key local priority @@ -448,7 +448,7 @@ ynh_install_extra_repo () { ynh_remove_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=n - declare -Ar args_array=( [n]=name= ) + local -A args_array=( [n]=name= ) local name # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -481,7 +481,7 @@ ynh_remove_extra_repo () { ynh_add_repo () { # Declare an array to define the options of this helper. local legacy_args=uscna - declare -Ar args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) + local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) local uri local suite local component @@ -521,7 +521,7 @@ ynh_add_repo () { ynh_pin_repo () { # Declare an array to define the options of this helper. local legacy_args=pirna - declare -Ar args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) + local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) local package local pin local priority diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 590e951a5..9ffb13bbb 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -46,7 +46,7 @@ ynh_backup() { # Declare an array to define the options of this helper. local legacy_args=sdbm - declare -Ar args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory ) + local -A args_array=( [s]=src_path= [d]=dest_path= [b]=is_big [m]=not_mandatory ) local src_path local dest_path local is_big @@ -220,7 +220,7 @@ with open(sys.argv[1], 'r') as backup_file: ynh_restore_file () { # Declare an array to define the options of this helper. local legacy_args=odm - declare -Ar args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory ) + local -A args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory ) local origin_path local archive_path local dest_path @@ -296,7 +296,7 @@ ynh_bind_or_cp() { ynh_store_file_checksum () { # Declare an array to define the options of this helper. local legacy_args=f - declare -Ar args_array=( [f]=file= ) + local -A args_array=( [f]=file= ) local file # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -328,7 +328,7 @@ ynh_store_file_checksum () { ynh_backup_if_checksum_is_different () { # Declare an array to define the options of this helper. local legacy_args=f - declare -Ar args_array=( [f]=file= ) + local -A args_array=( [f]=file= ) local file # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -361,7 +361,7 @@ ynh_backup_if_checksum_is_different () { ynh_delete_file_checksum () { # Declare an array to define the options of this helper. local legacy_args=f - declare -Ar args_array=( [f]=file= ) + local -A args_array=( [f]=file= ) local file # Manage arguments with getopts ynh_handle_getopts_args "$@" diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 58af9ec0b..5c4cb89a9 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -65,7 +65,7 @@ ynh_add_fail2ban_config () { # Declare an array to define the options of this helper. local legacy_args=lrmptv - declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=) + local -A args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=) local logpath local failregex local max_retry diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index c8045fa25..285375915 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -6,7 +6,7 @@ # # example: function my_helper() # { -# declare -Ar args_array=( [a]=arg1= [b]=arg2= [c]=arg3 ) +# local -A args_array=( [a]=arg1= [b]=arg2= [c]=arg3 ) # local arg1 # local arg2 # local arg3 @@ -22,13 +22,13 @@ # This helper need an array, named "args_array" with all the arguments used by the helper # that want to use ynh_handle_getopts_args # Be carreful, this array has to be an associative array, as the following example: -# declare -Ar args_array=( [a]=arg1 [b]=arg2= [c]=arg3 ) +# local -A args_array=( [a]=arg1 [b]=arg2= [c]=arg3 ) # Let's explain this array: # a, b and c are short options, -a, -b and -c # arg1, arg2 and arg3 are the long options associated to the previous short ones. --arg1, --arg2 and --arg3 # For each option, a short and long version has to be defined. # Let's see something more significant -# declare -Ar args_array=( [u]=user [f]=finalpath= [d]=database ) +# local -A args_array=( [u]=user [f]=finalpath= [d]=database ) # # NB: Because we're using 'declare' without -g, the array will be declared as a local variable. # diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index 46e27caf4..1bfc648fe 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -10,7 +10,7 @@ ynh_get_ram () { # Declare an array to define the options of this helper. local legacy_args=ftso - declare -Ar args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local free local total local ignore_swap @@ -75,7 +75,7 @@ ynh_get_ram () { ynh_require_ram () { # Declare an array to define the options of this helper. local legacy_args=rftso - declare -Ar args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local -A args_array=( [r]=required= [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) local required local free local total diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 89fb89c6e..9f4a89df8 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -8,7 +8,7 @@ ynh_die() { # Declare an array to define the options of this helper. local legacy_args=mc - declare -Ar args_array=( [m]=message= [c]=ret_code= ) + local -A args_array=( [m]=message= [c]=ret_code= ) local message local ret_code # Manage arguments with getopts @@ -26,7 +26,7 @@ ynh_die() { ynh_print_info() { # Declare an array to define the options of this helper. local legacy_args=m - declare -Ar args_array=( [m]=message= ) + local -A args_array=( [m]=message= ) local message # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -71,7 +71,7 @@ ynh_print_log () { ynh_print_warn () { # Declare an array to define the options of this helper. local legacy_args=m - declare -Ar args_array=( [m]=message= ) + local -A args_array=( [m]=message= ) local message # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -88,7 +88,7 @@ ynh_print_warn () { ynh_print_err () { # Declare an array to define the options of this helper. local legacy_args=m - declare -Ar args_array=( [m]=message= ) + local -A args_array=( [m]=message= ) local message # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -224,7 +224,7 @@ ynh_script_progression () { set +x # Declare an array to define the options of this helper. local legacy_args=mwtl - declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) + local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) local message local weight local time @@ -320,7 +320,7 @@ ynh_debug () { set +x # Declare an array to define the options of this helper. local legacy_args=mt - declare -Ar args_array=( [m]=message= [t]=trace= ) + local -A args_array=( [m]=message= [t]=trace= ) local message local trace # Manage arguments with getopts diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 9e2429218..f77e25342 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -19,7 +19,7 @@ ynh_use_logrotate () { # Declare an array to define the options of this helper. local legacy_args=lnuya - declare -Ar args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append ) + local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append ) # [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append' local logfile local nonappend diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index 91d4abcd2..658a79c17 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -16,7 +16,7 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql ynh_mysql_connect_as() { # Declare an array to define the options of this helper. local legacy_args=upd - declare -Ar args_array=( [u]=user= [p]=password= [d]=database= ) + local -A args_array=( [u]=user= [p]=password= [d]=database= ) local user local password local database @@ -37,7 +37,7 @@ ynh_mysql_connect_as() { ynh_mysql_execute_as_root() { # Declare an array to define the options of this helper. local legacy_args=sd - declare -Ar args_array=( [s]=sql= [d]=database= ) + local -A args_array=( [s]=sql= [d]=database= ) local sql local database # Manage arguments with getopts @@ -58,7 +58,7 @@ ynh_mysql_execute_as_root() { ynh_mysql_execute_file_as_root() { # Declare an array to define the options of this helper. local legacy_args=fd - declare -Ar args_array=( [f]=file= [d]=database= ) + local -A args_array=( [f]=file= [d]=database= ) local file local database # Manage arguments with getopts @@ -121,7 +121,7 @@ ynh_mysql_drop_db() { ynh_mysql_dump_db() { # Declare an array to define the options of this helper. local legacy_args=d - declare -Ar args_array=( [d]=database= ) + local -A args_array=( [d]=database= ) local database # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -153,7 +153,7 @@ ynh_mysql_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u - declare -Ar args_array=( [u]=user= ) + local -A args_array=( [u]=user= ) local user # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -192,7 +192,7 @@ ynh_mysql_drop_user() { ynh_mysql_setup_db () { # Declare an array to define the options of this helper. local legacy_args=unp - declare -Ar args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= ) + local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= ) local db_user local db_name db_pwd="" @@ -217,7 +217,7 @@ ynh_mysql_setup_db () { ynh_mysql_remove_db () { # Declare an array to define the options of this helper. local legacy_args=un - declare -Ar args_array=( [u]=db_user= [n]=db_name= ) + local -A args_array=( [u]=db_user= [n]=db_name= ) local db_user local db_name # Manage arguments with getopts diff --git a/data/helpers.d/network b/data/helpers.d/network index 330aa5383..0f6e9c442 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -11,7 +11,7 @@ ynh_find_port () { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=port= ) + local -A args_array=( [p]=port= ) local port # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -35,7 +35,7 @@ ynh_find_port () { ynh_port_available () { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=port= ) + local -A args_array=( [p]=port= ) local port # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -63,7 +63,7 @@ ynh_validate_ip() # Declare an array to define the options of this helper. local legacy_args=fi - declare -Ar args_array=( [f]=family= [i]=ip_address= ) + local -A args_array=( [f]=family= [i]=ip_address= ) local family local ip_address # Manage arguments with getopts @@ -95,7 +95,7 @@ ynh_validate_ip4() { # Declare an array to define the options of this helper. local legacy_args=i - declare -Ar args_array=( [i]=ip_address= ) + local -A args_array=( [i]=ip_address= ) local ip_address # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -116,7 +116,7 @@ ynh_validate_ip6() { # Declare an array to define the options of this helper. local legacy_args=i - declare -Ar args_array=( [i]=ip_address= ) + local -A args_array=( [i]=ip_address= ) local ip_address # Manage arguments with getopts ynh_handle_getopts_args "$@" diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index 288240b1b..03cb5dffb 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -68,7 +68,7 @@ ynh_install_nodejs () { # Declare an array to define the options of this helper. local legacy_args=n - declare -Ar args_array=( [n]=nodejs_version= ) + local -A args_array=( [n]=nodejs_version= ) local nodejs_version # Manage arguments with getopts ynh_handle_getopts_args "$@" diff --git a/data/helpers.d/php b/data/helpers.d/php index d5b17c58f..c1ae91c2e 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -59,7 +59,7 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} ynh_add_fpm_config () { # Declare an array to define the options of this helper. local legacy_args=vtufpd - declare -Ar args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) + local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) local phpversion local use_template local usage @@ -312,7 +312,7 @@ ynh_remove_fpm_config () { ynh_install_php () { # Declare an array to define the options of this helper. local legacy_args=vp - declare -Ar args_array=( [v]=phpversion= [p]=package= ) + local -A args_array=( [v]=phpversion= [p]=package= ) local phpversion local package # Manage arguments with getopts @@ -415,7 +415,7 @@ ynh_remove_php () { ynh_get_scalable_phpfpm () { local legacy_args=ufp # Declare an array to define the options of this helper. - declare -Ar args_array=( [u]=usage= [f]=footprint= [p]=print ) + local -A args_array=( [u]=usage= [f]=footprint= [p]=print ) local usage local footprint local print diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index 03c713afd..ff6ef0f57 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -17,7 +17,7 @@ PSQL_ROOT_PWD_FILE=/etc/yunohost/psql ynh_psql_connect_as() { # Declare an array to define the options of this helper. local legacy_args=upd - declare -Ar args_array=([u]=user= [p]=password= [d]=database=) + local -A args_array=([u]=user= [p]=password= [d]=database=) local user local password local database @@ -38,7 +38,7 @@ ynh_psql_connect_as() { ynh_psql_execute_as_root() { # Declare an array to define the options of this helper. local legacy_args=sd - declare -Ar args_array=([s]=sql= [d]=database=) + local -A args_array=([s]=sql= [d]=database=) local sql local database # Manage arguments with getopts @@ -59,7 +59,7 @@ ynh_psql_execute_as_root() { ynh_psql_execute_file_as_root() { # Declare an array to define the options of this helper. local legacy_args=fd - declare -Ar args_array=([f]=file= [d]=database=) + local -A args_array=([f]=file= [d]=database=) local file local database # Manage arguments with getopts @@ -125,7 +125,7 @@ ynh_psql_drop_db() { ynh_psql_dump_db() { # Declare an array to define the options of this helper. local legacy_args=d - declare -Ar args_array=([d]=database=) + local -A args_array=([d]=database=) local database # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -155,7 +155,7 @@ ynh_psql_create_user() { ynh_psql_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u - declare -Ar args_array=([u]=user=) + local -A args_array=([u]=user=) local user # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -174,7 +174,7 @@ ynh_psql_user_exists() { ynh_psql_database_exists() { # Declare an array to define the options of this helper. local legacy_args=d - declare -Ar args_array=([d]=database=) + local -A args_array=([d]=database=) local database # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -210,7 +210,7 @@ ynh_psql_drop_user() { ynh_psql_setup_db() { # Declare an array to define the options of this helper. local legacy_args=unp - declare -Ar args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=) + local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=) local db_user local db_name db_pwd="" @@ -237,7 +237,7 @@ ynh_psql_setup_db() { ynh_psql_remove_db() { # Declare an array to define the options of this helper. local legacy_args=un - declare -Ar args_array=([u]=db_user= [n]=db_name=) + local -A args_array=([u]=db_user= [n]=db_name=) local db_user local db_name # Manage arguments with getopts diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 350ed3ea0..5cc5d19dd 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -10,7 +10,7 @@ ynh_app_setting_get() { # Declare an array to define the options of this helper. local legacy_args=ak - declare -Ar args_array=( [a]=app= [k]=key= ) + local -A args_array=( [a]=app= [k]=key= ) local app local key # Manage arguments with getopts @@ -30,7 +30,7 @@ ynh_app_setting_get() { ynh_app_setting_set() { # Declare an array to define the options of this helper. local legacy_args=akv - declare -Ar args_array=( [a]=app= [k]=key= [v]=value= ) + local -A args_array=( [a]=app= [k]=key= [v]=value= ) local app local key local value @@ -50,7 +50,7 @@ ynh_app_setting_set() { ynh_app_setting_delete() { # Declare an array to define the options of this helper. local legacy_args=ak - declare -Ar args_array=( [a]=app= [k]=key= ) + local -A args_array=( [a]=app= [k]=key= ) local app local key # Manage arguments with getopts @@ -124,7 +124,7 @@ EOF ynh_webpath_available () { # Declare an array to define the options of this helper. local legacy_args=dp - declare -Ar args_array=( [d]=domain= [p]=path_url= ) + local -A args_array=( [d]=domain= [p]=path_url= ) local domain local path_url # Manage arguments with getopts @@ -146,7 +146,7 @@ ynh_webpath_available () { ynh_webpath_register () { # Declare an array to define the options of this helper. local legacy_args=adp - declare -Ar args_array=( [a]=app= [d]=domain= [p]=path_url= ) + local -A args_array=( [a]=app= [d]=domain= [p]=path_url= ) local app local domain local path_url @@ -180,7 +180,7 @@ ynh_webpath_register () { ynh_permission_create() { # Declare an array to define the options of this helper. local legacy_args=pua - declare -Ar args_array=( [p]=permission= [u]=url= [a]=allowed= ) + local -A args_array=( [p]=permission= [u]=url= [a]=allowed= ) local permission local url local allowed @@ -210,7 +210,7 @@ ynh_permission_create() { ynh_permission_delete() { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=permission= ) + local -A args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -226,7 +226,7 @@ ynh_permission_delete() { ynh_permission_exists() { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=permission= ) + local -A args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -243,7 +243,7 @@ ynh_permission_exists() { ynh_permission_url() { # Declare an array to define the options of this helper. local legacy_args=pu - declare -Ar args_array=([p]=permission= [u]=url=) + local -A args_array=([p]=permission= [u]=url=) local permission local url ynh_handle_getopts_args "$@" @@ -270,7 +270,7 @@ ynh_permission_url() { ynh_permission_update() { # Declare an array to define the options of this helper. local legacy_args=par - declare -Ar args_array=( [p]=permission= [a]=add= [r]=remove= ) + local -A args_array=( [p]=permission= [a]=add= [r]=remove= ) local permission local add local remove @@ -298,7 +298,7 @@ ynh_permission_update() { ynh_permission_has_user() { local legacy_args=pu # Declare an array to define the options of this helper. - declare -Ar args_array=( [p]=permission= [u]=user= ) + local -A args_array=( [p]=permission= [u]=user= ) local permission local user # Manage arguments with getopts diff --git a/data/helpers.d/string b/data/helpers.d/string index e50f781fe..9b8437953 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -11,7 +11,7 @@ ynh_string_random() { # Declare an array to define the options of this helper. local legacy_args=l - declare -Ar args_array=( [l]=length= ) + local -A args_array=( [l]=length= ) local length # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -37,7 +37,7 @@ ynh_string_random() { ynh_replace_string () { # Declare an array to define the options of this helper. local legacy_args=mrf - declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) + local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) local match_string local replace_string local target_file @@ -66,7 +66,7 @@ ynh_replace_string () { ynh_replace_special_string () { # Declare an array to define the options of this helper. local legacy_args=mrf - declare -Ar args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) + local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) local match_string local replace_string local target_file @@ -97,7 +97,7 @@ ynh_replace_special_string () { ynh_sanitize_dbid () { # Declare an array to define the options of this helper. local legacy_args=n - declare -Ar args_array=( [n]=db_name= ) + local -A args_array=( [n]=db_name= ) local db_name # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -125,7 +125,7 @@ ynh_sanitize_dbid () { ynh_normalize_url_path () { # Declare an array to define the options of this helper. local legacy_args=p - declare -Ar args_array=( [p]=path_url= ) + local -A args_array=( [p]=path_url= ) local path_url # Manage arguments with getopts ynh_handle_getopts_args "$@" diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 47e905f0f..276674e70 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -18,7 +18,7 @@ ynh_add_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=st - declare -Ar args_array=( [s]=service= [t]=template= ) + local -A args_array=( [s]=service= [t]=template= ) local service local template # Manage arguments with getopts @@ -54,7 +54,7 @@ ynh_add_systemd_config () { ynh_remove_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=s - declare -Ar args_array=( [s]=service= ) + local -A args_array=( [s]=service= ) local service # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -81,7 +81,7 @@ ynh_remove_systemd_config () { ynh_systemd_action() { # Declare an array to define the options of this helper. local legacy_args=nalpte - declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= ) + local -A args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= ) local service_name local action local line_match diff --git a/data/helpers.d/user b/data/helpers.d/user index 7051ed4c0..72cb9bece 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -11,7 +11,7 @@ ynh_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u - declare -Ar args_array=( [u]=username= ) + local -A args_array=( [u]=username= ) local username # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -32,7 +32,7 @@ ynh_user_exists() { ynh_user_get_info() { # Declare an array to define the options of this helper. local legacy_args=uk - declare -Ar args_array=( [u]=username= [k]=key= ) + local -A args_array=( [u]=username= [k]=key= ) local username local key # Manage arguments with getopts @@ -63,7 +63,7 @@ ynh_user_list() { ynh_system_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u - declare -Ar args_array=( [u]=username= ) + local -A args_array=( [u]=username= ) local username # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -78,7 +78,7 @@ ynh_system_user_exists() { ynh_system_group_exists() { # Declare an array to define the options of this helper. local legacy_args=g - declare -Ar args_array=( [g]=group= ) + local -A args_array=( [g]=group= ) local group # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -103,7 +103,7 @@ ynh_system_group_exists() { ynh_system_user_create () { # Declare an array to define the options of this helper. local legacy_args=uhs - declare -Ar args_array=( [u]=username= [h]=home_dir= [s]=use_shell ) + local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell ) local username local home_dir local use_shell @@ -137,7 +137,7 @@ ynh_system_user_create () { ynh_system_user_delete () { # Declare an array to define the options of this helper. local legacy_args=u - declare -Ar args_array=( [u]=username= ) + local -A args_array=( [u]=username= ) local username # Manage arguments with getopts ynh_handle_getopts_args "$@" diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 133a47247..5f352ab96 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -99,7 +99,7 @@ ynh_abort_if_errors () { ynh_setup_source () { # Declare an array to define the options of this helper. local legacy_args=ds - declare -Ar args_array=( [d]=dest_dir= [s]=source_id= ) + local -A args_array=( [d]=dest_dir= [s]=source_id= ) local dest_dir local source_id # Manage arguments with getopts @@ -304,7 +304,7 @@ properly with chmod/chown." ynh_secure_remove () { # Declare an array to define the options of this helper. local legacy_args=f - declare -Ar args_array=( [f]=file= ) + local -A args_array=( [f]=file= ) local file # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -378,7 +378,7 @@ ynh_get_plain_key() { ynh_read_manifest () { # Declare an array to define the options of this helper. local legacy_args=mk - declare -Ar args_array=( [m]=manifest= [k]=manifest_key= ) + local -A args_array=( [m]=manifest= [k]=manifest_key= ) local manifest local manifest_key # Manage arguments with getopts @@ -406,7 +406,7 @@ ynh_read_manifest () { ynh_app_upstream_version () { # Declare an array to define the options of this helper. local legacy_args=m - declare -Ar args_array=( [m]=manifest= ) + local -A args_array=( [m]=manifest= ) local manifest # Manage arguments with getopts ynh_handle_getopts_args "$@" @@ -430,7 +430,7 @@ ynh_app_upstream_version () { ynh_app_package_version () { # Declare an array to define the options of this helper. local legacy_args=m - declare -Ar args_array=( [m]=manifest= ) + local -A args_array=( [m]=manifest= ) local manifest # Manage arguments with getopts ynh_handle_getopts_args "$@" From 80964a13121e5b2a5f802ede2bf411c356a66244 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 19 Apr 2020 20:03:55 +0200 Subject: [PATCH 186/317] Standardize tabulations --- data/helpers.d/apt | 306 +++++++++++------------ data/helpers.d/backup | 18 +- data/helpers.d/fail2ban | 98 ++++---- data/helpers.d/getopts | 316 ++++++++++++------------ data/helpers.d/hardware | 98 ++++---- data/helpers.d/logging | 294 +++++++++++----------- data/helpers.d/logrotate | 142 +++++------ data/helpers.d/mysql | 85 ++++--- data/helpers.d/network | 82 +++--- data/helpers.d/nginx | 86 +++---- data/helpers.d/nodejs | 190 +++++++------- data/helpers.d/php | 508 +++++++++++++++++++------------------- data/helpers.d/postgresql | 226 ++++++++--------- data/helpers.d/setting | 54 ++-- data/helpers.d/string | 104 ++++---- data/helpers.d/systemd | 78 +++--- data/helpers.d/user | 58 ++--- data/helpers.d/utils | 116 ++++----- 18 files changed, 1429 insertions(+), 1430 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 44d5c9c38..4093e593f 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -114,7 +114,7 @@ ynh_package_update() { # Requires YunoHost version 2.2.4 or higher. ynh_package_install() { ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \ - -o Dpkg::Options::=--force-confold install $@ + -o Dpkg::Options::=--force-confold install $@ } # Remove package(s) @@ -194,7 +194,7 @@ ynh_package_install_from_equivs () { { # If the installation failed # Get the list of dependencies from the deb local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ - sed 's/^ Depends: //' | sed 's/,//g')" + sed 's/^ Depends: //' | sed 's/,//g')" # Fake an install of those dependencies to see the errors # The sed command here is, Print only from '--fix-broken' to the end. ynh_package_install $dependencies --dry-run | sed -n '/--fix-broken/,$p' >&2 @@ -222,7 +222,7 @@ ynh_install_app_dependencies () { local dependencies=${dependencies//|/ | } local manifest_path="../manifest.json" if [ ! -e "$manifest_path" ]; then - manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place + manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place fi local version=$(grep '\"version\": ' "$manifest_path" | cut -d '"' -f 4) # Retrieve the version number in the manifest file. @@ -293,28 +293,28 @@ EOF # | arg: -p, --package - Packages to add as dependencies for the app. # | arg: -r, --replace - Replace dependencies instead of adding to existing ones. ynh_add_app_dependencies () { - # Declare an array to define the options of this helper. - local legacy_args=pr - local -A args_array=( [p]=package= [r]=replace) - local package - local replace - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - replace=${replace:-0} + # Declare an array to define the options of this helper. + local legacy_args=pr + local -A args_array=( [p]=package= [r]=replace) + local package + local replace + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + replace=${replace:-0} - local current_dependencies="" - if [ $replace -eq 0 ] - then - local dep_app=${app//_/-} # Replace all '_' by '-' - if ynh_package_is_installed --package="${dep_app}-ynh-deps" - then - current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) " - fi + local current_dependencies="" + if [ $replace -eq 0 ] + then + local dep_app=${app//_/-} # Replace all '_' by '-' + if ynh_package_is_installed --package="${dep_app}-ynh-deps" + then + current_dependencies="$(dpkg-query --show --showformat='${Depends}' ${dep_app}-ynh-deps) " + fi - current_dependencies=${current_dependencies// | /|} - fi + current_dependencies=${current_dependencies// | /|} + fi - ynh_install_app_dependencies "${current_dependencies}${package}" + ynh_install_app_dependencies "${current_dependencies}${package}" } # Remove fake package and its dependencies @@ -339,31 +339,31 @@ ynh_remove_app_dependencies () { # | arg: -k, --key - url to get the public key. # | arg: -n, --name - Name for the files for this repo, $app as default value. ynh_install_extra_app_dependencies () { - # Declare an array to define the options of this helper. - local legacy_args=rpkn - local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) - local repo - local package - local key - local name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - name="${name:-$app}" - key=${key:-} + # Declare an array to define the options of this helper. + local legacy_args=rpkn + local -A args_array=( [r]=repo= [p]=package= [k]=key= [n]=name= ) + local repo + local package + local key + local name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + key=${key:-} - # Set a key only if asked - if [ -n "$key" ] - then - key="--key=$key" - fi - # Add an extra repository for those packages - ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name + # Set a key only if asked + if [ -n "$key" ] + then + key="--key=$key" + fi + # Add an extra repository for those packages + ynh_install_extra_repo --repo="$repo" $key --priority=995 --name=$name - # Install requested dependencies from this extra repository. - ynh_add_app_dependencies --package="$package" + # Install requested dependencies from this extra repository. + ynh_add_app_dependencies --package="$package" - # Remove this extra repository after packages are installed - ynh_remove_extra_repo --name=$app + # Remove this extra repository after packages are installed + ynh_remove_extra_repo --name=$app } # Add an extra repository correctly, pin it and get the key. @@ -377,66 +377,66 @@ ynh_install_extra_app_dependencies () { # | arg: -n, --name - Name for the files for this repo, $app as default value. # | arg: -a, --append - Do not overwrite existing files. ynh_install_extra_repo () { - # Declare an array to define the options of this helper. - local legacy_args=rkpna - local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) - local repo - local key - local priority - local name - local append - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - name="${name:-$app}" - append=${append:-0} - key=${key:-} - priority=${priority:-} + # Declare an array to define the options of this helper. + local legacy_args=rkpna + local -A args_array=( [r]=repo= [k]=key= [p]=priority= [n]=name= [a]=append ) + local repo + local key + local priority + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + append=${append:-0} + key=${key:-} + priority=${priority:-} - if [ $append -eq 1 ] - then - append="--append" - wget_append="tee -a" - else - append="" - wget_append="tee" - fi + if [ $append -eq 1 ] + then + append="--append" + wget_append="tee -a" + else + append="" + wget_append="tee" + fi - # Split the repository into uri, suite and components. - # Remove "deb " at the beginning of the repo. - repo="${repo#deb }" + # Split the repository into uri, suite and components. + # Remove "deb " at the beginning of the repo. + repo="${repo#deb }" - # Get the uri - local uri="$(echo "$repo" | awk '{ print $1 }')" + # Get the uri + local uri="$(echo "$repo" | awk '{ print $1 }')" - # Get the suite - local suite="$(echo "$repo" | awk '{ print $2 }')" + # Get the suite + local suite="$(echo "$repo" | awk '{ print $2 }')" - # Get the components - local component="${repo##$uri $suite }" + # Get the components + local component="${repo##$uri $suite }" - # Add the repository into sources.list.d - ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append + # Add the repository into sources.list.d + ynh_add_repo --uri="$uri" --suite="$suite" --component="$component" --name="$name" $append - # Pin the new repo with the default priority, so it won't be used for upgrades. - # Build $pin from the uri without http and any sub path - local pin="${uri#*://}" - pin="${pin%%/*}" - # Set a priority only if asked - if [ -n "$priority" ] - then - priority="--priority=$priority" - fi - ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append + # Pin the new repo with the default priority, so it won't be used for upgrades. + # Build $pin from the uri without http and any sub path + local pin="${uri#*://}" + pin="${pin%%/*}" + # Set a priority only if asked + if [ -n "$priority" ] + then + priority="--priority=$priority" + fi + ynh_pin_repo --package="*" --pin="origin \"$pin\"" $priority --name="$name" $append - # Get the public key for the repo - if [ -n "$key" ] - then - mkdir -p "/etc/apt/trusted.gpg.d" - wget -q "$key" -O - | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null - fi + # Get the public key for the repo + if [ -n "$key" ] + then + mkdir -p "/etc/apt/trusted.gpg.d" + wget -q "$key" -O - | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null + fi - # Update the list of package with the new repo - ynh_package_update + # Update the list of package with the new repo + ynh_package_update } # Remove an extra repository and the assiociated configuration. @@ -446,21 +446,21 @@ ynh_install_extra_repo () { # usage: ynh_remove_extra_repo [--name=name] # | arg: -n, --name - Name for the files for this repo, $app as default value. ynh_remove_extra_repo () { - # Declare an array to define the options of this helper. - local legacy_args=n - local -A args_array=( [n]=name= ) - local name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - name="${name:-$app}" + # Declare an array to define the options of this helper. + local legacy_args=n + local -A args_array=( [n]=name= ) + local name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" - ynh_secure_remove "/etc/apt/sources.list.d/$name.list" - ynh_secure_remove "/etc/apt/preferences.d/$name" - ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.gpg" - ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.asc" + ynh_secure_remove "/etc/apt/sources.list.d/$name.list" + ynh_secure_remove "/etc/apt/preferences.d/$name" + ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.gpg" + ynh_secure_remove "/etc/apt/trusted.gpg.d/$name.asc" - # Update the list of package to exclude the old repo - ynh_package_update + # Update the list of package to exclude the old repo + ynh_package_update } # Add a repository. @@ -479,30 +479,30 @@ ynh_remove_extra_repo () { # ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable # ynh_add_repo () { - # Declare an array to define the options of this helper. - local legacy_args=uscna - local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) - local uri - local suite - local component - local name - local append - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - name="${name:-$app}" - append=${append:-0} + # Declare an array to define the options of this helper. + local legacy_args=uscna + local -A args_array=( [u]=uri= [s]=suite= [c]=component= [n]=name= [a]=append ) + local uri + local suite + local component + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + name="${name:-$app}" + append=${append:-0} - if [ $append -eq 1 ] - then - append="tee -a" - else - append="tee" - fi + if [ $append -eq 1 ] + then + append="tee -a" + else + append="tee" + fi - mkdir -p "/etc/apt/sources.list.d" - # Add the new repo in sources.list.d - echo "deb $uri $suite $component" \ - | $append "/etc/apt/sources.list.d/$name.list" + mkdir -p "/etc/apt/sources.list.d" + # Add the new repo in sources.list.d + echo "deb $uri $suite $component" \ + | $append "/etc/apt/sources.list.d/$name.list" } # Pin a repository. @@ -519,32 +519,32 @@ ynh_add_repo () { # See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning. # ynh_pin_repo () { - # Declare an array to define the options of this helper. - local legacy_args=pirna - local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) - local package - local pin - local priority - local name - local append - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - package="${package:-*}" - priority=${priority:-50} - name="${name:-$app}" - append=${append:-0} + # Declare an array to define the options of this helper. + local legacy_args=pirna + local -A args_array=( [p]=package= [i]=pin= [r]=priority= [n]=name= [a]=append ) + local package + local pin + local priority + local name + local append + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package="${package:-*}" + priority=${priority:-50} + name="${name:-$app}" + append=${append:-0} - if [ $append -eq 1 ] - then - append="tee -a" - else - append="tee" - fi + if [ $append -eq 1 ] + then + append="tee -a" + else + append="tee" + fi - mkdir -p "/etc/apt/preferences.d" - echo "Package: $package + mkdir -p "/etc/apt/preferences.d" + echo "Package: $package Pin: $pin Pin-Priority: $priority " \ - | $append "/etc/apt/preferences.d/$name" + | $append "/etc/apt/preferences.d/$name" } diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 9ffb13bbb..bb676a0e0 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -80,16 +80,16 @@ ynh_backup() { ynh_print_warn --message="Source path '${src_path}' does not exist" if [ "$not_mandatory" == "0" ] then - # This is a temporary fix for fail2ban config files missing after the migration to stretch. - if echo "${src_path}" | grep --quiet "/etc/fail2ban" - then - touch "${src_path}" - ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!" - else - return 1 - fi + # This is a temporary fix for fail2ban config files missing after the migration to stretch. + if echo "${src_path}" | grep --quiet "/etc/fail2ban" + then + touch "${src_path}" + ynh_print_info --message="The missing file will be replaced by a dummy one for the backup !!!" + else + return 1 + fi else - return 0 + return 0 fi } diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 5c4cb89a9..2c17e1300 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -63,47 +63,47 @@ # # Requires YunoHost version 3.5.0 or higher. ynh_add_fail2ban_config () { - # Declare an array to define the options of this helper. - local legacy_args=lrmptv - local -A args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=) - local logpath - local failregex - local max_retry - local ports - local others_var - local use_template - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - use_template="${use_template:-0}" - max_retry=${max_retry:-3} - ports=${ports:-http,https} + # Declare an array to define the options of this helper. + local legacy_args=lrmptv + local -A args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=) + local logpath + local failregex + local max_retry + local ports + local others_var + local use_template + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + use_template="${use_template:-0}" + max_retry=${max_retry:-3} + ports=${ports:-http,https} - finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf" - finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf" - ynh_backup_if_checksum_is_different "$finalfail2banjailconf" - ynh_backup_if_checksum_is_different "$finalfail2banfilterconf" + finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf" + finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf" + ynh_backup_if_checksum_is_different "$finalfail2banjailconf" + ynh_backup_if_checksum_is_different "$finalfail2banfilterconf" - if [ $use_template -eq 1 ] - then - # Usage 2, templates - cp ../conf/f2b_jail.conf $finalfail2banjailconf - cp ../conf/f2b_filter.conf $finalfail2banfilterconf - - if [ -n "${app:-}" ] + if [ $use_template -eq 1 ] then - ynh_replace_string "__APP__" "$app" "$finalfail2banjailconf" - ynh_replace_string "__APP__" "$app" "$finalfail2banfilterconf" - fi + # Usage 2, templates + cp ../conf/f2b_jail.conf $finalfail2banjailconf + cp ../conf/f2b_filter.conf $finalfail2banfilterconf - # Replace all other variable given as arguments - for var_to_replace in ${others_var:-}; do - # ${var_to_replace^^} make the content of the variable on upper-cases - # ${!var_to_replace} get the content of the variable named $var_to_replace - ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf" - ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banfilterconf" - done + if [ -n "${app:-}" ] + then + ynh_replace_string "__APP__" "$app" "$finalfail2banjailconf" + ynh_replace_string "__APP__" "$app" "$finalfail2banfilterconf" + fi - else + # Replace all other variable given as arguments + for var_to_replace in ${others_var:-}; do + # ${var_to_replace^^} make the content of the variable on upper-cases + # ${!var_to_replace} get the content of the variable named $var_to_replace + ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf" + ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banfilterconf" + done + + else # Usage 1, no template. Build a config file from scratch. test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing." test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing." @@ -124,19 +124,19 @@ before = common.conf failregex = $failregex ignoreregex = EOF - fi + fi - # Common to usage 1 and 2. - ynh_store_file_checksum "$finalfail2banjailconf" - ynh_store_file_checksum "$finalfail2banfilterconf" + # Common to usage 1 and 2. + ynh_store_file_checksum "$finalfail2banjailconf" + ynh_store_file_checksum "$finalfail2banfilterconf" - ynh_systemd_action --service_name=fail2ban --action=reload + ynh_systemd_action --service_name=fail2ban --action=reload - local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")" - if [[ -n "$fail2ban_error" ]]; then - ynh_print_err --message="Fail2ban failed to load the jail for $app" - ynh_print_warn --message="${fail2ban_error#*WARNING}" - fi + local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")" + if [[ -n "$fail2ban_error" ]]; then + ynh_print_err --message="Fail2ban failed to load the jail for $app" + ynh_print_warn --message="${fail2ban_error#*WARNING}" + fi } # Remove the dedicated fail2ban config (jail and filter conf files) @@ -145,7 +145,7 @@ EOF # # Requires YunoHost version 3.5.0 or higher. ynh_remove_fail2ban_config () { - ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf" - ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf" - ynh_systemd_action --service_name=fail2ban --action=reload + ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf" + ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf" + ynh_systemd_action --service_name=fail2ban --action=reload } diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index 285375915..3bdfc80eb 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -46,173 +46,173 @@ # # Requires YunoHost version 3.2.2 or higher. ynh_handle_getopts_args () { - # Manage arguments only if there's some provided - set +x - if [ $# -ne 0 ] - then - # Store arguments in an array to keep each argument separated - local arguments=("$@") + # Manage arguments only if there's some provided + set +x + if [ $# -ne 0 ] + then + # Store arguments in an array to keep each argument separated + local arguments=("$@") - # For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u) - # And built parameters string for getopts - # ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value) - local getopts_parameters="" - local option_flag="" - for option_flag in "${!args_array[@]}" - do - # Concatenate each option_flags of the array to build the string of arguments for getopts - # Will looks like 'abcd' for -a -b -c -d - # If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob) - # Check the last character of the value associate to the option_flag - if [ "${args_array[$option_flag]: -1}" = "=" ] - then - # For an option with additionnal values, add a ':' after the letter for getopts. - getopts_parameters="${getopts_parameters}${option_flag}:" - else - getopts_parameters="${getopts_parameters}${option_flag}" - fi - # Check each argument given to the function - local arg="" - # ${#arguments[@]} is the size of the array - for arg in `seq 0 $(( ${#arguments[@]} - 1 ))` - do - # Escape options' values starting with -. Otherwise the - will be considered as another option. - arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}" - # And replace long option (value of the option_flag) by the short option, the option_flag itself - # (e.g. for [u]=user, --user will be -u) - # Replace long option with = - arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}/-${option_flag} }" - # And long option without = - arguments[arg]="${arguments[arg]//--${args_array[$option_flag]%=}/-${option_flag}}" - done - done + # For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u) + # And built parameters string for getopts + # ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value) + local getopts_parameters="" + local option_flag="" + for option_flag in "${!args_array[@]}" + do + # Concatenate each option_flags of the array to build the string of arguments for getopts + # Will looks like 'abcd' for -a -b -c -d + # If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob) + # Check the last character of the value associate to the option_flag + if [ "${args_array[$option_flag]: -1}" = "=" ] + then + # For an option with additionnal values, add a ':' after the letter for getopts. + getopts_parameters="${getopts_parameters}${option_flag}:" + else + getopts_parameters="${getopts_parameters}${option_flag}" + fi + # Check each argument given to the function + local arg="" + # ${#arguments[@]} is the size of the array + for arg in `seq 0 $(( ${#arguments[@]} - 1 ))` + do + # Escape options' values starting with -. Otherwise the - will be considered as another option. + arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}-/--${args_array[$option_flag]}\\TOBEREMOVED\\-}" + # And replace long option (value of the option_flag) by the short option, the option_flag itself + # (e.g. for [u]=user, --user will be -u) + # Replace long option with = + arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}/-${option_flag} }" + # And long option without = + arguments[arg]="${arguments[arg]//--${args_array[$option_flag]%=}/-${option_flag}}" + done + done - # Read and parse all the arguments - # Use a function here, to use standart arguments $@ and be able to use shift. - parse_arg () { - # Read all arguments, until no arguments are left - while [ $# -ne 0 ] - do - # Initialize the index of getopts - OPTIND=1 - # Parse with getopts only if the argument begin by -, that means the argument is an option - # getopts will fill $parameter with the letter of the option it has read. - local parameter="" - getopts ":$getopts_parameters" parameter || true + # Read and parse all the arguments + # Use a function here, to use standart arguments $@ and be able to use shift. + parse_arg () { + # Read all arguments, until no arguments are left + while [ $# -ne 0 ] + do + # Initialize the index of getopts + OPTIND=1 + # Parse with getopts only if the argument begin by -, that means the argument is an option + # getopts will fill $parameter with the letter of the option it has read. + local parameter="" + getopts ":$getopts_parameters" parameter || true - if [ "$parameter" = "?" ] - then - ynh_die --message="Invalid argument: -${OPTARG:-}" - elif [ "$parameter" = ":" ] - then - ynh_die --message="-$OPTARG parameter requires an argument." - else - local shift_value=1 - # Use the long option, corresponding to the short option read by getopts, as a variable - # (e.g. for [u]=user, 'user' will be used as a variable) - # Also, remove '=' at the end of the long option - # The variable name will be stored in 'option_var' - local option_var="${args_array[$parameter]%=}" - # If this option doesn't take values - # if there's a '=' at the end of the long option name, this option takes values - if [ "${args_array[$parameter]: -1}" != "=" ] - then - # 'eval ${option_var}' will use the content of 'option_var' - eval ${option_var}=1 - else - # Read all other arguments to find multiple value for this option. - # Load args in a array - local all_args=("$@") + if [ "$parameter" = "?" ] + then + ynh_die --message="Invalid argument: -${OPTARG:-}" + elif [ "$parameter" = ":" ] + then + ynh_die --message="-$OPTARG parameter requires an argument." + else + local shift_value=1 + # Use the long option, corresponding to the short option read by getopts, as a variable + # (e.g. for [u]=user, 'user' will be used as a variable) + # Also, remove '=' at the end of the long option + # The variable name will be stored in 'option_var' + local option_var="${args_array[$parameter]%=}" + # If this option doesn't take values + # if there's a '=' at the end of the long option name, this option takes values + if [ "${args_array[$parameter]: -1}" != "=" ] + then + # 'eval ${option_var}' will use the content of 'option_var' + eval ${option_var}=1 + else + # Read all other arguments to find multiple value for this option. + # Load args in a array + local all_args=("$@") - # If the first argument is longer than 2 characters, - # There's a value attached to the option, in the same array cell - if [ ${#all_args[0]} -gt 2 ]; then - # Remove the option and the space, so keep only the value itself. - all_args[0]="${all_args[0]#-${parameter} }" - # Reduce the value of shift, because the option has been removed manually - shift_value=$(( shift_value - 1 )) - fi + # If the first argument is longer than 2 characters, + # There's a value attached to the option, in the same array cell + if [ ${#all_args[0]} -gt 2 ]; then + # Remove the option and the space, so keep only the value itself. + all_args[0]="${all_args[0]#-${parameter} }" + # Reduce the value of shift, because the option has been removed manually + shift_value=$(( shift_value - 1 )) + fi - # Declare the content of option_var as a variable. - eval ${option_var}="" - # Then read the array value per value - local i - for i in `seq 0 $(( ${#all_args[@]} - 1 ))` - do - # If this argument is an option, end here. - if [ "${all_args[$i]:0:1}" == "-" ] - then - # Ignore the first value of the array, which is the option itself - if [ "$i" -ne 0 ]; then - break - fi - else - # Else, add this value to this option - # Each value will be separated by ';' - if [ -n "${!option_var}" ] - then - # If there's already another value for this option, add a ; before adding the new value - eval ${option_var}+="\;" - fi + # Declare the content of option_var as a variable. + eval ${option_var}="" + # Then read the array value per value + local i + for i in `seq 0 $(( ${#all_args[@]} - 1 ))` + do + # If this argument is an option, end here. + if [ "${all_args[$i]:0:1}" == "-" ] + then + # Ignore the first value of the array, which is the option itself + if [ "$i" -ne 0 ]; then + break + fi + else + # Else, add this value to this option + # Each value will be separated by ';' + if [ -n "${!option_var}" ] + then + # If there's already another value for this option, add a ; before adding the new value + eval ${option_var}+="\;" + fi - # Remove the \ that escape - at beginning of values. - all_args[i]="${all_args[i]//\\TOBEREMOVED\\/}" + # Remove the \ that escape - at beginning of values. + all_args[i]="${all_args[i]//\\TOBEREMOVED\\/}" - # For the record. - # We're using eval here to get the content of the variable stored itself as simple text in $option_var... - # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var} - # But... ${!option_var} can't be used as left part of an assignation. - # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself. - # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one! + # For the record. + # We're using eval here to get the content of the variable stored itself as simple text in $option_var... + # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var} + # But... ${!option_var} can't be used as left part of an assignation. + # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself. + # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one! - eval ${option_var}+='"${all_args[$i]}"' - shift_value=$(( shift_value + 1 )) - fi - done - fi - fi + eval ${option_var}+='"${all_args[$i]}"' + shift_value=$(( shift_value + 1 )) + fi + done + fi + fi - # Shift the parameter and its argument(s) - shift $shift_value - done - } + # Shift the parameter and its argument(s) + shift $shift_value + done + } - # LEGACY MODE - # Check if there's getopts arguments - if [ "${arguments[0]:0:1}" != "-" ] - then - # If not, enter in legacy mode and manage the arguments as positionnal ones.. - # Dot not echo, to prevent to go through a helper output. But print only in the log. - set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x - local i - for i in `seq 0 $(( ${#arguments[@]} -1 ))` - do - # Try to use legacy_args as a list of option_flag of the array args_array - # Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order... - # Remove all ':' in getopts_parameters - getopts_parameters=${legacy_args:-${getopts_parameters//:}} - # Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument. - option_flag=${getopts_parameters:$i:1} - if [ -z "$option_flag" ]; then - ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored." - continue - fi - # Use the long option, corresponding to the option_flag, as a variable - # (e.g. for [u]=user, 'user' will be used as a variable) - # Also, remove '=' at the end of the long option - # The variable name will be stored in 'option_var' - local option_var="${args_array[$option_flag]%=}" + # LEGACY MODE + # Check if there's getopts arguments + if [ "${arguments[0]:0:1}" != "-" ] + then + # If not, enter in legacy mode and manage the arguments as positionnal ones.. + # Dot not echo, to prevent to go through a helper output. But print only in the log. + set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x + local i + for i in `seq 0 $(( ${#arguments[@]} -1 ))` + do + # Try to use legacy_args as a list of option_flag of the array args_array + # Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order... + # Remove all ':' in getopts_parameters + getopts_parameters=${legacy_args:-${getopts_parameters//:}} + # Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument. + option_flag=${getopts_parameters:$i:1} + if [ -z "$option_flag" ]; then + ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored." + continue + fi + # Use the long option, corresponding to the option_flag, as a variable + # (e.g. for [u]=user, 'user' will be used as a variable) + # Also, remove '=' at the end of the long option + # The variable name will be stored in 'option_var' + local option_var="${args_array[$option_flag]%=}" - # Store each value given as argument in the corresponding variable - # The values will be stored in the same order than $args_array - eval ${option_var}+='"${arguments[$i]}"' - done - unset legacy_args - else - # END LEGACY MODE - # Call parse_arg and pass the modified list of args as an array of arguments. - parse_arg "${arguments[@]}" - fi - fi - set -x + # Store each value given as argument in the corresponding variable + # The values will be stored in the same order than $args_array + eval ${option_var}+='"${arguments[$i]}"' + done + unset legacy_args + else + # END LEGACY MODE + # Call parse_arg and pass the modified list of args as an array of arguments. + parse_arg "${arguments[@]}" + fi + fi + set -x } diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index 1bfc648fe..d7e14ccc5 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -8,58 +8,58 @@ # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -o, --only_swap - Ignore real RAM, consider only swap ynh_get_ram () { - # Declare an array to define the options of this helper. - local legacy_args=ftso - local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) - local free - local total - local ignore_swap - local only_swap - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - ignore_swap=${ignore_swap:-0} - only_swap=${only_swap:-0} - free=${free:-0} - total=${total:-0} + # Declare an array to define the options of this helper. + local legacy_args=ftso + local -A args_array=( [f]=free [t]=total [s]=ignore_swap [o]=only_swap ) + local free + local total + local ignore_swap + local only_swap + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + ignore_swap=${ignore_swap:-0} + only_swap=${only_swap:-0} + free=${free:-0} + total=${total:-0} - local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') - local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') - local total_ram_swap=$(( total_ram + total_swap )) + local total_ram=$(vmstat --stats --unit M | grep "total memory" | awk '{print $1}') + local total_swap=$(vmstat --stats --unit M | grep "total swap" | awk '{print $1}') + local total_ram_swap=$(( total_ram + total_swap )) - local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}') - local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}') - local free_ram_swap=$(( free_ram + free_swap )) + local free_ram=$(vmstat --stats --unit M | grep "free memory" | awk '{print $1}') + local free_swap=$(vmstat --stats --unit M | grep "free swap" | awk '{print $1}') + local free_ram_swap=$(( free_ram + free_swap )) - # Use the total amount of ram - if [ $free -eq 1 ] - then - # Use the total amount of free ram - local ram=$free_ram_swap - if [ $ignore_swap -eq 1 ] - then - # Use only the amount of free ram - ram=$free_ram - elif [ $only_swap -eq 1 ] - then - # Use only the amount of free swap - ram=$free_swap - fi - elif [ $total -eq 1 ] - then - local ram=$total_ram_swap - if [ $ignore_swap -eq 1 ] - then - # Use only the amount of free ram - ram=$total_ram - elif [ $only_swap -eq 1 ] - then - # Use only the amount of free swap - ram=$total_swap - fi - else - ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram" - ram=0 - fi + # Use the total amount of ram + if [ $free -eq 1 ] + then + # Use the total amount of free ram + local ram=$free_ram_swap + if [ $ignore_swap -eq 1 ] + then + # Use only the amount of free ram + ram=$free_ram + elif [ $only_swap -eq 1 ] + then + # Use only the amount of free swap + ram=$free_swap + fi + elif [ $total -eq 1 ] + then + local ram=$total_ram_swap + if [ $ignore_swap -eq 1 ] + then + # Use only the amount of free ram + ram=$total_ram + elif [ $only_swap -eq 1 ] + then + # Use only the amount of free swap + ram=$total_swap + fi + else + ynh_print_warn --message="You have to choose --free or --total when using ynh_get_ram" + ram=0 + fi echo $ram } diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 9f4a89df8..0cd25fb57 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -6,16 +6,16 @@ # # Requires YunoHost version 2.4.0 or higher. ynh_die() { - # Declare an array to define the options of this helper. - local legacy_args=mc - local -A args_array=( [m]=message= [c]=ret_code= ) - local message - local ret_code - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=mc + local -A args_array=( [m]=message= [c]=ret_code= ) + local message + local ret_code + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - echo "$message" 1>&2 - exit "${ret_code:-1}" + echo "$message" 1>&2 + exit "${ret_code:-1}" } # Display a message in the 'INFO' logging category @@ -45,12 +45,12 @@ ynh_print_info() { # # Requires YunoHost version 2.6.4 or higher. ynh_no_log() { - local ynh_cli_log=/var/log/yunohost/yunohost-cli.log - cp -a ${ynh_cli_log} ${ynh_cli_log}-move - eval $@ - local exit_code=$? - mv ${ynh_cli_log}-move ${ynh_cli_log} - return $? + local ynh_cli_log=/var/log/yunohost/yunohost-cli.log + cp -a ${ynh_cli_log} ${ynh_cli_log}-move + eval $@ + local exit_code=$? + mv ${ynh_cli_log}-move ${ynh_cli_log} + return $? } # Main printer, just in case in the future we have to change anything about that. @@ -59,7 +59,7 @@ ynh_no_log() { # # Requires YunoHost version 3.2.0 or higher. ynh_print_log () { - echo -e "${1}" + echo -e "${1}" } # Print a warning on stderr @@ -69,14 +69,14 @@ ynh_print_log () { # # Requires YunoHost version 3.2.0 or higher. ynh_print_warn () { - # Declare an array to define the options of this helper. - local legacy_args=m - local -A args_array=( [m]=message= ) - local message - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=m + local -A args_array=( [m]=message= ) + local message + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - ynh_print_log "\e[93m\e[1m[WARN]\e[0m ${message}" >&2 + ynh_print_log "\e[93m\e[1m[WARN]\e[0m ${message}" >&2 } # Print an error on stderr @@ -86,14 +86,14 @@ ynh_print_warn () { # # Requires YunoHost version 3.2.0 or higher. ynh_print_err () { - # Declare an array to define the options of this helper. - local legacy_args=m - local -A args_array=( [m]=message= ) - local message - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=m + local -A args_array=( [m]=message= ) + local message + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - ynh_print_log "\e[91m\e[1m[ERR]\e[0m ${message}" >&2 + ynh_print_log "\e[91m\e[1m[ERR]\e[0m ${message}" >&2 } # Execute a command and print the result as an error @@ -109,7 +109,7 @@ ynh_print_err () { # # Requires YunoHost version 3.2.0 or higher. ynh_exec_err () { - ynh_print_err "$(eval $@)" + ynh_print_err "$(eval $@)" } # Execute a command and print the result as a warning @@ -125,7 +125,7 @@ ynh_exec_err () { # # Requires YunoHost version 3.2.0 or higher. ynh_exec_warn () { - ynh_print_warn "$(eval $@)" + ynh_print_warn "$(eval $@)" } # Execute a command and force the result to be printed on stdout @@ -141,7 +141,7 @@ ynh_exec_warn () { # # Requires YunoHost version 3.2.0 or higher. ynh_exec_warn_less () { - eval $@ 2>&1 + eval $@ 2>&1 } # Execute a command and redirect stdout in /dev/null @@ -157,7 +157,7 @@ ynh_exec_warn_less () { # # Requires YunoHost version 3.2.0 or higher. ynh_exec_quiet () { - eval $@ > /dev/null + eval $@ > /dev/null } # Execute a command and redirect stdout and stderr in /dev/null @@ -173,7 +173,7 @@ ynh_exec_quiet () { # # Requires YunoHost version 3.2.0 or higher. ynh_exec_fully_quiet () { - eval $@ > /dev/null 2>&1 + eval $@ > /dev/null 2>&1 } # Remove any logs for all the following commands. @@ -184,7 +184,7 @@ ynh_exec_fully_quiet () { # # Requires YunoHost version 3.2.0 or higher. ynh_print_OFF () { - exec {BASH_XTRACEFD}>/dev/null + exec {BASH_XTRACEFD}>/dev/null } # Restore the logging after ynh_print_OFF @@ -193,9 +193,9 @@ ynh_print_OFF () { # # Requires YunoHost version 3.2.0 or higher. ynh_print_ON () { - exec {BASH_XTRACEFD}>&1 - # Print an echo only for the log, to be able to know that ynh_print_ON has been called. - echo ynh_print_ON > /dev/null + exec {BASH_XTRACEFD}>&1 + # Print an echo only for the log, to be able to know that ynh_print_ON has been called. + echo ynh_print_ON > /dev/null } # Initial definitions for ynh_script_progression @@ -221,81 +221,81 @@ base_time=$(date +%s) # # Requires YunoHost version 3.5.0 or higher. ynh_script_progression () { - set +x - # Declare an array to define the options of this helper. - local legacy_args=mwtl - local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) - local message - local weight - local time - local last - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - set +x - weight=${weight:-1} - time=${time:-0} - last=${last:-0} + set +x + # Declare an array to define the options of this helper. + local legacy_args=mwtl + local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) + local message + local weight + local time + local last + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + set +x + weight=${weight:-1} + time=${time:-0} + last=${last:-0} - # Get execution time since the last $base_time - local exec_time=$(( $(date +%s) - $base_time )) - base_time=$(date +%s) + # Get execution time since the last $base_time + local exec_time=$(( $(date +%s) - $base_time )) + base_time=$(date +%s) - # Compute $max_progression (if we didn't already) - if [ "$max_progression" = -1 ] - then - # Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented. - local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)" - # Get the number of call with a weight value - local weight_calls=$(grep --perl-regexp --count "^[^#]*ynh_script_progression.*(--weight|-w )" $0) + # Compute $max_progression (if we didn't already) + if [ "$max_progression" = -1 ] + then + # Get the number of occurrences of 'ynh_script_progression' in the script. Except those are commented. + local helper_calls="$(grep --count "^[^#]*ynh_script_progression" $0)" + # Get the number of call with a weight value + local weight_calls=$(grep --perl-regexp --count "^[^#]*ynh_script_progression.*(--weight|-w )" $0) - # Get the weight of each occurrences of 'ynh_script_progression' in the script using --weight - local weight_valuesA="$(grep --perl-regexp "^[^#]*ynh_script_progression.*--weight" $0 | sed 's/.*--weight[= ]\([[:digit:]]*\).*/\1/g')" - # Get the weight of each occurrences of 'ynh_script_progression' in the script using -w - local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')" - # Each value will be on a different line. - # Remove each 'end of line' and replace it by a '+' to sum the values. - local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 )) + # Get the weight of each occurrences of 'ynh_script_progression' in the script using --weight + local weight_valuesA="$(grep --perl-regexp "^[^#]*ynh_script_progression.*--weight" $0 | sed 's/.*--weight[= ]\([[:digit:]]*\).*/\1/g')" + # Get the weight of each occurrences of 'ynh_script_progression' in the script using -w + local weight_valuesB="$(grep --perl-regexp "^[^#]*ynh_script_progression.*-w " $0 | sed 's/.*-w[= ]\([[:digit:]]*\).*/\1/g')" + # Each value will be on a different line. + # Remove each 'end of line' and replace it by a '+' to sum the values. + local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 )) - # max_progression is a total number of calls to this helper. - # Less the number of calls with a weight value. - # Plus the total of weight values - max_progression=$(( $helper_calls - $weight_calls + $weight_values )) - fi + # max_progression is a total number of calls to this helper. + # Less the number of calls with a weight value. + # Plus the total of weight values + max_progression=$(( $helper_calls - $weight_calls + $weight_values )) + fi - # Increment each execution of ynh_script_progression in this script by the weight of the previous call. - increment_progression=$(( $increment_progression + $previous_weight )) - # Store the weight of the current call in $previous_weight for next call - previous_weight=$weight + # Increment each execution of ynh_script_progression in this script by the weight of the previous call. + increment_progression=$(( $increment_progression + $previous_weight )) + # Store the weight of the current call in $previous_weight for next call + previous_weight=$weight - # Reduce $increment_progression to the size of the scale - if [ $last -eq 0 ] - then - local effective_progression=$(( $increment_progression * $progress_scale / $max_progression )) - # If last is specified, fill immediately the progression_bar - else - local effective_progression=$progress_scale - fi + # Reduce $increment_progression to the size of the scale + if [ $last -eq 0 ] + then + local effective_progression=$(( $increment_progression * $progress_scale / $max_progression )) + # If last is specified, fill immediately the progression_bar + else + local effective_progression=$progress_scale + fi - # Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task - # expected_progression is the progression expected after the current task - local expected_progression="$(( ( $increment_progression + $weight ) * $progress_scale / $max_progression - $effective_progression ))" - if [ $last -eq 1 ] - then - expected_progression=0 - fi - # left_progression is the progression not yet done - local left_progression="$(( $progress_scale - $effective_progression - $expected_progression ))" - # Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done. - local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}" + # Build $progression_bar from progress_string(0,1,2) according to $effective_progression and the weight of the current task + # expected_progression is the progression expected after the current task + local expected_progression="$(( ( $increment_progression + $weight ) * $progress_scale / $max_progression - $effective_progression ))" + if [ $last -eq 1 ] + then + expected_progression=0 + fi + # left_progression is the progression not yet done + local left_progression="$(( $progress_scale - $effective_progression - $expected_progression ))" + # Build the progression bar with $effective_progression, work done, $expected_progression, current work and $left_progression, work to be done. + local progression_bar="${progress_string2:0:$effective_progression}${progress_string1:0:$expected_progression}${progress_string0:0:$left_progression}" - local print_exec_time="" - if [ $time -eq 1 ] - then - print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]" - fi + local print_exec_time="" + if [ $time -eq 1 ] + then + print_exec_time=" [$(date +%Hh%Mm,%Ss --date="0 + $exec_time sec")]" + fi - ynh_print_info "[$progression_bar] > ${message}${print_exec_time}" - set -x + ynh_print_info "[$progression_bar] > ${message}${print_exec_time}" + set -x } # Return data to the Yunohost core for later processing @@ -316,49 +316,49 @@ ynh_return () { # # Requires YunoHost version 3.5.0 or higher. ynh_debug () { - # Disable set xtrace for the helper itself, to not pollute the debug log - set +x - # Declare an array to define the options of this helper. - local legacy_args=mt - local -A args_array=( [m]=message= [t]=trace= ) - local message - local trace - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - # Redisable xtrace, ynh_handle_getopts_args set it back - set +x - message=${message:-} - trace=${trace:-} + # Disable set xtrace for the helper itself, to not pollute the debug log + set +x + # Declare an array to define the options of this helper. + local legacy_args=mt + local -A args_array=( [m]=message= [t]=trace= ) + local message + local trace + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + # Redisable xtrace, ynh_handle_getopts_args set it back + set +x + message=${message:-} + trace=${trace:-} - if [ -n "$message" ] - then - ynh_print_log "\e[34m\e[1m[DEBUG]\e[0m ${message}" >&2 - fi + if [ -n "$message" ] + then + ynh_print_log "\e[34m\e[1m[DEBUG]\e[0m ${message}" >&2 + fi - if [ "$trace" == "1" ] - then - ynh_debug --message="Enable debugging" - set +x - # Get the current file descriptor of xtrace - old_bash_xtracefd=$BASH_XTRACEFD - # Add the current file name and the line number of any command currently running while tracing. - PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: ' - # Force xtrace to stderr - BASH_XTRACEFD=2 - # Force stdout to stderr - exec 1>&2 - fi - if [ "$trace" == "0" ] - then - ynh_debug --message="Disable debugging" - set +x - # Put xtrace back to its original fild descriptor - BASH_XTRACEFD=$old_bash_xtracefd - # Restore stdout - exec 1>&1 - fi - # Renable set xtrace - set -x + if [ "$trace" == "1" ] + then + ynh_debug --message="Enable debugging" + set +x + # Get the current file descriptor of xtrace + old_bash_xtracefd=$BASH_XTRACEFD + # Add the current file name and the line number of any command currently running while tracing. + PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: ' + # Force xtrace to stderr + BASH_XTRACEFD=2 + # Force stdout to stderr + exec 1>&2 + fi + if [ "$trace" == "0" ] + then + ynh_debug --message="Disable debugging" + set +x + # Put xtrace back to its original fild descriptor + BASH_XTRACEFD=$old_bash_xtracefd + # Restore stdout + exec 1>&1 + fi + # Renable set xtrace + set -x } # Execute a command and print the result as debug @@ -374,5 +374,5 @@ ynh_debug () { # # Requires YunoHost version 3.5.0 or higher. ynh_debug_exec () { - ynh_debug --message="$(eval $@)" + ynh_debug --message="$(eval $@)" } diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index f77e25342..b0a64f553 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -17,81 +17,81 @@ # # Requires YunoHost version 2.6.4 or higher. ynh_use_logrotate () { - # Declare an array to define the options of this helper. - local legacy_args=lnuya - local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append ) - # [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append' - local logfile - local nonappend - local specific_user - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - local logfile="${logfile:-}" - local nonappend="${nonappend:-0}" - local specific_user="${specific_user:-}" + # Declare an array to define the options of this helper. + local legacy_args=lnuya + local -A args_array=( [l]=logfile= [n]=nonappend [u]=specific_user= [y]=non [a]=append ) + # [y]=non [a]=append are only for legacy purpose, to not fail on the old option '--non-append' + local logfile + local nonappend + local specific_user + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + local logfile="${logfile:-}" + local nonappend="${nonappend:-0}" + local specific_user="${specific_user:-}" - # LEGACY CODE - PRE GETOPTS - if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then - nonappend=1 - # Destroy this argument for the next command. - shift - elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then - nonappend=1 - fi + # LEGACY CODE - PRE GETOPTS + if [ $# -gt 0 ] && [ "$1" == "--non-append" ]; then + nonappend=1 + # Destroy this argument for the next command. + shift + elif [ $# -gt 1 ] && [ "$2" == "--non-append" ]; then + nonappend=1 + fi - if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then - # If the given logfile parameter already exists as a file, or if it ends up with ".log", - # we just want to manage a single file - if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then - local logfile=$1 - # Otherwise we assume we want to manage a directory and all its .log file inside - else - local logfile=$1/*.log - fi - fi - # LEGACY CODE + if [ $# -gt 0 ] && [ "$(echo ${1:0:1})" != "-" ]; then + # If the given logfile parameter already exists as a file, or if it ends up with ".log", + # we just want to manage a single file + if [ -f "$1" ] || [ "$(echo ${1##*.})" == "log" ]; then + local logfile=$1 + # Otherwise we assume we want to manage a directory and all its .log file inside + else + local logfile=$1/*.log + fi + fi + # LEGACY CODE - local customtee="tee -a" - if [ "$nonappend" -eq 1 ]; then - customtee="tee" - fi - if [ -n "$logfile" ] - then - if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile - local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it. - fi - else - logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log - fi - local su_directive="" - if [[ -n $specific_user ]]; then - su_directive=" # Run logorotate as specific user - group - su ${specific_user%/*} ${specific_user#*/}" - fi + local customtee="tee -a" + if [ "$nonappend" -eq 1 ]; then + customtee="tee" + fi + if [ -n "$logfile" ] + then + if [ ! -f "$1" ] && [ "$(echo ${logfile##*.})" != "log" ]; then # Keep only the extension to check if it's a logfile + local logfile="$logfile/*.log" # Else, uses the directory and all logfile into it. + fi + else + logfile="/var/log/${app}/*.log" # Without argument, use a defaut directory in /var/log + fi + local su_directive="" + if [[ -n $specific_user ]]; then + su_directive=" # Run logorotate as specific user - group + su ${specific_user%/*} ${specific_user#*/}" + fi - cat > ./${app}-logrotate << EOF # Build a config file for logrotate + cat > ./${app}-logrotate << EOF # Build a config file for logrotate $logfile { - # Rotate if the logfile exceeds 100Mo - size 100M - # Keep 12 old log maximum - rotate 12 - # Compress the logs with gzip - compress - # Compress the log at the next cycle. So keep always 2 non compressed logs - delaycompress - # Copy and truncate the log to allow to continue write on it. Instead of move the log. - copytruncate - # Do not do an error if the log is missing - missingok - # Not rotate if the log is empty - notifempty - # Keep old logs in the same dir - noolddir - $su_directive + # Rotate if the logfile exceeds 100Mo + size 100M + # Keep 12 old log maximum + rotate 12 + # Compress the logs with gzip + compress + # Compress the log at the next cycle. So keep always 2 non compressed logs + delaycompress + # Copy and truncate the log to allow to continue write on it. Instead of move the log. + copytruncate + # Do not do an error if the log is missing + missingok + # Not rotate if the log is empty + notifempty + # Keep old logs in the same dir + noolddir + $su_directive } EOF - mkdir -p $(dirname "$logfile") # Create the log directory, if not exist - cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee) + mkdir -p $(dirname "$logfile") # Create the log directory, if not exist + cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee) } # Remove the app's logrotate config. @@ -100,7 +100,7 @@ EOF # # Requires YunoHost version 2.6.4 or higher. ynh_remove_logrotate () { - if [ -e "/etc/logrotate.d/$app" ]; then - rm "/etc/logrotate.d/$app" - fi + if [ -e "/etc/logrotate.d/$app" ]; then + rm "/etc/logrotate.d/$app" + fi } diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index 658a79c17..8e7518d8f 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -151,19 +151,19 @@ ynh_mysql_create_user() { # Requires YunoHost version 2.2.4 or higher. ynh_mysql_user_exists() { - # Declare an array to define the options of this helper. - local legacy_args=u - local -A args_array=( [u]=user= ) - local user - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=u + local -A args_array=( [u]=user= ) + local user + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]] - then - return 1 - else - return 0 - fi + if [[ -z $(ynh_mysql_execute_as_root --sql="SELECT User from mysql.user WHERE User = '$user';") ]] + then + return 1 + else + return 0 + fi } # Drop a user @@ -190,21 +190,21 @@ ynh_mysql_drop_user() { # # Requires YunoHost version 2.6.4 or higher. ynh_mysql_setup_db () { - # Declare an array to define the options of this helper. - local legacy_args=unp - local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= ) - local db_user - local db_name - db_pwd="" - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=unp + local -A args_array=( [u]=db_user= [n]=db_name= [p]=db_pwd= ) + local db_user + local db_name + db_pwd="" + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - local new_db_pwd=$(ynh_string_random) # Generate a random password - # If $db_pwd is not provided, use new_db_pwd instead for db_pwd - db_pwd="${db_pwd:-$new_db_pwd}" + local new_db_pwd=$(ynh_string_random) # Generate a random password + # If $db_pwd is not provided, use new_db_pwd instead for db_pwd + db_pwd="${db_pwd:-$new_db_pwd}" - ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database - ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd # Store the password in the app's config + ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database + ynh_app_setting_set --app=$app --key=mysqlpwd --value=$db_pwd # Store the password in the app's config } # Remove a database if it exists, and the associated user @@ -215,24 +215,23 @@ ynh_mysql_setup_db () { # # Requires YunoHost version 2.6.4 or higher. ynh_mysql_remove_db () { - # Declare an array to define the options of this helper. - local legacy_args=un - local -A args_array=( [u]=db_user= [n]=db_name= ) - local db_user - local db_name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=un + local -A args_array=( [u]=db_user= [n]=db_name= ) + local db_user + local db_name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE) - if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists - ynh_mysql_drop_db $db_name # Remove the database - else - ynh_print_warn --message="Database $db_name not found" - fi + local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE) + if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name"; then # Check if the database exists + ynh_mysql_drop_db $db_name # Remove the database + else + ynh_print_warn --message="Database $db_name not found" + fi - # Remove mysql user if it exists - if ynh_mysql_user_exists --user=$db_user; then - ynh_mysql_drop_user $db_user - fi + # Remove mysql user if it exists + if ynh_mysql_user_exists --user=$db_user; then + ynh_mysql_drop_user $db_user + fi } - diff --git a/data/helpers.d/network b/data/helpers.d/network index 0f6e9c442..ca15e6919 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -9,19 +9,19 @@ # # Requires YunoHost version 2.6.4 or higher. ynh_find_port () { - # Declare an array to define the options of this helper. - local legacy_args=p - local -A args_array=( [p]=port= ) - local port - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=p + local -A args_array=( [p]=port= ) + local port + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port." - while ss -nltu | awk '{print$5}' | grep -q -E ":$port$" # Check if the port is free - do - port=$((port+1)) # Else, pass to next port - done - echo $port + test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port." + while ss -nltu | awk '{print$5}' | grep -q -E ":$port$" # Check if the port is free + do + port=$((port+1)) # Else, pass to next port + done + echo $port } # Test if a port is available @@ -33,12 +33,12 @@ ynh_find_port () { # # Requires YunoHost version 3.7.x or higher. ynh_port_available () { - # Declare an array to define the options of this helper. - local legacy_args=p - local -A args_array=( [p]=port= ) - local port - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=p + local -A args_array=( [p]=port= ) + local port + # Manage arguments with getopts + ynh_handle_getopts_args "$@" if ss -nltu | grep -q -w :$port then @@ -59,17 +59,17 @@ ynh_port_available () { # Requires YunoHost version 2.2.4 or higher. ynh_validate_ip() { - # http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298 + # http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python#319298 - # Declare an array to define the options of this helper. - local legacy_args=fi - local -A args_array=( [f]=family= [i]=ip_address= ) - local family - local ip_address - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=fi + local -A args_array=( [f]=family= [i]=ip_address= ) + local family + local ip_address + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - [ "$family" == "4" ] || [ "$family" == "6" ] || return 1 + [ "$family" == "4" ] || [ "$family" == "6" ] || return 1 python /dev/stdin << EOF import socket @@ -93,14 +93,14 @@ EOF # Requires YunoHost version 2.2.4 or higher. ynh_validate_ip4() { - # Declare an array to define the options of this helper. - local legacy_args=i - local -A args_array=( [i]=ip_address= ) - local ip_address - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=i + local -A args_array=( [i]=ip_address= ) + local ip_address + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - ynh_validate_ip 4 $ip_address + ynh_validate_ip 4 $ip_address } @@ -114,12 +114,12 @@ ynh_validate_ip4() # Requires YunoHost version 2.2.4 or higher. ynh_validate_ip6() { - # Declare an array to define the options of this helper. - local legacy_args=i - local -A args_array=( [i]=ip_address= ) - local ip_address - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=i + local -A args_array=( [i]=ip_address= ) + local ip_address + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - ynh_validate_ip 6 $ip_address + ynh_validate_ip 6 $ip_address } diff --git a/data/helpers.d/nginx b/data/helpers.d/nginx index b34ebb4e1..161a1b413 100644 --- a/data/helpers.d/nginx +++ b/data/helpers.d/nginx @@ -20,51 +20,51 @@ # # Requires YunoHost version 2.7.2 or higher. ynh_add_nginx_config () { - finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" - local others_var=${1:-} - ynh_backup_if_checksum_is_different --file="$finalnginxconf" - cp ../conf/nginx.conf "$finalnginxconf" + finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" + local others_var=${1:-} + ynh_backup_if_checksum_is_different --file="$finalnginxconf" + cp ../conf/nginx.conf "$finalnginxconf" - # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. - # Substitute in a nginx config file only if the variable is not empty - if test -n "${path_url:-}"; then - # path_url_slash_less is path_url, or a blank value if path_url is only '/' - local path_url_slash_less=${path_url%/} - ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf" - ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$finalnginxconf" - fi - if test -n "${domain:-}"; then - ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$finalnginxconf" - fi - if test -n "${port:-}"; then - ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$finalnginxconf" - fi - if test -n "${app:-}"; then - ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$finalnginxconf" - fi - if test -n "${final_path:-}"; then - ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf" - fi - ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$finalnginxconf" + # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. + # Substitute in a nginx config file only if the variable is not empty + if test -n "${path_url:-}"; then + # path_url_slash_less is path_url, or a blank value if path_url is only '/' + local path_url_slash_less=${path_url%/} + ynh_replace_string --match_string="__PATH__/" --replace_string="$path_url_slash_less/" --target_file="$finalnginxconf" + ynh_replace_string --match_string="__PATH__" --replace_string="$path_url" --target_file="$finalnginxconf" + fi + if test -n "${domain:-}"; then + ynh_replace_string --match_string="__DOMAIN__" --replace_string="$domain" --target_file="$finalnginxconf" + fi + if test -n "${port:-}"; then + ynh_replace_string --match_string="__PORT__" --replace_string="$port" --target_file="$finalnginxconf" + fi + if test -n "${app:-}"; then + ynh_replace_string --match_string="__NAME__" --replace_string="$app" --target_file="$finalnginxconf" + fi + if test -n "${final_path:-}"; then + ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalnginxconf" + fi + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$YNH_PHP_VERSION" --target_file="$finalnginxconf" - # Replace all other variable given as arguments - for var_to_replace in $others_var - do - # ${var_to_replace^^} make the content of the variable on upper-cases - # ${!var_to_replace} get the content of the variable named $var_to_replace - ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf" - done - - if [ "${path_url:-}" != "/" ] - then - ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf" - else - ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf" - fi + # Replace all other variable given as arguments + for var_to_replace in $others_var + do + # ${var_to_replace^^} make the content of the variable on upper-cases + # ${!var_to_replace} get the content of the variable named $var_to_replace + ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalnginxconf" + done - ynh_store_file_checksum --file="$finalnginxconf" + if [ "${path_url:-}" != "/" ] + then + ynh_replace_string --match_string="^#sub_path_only" --replace_string="" --target_file="$finalnginxconf" + else + ynh_replace_string --match_string="^#root_path_only" --replace_string="" --target_file="$finalnginxconf" + fi - ynh_systemd_action --service_name=nginx --action=reload + ynh_store_file_checksum --file="$finalnginxconf" + + ynh_systemd_action --service_name=nginx --action=reload } # Remove the dedicated nginx config @@ -73,6 +73,6 @@ ynh_add_nginx_config () { # # Requires YunoHost version 2.7.2 or higher. ynh_remove_nginx_config () { - ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf" - ynh_systemd_action --service_name=nginx --action=reload + ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf" + ynh_systemd_action --service_name=nginx --action=reload } diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index 03cb5dffb..2d4ea66dc 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -13,16 +13,16 @@ export N_PREFIX="$n_install_dir" # # Requires YunoHost version 2.7.12 or higher. ynh_install_n () { - ynh_print_info --message="Installation of N - Node.js version management" - # Build an app.src for n - mkdir -p "../conf" - echo "SOURCE_URL=https://github.com/tj/n/archive/v4.1.0.tar.gz + ynh_print_info --message="Installation of N - Node.js version management" + # Build an app.src for n + mkdir -p "../conf" + echo "SOURCE_URL=https://github.com/tj/n/archive/v4.1.0.tar.gz SOURCE_SUM=3983fa3f00d4bf85ba8e21f1a590f6e28938093abe0bb950aeea52b1717471fc" > "../conf/n.src" - # Download and extract n - ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n - # Install n - (cd "$n_install_dir/git" - PREFIX=$N_PREFIX make install 2>&1) + # Download and extract n + ynh_setup_source --dest_dir="$n_install_dir/git" --source_id=n + # Install n + (cd "$n_install_dir/git" + PREFIX=$N_PREFIX make install 2>&1) } # Load the version of node for an app, and set variables. @@ -41,15 +41,15 @@ SOURCE_SUM=3983fa3f00d4bf85ba8e21f1a590f6e28938093abe0bb950aeea52b1717471fc" > " # # Requires YunoHost version 2.7.12 or higher. ynh_use_nodejs () { - nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) + nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) - nodejs_use_version="echo \"Deprecated command, should be removed\"" + nodejs_use_version="echo \"Deprecated command, should be removed\"" - # Get the absolute path of this version of node - nodejs_path="$node_version_path/$nodejs_version/bin" + # Get the absolute path of this version of node + nodejs_path="$node_version_path/$nodejs_version/bin" - # Load the path of this version of node in $PATH - [[ :$PATH: == *":$nodejs_path"* ]] || PATH="$nodejs_path:$PATH" + # Load the path of this version of node in $PATH + [[ :$PATH: == *":$nodejs_path"* ]] || PATH="$nodejs_path:$PATH" } # Install a specific version of nodejs @@ -64,72 +64,72 @@ ynh_use_nodejs () { # # Requires YunoHost version 2.7.12 or higher. ynh_install_nodejs () { - # Use n, https://github.com/tj/n to manage the nodejs versions + # Use n, https://github.com/tj/n to manage the nodejs versions - # Declare an array to define the options of this helper. - local legacy_args=n - local -A args_array=( [n]=nodejs_version= ) - local nodejs_version - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=n + local -A args_array=( [n]=nodejs_version= ) + local nodejs_version + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - # Create $n_install_dir - mkdir -p "$n_install_dir" + # Create $n_install_dir + mkdir -p "$n_install_dir" - # Load n path in PATH - CLEAR_PATH="$n_install_dir/bin:$PATH" - # Remove /usr/local/bin in PATH in case of node prior installation - PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@') + # Load n path in PATH + CLEAR_PATH="$n_install_dir/bin:$PATH" + # Remove /usr/local/bin in PATH in case of node prior installation + PATH=$(echo $CLEAR_PATH | sed 's@/usr/local/bin:@@') - # Move an existing node binary, to avoid to block n. - test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n - test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n + # Move an existing node binary, to avoid to block n. + test -x /usr/bin/node && mv /usr/bin/node /usr/bin/node_n + test -x /usr/bin/npm && mv /usr/bin/npm /usr/bin/npm_n - # If n is not previously setup, install it - if ! test $(n --version > /dev/null 2>&1) - then - ynh_install_n - fi + # If n is not previously setup, install it + if ! test $(n --version > /dev/null 2>&1) + then + ynh_install_n + fi - # Modify the default N_PREFIX in n script - ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n" + # Modify the default N_PREFIX in n script + ynh_replace_string --match_string="^N_PREFIX=\${N_PREFIX-.*}$" --replace_string="N_PREFIX=\${N_PREFIX-$N_PREFIX}" --target_file="$n_install_dir/bin/n" - # Restore /usr/local/bin in PATH - PATH=$CLEAR_PATH + # Restore /usr/local/bin in PATH + PATH=$CLEAR_PATH - # And replace the old node binary. - test -x /usr/bin/node_n && mv /usr/bin/node_n /usr/bin/node - test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm + # And replace the old node binary. + test -x /usr/bin/node_n && mv /usr/bin/node_n /usr/bin/node + test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm - # Install the requested version of nodejs - uname=$(uname -m) - if [[ $uname =~ aarch64 || $uname =~ arm64 ]] - then - n $nodejs_version --arch=arm64 - else - n $nodejs_version - fi + # Install the requested version of nodejs + uname=$(uname -m) + if [[ $uname =~ aarch64 || $uname =~ arm64 ]] + then + n $nodejs_version --arch=arm64 + else + n $nodejs_version + fi - # Find the last "real" version for this major version of node. - real_nodejs_version=$(find $node_version_path/$nodejs_version* -maxdepth 0 | sort --version-sort | tail --lines=1) - real_nodejs_version=$(basename $real_nodejs_version) + # Find the last "real" version for this major version of node. + real_nodejs_version=$(find $node_version_path/$nodejs_version* -maxdepth 0 | sort --version-sort | tail --lines=1) + real_nodejs_version=$(basename $real_nodejs_version) - # Create a symbolic link for this major version if the file doesn't already exist - if [ ! -e "$node_version_path/$nodejs_version" ] - then - ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version - fi + # Create a symbolic link for this major version if the file doesn't already exist + if [ ! -e "$node_version_path/$nodejs_version" ] + then + ln --symbolic --force --no-target-directory $node_version_path/$real_nodejs_version $node_version_path/$nodejs_version + fi - # Store the ID of this app and the version of node requested for it - echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" + # Store the ID of this app and the version of node requested for it + echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version" - # Store nodejs_version into the config of this app - ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version + # Store nodejs_version into the config of this app + ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version - # Build the update script and set the cronjob - ynh_cron_upgrade_node + # Build the update script and set the cronjob + ynh_cron_upgrade_node - ynh_use_nodejs + ynh_use_nodejs } # Remove the version of node used by the app. @@ -142,25 +142,25 @@ ynh_install_nodejs () { # # Requires YunoHost version 2.7.12 or higher. ynh_remove_nodejs () { - nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) + nodejs_version=$(ynh_app_setting_get --app=$app --key=nodejs_version) - # Remove the line for this app - sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version" + # Remove the line for this app + sed --in-place "/$YNH_APP_INSTANCE_NAME:$nodejs_version/d" "$n_install_dir/ynh_app_version" - # If no other app uses this version of nodejs, remove it. - if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version" - then - $n_install_dir/bin/n rm $nodejs_version - fi + # If no other app uses this version of nodejs, remove it. + if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version" + then + $n_install_dir/bin/n rm $nodejs_version + fi - # If no other app uses n, remove n - if [ ! -s "$n_install_dir/ynh_app_version" ] - then - ynh_secure_remove --file="$n_install_dir" - ynh_secure_remove --file="/usr/local/n" - sed --in-place "/N_PREFIX/d" /root/.bashrc - rm -f /etc/cron.daily/node_update - fi + # If no other app uses n, remove n + if [ ! -s "$n_install_dir/ynh_app_version" ] + then + ynh_secure_remove --file="$n_install_dir" + ynh_secure_remove --file="/usr/local/n" + sed --in-place "/N_PREFIX/d" /root/.bashrc + rm -f /etc/cron.daily/node_update + fi } # Set a cron design to update your node versions @@ -173,8 +173,8 @@ ynh_remove_nodejs () { # # Requires YunoHost version 2.7.12 or higher. ynh_cron_upgrade_node () { - # Build the update script - cat > "$n_install_dir/node_update.sh" << EOF + # Build the update script + cat > "$n_install_dir/node_update.sh" << EOF #!/bin/bash version_path="$node_version_path" @@ -195,26 +195,26 @@ all_real_version=\$(echo "\$all_real_version" | sort --unique) # Read each major version while read version do - echo "Update of the version \$version" - sudo \$n_install_dir/bin/n \$version + echo "Update of the version \$version" + sudo \$n_install_dir/bin/n \$version - # Find the last "real" version for this major version of node. - real_nodejs_version=\$(find \$version_path/\$version* -maxdepth 0 | sort --version-sort | tail --lines=1) - real_nodejs_version=\$(basename \$real_nodejs_version) + # Find the last "real" version for this major version of node. + real_nodejs_version=\$(find \$version_path/\$version* -maxdepth 0 | sort --version-sort | tail --lines=1) + real_nodejs_version=\$(basename \$real_nodejs_version) - # Update the symbolic link for this version - sudo ln --symbolic --force --no-target-directory \$version_path/\$real_nodejs_version \$version_path/\$version + # Update the symbolic link for this version + sudo ln --symbolic --force --no-target-directory \$version_path/\$real_nodejs_version \$version_path/\$version done <<< "\$(echo "\$all_real_version")" EOF - chmod +x "$n_install_dir/node_update.sh" + chmod +x "$n_install_dir/node_update.sh" - # Build the cronjob - cat > "/etc/cron.daily/node_update" << EOF + # Build the cronjob + cat > "/etc/cron.daily/node_update" << EOF #!/bin/bash $n_install_dir/node_update.sh >> $n_install_dir/node_update.log EOF - chmod +x "/etc/cron.daily/node_update" + chmod +x "/etc/cron.daily/node_update" } diff --git a/data/helpers.d/php b/data/helpers.d/php index c1ae91c2e..8bd96e42b 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -57,179 +57,179 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # # Requires YunoHost version 2.7.2 or higher. ynh_add_fpm_config () { - # Declare an array to define the options of this helper. - local legacy_args=vtufpd - local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) - local phpversion - local use_template - local usage - local footprint - local package - local dedicated_service - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - package=${package:-} + # Declare an array to define the options of this helper. + local legacy_args=vtufpd + local -A args_array=( [v]=phpversion= [t]=use_template [u]=usage= [f]=footprint= [p]=package= [d]=dedicated_service ) + local phpversion + local use_template + local usage + local footprint + local package + local dedicated_service + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package=${package:-} - # The default behaviour is to use the template. - use_template="${use_template:-1}" - usage="${usage:-}" - footprint="${footprint:-}" - if [ -n "$usage" ] || [ -n "$footprint" ]; then - use_template=0 - fi - # Do not use a dedicated service by default - dedicated_service=${dedicated_service:-0} + # The default behaviour is to use the template. + use_template="${use_template:-1}" + usage="${usage:-}" + footprint="${footprint:-}" + if [ -n "$usage" ] || [ -n "$footprint" ]; then + use_template=0 + fi + # Do not use a dedicated service by default + dedicated_service=${dedicated_service:-0} - # Set the default PHP-FPM version by default - phpversion="${phpversion:-$YNH_PHP_VERSION}" + # Set the default PHP-FPM version by default + phpversion="${phpversion:-$YNH_PHP_VERSION}" - # If the requested php version is not the default version for YunoHost - if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] - then - # If the argument --package is used, add the packages to ynh_install_php to install them from sury - if [ -n "$package" ]; then - local additionnal_packages="--package=$package" - else - local additionnal_packages="" - fi - # Install this specific version of php. - ynh_install_php --phpversion=$phpversion "$additionnal_packages" - elif [ -n "$package" ] - then - # Install the additionnal packages from the default repository - ynh_add_app_dependencies --package="$package" - fi + # If the requested php version is not the default version for YunoHost + if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] + then + # If the argument --package is used, add the packages to ynh_install_php to install them from sury + if [ -n "$package" ]; then + local additionnal_packages="--package=$package" + else + local additionnal_packages="" + fi + # Install this specific version of php. + ynh_install_php --phpversion=$phpversion "$additionnal_packages" + elif [ -n "$package" ] + then + # Install the additionnal packages from the default repository + ynh_add_app_dependencies --package="$package" + fi - if [ $dedicated_service -eq 1 ] - then - local fpm_service="${app}-phpfpm" - local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" - else - local fpm_service="php${phpversion}-fpm" - local fpm_config_dir="/etc/php/$phpversion/fpm" - fi - # Configure PHP-FPM 5 on Debian Jessie - if [ "$(ynh_get_debian_release)" == "jessie" ]; then - fpm_config_dir="/etc/php5/fpm" - fpm_service="php5-fpm" - fi + if [ $dedicated_service -eq 1 ] + then + local fpm_service="${app}-phpfpm" + local fpm_config_dir="/etc/php/$phpversion/dedicated-fpm" + else + local fpm_service="php${phpversion}-fpm" + local fpm_config_dir="/etc/php/$phpversion/fpm" + fi + # Configure PHP-FPM 5 on Debian Jessie + if [ "$(ynh_get_debian_release)" == "jessie" ]; then + fpm_config_dir="/etc/php5/fpm" + fpm_service="php5-fpm" + fi - # Create the directory for fpm pools - mkdir -p "$fpm_config_dir/pool.d" + # Create the directory for fpm pools + mkdir -p "$fpm_config_dir/pool.d" - ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" - ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" - ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service" - ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion - finalphpconf="$fpm_config_dir/pool.d/$app.conf" + ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" + ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" + ynh_app_setting_set --app=$app --key=fpm_dedicated_service --value="$dedicated_service" + ynh_app_setting_set --app=$app --key=phpversion --value=$phpversion + finalphpconf="$fpm_config_dir/pool.d/$app.conf" - # Migrate from mutual php service to dedicated one. - if [ $dedicated_service -eq 1 ] - then - local old_fpm_config_dir="/etc/php/$phpversion/fpm" - # If a config file exist in the common pool, move it. - if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] - then - ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." - # Create a backup of the old file before migration - ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" - # Remove the old php config file - ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" - # Reload php to release the socket and allow the dedicated service to use it - ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload - fi - fi + # Migrate from mutual php service to dedicated one. + if [ $dedicated_service -eq 1 ] + then + local old_fpm_config_dir="/etc/php/$phpversion/fpm" + # If a config file exist in the common pool, move it. + if [ -e "$old_fpm_config_dir/pool.d/$app.conf" ] + then + ynh_print_info --message="Migrate to a dedicated php-fpm service for $app." + # Create a backup of the old file before migration + ynh_backup_if_checksum_is_different --file="$old_fpm_config_dir/pool.d/$app.conf" + # Remove the old php config file + ynh_secure_remove --file="$old_fpm_config_dir/pool.d/$app.conf" + # Reload php to release the socket and allow the dedicated service to use it + ynh_systemd_action --service_name=php${phpversion}-fpm --action=reload + fi + fi - ynh_backup_if_checksum_is_different --file="$finalphpconf" + ynh_backup_if_checksum_is_different --file="$finalphpconf" - if [ $use_template -eq 1 ] - then - # Usage 1, use the template in ../conf/php-fpm.conf - cp ../conf/php-fpm.conf "$finalphpconf" - ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" - ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" - ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" + if [ $use_template -eq 1 ] + then + # Usage 1, use the template in ../conf/php-fpm.conf + cp ../conf/php-fpm.conf "$finalphpconf" + ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$finalphpconf" + ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalphpconf" + ynh_replace_string --match_string="__USER__" --replace_string="$app" --target_file="$finalphpconf" + ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf" - else - # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm + else + # Usage 2, generate a php-fpm config file with ynh_get_scalable_phpfpm - # Store settings - ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint - ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage + # Store settings + ynh_app_setting_set --app=$app --key=fpm_footprint --value=$footprint + ynh_app_setting_set --app=$app --key=fpm_usage --value=$usage - # Define the values to use for the configuration of php. - ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint + # Define the values to use for the configuration of php. + ynh_get_scalable_phpfpm --usage=$usage --footprint=$footprint - # Copy the default file - cp "/etc/php/$phpversion/fpm/pool.d/www.conf" "$finalphpconf" + # Copy the default file + cp "/etc/php/$phpversion/fpm/pool.d/www.conf" "$finalphpconf" - # Replace standard variables into the default file - ynh_replace_string --match_string="^\[www\]" --replace_string="[$app]" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*listen = .*" --replace_string="listen = /var/run/php/php$phpversion-fpm-$app.sock" --target_file="$finalphpconf" - ynh_replace_string --match_string="^user = .*" --replace_string="user = $app" --target_file="$finalphpconf" - ynh_replace_string --match_string="^group = .*" --replace_string="group = $app" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*chdir = .*" --replace_string="chdir = $final_path" --target_file="$finalphpconf" + # Replace standard variables into the default file + ynh_replace_string --match_string="^\[www\]" --replace_string="[$app]" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*listen = .*" --replace_string="listen = /var/run/php/php$phpversion-fpm-$app.sock" --target_file="$finalphpconf" + ynh_replace_string --match_string="^user = .*" --replace_string="user = $app" --target_file="$finalphpconf" + ynh_replace_string --match_string="^group = .*" --replace_string="group = $app" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*chdir = .*" --replace_string="chdir = $final_path" --target_file="$finalphpconf" - # Configure fpm children - ynh_replace_string --match_string=".*pm = .*" --replace_string="pm = $php_pm" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_children = .*" --replace_string="pm.max_children = $php_max_children" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_requests = .*" --replace_string="pm.max_requests = 500" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*request_terminate_timeout = .*" --replace_string="request_terminate_timeout = 1d" --target_file="$finalphpconf" - if [ "$php_pm" = "dynamic" ] - then - ynh_replace_string --match_string=".*pm.start_servers = .*" --replace_string="pm.start_servers = $php_start_servers" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.min_spare_servers = .*" --replace_string="pm.min_spare_servers = $php_min_spare_servers" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*pm.max_spare_servers = .*" --replace_string="pm.max_spare_servers = $php_max_spare_servers" --target_file="$finalphpconf" - elif [ "$php_pm" = "ondemand" ] - then - ynh_replace_string --match_string=".*pm.process_idle_timeout = .*" --replace_string="pm.process_idle_timeout = 10s" --target_file="$finalphpconf" - fi + # Configure fpm children + ynh_replace_string --match_string=".*pm = .*" --replace_string="pm = $php_pm" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_children = .*" --replace_string="pm.max_children = $php_max_children" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_requests = .*" --replace_string="pm.max_requests = 500" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*request_terminate_timeout = .*" --replace_string="request_terminate_timeout = 1d" --target_file="$finalphpconf" + if [ "$php_pm" = "dynamic" ] + then + ynh_replace_string --match_string=".*pm.start_servers = .*" --replace_string="pm.start_servers = $php_start_servers" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.min_spare_servers = .*" --replace_string="pm.min_spare_servers = $php_min_spare_servers" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*pm.max_spare_servers = .*" --replace_string="pm.max_spare_servers = $php_max_spare_servers" --target_file="$finalphpconf" + elif [ "$php_pm" = "ondemand" ] + then + ynh_replace_string --match_string=".*pm.process_idle_timeout = .*" --replace_string="pm.process_idle_timeout = 10s" --target_file="$finalphpconf" + fi - # Comment unused parameters - if [ "$php_pm" != "dynamic" ] - then - ynh_replace_string --match_string=".*\(pm.start_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*\(pm.min_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - ynh_replace_string --match_string=".*\(pm.max_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - fi - if [ "$php_pm" != "ondemand" ] - then - ynh_replace_string --match_string=".*\(pm.process_idle_timeout = .*\)" --replace_string=";\1" --target_file="$finalphpconf" - fi + # Comment unused parameters + if [ "$php_pm" != "dynamic" ] + then + ynh_replace_string --match_string=".*\(pm.start_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*\(pm.min_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + ynh_replace_string --match_string=".*\(pm.max_spare_servers = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + fi + if [ "$php_pm" != "ondemand" ] + then + ynh_replace_string --match_string=".*\(pm.process_idle_timeout = .*\)" --replace_string=";\1" --target_file="$finalphpconf" + fi - # Concatene the extra config. - if [ -e ../conf/extra_php-fpm.conf ]; then - cat ../conf/extra_php-fpm.conf >> "$finalphpconf" - fi - fi + # Concatene the extra config. + if [ -e ../conf/extra_php-fpm.conf ]; then + cat ../conf/extra_php-fpm.conf >> "$finalphpconf" + fi + fi - chown root: "$finalphpconf" - ynh_store_file_checksum --file="$finalphpconf" + chown root: "$finalphpconf" + ynh_store_file_checksum --file="$finalphpconf" - if [ -e "../conf/php-fpm.ini" ] - then - ynh_print_warn -message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." - finalphpini="$fpm_config_dir/conf.d/20-$app.ini" - ynh_backup_if_checksum_is_different "$finalphpini" - cp ../conf/php-fpm.ini "$finalphpini" - chown root: "$finalphpini" - ynh_store_file_checksum "$finalphpini" - fi + if [ -e "../conf/php-fpm.ini" ] + then + ynh_print_warn -message="Packagers ! Please do not use a separate php ini file, merge your directives in the pool file instead." + finalphpini="$fpm_config_dir/conf.d/20-$app.ini" + ynh_backup_if_checksum_is_different "$finalphpini" + cp ../conf/php-fpm.ini "$finalphpini" + chown root: "$finalphpini" + ynh_store_file_checksum "$finalphpini" + fi - if [ $dedicated_service -eq 1 ] - then - # Create a dedicated php-fpm.conf for the service - local globalphpconf=$fpm_config_dir/php-fpm-$app.conf - cp /etc/php/${phpversion}/fpm/php-fpm.conf $globalphpconf + if [ $dedicated_service -eq 1 ] + then + # Create a dedicated php-fpm.conf for the service + local globalphpconf=$fpm_config_dir/php-fpm-$app.conf + cp /etc/php/${phpversion}/fpm/php-fpm.conf $globalphpconf - ynh_replace_string --match_string="^[; ]*pid *=.*" --replace_string="pid = /run/php/php${phpversion}-fpm-$app.pid" --target_file="$globalphpconf" - ynh_replace_string --match_string="^[; ]*error_log *=.*" --replace_string="error_log = /var/log/php/fpm-php.$app.log" --target_file="$globalphpconf" - ynh_replace_string --match_string="^[; ]*syslog.ident *=.*" --replace_string="syslog.ident = php-fpm-$app" --target_file="$globalphpconf" - ynh_replace_string --match_string="^[; ]*include *=.*" --replace_string="include = $finalphpconf" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*pid *=.*" --replace_string="pid = /run/php/php${phpversion}-fpm-$app.pid" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*error_log *=.*" --replace_string="error_log = /var/log/php/fpm-php.$app.log" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*syslog.ident *=.*" --replace_string="syslog.ident = php-fpm-$app" --target_file="$globalphpconf" + ynh_replace_string --match_string="^[; ]*include *=.*" --replace_string="include = $finalphpconf" --target_file="$globalphpconf" - # Create a config for a dedicated php-fpm service for the app - echo "[Unit] + # Create a config for a dedicated php-fpm service for the app + echo "[Unit] Description=PHP $phpversion FastCGI Process Manager for $app After=network.target @@ -243,18 +243,18 @@ ExecReload=/bin/kill -USR2 \$MAINPID WantedBy=multi-user.target " > ../conf/$fpm_service - # Create this dedicated php-fpm service - ynh_add_systemd_config --service=$fpm_service --template=$fpm_service - # Integrate the service in YunoHost admin panel - yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --log_type file --description "Php-fpm dedicated to $app" - # Configure log rotate - ynh_use_logrotate --logfile=/var/log/php - # Restart the service, as this service is either stopped or only for this app - ynh_systemd_action --service_name=$fpm_service --action=restart - else - # Reload php, to not impact other parts of the system using php - ynh_systemd_action --service_name=$fpm_service --action=reload - fi + # Create this dedicated php-fpm service + ynh_add_systemd_config --service=$fpm_service --template=$fpm_service + # Integrate the service in YunoHost admin panel + yunohost service add $fpm_service --log /var/log/php/fpm-php.$app.log --log_type file --description "Php-fpm dedicated to $app" + # Configure log rotate + ynh_use_logrotate --logfile=/var/log/php + # Restart the service, as this service is either stopped or only for this app + ynh_systemd_action --service_name=$fpm_service --action=restart + else + # Reload php, to not impact other parts of the system using php + ynh_systemd_action --service_name=$fpm_service --action=reload + fi } # Remove the dedicated php-fpm config @@ -263,43 +263,43 @@ WantedBy=multi-user.target # # Requires YunoHost version 2.7.2 or higher. ynh_remove_fpm_config () { - local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) - local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) - local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service) - dedicated_service=${dedicated_service:-0} - # Get the version of php used by this app - local phpversion=$(ynh_app_setting_get $app phpversion) + local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir) + local fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service) + local dedicated_service=$(ynh_app_setting_get --app=$app --key=fpm_dedicated_service) + dedicated_service=${dedicated_service:-0} + # Get the version of php used by this app + local phpversion=$(ynh_app_setting_get $app phpversion) - # Assume default PHP-FPM version by default - phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}" + # Assume default PHP-FPM version by default + phpversion="${phpversion:-$YNH_DEFAULT_PHP_VERSION}" - # Assume default php files if not set - if [ -z "$fpm_config_dir" ]; then - fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm" - fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm" - fi + # Assume default php files if not set + if [ -z "$fpm_config_dir" ]; then + fpm_config_dir="/etc/php/$YNH_DEFAULT_PHP_VERSION/fpm" + fpm_service="php$YNH_DEFAULT_PHP_VERSION-fpm" + fi - if [ $dedicated_service -eq 1 ] - then - # Remove the dedicated service php-fpm service for the app - ynh_remove_systemd_config --service=$fpm_service - # Remove the global php-fpm conf - ynh_secure_remove --file="$fpm_config_dir/php-fpm-$app.conf" - # Remove the service from the list of services known by Yunohost - yunohost service remove $fpm_service - elif ynh_package_is_installed --package="php${phpversion}-fpm"; then - ynh_systemd_action --service_name=$fpm_service --action=reload - fi + if [ $dedicated_service -eq 1 ] + then + # Remove the dedicated service php-fpm service for the app + ynh_remove_systemd_config --service=$fpm_service + # Remove the global php-fpm conf + ynh_secure_remove --file="$fpm_config_dir/php-fpm-$app.conf" + # Remove the service from the list of services known by Yunohost + yunohost service remove $fpm_service + elif ynh_package_is_installed --package="php${phpversion}-fpm"; then + ynh_systemd_action --service_name=$fpm_service --action=reload + fi - ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" - ynh_exec_warn_less ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" + ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf" + ynh_exec_warn_less ynh_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" - # If the php version used is not the default version for YunoHost - if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] - then - # Remove this specific version of php - ynh_remove_php - fi + # If the php version used is not the default version for YunoHost + if [ "$phpversion" != "$YNH_DEFAULT_PHP_VERSION" ] + then + # Remove this specific version of php + ynh_remove_php + fi } # Install another version of php. @@ -310,50 +310,50 @@ ynh_remove_fpm_config () { # | arg: -v, --phpversion - Version of php to install. # | arg: -p, --package - Additionnal php packages to install ynh_install_php () { - # Declare an array to define the options of this helper. - local legacy_args=vp - local -A args_array=( [v]=phpversion= [p]=package= ) - local phpversion - local package - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - package=${package:-} + # Declare an array to define the options of this helper. + local legacy_args=vp + local -A args_array=( [v]=phpversion= [p]=package= ) + local phpversion + local package + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + package=${package:-} - # Store phpversion into the config of this app - ynh_app_setting_set $app phpversion $phpversion + # Store phpversion into the config of this app + ynh_app_setting_set $app phpversion $phpversion - if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] - then - ynh_die "Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION" - fi + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] + then + ynh_die "Do not use ynh_install_php to install php$YNH_DEFAULT_PHP_VERSION" + fi - # Create the file if doesn't exist already - touch /etc/php/ynh_app_version + # Create the file if doesn't exist already + touch /etc/php/ynh_app_version - # Do not add twice the same line - if ! grep --quiet "$YNH_APP_INSTANCE_NAME:" "/etc/php/ynh_app_version" - then - # Store the ID of this app and the version of php requested for it - echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version" - fi + # Do not add twice the same line + if ! grep --quiet "$YNH_APP_INSTANCE_NAME:" "/etc/php/ynh_app_version" + then + # Store the ID of this app and the version of php requested for it + echo "$YNH_APP_INSTANCE_NAME:$phpversion" | tee --append "/etc/php/ynh_app_version" + fi - # Add an extra repository for those packages - ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version + # Add an extra repository for those packages + ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version - # Install requested dependencies from this extra repository. - # Install php-fpm first, otherwise php will install apache as a dependency. - ynh_add_app_dependencies --package="php${phpversion}-fpm" - ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package" + # Install requested dependencies from this extra repository. + # Install php-fpm first, otherwise php will install apache as a dependency. + ynh_add_app_dependencies --package="php${phpversion}-fpm" + ynh_add_app_dependencies --package="php$phpversion php${phpversion}-common $package" - # Set the default php version back as the default version for php-cli. - update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION + # Set the default php version back as the default version for php-cli. + update-alternatives --set php /usr/bin/php$YNH_DEFAULT_PHP_VERSION - # Pin this extra repository after packages are installed to prevent sury of doing shit - ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version - ynh_pin_repo --package="php${YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append + # Pin this extra repository after packages are installed to prevent sury of doing shit + ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version + ynh_pin_repo --package="php${YNH_DEFAULT_PHP_VERSION}*" --pin="origin \"packages.sury.org\"" --priority=600 --name=extra_php_version --append - # Advertise service in admin panel - yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" + # Advertise service in admin panel + yunohost service add php${phpversion}-fpm --log "/var/log/php${phpversion}-fpm.log" } # Remove the specific version of php used by the app. @@ -362,35 +362,35 @@ ynh_install_php () { # # usage: ynh_install_php ynh_remove_php () { - # Get the version of php used by this app - local phpversion=$(ynh_app_setting_get $app phpversion) + # Get the version of php used by this app + local phpversion=$(ynh_app_setting_get $app phpversion) - if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] || [ -z "$phpversion" ] - then - if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] - then - ynh_print_err "Do not use ynh_remove_php to remove php$YNH_DEFAULT_PHP_VERSION !" - fi - return 0 - fi + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] || [ -z "$phpversion" ] + then + if [ "$phpversion" == "$YNH_DEFAULT_PHP_VERSION" ] + then + ynh_print_err "Do not use ynh_remove_php to remove php$YNH_DEFAULT_PHP_VERSION !" + fi + return 0 + fi - # Create the file if doesn't exist already - touch /etc/php/ynh_app_version + # Create the file if doesn't exist already + touch /etc/php/ynh_app_version - # Remove the line for this app - sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version" + # Remove the line for this app + sed --in-place "/$YNH_APP_INSTANCE_NAME:$phpversion/d" "/etc/php/ynh_app_version" - # If no other app uses this version of php, remove it. - if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version" - then - # Remove the service from the admin panel - if ynh_package_is_installed --package="php${phpversion}-fpm"; then - yunohost service remove php${phpversion}-fpm - fi + # If no other app uses this version of php, remove it. + if ! grep --quiet "$phpversion" "/etc/php/ynh_app_version" + then + # Remove the service from the admin panel + if ynh_package_is_installed --package="php${phpversion}-fpm"; then + yunohost service remove php${phpversion}-fpm + fi - # Purge php dependencies for this version. - ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common" - fi + # Purge php dependencies for this version. + ynh_package_autopurge "php$phpversion php${phpversion}-fpm php${phpversion}-common" + fi } # Define the values to configure php-fpm diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index ff6ef0f57..e6984c8db 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -15,17 +15,17 @@ PSQL_ROOT_PWD_FILE=/etc/yunohost/psql # # Requires YunoHost version 3.5.0 or higher. ynh_psql_connect_as() { - # Declare an array to define the options of this helper. - local legacy_args=upd - local -A args_array=([u]=user= [p]=password= [d]=database=) - local user - local password - local database - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - database="${database:-}" + # Declare an array to define the options of this helper. + local legacy_args=upd + local -A args_array=([u]=user= [p]=password= [d]=database=) + local user + local password + local database + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + database="${database:-}" - sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$password" psql "$database" + sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$password" psql "$database" } # Execute a command as root user @@ -36,17 +36,17 @@ ynh_psql_connect_as() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_execute_as_root() { - # Declare an array to define the options of this helper. - local legacy_args=sd - local -A args_array=([s]=sql= [d]=database=) - local sql - local database - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - database="${database:-}" + # Declare an array to define the options of this helper. + local legacy_args=sd + local -A args_array=([s]=sql= [d]=database=) + local sql + local database + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + database="${database:-}" - ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ - --database="$database" <<<"$sql" + ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ + --database="$database" <<<"$sql" } # Execute a command from a file as root user @@ -57,17 +57,17 @@ ynh_psql_execute_as_root() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_execute_file_as_root() { - # Declare an array to define the options of this helper. - local legacy_args=fd - local -A args_array=([f]=file= [d]=database=) - local file - local database - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - database="${database:-}" + # Declare an array to define the options of this helper. + local legacy_args=fd + local -A args_array=([f]=file= [d]=database=) + local file + local database + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + database="${database:-}" - ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ - --database="$database" <"$file" + ynh_psql_connect_as --user="postgres" --password="$(cat $PSQL_ROOT_PWD_FILE)" \ + --database="$database" <"$file" } # Create a database and grant optionnaly privilegies to a user @@ -80,17 +80,17 @@ ynh_psql_execute_file_as_root() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_create_db() { - local db=$1 - local user=${2:-} + local db=$1 + local user=${2:-} - local sql="CREATE DATABASE ${db};" + local sql="CREATE DATABASE ${db};" - # grant all privilegies to user - if [ -n "$user" ]; then - sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" - fi + # grant all privilegies to user + if [ -n "$user" ]; then + sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" + fi - ynh_psql_execute_as_root --sql="$sql" + ynh_psql_execute_as_root --sql="$sql" } # Drop a database @@ -105,12 +105,12 @@ ynh_psql_create_db() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_drop_db() { - local db=$1 - # First, force disconnection of all clients connected to the database - # https://stackoverflow.com/questions/17449420/postgresql-unable-to-drop-database-because-of-some-auto-connections-to-db - ynh_psql_execute_as_root --sql="REVOKE CONNECT ON DATABASE $db FROM public;" --database="$db" - ynh_psql_execute_as_root --sql="SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$db' AND pid <> pg_backend_pid();" --database="$db" - sudo --login --user=postgres dropdb $db + local db=$1 + # First, force disconnection of all clients connected to the database + # https://stackoverflow.com/questions/17449420/postgresql-unable-to-drop-database-because-of-some-auto-connections-to-db + ynh_psql_execute_as_root --sql="REVOKE CONNECT ON DATABASE $db FROM public;" --database="$db" + ynh_psql_execute_as_root --sql="SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$db' AND pid <> pg_backend_pid();" --database="$db" + sudo --login --user=postgres dropdb $db } # Dump a database @@ -123,14 +123,14 @@ ynh_psql_drop_db() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_dump_db() { - # Declare an array to define the options of this helper. - local legacy_args=d - local -A args_array=([d]=database=) - local database - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=d + local -A args_array=([d]=database=) + local database + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - sudo --login --user=postgres pg_dump "$database" + sudo --login --user=postgres pg_dump "$database" } # Create a user @@ -143,9 +143,9 @@ ynh_psql_dump_db() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_create_user() { - local user=$1 - local pwd=$2 - ynh_psql_execute_as_root --sql="CREATE USER $user WITH ENCRYPTED PASSWORD '$pwd'" + local user=$1 + local pwd=$2 + ynh_psql_execute_as_root --sql="CREATE USER $user WITH ENCRYPTED PASSWORD '$pwd'" } # Check if a psql user exists @@ -153,18 +153,18 @@ ynh_psql_create_user() { # usage: ynh_psql_user_exists --user=user # | arg: -u, --user - the user for which to check existence ynh_psql_user_exists() { - # Declare an array to define the options of this helper. - local legacy_args=u - local -A args_array=([u]=user=) - local user - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=u + local -A args_array=([u]=user=) + local user + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then - return 1 - else - return 0 - fi + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT rolname FROM pg_roles WHERE rolname='$user';" | grep --quiet "$user" ; then + return 1 + else + return 0 + fi } # Check if a psql database exists @@ -172,18 +172,18 @@ ynh_psql_user_exists() { # usage: ynh_psql_database_exists --database=database # | arg: -d, --database - the database for which to check existence ynh_psql_database_exists() { - # Declare an array to define the options of this helper. - local legacy_args=d - local -A args_array=([d]=database=) - local database - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=d + local -A args_array=([d]=database=) + local database + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then - return 1 - else - return 0 - fi + if ! sudo --login --user=postgres PGUSER="postgres" PGPASSWORD="$(cat $PSQL_ROOT_PWD_FILE)" psql -tAc "SELECT datname FROM pg_database WHERE datname='$database';" | grep --quiet "$database"; then + return 1 + else + return 0 + fi } # Drop a user @@ -195,7 +195,7 @@ ynh_psql_database_exists() { # # Requires YunoHost version 3.5.0 or higher. ynh_psql_drop_user() { - ynh_psql_execute_as_root --sql="DROP USER ${1};" + ynh_psql_execute_as_root --sql="DROP USER ${1};" } # Create a database, an user and its password. Then store the password in the app's config @@ -208,25 +208,25 @@ ynh_psql_drop_user() { # | arg: -n, --db_name - Name of the database # | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated ynh_psql_setup_db() { - # Declare an array to define the options of this helper. - local legacy_args=unp - local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=) - local db_user - local db_name - db_pwd="" - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=unp + local -A args_array=([u]=db_user= [n]=db_name= [p]=db_pwd=) + local db_user + local db_name + db_pwd="" + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - local new_db_pwd=$(ynh_string_random) # Generate a random password - # If $db_pwd is not given, use new_db_pwd instead for db_pwd - db_pwd="${db_pwd:-$new_db_pwd}" + local new_db_pwd=$(ynh_string_random) # Generate a random password + # If $db_pwd is not given, use new_db_pwd instead for db_pwd + db_pwd="${db_pwd:-$new_db_pwd}" - if ! ynh_psql_user_exists --user=$db_user; then - ynh_psql_create_user "$db_user" "$db_pwd" - fi + if ! ynh_psql_user_exists --user=$db_user; then + ynh_psql_create_user "$db_user" "$db_pwd" + fi - ynh_psql_create_db "$db_name" "$db_user" # Create the database - ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config + ynh_psql_create_db "$db_name" "$db_user" # Create the database + ynh_app_setting_set --app=$app --key=psqlpwd --value=$db_pwd # Store the password in the app's config } # Remove a database if it exists, and the associated user @@ -235,26 +235,26 @@ ynh_psql_setup_db() { # | arg: -u, --db_user - Owner of the database # | arg: -n, --db_name - Name of the database ynh_psql_remove_db() { - # Declare an array to define the options of this helper. - local legacy_args=un - local -A args_array=([u]=db_user= [n]=db_name=) - local db_user - local db_name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=un + local -A args_array=([u]=db_user= [n]=db_name=) + local db_user + local db_name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - if ynh_psql_database_exists --database=$db_name; then # Check if the database exists - ynh_psql_drop_db $db_name # Remove the database - else - ynh_print_warn --message="Database $db_name not found" - fi + if ynh_psql_database_exists --database=$db_name; then # Check if the database exists + ynh_psql_drop_db $db_name # Remove the database + else + ynh_print_warn --message="Database $db_name not found" + fi - # Remove psql user if it exists - if ynh_psql_user_exists --user=$db_user; then - ynh_psql_drop_user $db_user - else - ynh_print_warn --message="User $db_user not found" - fi + # Remove psql user if it exists + if ynh_psql_user_exists --user=$db_user; then + ynh_psql_drop_user $db_user + else + ynh_print_warn --message="User $db_user not found" + fi } # Create a master password and set up global settings @@ -262,8 +262,8 @@ ynh_psql_remove_db() { # # usage: ynh_psql_test_if_first_run ynh_psql_test_if_first_run() { - if [ -f "$PSQL_ROOT_PWD_FILE" ]; then - echo "PostgreSQL is already installed, no need to create master password" + if [ -f "$PSQL_ROOT_PWD_FILE" ]; then + echo "PostgreSQL is already installed, no need to create master password" return fi diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 5cc5d19dd..874ae44c1 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -122,15 +122,15 @@ EOF # # Requires YunoHost version 2.6.4 or higher. ynh_webpath_available () { - # Declare an array to define the options of this helper. - local legacy_args=dp - local -A args_array=( [d]=domain= [p]=path_url= ) - local domain - local path_url - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=dp + local -A args_array=( [d]=domain= [p]=path_url= ) + local domain + local path_url + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - yunohost domain url-available $domain $path_url + yunohost domain url-available $domain $path_url } # Register/book a web path for an app @@ -144,16 +144,16 @@ ynh_webpath_available () { # # Requires YunoHost version 2.6.4 or higher. ynh_webpath_register () { - # Declare an array to define the options of this helper. - local legacy_args=adp - local -A args_array=( [a]=app= [d]=domain= [p]=path_url= ) - local app - local domain - local path_url - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=adp + local -A args_array=( [a]=app= [d]=domain= [p]=path_url= ) + local app + local domain + local path_url + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - yunohost app register-url $app $domain $path_url + yunohost app register-url $app $domain $path_url } # Create a new permission for the app @@ -178,8 +178,8 @@ ynh_webpath_register () { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_create() { - # Declare an array to define the options of this helper. - local legacy_args=pua + # Declare an array to define the options of this helper. + local legacy_args=pua local -A args_array=( [p]=permission= [u]=url= [a]=allowed= ) local permission local url @@ -208,8 +208,8 @@ ynh_permission_create() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_delete() { - # Declare an array to define the options of this helper. - local legacy_args=p + # Declare an array to define the options of this helper. + local legacy_args=p local -A args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -224,8 +224,8 @@ ynh_permission_delete() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_exists() { - # Declare an array to define the options of this helper. - local legacy_args=p + # Declare an array to define the options of this helper. + local legacy_args=p local -A args_array=( [p]=permission= ) local permission ynh_handle_getopts_args "$@" @@ -241,8 +241,8 @@ ynh_permission_exists() { # # Requires YunoHost version 3.7.0 or higher. ynh_permission_url() { - # Declare an array to define the options of this helper. - local legacy_args=pu + # Declare an array to define the options of this helper. + local legacy_args=pu local -A args_array=([p]=permission= [u]=url=) local permission local url @@ -268,8 +268,8 @@ ynh_permission_url() { # example: ynh_permission_update --permission admin --add samdoe --remove all_users # Requires YunoHost version 3.7.0 or higher. ynh_permission_update() { - # Declare an array to define the options of this helper. - local legacy_args=par + # Declare an array to define the options of this helper. + local legacy_args=par local -A args_array=( [p]=permission= [a]=add= [r]=remove= ) local permission local add diff --git a/data/helpers.d/string b/data/helpers.d/string index 9b8437953..76c3b37e4 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -18,8 +18,8 @@ ynh_string_random() { length=${length:-24} dd if=/dev/urandom bs=1 count=1000 2> /dev/null \ - | tr -c -d 'A-Za-z0-9' \ - | sed -n 's/\(.\{'"$length"'\}\).*/\1/p' + | tr -c -d 'A-Za-z0-9' \ + | sed -n 's/\(.\{'"$length"'\}\).*/\1/p' } # Substitute/replace a string (or expression) by another in a file @@ -35,21 +35,21 @@ ynh_string_random() { # # Requires YunoHost version 2.6.4 or higher. ynh_replace_string () { - # Declare an array to define the options of this helper. - local legacy_args=mrf - local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) - local match_string - local replace_string - local target_file - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=mrf + local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) + local match_string + local replace_string + local target_file + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - local delimit=@ - # Escape the delimiter if it's in the string. - match_string=${match_string//${delimit}/"\\${delimit}"} - replace_string=${replace_string//${delimit}/"\\${delimit}"} + local delimit=@ + # Escape the delimiter if it's in the string. + match_string=${match_string//${delimit}/"\\${delimit}"} + replace_string=${replace_string//${delimit}/"\\${delimit}"} - sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" + sed --in-place "s${delimit}${match_string}${delimit}${replace_string}${delimit}g" "$target_file" } # Substitute/replace a special string by another in a file @@ -64,24 +64,24 @@ ynh_replace_string () { # # Requires YunoHost version 2.7.7 or higher. ynh_replace_special_string () { - # Declare an array to define the options of this helper. - local legacy_args=mrf - local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) - local match_string - local replace_string - local target_file - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=mrf + local -A args_array=( [m]=match_string= [r]=replace_string= [f]=target_file= ) + local match_string + local replace_string + local target_file + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - # Escape any backslash to preserve them as simple backslash. - match_string=${match_string//\\/"\\\\"} - replace_string=${replace_string//\\/"\\\\"} + # Escape any backslash to preserve them as simple backslash. + match_string=${match_string//\\/"\\\\"} + replace_string=${replace_string//\\/"\\\\"} - # Escape the & character, who has a special function in sed. - match_string=${match_string//&/"\&"} - replace_string=${replace_string//&/"\&"} + # Escape the & character, who has a special function in sed. + match_string=${match_string//&/"\&"} + replace_string=${replace_string//&/"\&"} - ynh_replace_string --match_string="$match_string" --replace_string="$replace_string" --target_file="$target_file" + ynh_replace_string --match_string="$match_string" --replace_string="$replace_string" --target_file="$target_file" } # Sanitize a string intended to be the name of a database @@ -95,15 +95,15 @@ ynh_replace_special_string () { # # Requires YunoHost version 2.2.4 or higher. ynh_sanitize_dbid () { - # Declare an array to define the options of this helper. - local legacy_args=n - local -A args_array=( [n]=db_name= ) - local db_name - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=n + local -A args_array=( [n]=db_name= ) + local db_name + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - # We should avoid having - and . in the name of databases. They are replaced by _ - echo ${db_name//[-.]/_} + # We should avoid having - and . in the name of databases. They are replaced by _ + echo ${db_name//[-.]/_} } # Normalize the url path syntax @@ -123,19 +123,19 @@ ynh_sanitize_dbid () { # # Requires YunoHost version 2.6.4 or higher. ynh_normalize_url_path () { - # Declare an array to define the options of this helper. - local legacy_args=p - local -A args_array=( [p]=path_url= ) - local path_url - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=p + local -A args_array=( [p]=path_url= ) + local path_url + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - test -n "$path_url" || ynh_die --message="ynh_normalize_url_path expect a URL path as first argument and received nothing." - if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a / - path_url="/$path_url" # Add / at begin of path variable - fi - if [ "${path_url:${#path_url}-1}" == "/" ] && [ ${#path_url} -gt 1 ]; then # If the last character is a / and that not the only character. - path_url="${path_url:0:${#path_url}-1}" # Delete the last character - fi - echo $path_url + test -n "$path_url" || ynh_die --message="ynh_normalize_url_path expect a URL path as first argument and received nothing." + if [ "${path_url:0:1}" != "/" ]; then # If the first character is not a / + path_url="/$path_url" # Add / at begin of path variable + fi + if [ "${path_url:${#path_url}-1}" == "/" ] && [ ${#path_url} -gt 1 ]; then # If the last character is a / and that not the only character. + path_url="${path_url:0:${#path_url}-1}" # Delete the last character + fi + echo $path_url } diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 276674e70..9ab3ff150 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -16,33 +16,33 @@ # # Requires YunoHost version 2.7.2 or higher. ynh_add_systemd_config () { - # Declare an array to define the options of this helper. - local legacy_args=st - local -A args_array=( [s]=service= [t]=template= ) - local service - local template - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - local service="${service:-$app}" - local template="${template:-systemd.service}" + # Declare an array to define the options of this helper. + local legacy_args=st + local -A args_array=( [s]=service= [t]=template= ) + local service + local template + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + local service="${service:-$app}" + local template="${template:-systemd.service}" - finalsystemdconf="/etc/systemd/system/$service.service" - ynh_backup_if_checksum_is_different --file="$finalsystemdconf" - cp ../conf/$template "$finalsystemdconf" + finalsystemdconf="/etc/systemd/system/$service.service" + ynh_backup_if_checksum_is_different --file="$finalsystemdconf" + cp ../conf/$template "$finalsystemdconf" - # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. - # Substitute in a nginx config file only if the variable is not empty - if test -n "${final_path:-}"; then - ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf" - fi - if test -n "${app:-}"; then - ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf" - fi - ynh_store_file_checksum --file="$finalsystemdconf" + # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. + # Substitute in a nginx config file only if the variable is not empty + if test -n "${final_path:-}"; then + ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf" + fi + if test -n "${app:-}"; then + ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf" + fi + ynh_store_file_checksum --file="$finalsystemdconf" - chown root: "$finalsystemdconf" - systemctl enable $service - systemctl daemon-reload + chown root: "$finalsystemdconf" + systemctl enable $service + systemctl daemon-reload } # Remove the dedicated systemd config @@ -52,21 +52,21 @@ ynh_add_systemd_config () { # # Requires YunoHost version 2.7.2 or higher. ynh_remove_systemd_config () { - # Declare an array to define the options of this helper. - local legacy_args=s - local -A args_array=( [s]=service= ) - local service - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - local service="${service:-$app}" + # Declare an array to define the options of this helper. + local legacy_args=s + local -A args_array=( [s]=service= ) + local service + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + local service="${service:-$app}" - local finalsystemdconf="/etc/systemd/system/$service.service" - if [ -e "$finalsystemdconf" ]; then - ynh_systemd_action --service_name=$service --action=stop - systemctl disable $service - ynh_secure_remove --file="$finalsystemdconf" - systemctl daemon-reload - fi + local finalsystemdconf="/etc/systemd/system/$service.service" + if [ -e "$finalsystemdconf" ]; then + ynh_systemd_action --service_name=$service --action=stop + systemctl disable $service + ynh_secure_remove --file="$finalsystemdconf" + systemctl daemon-reload + fi } # Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started @@ -172,7 +172,7 @@ ynh_clean_check_starting () { fi if [ -n "$templog" ] then - ynh_secure_remove "$templog" 2>&1 + ynh_secure_remove "$templog" 2>&1 fi } diff --git a/data/helpers.d/user b/data/helpers.d/user index 72cb9bece..9d9bc9089 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -51,7 +51,7 @@ ynh_user_get_info() { # Requires YunoHost version 2.4.0 or higher. ynh_user_list() { yunohost user list --output-as plain --quiet \ - | awk '/^##username$/{getline; print}' + | awk '/^##username$/{getline; print}' } # Check if a user exists on the system @@ -101,31 +101,31 @@ ynh_system_group_exists() { # # Requires YunoHost version 2.6.4 or higher. ynh_system_user_create () { - # Declare an array to define the options of this helper. - local legacy_args=uhs - local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell ) - local username - local home_dir - local use_shell - # Manage arguments with getopts - ynh_handle_getopts_args "$@" - use_shell="${use_shell:-0}" - home_dir="${home_dir:-}" + # Declare an array to define the options of this helper. + local legacy_args=uhs + local -A args_array=( [u]=username= [h]=home_dir= [s]=use_shell ) + local username + local home_dir + local use_shell + # Manage arguments with getopts + ynh_handle_getopts_args "$@" + use_shell="${use_shell:-0}" + home_dir="${home_dir:-}" - if ! ynh_system_user_exists "$username" # Check if the user exists on the system - then # If the user doesn't exist - if [ -n "$home_dir" ]; then # If a home dir is mentioned - local user_home_dir="-d $home_dir" - else - local user_home_dir="--no-create-home" - fi - if [ $use_shell -eq 1 ]; then # If we want a shell for the user - local shell="" # Use default shell - else - local shell="--shell /usr/sbin/nologin" - fi - useradd $user_home_dir --system --user-group $username $shell || ynh_die "Unable to create $username system account" - fi + if ! ynh_system_user_exists "$username" # Check if the user exists on the system + then # If the user doesn't exist + if [ -n "$home_dir" ]; then # If a home dir is mentioned + local user_home_dir="-d $home_dir" + else + local user_home_dir="--no-create-home" + fi + if [ $use_shell -eq 1 ]; then # If we want a shell for the user + local shell="" # Use default shell + else + local shell="--shell /usr/sbin/nologin" + fi + useradd $user_home_dir --system --user-group $username $shell || ynh_die "Unable to create $username system account" + fi } # Delete a system user @@ -145,14 +145,14 @@ ynh_system_user_delete () { # Check if the user exists on the system if ynh_system_user_exists "$username" then - deluser $username - else - ynh_print_warn --message="The user $username was not found" + deluser $username + else + ynh_print_warn --message="The user $username was not found" fi # Check if the group exists on the system if ynh_system_group_exists "$username" then - delgroup $username + delgroup $username fi } diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 5f352ab96..bdc8ee849 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -17,22 +17,22 @@ # It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script # ynh_exit_properly () { - local exit_code=$? - if [ "$exit_code" -eq 0 ]; then - exit 0 # Exit without error if the script ended correctly - fi + local exit_code=$? + if [ "$exit_code" -eq 0 ]; then + exit 0 # Exit without error if the script ended correctly + fi - trap '' EXIT # Ignore new exit signals - set +eu # Do not exit anymore if a command fail or if a variable is empty + trap '' EXIT # Ignore new exit signals + set +eu # Do not exit anymore if a command fail or if a variable is empty - # Small tempo to avoid the next message being mixed up with other DEBUG messages - sleep 0.5 + # Small tempo to avoid the next message being mixed up with other DEBUG messages + sleep 0.5 - if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script. - ynh_clean_setup # Call the function to do specific cleaning for the app. - fi + if type -t ynh_clean_setup > /dev/null; then # Check if the function exist in the app script. + ynh_clean_setup # Call the function to do specific cleaning for the app. + fi - ynh_die # Exit with error status + ynh_die # Exit with error status } # Exits if an error occurs during the execution of the script. @@ -46,8 +46,8 @@ ynh_exit_properly () { # # Requires YunoHost version 2.6.4 or higher. ynh_abort_if_errors () { - set -eu # Exit if a command fail, and if a variable is used unset. - trap ynh_exit_properly EXIT # Capturing exit signals on shell script + set -eu # Exit if a command fail, and if a variable is used unset. + trap ynh_exit_properly EXIT # Capturing exit signals on shell script } # Download, check integrity, uncompress and patch the source from app.src @@ -256,13 +256,13 @@ ynh_local_curl () { # | arg: some_template - Template file to be rendered # | arg: output_path - The path where the output will be redirected to ynh_render_template() { - local template_path=$1 - local output_path=$2 - mkdir -p "$(dirname $output_path)" - # Taken from https://stackoverflow.com/a/35009576 - python2.7 -c 'import os, sys, jinja2; sys.stdout.write( + local template_path=$1 + local output_path=$2 + mkdir -p "$(dirname $output_path)" + # Taken from https://stackoverflow.com/a/35009576 + python2.7 -c 'import os, sys, jinja2; sys.stdout.write( jinja2.Template(sys.stdin.read() - ).render(os.environ));' < $template_path > $output_path + ).render(os.environ));' < $template_path > $output_path } # Fetch the Debian release codename @@ -272,7 +272,7 @@ ynh_render_template() { # # Requires YunoHost version 2.7.12 or higher. ynh_get_debian_release () { - echo $(lsb_release --codename --short) + echo $(lsb_release --codename --short) } # Create a directory under /tmp @@ -376,20 +376,20 @@ ynh_get_plain_key() { # # Requires YunoHost version 3.5.0 or higher. ynh_read_manifest () { - # Declare an array to define the options of this helper. - local legacy_args=mk - local -A args_array=( [m]=manifest= [k]=manifest_key= ) - local manifest - local manifest_key - # Manage arguments with getopts - ynh_handle_getopts_args "$@" + # Declare an array to define the options of this helper. + local legacy_args=mk + local -A args_array=( [m]=manifest= [k]=manifest_key= ) + local manifest + local manifest_key + # Manage arguments with getopts + ynh_handle_getopts_args "$@" - if [ ! -e "$manifest" ]; then - # If the manifest isn't found, try the common place for backup and restore script. - manifest="../settings/manifest.json" - fi + if [ ! -e "$manifest" ]; then + # If the manifest isn't found, try the common place for backup and restore script. + manifest="../settings/manifest.json" + fi - jq ".$manifest_key" "$manifest" --raw-output + jq ".$manifest_key" "$manifest" --raw-output } # Read the upstream version from the manifest @@ -458,32 +458,32 @@ ynh_app_package_version () { # # Requires YunoHost version 3.5.0 or higher. ynh_check_app_version_changed () { - local force_upgrade=${YNH_FORCE_UPGRADE:-0} - local package_check=${PACKAGE_CHECK_EXEC:-0} + local force_upgrade=${YNH_FORCE_UPGRADE:-0} + local package_check=${PACKAGE_CHECK_EXEC:-0} - # By default, upstream app version has changed - local return_value="UPGRADE_APP" + # By default, upstream app version has changed + local return_value="UPGRADE_APP" - local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0) - local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")" - local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0) - local update_upstream_version="$(ynh_app_upstream_version)" + local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0) + local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")" + local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0) + local update_upstream_version="$(ynh_app_upstream_version)" - if [ "$current_version" == "$update_version" ] ; then - # Complete versions are the same - if [ "$force_upgrade" != "0" ] - then - ynh_print_info --message="Upgrade forced by YNH_FORCE_UPGRADE." - unset YNH_FORCE_UPGRADE - elif [ "$package_check" != "0" ] - then - ynh_print_info --message="Upgrade forced for package check." - else - ynh_die "Up-to-date, nothing to do" 0 - fi - elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then - # Upstream versions are the same, only YunoHost package versions differ - return_value="UPGRADE_PACKAGE" - fi - echo $return_value + if [ "$current_version" == "$update_version" ] ; then + # Complete versions are the same + if [ "$force_upgrade" != "0" ] + then + ynh_print_info --message="Upgrade forced by YNH_FORCE_UPGRADE." + unset YNH_FORCE_UPGRADE + elif [ "$package_check" != "0" ] + then + ynh_print_info --message="Upgrade forced for package check." + else + ynh_die "Up-to-date, nothing to do" 0 + fi + elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then + # Upstream versions are the same, only YunoHost package versions differ + return_value="UPGRADE_PACKAGE" + fi + echo $return_value } From 57061b8e1db1171ddebf4f8a7ffdad25a1bb11f7 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 19 Apr 2020 20:31:06 +0200 Subject: [PATCH 187/317] Unfold if-then when more than one line --- data/helpers.d/apt | 5 +++-- data/helpers.d/backup | 22 ++++++++++++++-------- data/helpers.d/fail2ban | 14 ++++++++------ data/helpers.d/getopts | 6 ++++-- data/helpers.d/logrotate | 15 ++++++++++----- data/helpers.d/mysql | 6 ++++-- data/helpers.d/nginx | 3 ++- data/helpers.d/php | 21 ++++++++++++++------- data/helpers.d/postgresql | 21 ++++++++++++++------- data/helpers.d/setting | 6 ++++-- data/helpers.d/systemd | 6 ++++-- data/helpers.d/user | 6 ++++-- data/helpers.d/utils | 35 ++++++++++++++++++++++------------- 13 files changed, 107 insertions(+), 59 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 4093e593f..a1eb6f470 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -78,7 +78,8 @@ ynh_package_version() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ynh_package_is_installed "$package"; then + if ynh_package_is_installed "$package" + then dpkg-query -W -f '${Version}' "$package" 2>/dev/null else echo '' @@ -251,7 +252,7 @@ ynh_install_app_dependencies () { # https://github.com/YunoHost/issues/issues/1407 # # If we require to install php dependency - if echo $dependencies | grep -q 'php'; + if echo $dependencies | grep -q 'php' then # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9" diff --git a/data/helpers.d/backup b/data/helpers.d/backup index bb676a0e0..096804380 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -64,7 +64,8 @@ ynh_backup() { # don't backup big data items if [ $is_big -eq 1 ] && ( [ ${do_not_backup_data:-0} -eq 1 ] || [ $BACKUP_CORE_ONLY -eq 1 ] ) then - if [ $BACKUP_CORE_ONLY -eq 1 ]; then + if [ $BACKUP_CORE_ONLY -eq 1 ] + then ynh_print_warn --message="$src_path will not be saved, because 'BACKUP_CORE_ONLY' is set." else ynh_print_warn --message="$src_path will not be saved, because 'do_not_backup_data' is set." @@ -100,12 +101,13 @@ ynh_backup() { # If there is no destination path, initialize it with the source path # relative to "/". # eg: src_path=/etc/yunohost -> dest_path=etc/yunohost - if [[ -z "$dest_path" ]]; then - + if [[ -z "$dest_path" ]] + then dest_path="${src_path#/}" else - if [[ "${dest_path:0:1}" == "/" ]]; then + if [[ "${dest_path:0:1}" == "/" ]] + then # If the destination path is an absolute path, transform it as a path # relative to the current working directory ($YNH_CWD) @@ -165,7 +167,8 @@ ynh_restore () { # For each destination path begining by $REL_DIR cat ${YNH_BACKUP_CSV} | tr -d $'\r' | grep -ohP "^\".*\",\"$REL_DIR.*\"$" | \ - while read line; do + while read line + do local ORIGIN_PATH=$(echo "$line" | grep -ohP "^\"\K.*(?=\",\".*\"$)") local ARCHIVE_PATH=$(echo "$line" | grep -ohP "^\".*\",\"$REL_DIR\K.*(?=\"$)") ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH" @@ -234,7 +237,8 @@ ynh_restore_file () { local not_mandatory="${not_mandatory:-0}" # If archive_path doesn't exist, search for a corresponding path in CSV - if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ]; then + if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ] + then if [ "$not_mandatory" == "0" ] then archive_path="$YNH_BACKUP_DIR/$(_get_archive_path \"$origin_path\")" @@ -261,8 +265,10 @@ ynh_restore_file () { mkdir -p $(dirname "$dest_path") # Do a copy if it's just a mounting point - if mountpoint -q $YNH_BACKUP_DIR; then - if [[ -d "${archive_path}" ]]; then + if mountpoint -q $YNH_BACKUP_DIR + then + if [[ -d "${archive_path}" ]] + then archive_path="${archive_path}/." mkdir -p "$dest_path" fi diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 2c17e1300..438b3b355 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -96,7 +96,8 @@ ynh_add_fail2ban_config () { fi # Replace all other variable given as arguments - for var_to_replace in ${others_var:-}; do + for var_to_replace in ${others_var:-} + do # ${var_to_replace^^} make the content of the variable on upper-cases # ${!var_to_replace} get the content of the variable named $var_to_replace ynh_replace_string --match_string="__${var_to_replace^^}__" --replace_string="${!var_to_replace}" --target_file="$finalfail2banjailconf" @@ -104,11 +105,11 @@ ynh_add_fail2ban_config () { done else - # Usage 1, no template. Build a config file from scratch. - test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing." - test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing." + # Usage 1, no template. Build a config file from scratch. + test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing." + test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing." - tee $finalfail2banjailconf <$PSQL_ROOT_PWD_FILE - if [ -e /etc/postgresql/9.4/ ]; then + if [ -e /etc/postgresql/9.4/ ] + then local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf local logfile=/var/log/postgresql/postgresql-9.4-main.log - elif [ -e /etc/postgresql/9.6/ ]; then + elif [ -e /etc/postgresql/9.6/ ] + then local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf local logfile=/var/log/postgresql/postgresql-9.6-main.log else diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 874ae44c1..eca529069 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -186,7 +186,8 @@ ynh_permission_create() { local allowed ynh_handle_getopts_args "$@" - if [[ -n ${url:-} ]]; then + if [[ -n ${url:-} ]] + then url="'$url'" else url="None" @@ -248,7 +249,8 @@ ynh_permission_url() { local url ynh_handle_getopts_args "$@" - if [[ -n ${url:-} ]]; then + if [[ -n ${url:-} ]] + then url="'$url'" else url="None" diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 9ab3ff150..6257b9138 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -61,7 +61,8 @@ ynh_remove_systemd_config () { local service="${service:-$app}" local finalsystemdconf="/etc/systemd/system/$service.service" - if [ -e "$finalsystemdconf" ]; then + if [ -e "$finalsystemdconf" ] + then ynh_systemd_action --service_name=$service --action=stop systemctl disable $service ynh_secure_remove --file="$finalsystemdconf" @@ -103,7 +104,8 @@ ynh_systemd_action() { then local templog="$(mktemp)" # Following the starting of the app in its log - if [ "$log_path" == "systemd" ] ; then + if [ "$log_path" == "systemd" ] + then # Read the systemd journal journalctl --unit=$service_name --follow --since=-0 --quiet > "$templog" & # Get the PID of the journalctl command diff --git a/data/helpers.d/user b/data/helpers.d/user index 9d9bc9089..0b964c7c0 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -114,12 +114,14 @@ ynh_system_user_create () { if ! ynh_system_user_exists "$username" # Check if the user exists on the system then # If the user doesn't exist - if [ -n "$home_dir" ]; then # If a home dir is mentioned + if [ -n "$home_dir" ] + then # If a home dir is mentioned local user_home_dir="-d $home_dir" else local user_home_dir="--no-create-home" fi - if [ $use_shell -eq 1 ]; then # If we want a shell for the user + if [ $use_shell -eq 1 ] + then # If we want a shell for the user local shell="" # Use default shell else local shell="--shell /usr/sbin/nologin" diff --git a/data/helpers.d/utils b/data/helpers.d/utils index bdc8ee849..2ad05f93c 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -129,7 +129,7 @@ ynh_setup_source () { src_format=${src_format:-tar.gz} src_format=$(echo "$src_format" | tr '[:upper:]' '[:lower:]') src_extract=${src_extract:-true} - if [ "$src_filename" = "" ] ; then + if [ "$src_filename" = "" ]; then src_filename="${source_id}.${src_format}" fi local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${src_filename}" @@ -155,7 +155,8 @@ ynh_setup_source () { then # Zip format # Using of a temp directory, because unzip doesn't manage --strip-components - if $src_in_subdir ; then + if $src_in_subdir + then local tmp_dir=$(mktemp -d) unzip -quo $src_filename -d "$tmp_dir" cp -a $tmp_dir/*/. "$dest_dir" @@ -167,14 +168,16 @@ ynh_setup_source () { local strip="" if [ "$src_in_subdir" != "false" ] then - if [ "$src_in_subdir" == "true" ]; then + if [ "$src_in_subdir" == "true" ] + then local sub_dirs=1 else local sub_dirs="$src_in_subdir" fi strip="--strip-components $sub_dirs" fi - if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] ; then + if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] + then tar -xf $src_filename -C "$dest_dir" $strip else ynh_die --message="Archive format unrecognized." @@ -321,7 +324,7 @@ ynh_secure_remove () { if [[ -z "$file" ]] then ynh_print_warn --message="ynh_secure_remove called with empty argument, ignoring." - else if [[ "$forbidden_path" =~ "$file" \ + elif [[ "$forbidden_path" =~ "$file" \ # Match all paths or subpaths in $forbidden_path || "$file" =~ ^/[[:alnum:]]+$ \ # Match all first level paths from / (Like /var, /root, etc...) @@ -329,12 +332,12 @@ ynh_secure_remove () { # Match if the path finishes by /. Because it seems there is an empty variable then ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete." - else if [ -e "$file" ] + elif [ -e "$file" ] then rm -R "$file" else ynh_print_info --message="'$file' wasn't deleted because it doesn't exist." - fi fi fi + fi } # Extract a key from a plain command output @@ -352,12 +355,16 @@ ynh_get_plain_key() { # an info to be redacted by the core local key_=$1 shift - while read line; do - if [[ "$founded" == "1" ]] ; then + while read line + do + if [[ "$founded" == "1" ]] + then [[ "$line" =~ ^${prefix}[^#] ]] && return echo $line - elif [[ "$line" =~ ^${prefix}${key_}$ ]]; then - if [[ -n "${1:-}" ]]; then + elif [[ "$line" =~ ^${prefix}${key_}$ ]] + then + if [[ -n "${1:-}" ]] + then prefix+="#" key_=$1 shift @@ -469,7 +476,8 @@ ynh_check_app_version_changed () { local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0) local update_upstream_version="$(ynh_app_upstream_version)" - if [ "$current_version" == "$update_version" ] ; then + if [ "$current_version" == "$update_version" ] + then # Complete versions are the same if [ "$force_upgrade" != "0" ] then @@ -481,7 +489,8 @@ ynh_check_app_version_changed () { else ynh_die "Up-to-date, nothing to do" 0 fi - elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then + elif [ "$current_upstream_version" == "$update_upstream_version" ] + then # Upstream versions are the same, only YunoHost package versions differ return_value="UPGRADE_PACKAGE" fi From b0398ae6dce76fa13d762bc544db7662c477a332 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 15:20:31 +0200 Subject: [PATCH 188/317] Use long arguments instead of short ones --- data/helpers.d/apt | 52 ++++++++++++++++++++-------------------- data/helpers.d/backup | 38 ++++++++++++++--------------- data/helpers.d/fail2ban | 2 +- data/helpers.d/getopts | 4 ++-- data/helpers.d/logging | 18 +++++++------- data/helpers.d/logrotate | 4 ++-- data/helpers.d/mysql | 6 ++--- data/helpers.d/network | 4 ++-- data/helpers.d/nodejs | 8 +++---- data/helpers.d/php | 4 ++-- data/helpers.d/setting | 4 ++-- data/helpers.d/string | 4 ++-- data/helpers.d/systemd | 4 ++-- data/helpers.d/user | 4 ++-- data/helpers.d/utils | 41 ++++++++++++++++--------------- 15 files changed, 100 insertions(+), 97 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index a1eb6f470..9d2c2b64c 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -27,7 +27,7 @@ ynh_wait_dpkg_free() { while read dpkg_file <&9 do # Check if the name of this file contains only numbers. - if echo "$dpkg_file" | grep -Pq "^[[:digit:]]+$" + if echo "$dpkg_file" | grep --perl-regexp --quiet "^[[:digit:]]+$" then # If so, that a remaining of dpkg. ynh_print_err "E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem." @@ -57,8 +57,8 @@ ynh_package_is_installed() { ynh_handle_getopts_args "$@" ynh_wait_dpkg_free - dpkg-query -W -f '${Status}' "$package" 2>/dev/null \ - | grep -c "ok installed" &>/dev/null + dpkg-query --show --showformat='${Status}' "$package" 2>/dev/null \ + | grep --count "ok installed" &>/dev/null } # Get the version of an installed package @@ -80,7 +80,7 @@ ynh_package_version() { if ynh_package_is_installed "$package" then - dpkg-query -W -f '${Version}' "$package" 2>/dev/null + dpkg-query --show --showformat='${Version}' "$package" 2>/dev/null else echo '' fi @@ -95,7 +95,7 @@ ynh_package_version() { # Requires YunoHost version 2.4.0.3 or higher. ynh_apt() { ynh_wait_dpkg_free - LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get -y $@ + LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get --assume-yes $@ } # Update package index files @@ -114,8 +114,8 @@ ynh_package_update() { # # Requires YunoHost version 2.2.4 or higher. ynh_package_install() { - ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \ - -o Dpkg::Options::=--force-confold install $@ + ynh_apt --no-remove --option Dpkg::Options::=--force-confdef \ + --option Dpkg::Options::=--force-confold install $@ } # Remove package(s) @@ -164,8 +164,8 @@ ynh_package_install_from_equivs () { local controlfile=$1 # retrieve package information - local pkgname=$(grep '^Package: ' $controlfile | cut -d' ' -f 2) # Retrieve the name of the debian package - local pkgversion=$(grep '^Version: ' $controlfile | cut -d' ' -f 2) # And its version number + local pkgname=$(grep '^Package: ' $controlfile | cut --delimiter=' ' --fields=2) # Retrieve the name of the debian package + local pkgversion=$(grep '^Version: ' $controlfile | cut --delimiter=' ' --fields=2) # And its version number [[ -z "$pkgname" || -z "$pkgversion" ]] \ && ynh_die --message="Invalid control file" # Check if this 2 variables aren't empty. @@ -173,7 +173,7 @@ ynh_package_install_from_equivs () { ynh_package_update # Build and install the package - local TMPDIR=$(mktemp -d) + local TMPDIR=$(mktemp --directory) # Force the compatibility level at 10, levels below are deprecated echo 10 > /usr/share/equivs/template/debian/compat @@ -186,21 +186,21 @@ ynh_package_install_from_equivs () { cp "$controlfile" "${TMPDIR}/control" (cd "$TMPDIR" LC_ALL=C equivs-build ./control 1> /dev/null - dpkg --force-depends -i "./${pkgname}_${pkgversion}_all.deb" 2>&1) + dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1) # If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies # Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell). # Be careful with the syntax : the semicolon + space at the end is important! - ynh_package_install -f || \ + ynh_package_install --fix-broken || \ { # If the installation failed # Get the list of dependencies from the deb local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ sed 's/^ Depends: //' | sed 's/,//g')" # Fake an install of those dependencies to see the errors # The sed command here is, Print only from '--fix-broken' to the end. - ynh_package_install $dependencies --dry-run | sed -n '/--fix-broken/,$p' >&2 + ynh_package_install $dependencies --dry-run | sed --quiet '/--fix-broken/,$p' >&2 ynh_die --message="Unable to install dependencies"; } - [[ -n "$TMPDIR" ]] && rm -rf $TMPDIR # Remove the temp dir. + [[ -n "$TMPDIR" ]] && rm --recursive --force $TMPDIR # Remove the temp dir. # check if the package is actually installed ynh_package_is_installed "$pkgname" @@ -226,7 +226,7 @@ ynh_install_app_dependencies () { manifest_path="../settings/manifest.json" # Into the restore script, the manifest is not at the same place fi - local version=$(grep '\"version\": ' "$manifest_path" | cut -d '"' -f 4) # Retrieve the version number in the manifest file. + local version=$(grep '\"version\": ' "$manifest_path" | cut --delimiter='"' --fields=4) # Retrieve the version number in the manifest file. if [ ${#version} -eq 0 ]; then version="1.0" fi @@ -252,16 +252,16 @@ ynh_install_app_dependencies () { # https://github.com/YunoHost/issues/issues/1407 # # If we require to install php dependency - if echo $dependencies | grep -q 'php' + if echo $dependencies | grep --quiet 'php' then # And we have packages from sury installed (7.0.33-10+weirdshiftafter instead of 7.0.33-0 on debian) - if dpkg --list | grep "php7.0" | grep -q -v "7.0.33-0+deb9" + if dpkg --list | grep "php7.0" | grep --quiet --invert-match "7.0.33-0+deb9" then # And sury ain't already installed - if ! grep -nrq "sury" /etc/apt/sources.list* + if ! grep --line-number --recursive --quiet "sury" /etc/apt/sources.list* then # Re-add sury - ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version + ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --name=extra_php_version # Pin this sury repository to prevent sury of doing shit ynh_pin_repo --package="*" --pin="origin \"packages.sury.org\"" --priority=200 --name=extra_php_version @@ -396,7 +396,7 @@ ynh_install_extra_repo () { if [ $append -eq 1 ] then append="--append" - wget_append="tee -a" + wget_append="tee --append" else append="" wget_append="tee" @@ -432,8 +432,8 @@ ynh_install_extra_repo () { # Get the public key for the repo if [ -n "$key" ] then - mkdir -p "/etc/apt/trusted.gpg.d" - wget -q "$key" -O - | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null + mkdir --parents "/etc/apt/trusted.gpg.d" + wget --quiet "$key" --output-document=- | gpg --dearmor | $wget_append /etc/apt/trusted.gpg.d/$name.gpg > /dev/null fi # Update the list of package with the new repo @@ -495,12 +495,12 @@ ynh_add_repo () { if [ $append -eq 1 ] then - append="tee -a" + append="tee --append" else append="tee" fi - mkdir -p "/etc/apt/sources.list.d" + mkdir --parents "/etc/apt/sources.list.d" # Add the new repo in sources.list.d echo "deb $uri $suite $component" \ | $append "/etc/apt/sources.list.d/$name.list" @@ -537,12 +537,12 @@ ynh_pin_repo () { if [ $append -eq 1 ] then - append="tee -a" + append="tee --append" else append="tee" fi - mkdir -p "/etc/apt/preferences.d" + mkdir --parents "/etc/apt/preferences.d" echo "Package: $package Pin: $pin Pin-Priority: $priority diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 096804380..60e9fca94 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -144,15 +144,15 @@ ynh_backup() { # ============================================================================== # Write file to backup into backup_list # ============================================================================== - local src=$(echo "${src_path}" | sed -r 's/"/\"\"/g') - local dest=$(echo "${dest_path}" | sed -r 's/"/\"\"/g') + local src=$(echo "${src_path}" | sed --regexp-extended 's/"/\"\"/g') + local dest=$(echo "${dest_path}" | sed --regexp-extended 's/"/\"\"/g') echo "\"${src}\",\"${dest}\"" >> "${YNH_BACKUP_CSV}" # ============================================================================== # Create the parent dir of the destination path # It's for retro compatibility, some script consider ynh_backup creates this dir - mkdir -p $(dirname "$YNH_BACKUP_DIR/${dest_path}") + mkdir --parents $(dirname "$YNH_BACKUP_DIR/${dest_path}") } # Restore all files that were previously backuped in a core backup script or app backup script @@ -166,11 +166,11 @@ ynh_restore () { REL_DIR="${REL_DIR%/}/" # For each destination path begining by $REL_DIR - cat ${YNH_BACKUP_CSV} | tr -d $'\r' | grep -ohP "^\".*\",\"$REL_DIR.*\"$" | \ + cat ${YNH_BACKUP_CSV} | tr --delete $'\r' | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR.*\"$" | \ while read line do - local ORIGIN_PATH=$(echo "$line" | grep -ohP "^\"\K.*(?=\",\".*\"$)") - local ARCHIVE_PATH=$(echo "$line" | grep -ohP "^\".*\",\"$REL_DIR\K.*(?=\"$)") + local ORIGIN_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\"\K.*(?=\",\".*\"$)") + local ARCHIVE_PATH=$(echo "$line" | grep --only-matching --no-filename --perl-regexp "^\".*\",\"$REL_DIR\K.*(?=\"$)") ynh_restore_file --origin_path="$ARCHIVE_PATH" --dest_path="$ORIGIN_PATH" done } @@ -251,10 +251,10 @@ ynh_restore_file () { if [[ -e "${dest_path}" ]] then # Check if the file/dir size is less than 500 Mo - if [[ $(du -sb ${dest_path} | cut -d"/" -f1) -le "500000000" ]] + if [[ $(du --summarize --bytes ${dest_path} | cut --delimiter="/" --fields=1) -le "500000000" ]] then local backup_file="/home/yunohost.conf/backup/${dest_path}.backup.$(date '+%Y%m%d.%H%M%S')" - mkdir -p "$(dirname "$backup_file")" + mkdir --parents "$(dirname "$backup_file")" mv "${dest_path}" "$backup_file" # Move the current file or directory else ynh_secure_remove --file=${dest_path} @@ -262,17 +262,17 @@ ynh_restore_file () { fi # Restore origin_path into dest_path - mkdir -p $(dirname "$dest_path") + mkdir --parents $(dirname "$dest_path") # Do a copy if it's just a mounting point - if mountpoint -q $YNH_BACKUP_DIR + if mountpoint --quiet $YNH_BACKUP_DIR then if [[ -d "${archive_path}" ]] then archive_path="${archive_path}/." - mkdir -p "$dest_path" + mkdir --parents "$dest_path" fi - cp -a "$archive_path" "${dest_path}" + cp --archive "$archive_path" "${dest_path}" # Do a move if YNH_BACKUP_DIR is already a copy else mv "$archive_path" "${dest_path}" @@ -308,7 +308,7 @@ ynh_store_file_checksum () { ynh_handle_getopts_args "$@" local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_' - ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut -d' ' -f1) + ynh_app_setting_set --app=$app --key=$checksum_setting_name --value=$(md5sum "$file" | cut --delimiter=' ' --fields=1) # If backup_file_checksum isn't empty, ynh_backup_if_checksum_is_different has made a backup if [ -n "${backup_file_checksum-}" ] @@ -345,11 +345,11 @@ ynh_backup_if_checksum_is_different () { backup_file_checksum="" if [ -n "$checksum_value" ] then # Proceed only if a value was stored into the app settings - if [ -e $file ] && ! echo "$checksum_value $file" | md5sum -c --status + if [ -e $file ] && ! echo "$checksum_value $file" | md5sum --check --status then # If the checksum is now different backup_file_checksum="/home/yunohost.conf/backup/$file.backup.$(date '+%Y%m%d.%H%M%S')" - mkdir -p "$(dirname "$backup_file_checksum")" - cp -a "$file" "$backup_file_checksum" # Backup the current file + mkdir --parents "$(dirname "$backup_file_checksum")" + cp --archive "$file" "$backup_file_checksum" # Backup the current file ynh_print_warn "File $file has been manually modified since the installation or last upgrade. So it has been duplicated in $backup_file_checksum" echo "$backup_file_checksum" # Return the name of the backup file fi @@ -400,7 +400,7 @@ ynh_backup_before_upgrade () { if [ "$NO_BACKUP_UPGRADE" -eq 0 ] then # Check if a backup already exists with the prefix 1 - if yunohost backup list | grep -q $app_bck-pre-upgrade1 + if yunohost backup list | grep --quiet $app_bck-pre-upgrade1 then # Prefix becomes 2 to preserve the previous backup backup_number=2 @@ -412,7 +412,7 @@ ynh_backup_before_upgrade () { if [ "$?" -eq 0 ] then # If the backup succeeded, remove the previous backup - if yunohost backup list | grep -q $app_bck-pre-upgrade$old_backup_number + if yunohost backup list | grep --quiet $app_bck-pre-upgrade$old_backup_number then # Remove the previous backup only if it exists yunohost backup delete $app_bck-pre-upgrade$old_backup_number > /dev/null @@ -444,7 +444,7 @@ ynh_restore_upgradebackup () { if [ "$NO_BACKUP_UPGRADE" -eq 0 ] then # Check if an existing backup can be found before removing and restoring the application. - if yunohost backup list | grep -q $app_bck-pre-upgrade$backup_number + if yunohost backup list | grep --quiet $app_bck-pre-upgrade$backup_number then # Remove the application then restore it yunohost app remove $app diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 438b3b355..1eef67f5c 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -133,7 +133,7 @@ EOF ynh_systemd_action --service_name=fail2ban --action=reload - local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")" + local fail2ban_error="$(journalctl --unit=fail2ban | tail --lines=50 | grep "WARNING.*$app.*")" if [[ -n "$fail2ban_error" ]] then ynh_print_err --message="Fail2ban failed to load the jail for $app" diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index 1717ea8fc..4dfd08d9e 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -47,7 +47,7 @@ # Requires YunoHost version 3.2.2 or higher. ynh_handle_getopts_args () { # Manage arguments only if there's some provided - set +x + set +o xtrace # set +x if [ $# -ne 0 ] then # Store arguments in an array to keep each argument separated @@ -216,5 +216,5 @@ ynh_handle_getopts_args () { parse_arg "${arguments[@]}" fi fi - set -x + set -o xtrace # set -x } diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 0cd25fb57..812709921 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -46,7 +46,7 @@ ynh_print_info() { # Requires YunoHost version 2.6.4 or higher. ynh_no_log() { local ynh_cli_log=/var/log/yunohost/yunohost-cli.log - cp -a ${ynh_cli_log} ${ynh_cli_log}-move + cp --archive ${ynh_cli_log} ${ynh_cli_log}-move eval $@ local exit_code=$? mv ${ynh_cli_log}-move ${ynh_cli_log} @@ -221,7 +221,7 @@ base_time=$(date +%s) # # Requires YunoHost version 3.5.0 or higher. ynh_script_progression () { - set +x + set +o xtrace # set +x # Declare an array to define the options of this helper. local legacy_args=mwtl local -A args_array=( [m]=message= [w]=weight= [t]=time [l]=last ) @@ -231,7 +231,7 @@ ynh_script_progression () { local last # Manage arguments with getopts ynh_handle_getopts_args "$@" - set +x + set +o xtrace # set +x weight=${weight:-1} time=${time:-0} last=${last:-0} @@ -295,7 +295,7 @@ ynh_script_progression () { fi ynh_print_info "[$progression_bar] > ${message}${print_exec_time}" - set -x + set -o xtrace # set -x } # Return data to the Yunohost core for later processing @@ -317,7 +317,7 @@ ynh_return () { # Requires YunoHost version 3.5.0 or higher. ynh_debug () { # Disable set xtrace for the helper itself, to not pollute the debug log - set +x + set +o xtrace # set +x # Declare an array to define the options of this helper. local legacy_args=mt local -A args_array=( [m]=message= [t]=trace= ) @@ -326,7 +326,7 @@ ynh_debug () { # Manage arguments with getopts ynh_handle_getopts_args "$@" # Redisable xtrace, ynh_handle_getopts_args set it back - set +x + set +o xtrace # set +x message=${message:-} trace=${trace:-} @@ -338,7 +338,7 @@ ynh_debug () { if [ "$trace" == "1" ] then ynh_debug --message="Enable debugging" - set +x + set +o xtrace # set +x # Get the current file descriptor of xtrace old_bash_xtracefd=$BASH_XTRACEFD # Add the current file name and the line number of any command currently running while tracing. @@ -351,14 +351,14 @@ ynh_debug () { if [ "$trace" == "0" ] then ynh_debug --message="Disable debugging" - set +x + set +o xtrace # set +x # Put xtrace back to its original fild descriptor BASH_XTRACEFD=$old_bash_xtracefd # Restore stdout exec 1>&1 fi # Renable set xtrace - set -x + set -o xtrace # set -x } # Execute a command and print the result as debug diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 3cd835eee..b9af082a6 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -55,7 +55,7 @@ ynh_use_logrotate () { fi # LEGACY CODE - local customtee="tee -a" + local customtee="tee --append" if [ "$nonappend" -eq 1 ]; then customtee="tee" fi @@ -95,7 +95,7 @@ $logfile { $su_directive } EOF - mkdir -p $(dirname "$logfile") # Create the log directory, if not exist + mkdir --parents $(dirname "$logfile") # Create the log directory, if not exist cat ${app}-logrotate | $customtee /etc/logrotate.d/$app > /dev/null # Append this config to the existing config file, or replace the whole config file (depending on $customtee) } diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index 52c65cc63..62edd8822 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -24,7 +24,7 @@ ynh_mysql_connect_as() { ynh_handle_getopts_args "$@" database="${database:-}" - mysql -u "$user" --password="$password" -B "$database" + mysql --user="$user" --password="$password" --batch "$database" } # Execute a command as root user @@ -127,7 +127,7 @@ ynh_mysql_dump_db() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - mysqldump -u "root" -p"$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database" + mysqldump --user="root" --password="$(cat $MYSQL_ROOT_PWD_FILE)" --single-transaction --skip-dump-date "$database" } # Create a user @@ -225,7 +225,7 @@ ynh_mysql_remove_db () { ynh_handle_getopts_args "$@" local mysql_root_password=$(cat $MYSQL_ROOT_PWD_FILE) - if mysqlshow -u root -p$mysql_root_password | grep -q "^| $db_name" + if mysqlshow --user=root --password=$mysql_root_password | grep --quiet "^| $db_name" then # Check if the database exists ynh_mysql_drop_db $db_name # Remove the database else diff --git a/data/helpers.d/network b/data/helpers.d/network index ca15e6919..2e301090c 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -17,7 +17,7 @@ ynh_find_port () { ynh_handle_getopts_args "$@" test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port." - while ss -nltu | awk '{print$5}' | grep -q -E ":$port$" # Check if the port is free + while ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$" # Check if the port is free do port=$((port+1)) # Else, pass to next port done @@ -40,7 +40,7 @@ ynh_port_available () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ss -nltu | grep -q -w :$port + if ss --numeric --listening --tcp --udp | grep --quiet --word-regexp :$port then return 1 else diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index 2d4ea66dc..cb83e3136 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -15,7 +15,7 @@ export N_PREFIX="$n_install_dir" ynh_install_n () { ynh_print_info --message="Installation of N - Node.js version management" # Build an app.src for n - mkdir -p "../conf" + mkdir --parents "../conf" echo "SOURCE_URL=https://github.com/tj/n/archive/v4.1.0.tar.gz SOURCE_SUM=3983fa3f00d4bf85ba8e21f1a590f6e28938093abe0bb950aeea52b1717471fc" > "../conf/n.src" # Download and extract n @@ -74,7 +74,7 @@ ynh_install_nodejs () { ynh_handle_getopts_args "$@" # Create $n_install_dir - mkdir -p "$n_install_dir" + mkdir --parents "$n_install_dir" # Load n path in PATH CLEAR_PATH="$n_install_dir/bin:$PATH" @@ -102,7 +102,7 @@ ynh_install_nodejs () { test -x /usr/bin/npm_n && mv /usr/bin/npm_n /usr/bin/npm # Install the requested version of nodejs - uname=$(uname -m) + uname=$(uname --machine) if [[ $uname =~ aarch64 || $uname =~ arm64 ]] then n $nodejs_version --arch=arm64 @@ -159,7 +159,7 @@ ynh_remove_nodejs () { ynh_secure_remove --file="$n_install_dir" ynh_secure_remove --file="/usr/local/n" sed --in-place "/N_PREFIX/d" /root/.bashrc - rm -f /etc/cron.daily/node_update + rm --force /etc/cron.daily/node_update fi } diff --git a/data/helpers.d/php b/data/helpers.d/php index c904f8f1b..1bbb6c84b 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -117,7 +117,7 @@ ynh_add_fpm_config () { fi # Create the directory for fpm pools - mkdir -p "$fpm_config_dir/pool.d" + mkdir --parents "$fpm_config_dir/pool.d" ynh_app_setting_set --app=$app --key=fpm_config_dir --value="$fpm_config_dir" ynh_app_setting_set --app=$app --key=fpm_service --value="$fpm_service" @@ -341,7 +341,7 @@ ynh_install_php () { fi # Add an extra repository for those packages - ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(lsb_release -sc) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version + ynh_install_extra_repo --repo="https://packages.sury.org/php/ $(ynh_get_debian_release) main" --key="https://packages.sury.org/php/apt.gpg" --priority=995 --name=extra_php_version # Install requested dependencies from this extra repository. # Install php-fpm first, otherwise php will install apache as a dependency. diff --git a/data/helpers.d/setting b/data/helpers.d/setting index eca529069..86634dcc3 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -231,7 +231,7 @@ ynh_permission_exists() { local permission ynh_handle_getopts_args "$@" - yunohost user permission list -s | grep -w -q "$app.$permission" + yunohost user permission list --short | grep --word-regexp --quiet "$app.$permission" } # Redefine the url associated to a permission @@ -311,5 +311,5 @@ ynh_permission_has_user() { return 1 fi - yunohost user permission info "$app.$permission" | grep -w -q "$user" + yunohost user permission info "$app.$permission" | grep --word-regexp --quiet "$user" } diff --git a/data/helpers.d/string b/data/helpers.d/string index 76c3b37e4..dd318b4de 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -18,8 +18,8 @@ ynh_string_random() { length=${length:-24} dd if=/dev/urandom bs=1 count=1000 2> /dev/null \ - | tr -c -d 'A-Za-z0-9' \ - | sed -n 's/\(.\{'"$length"'\}\).*/\1/p' + | tr --complement --delete 'A-Za-z0-9' \ + | sed --quiet 's/\(.\{'"$length"'\}\).*/\1/p' } # Substitute/replace a string (or expression) by another in a file diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 6257b9138..b6c4722af 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -112,7 +112,7 @@ ynh_systemd_action() { local pid_tail=$! else # Read the specified log file - tail -F -n0 "$log_path" > "$templog" 2>&1 & + tail --follow --retry --lines=0 "$log_path" > "$templog" 2>&1 & # Get the PID of the tail command local pid_tail=$! fi @@ -170,7 +170,7 @@ ynh_clean_check_starting () { if [ -n "$pid_tail" ] then # Stop the execution of tail. - kill -s 15 $pid_tail 2>&1 + kill --signal 15 $pid_tail 2>&1 fi if [ -n "$templog" ] then diff --git a/data/helpers.d/user b/data/helpers.d/user index 0b964c7c0..ff6c4e6ea 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -16,7 +16,7 @@ ynh_user_exists() { # Manage arguments with getopts ynh_handle_getopts_args "$@" - yunohost user list --output-as json | grep -q "\"username\": \"${username}\"" + yunohost user list --output-as json | grep --quiet "\"username\": \"${username}\"" } # Retrieve a YunoHost user information @@ -116,7 +116,7 @@ ynh_system_user_create () { then # If the user doesn't exist if [ -n "$home_dir" ] then # If a home dir is mentioned - local user_home_dir="-d $home_dir" + local user_home_dir="--home-dir $home_dir" else local user_home_dir="--no-create-home" fi diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 2ad05f93c..41cef98c2 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -23,7 +23,9 @@ ynh_exit_properly () { fi trap '' EXIT # Ignore new exit signals - set +eu # Do not exit anymore if a command fail or if a variable is empty + # Do not exit anymore if a command fail or if a variable is empty + set +o errexit # set +e + set +o nounset # set +u # Small tempo to avoid the next message being mixed up with other DEBUG messages sleep 0.5 @@ -46,7 +48,8 @@ ynh_exit_properly () { # # Requires YunoHost version 2.6.4 or higher. ynh_abort_if_errors () { - set -eu # Exit if a command fail, and if a variable is used unset. + set -o errexit # set -e; Exit if a command fail + set -o nounset # set -u; And if a variable is used unset trap ynh_exit_properly EXIT # Capturing exit signals on shell script } @@ -115,13 +118,13 @@ ynh_setup_source () { # Load value from configuration file (see above for a small doc about this file # format) - local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut -d= -f2-) - local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut -d= -f2-) - local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut -d= -f2-) - local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut -d= -f2-) - local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut -d= -f2-) - local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut -d= -f2-) - local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut -d= -f2-) + local src_url=$(grep 'SOURCE_URL=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_sum=$(grep 'SOURCE_SUM=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_sumprg=$(grep 'SOURCE_SUM_PRG=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_format=$(grep 'SOURCE_FORMAT=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_extract=$(grep 'SOURCE_EXTRACT=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_in_subdir=$(grep 'SOURCE_IN_SUBDIR=' "$src_file_path" | cut --delimiter='=' --fields=2-) + local src_filename=$(grep 'SOURCE_FILENAME=' "$src_file_path" | cut --delimiter='=' --fields=2-) # Default value src_sumprg=${src_sumprg:-sha256sum} @@ -138,15 +141,15 @@ ynh_setup_source () { then # Use the local source file if it is present cp $local_src $src_filename else # If not, download the source - local out=`wget -nv -O $src_filename $src_url 2>&1` || ynh_print_err --message="$out" + local out=`wget --no-verbose --output-document=$src_filename $src_url 2>&1` || ynh_print_err --message="$out" fi # Check the control sum - echo "${src_sum} ${src_filename}" | ${src_sumprg} -c --status \ + echo "${src_sum} ${src_filename}" | ${src_sumprg} --check --status \ || ynh_die --message="Corrupt source" # Extract source into the app dir - mkdir -p "$dest_dir" + mkdir --parents "$dest_dir" if ! "$src_extract" then @@ -157,9 +160,9 @@ ynh_setup_source () { # Using of a temp directory, because unzip doesn't manage --strip-components if $src_in_subdir then - local tmp_dir=$(mktemp -d) + local tmp_dir=$(mktemp --directory) unzip -quo $src_filename -d "$tmp_dir" - cp -a $tmp_dir/*/. "$dest_dir" + cp --archive $tmp_dir/*/. "$dest_dir" ynh_secure_remove --file="$tmp_dir" else unzip -quo $src_filename -d "$dest_dir" @@ -178,7 +181,7 @@ ynh_setup_source () { fi if [[ "$src_format" =~ ^tar.gz|tar.bz2|tar.xz$ ]] then - tar -xf $src_filename -C "$dest_dir" $strip + tar --extract --file=$src_filename --directory="$dest_dir" $strip else ynh_die --message="Archive format unrecognized." fi @@ -196,7 +199,7 @@ ynh_setup_source () { # Add supplementary files if test -e "$YNH_CWD/../sources/extra_files/${source_id}"; then - cp -a $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir" + cp --archive $YNH_CWD/../sources/extra_files/$source_id/. "$dest_dir" fi } @@ -247,7 +250,7 @@ ynh_local_curl () { chmod 700 $cookiefile # Curl the URL - curl --silent --show-error -kL -H "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile + curl --silent --show-error --insecure --location --header "Host: $domain" --resolve $domain:443:127.0.0.1 $POST_data "$full_page_url" --cookie-jar $cookiefile --cookie $cookiefile } # Render templates with Jinja2 @@ -290,7 +293,7 @@ ynh_mkdir_tmp() { ynh_print_warn --message="The helper ynh_mkdir_tmp is deprecated." ynh_print_warn --message="You should use 'mktemp -d' instead and manage permissions \ properly with chmod/chown." - local TMP_DIR=$(mktemp -d) + local TMP_DIR=$(mktemp --directory) # Give rights to other users could be a security risk. # But for retrocompatibility we need it. (This helpers is deprecated) @@ -334,7 +337,7 @@ ynh_secure_remove () { ynh_print_warn --message="Not deleting '$file' because it is not an acceptable path to delete." elif [ -e "$file" ] then - rm -R "$file" + rm --recursive "$file" else ynh_print_info --message="'$file' wasn't deleted because it doesn't exist." fi From 3442ab5b806fb09281cc156e23fb2c9b3d1ba6b1 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 15:21:11 +0200 Subject: [PATCH 189/317] Add internal flags --- data/helpers.d/apt | 2 -- data/helpers.d/network | 2 ++ data/helpers.d/string | 2 ++ data/helpers.d/utils | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 9d2c2b64c..1c032f26c 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -288,8 +288,6 @@ EOF # Add dependencies to install with ynh_install_app_dependencies # -# [internal] -# # usage: ynh_add_app_dependencies --package=phpversion [--replace] # | arg: -p, --package - Packages to add as dependencies for the app. # | arg: -r, --replace - Replace dependencies instead of adding to existing ones. diff --git a/data/helpers.d/network b/data/helpers.d/network index 2e301090c..c8493d7ac 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -51,6 +51,8 @@ ynh_port_available () { # Validate an IP address # +# [internal] +# # usage: ynh_validate_ip --family=family --ip_address=ip_address # | ret: 0 for valid ip addresses, 1 otherwise # diff --git a/data/helpers.d/string b/data/helpers.d/string index dd318b4de..7a37f29c3 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -108,6 +108,8 @@ ynh_sanitize_dbid () { # Normalize the url path syntax # +# [internal] +# # Handle the slash at the beginning of path and its absence at ending # Return a normalized url path # diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 41cef98c2..a991853e3 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -255,6 +255,8 @@ ynh_local_curl () { # Render templates with Jinja2 # +# [internal] +# # Attention : Variables should be exported before calling this helper to be # accessible inside templates. # @@ -345,6 +347,8 @@ ynh_secure_remove () { # Extract a key from a plain command output # +# [internal] +# # example: yunohost user info tata --output-as plain | ynh_get_plain_key mail # # usage: ynh_get_plain_key key [subkey [subsubkey ...]] From 464149eb7664b91be9a6d2ee78ad293093ee75e9 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 15:21:37 +0200 Subject: [PATCH 190/317] Use ynh_print_info --- data/helpers.d/postgresql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index 4fc349169..f0aa6d0f0 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -268,7 +268,7 @@ ynh_psql_remove_db() { ynh_psql_test_if_first_run() { if [ -f "$PSQL_ROOT_PWD_FILE" ] then - echo "PostgreSQL is already installed, no need to create master password" + ynh_print_info --message="PostgreSQL is already installed, no need to create master password" return fi From e64eb3478e0ba9d8b734610e88aba18bc54efaab Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 15:24:07 +0200 Subject: [PATCH 191/317] Unfold AND OR --- data/helpers.d/backup | 20 ++++++++++++-------- data/helpers.d/mysql | 4 +++- data/helpers.d/systemd | 30 ++++++++++++++++++++++-------- data/helpers.d/utils | 14 +++++++------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 60e9fca94..e5186cb59 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -77,7 +77,8 @@ ynh_backup() { # Format correctly source and destination paths # ============================================================================== # Be sure the source path is not empty - [[ -e "${src_path}" ]] || { + if [ ! -e "$src_path" ] + then ynh_print_warn --message="Source path '${src_path}' does not exist" if [ "$not_mandatory" == "0" ] then @@ -92,7 +93,7 @@ ynh_backup() { else return 0 fi - } + fi # Transform the source path as an absolute path # If it's a dir remove the ending / @@ -119,20 +120,23 @@ ynh_backup() { dest_path="${dest_path#$YNH_CWD/}" # Case where $2 is an absolute dir but doesn't begin with $YNH_CWD - [[ "${dest_path:0:1}" == "/" ]] \ - && dest_path="${dest_path#/}" + if [[ "${dest_path:0:1}" == "/" ]]; then + dest_path="${dest_path#/}" + fi fi # Complete dest_path if ended by a / - [[ "${dest_path: -1}" == "/" ]] \ - && dest_path="${dest_path}/$(basename $src_path)" + if [[ "${dest_path: -1}" == "/" ]]; then + dest_path="${dest_path}/$(basename $src_path)" + fi fi # Check if dest_path already exists in tmp archive - [[ ! -e "${dest_path}" ]] || { + if [[ -e "${dest_path}" ]] + then ynh_print_err --message="Destination path '${dest_path}' already exist" return 1 - } + fi # Add the relative current working directory to the destination path local rel_dir="${YNH_CWD#$YNH_BACKUP_DIR}" diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index 62edd8822..7edc633b4 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -88,7 +88,9 @@ ynh_mysql_create_db() { if [[ $# -gt 1 ]] then sql+=" GRANT ALL PRIVILEGES ON ${db}.* TO '${2}'@'localhost'" - [[ -n ${3:-} ]] && sql+=" IDENTIFIED BY '${3}'" + if [[ -n ${3:-} ]]; then + sql+=" IDENTIFIED BY '${3}'" + fi sql+=" WITH GRANT OPTION;" fi diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index b6c4722af..871d6459d 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -32,10 +32,10 @@ ynh_add_systemd_config () { # To avoid a break by set -u, use a void substitution ${var:-}. If the variable is not set, it's simply set with an empty variable. # Substitute in a nginx config file only if the variable is not empty - if test -n "${final_path:-}"; then + if [ -n "${final_path:-}" ]; then ynh_replace_string --match_string="__FINALPATH__" --replace_string="$final_path" --target_file="$finalsystemdconf" fi - if test -n "${app:-}"; then + if [ -n "${app:-}" ]; then ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="$finalsystemdconf" fi ynh_store_file_checksum --file="$finalsystemdconf" @@ -123,10 +123,20 @@ ynh_systemd_action() { action="reload-or-restart" fi - systemctl $action $service_name \ - || ( journalctl --no-pager --lines=$length -u $service_name >&2 \ - ; test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 \ - ; false ) + # If the service fails to perform the action + if ! systemctl $action $service_name + then + # Show syslog for this service + ynh_exec_err journalctl --no-pager --lines=$length --unit=$service_name + # If a log is specified for this service, show also the content of this log + if [ -e "$log_path" ] + then + ynh_print_err --message="--" + ynh_exec_err tail --lines=$length "$log_path" + fi + # Fail the app script, since the service failed. + false + fi # Start the timeout and try to find line_match if [[ -n "${line_match:-}" ]] @@ -155,8 +165,12 @@ ynh_systemd_action() { then ynh_print_warn --message="The service $service_name didn't fully executed the action ${action} before the timeout." ynh_print_warn --message="Please find here an extract of the end of the log of the service $service_name:" - journalctl --no-pager --lines=$length -u $service_name >&2 - test -e "$log_path" && echo "--" >&2 && tail --lines=$length "$log_path" >&2 + ynh_exec_warn journalctl --no-pager --lines=$length --unit=$service_name + if [ -e "$log_path" ] + then + ynh_print_warn --message="--" + ynh_exec_warn tail --lines=$length "$log_path" + fi fi ynh_clean_check_starting fi diff --git a/data/helpers.d/utils b/data/helpers.d/utils index a991853e3..6b75426fc 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -188,13 +188,13 @@ ynh_setup_source () { fi # Apply patches - if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc -l) > "0" )); then - local old_dir=$(pwd) - (cd "$dest_dir" \ - && for p in $YNH_CWD/../sources/patches/${source_id}-*.patch; do \ - patch -p1 < $p; done) \ - || ynh_die --message="Unable to apply patches" - cd $old_dir + if (( $(find $YNH_CWD/../sources/patches/ -type f -name "${source_id}-*.patch" 2> /dev/null | wc --lines) > "0" )) + then + (cd "$dest_dir" + for p in $YNH_CWD/../sources/patches/${source_id}-*.patch + do + patch --strip=1 < $p + done) || ynh_die --message="Unable to apply patches" fi # Add supplementary files From 3b653994c7665410a2a925ba29a31d86b360b15d Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 20:58:17 +0200 Subject: [PATCH 192/317] Standardize helper comments --- data/helpers.d/apt | 49 ++++++++++++++------------- data/helpers.d/backup | 54 ++++++++++++++--------------- data/helpers.d/hardware | 20 ++++++----- data/helpers.d/logging | 29 +++++++--------- data/helpers.d/logrotate | 6 ++-- data/helpers.d/mysql | 39 ++++++++++----------- data/helpers.d/network | 8 +++-- data/helpers.d/nodejs | 8 ++--- data/helpers.d/php | 28 +++++++-------- data/helpers.d/postgresql | 35 ++++++++++--------- data/helpers.d/setting | 71 ++++++++++++++++++++------------------- data/helpers.d/string | 19 ++++++----- data/helpers.d/systemd | 8 ++--- data/helpers.d/user | 21 +++++++----- data/helpers.d/utils | 39 +++++++++++---------- 15 files changed, 226 insertions(+), 208 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 1c032f26c..50db7613f 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -5,6 +5,7 @@ # [internal] # # usage: ynh_wait_dpkg_free +# | exit: Return 1 if dpkg is broken # # Requires YunoHost version 3.3.1 or higher. ynh_wait_dpkg_free() { @@ -45,7 +46,7 @@ ynh_wait_dpkg_free() { # example: ynh_package_is_installed --package=yunohost && echo "ok" # # usage: ynh_package_is_installed --package=name -# | arg: -p, --package - the package name to check +# | arg: -p, --package= - the package name to check # # Requires YunoHost version 2.2.4 or higher. ynh_package_is_installed() { @@ -66,7 +67,7 @@ ynh_package_is_installed() { # example: version=$(ynh_package_version --package=yunohost) # # usage: ynh_package_version --package=name -# | arg: -p, --package - the package name to get version +# | arg: -p, --package= - the package name to get version # | ret: the version or an empty string # # Requires YunoHost version 2.2.4 or higher. @@ -289,8 +290,8 @@ EOF # Add dependencies to install with ynh_install_app_dependencies # # usage: ynh_add_app_dependencies --package=phpversion [--replace] -# | arg: -p, --package - Packages to add as dependencies for the app. -# | arg: -r, --replace - Replace dependencies instead of adding to existing ones. +# | arg: -p, --package= - Packages to add as dependencies for the app. +# | arg: -r, --replace - Replace dependencies instead of adding to existing ones. ynh_add_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=pr @@ -333,10 +334,10 @@ ynh_remove_app_dependencies () { # Install packages from an extra repository properly. # # usage: ynh_install_extra_app_dependencies --repo="repo" --package="dep1 dep2" [--key=key_url] [--name=name] -# | arg: -r, --repo - Complete url of the extra repository. -# | arg: -p, --package - The packages to install from this extra repository -# | arg: -k, --key - url to get the public key. -# | arg: -n, --name - Name for the files for this repo, $app as default value. +# | arg: -r, --repo= - Complete url of the extra repository. +# | arg: -p, --package= - The packages to install from this extra repository +# | arg: -k, --key= - url to get the public key. +# | arg: -n, --name= - Name for the files for this repo, $app as default value. ynh_install_extra_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=rpkn @@ -370,11 +371,11 @@ ynh_install_extra_app_dependencies () { # [internal] # # usage: ynh_install_extra_repo --repo="repo" [--key=key_url] [--priority=priority_value] [--name=name] [--append] -# | arg: -r, --repo - Complete url of the extra repository. -# | arg: -k, --key - url to get the public key. -# | arg: -p, --priority - Priority for the pin -# | arg: -n, --name - Name for the files for this repo, $app as default value. -# | arg: -a, --append - Do not overwrite existing files. +# | arg: -r, --repo= - Complete url of the extra repository. +# | arg: -k, --key= - url to get the public key. +# | arg: -p, --priority= - Priority for the pin +# | arg: -n, --name= - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. ynh_install_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=rkpna @@ -443,7 +444,7 @@ ynh_install_extra_repo () { # [internal] # # usage: ynh_remove_extra_repo [--name=name] -# | arg: -n, --name - Name for the files for this repo, $app as default value. +# | arg: -n, --name= - Name for the files for this repo, $app as default value. ynh_remove_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=n @@ -467,11 +468,11 @@ ynh_remove_extra_repo () { # [internal] # # usage: ynh_add_repo --uri=uri --suite=suite --component=component [--name=name] [--append] -# | arg: -u, --uri - Uri of the repository. -# | arg: -s, --suite - Suite of the repository. -# | arg: -c, --component - Component of the repository. -# | arg: -n, --name - Name for the files for this repo, $app as default value. -# | arg: -a, --append - Do not overwrite existing files. +# | arg: -u, --uri= - Uri of the repository. +# | arg: -s, --suite= - Suite of the repository. +# | arg: -c, --component= - Component of the repository. +# | arg: -n, --name= - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. # # Example for a repo like deb http://forge.yunohost.org/debian/ stretch stable # uri suite component @@ -509,11 +510,11 @@ ynh_add_repo () { # [internal] # # usage: ynh_pin_repo --package=packages --pin=pin_filter [--priority=priority_value] [--name=name] [--append] -# | arg: -p, --package - Packages concerned by the pin. Or all, *. -# | arg: -i, --pin - Filter for the pin. -# | arg: -p, --priority - Priority for the pin -# | arg: -n, --name - Name for the files for this repo, $app as default value. -# | arg: -a, --append - Do not overwrite existing files. +# | arg: -p, --package= - Packages concerned by the pin. Or all, *. +# | arg: -i, --pin= - Filter for the pin. +# | arg: -p, --priority= - Priority for the pin +# | arg: -n, --name= - Name for the files for this repo, $app as default value. +# | arg: -a, --append - Do not overwrite existing files. # # See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning. # diff --git a/data/helpers.d/backup b/data/helpers.d/backup index e5186cb59..2fae73ba0 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -4,6 +4,13 @@ CAN_BIND=${CAN_BIND:-1} # Add a file or a directory to the list of paths to backup # +# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory] +# | arg: -s, --src_path= - file or directory to bind or symlink or copy. it shouldn't be in the backup dir. +# | arg: -d, --dest_path= - destination file or directory inside the backup dir +# | arg: -b, --is_big - Indicate data are big (mail, video, image ...) +# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it. +# | arg: arg - Deprecated arg +# # This helper can be used both in a system backup hook, and in an app backup script # # Details: ynh_backup writes SRC and the relative DEST into a CSV file. And it @@ -11,13 +18,6 @@ CAN_BIND=${CAN_BIND:-1} # # If DEST is ended by a slash it complete this path with the basename of SRC. # -# usage: ynh_backup --src_path=src_path [--dest_path=dest_path] [--is_big] [--not_mandatory] -# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir. -# | arg: -d, --dest_path - destination file or directory inside the backup dir -# | arg: -b, --is_big - Indicate data are big (mail, video, image ...) -# | arg: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it. -# | arg: arg - Deprecated arg -# # Example in the context of a wordpress app # # ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" @@ -206,9 +206,9 @@ with open(sys.argv[1], 'r') as backup_file: # the right place. # # usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory] -# | arg: -o, --origin_path - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive -# | arg: -d, --dest_path - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv -# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it. +# | arg: -o, --origin_path= - Path where was located the file or the directory before to be backuped or relative path to $YNH_CWD where it is located in the backup archive +# | arg: -d, --dest_path= - Path where restore the file or the dir, if unspecified, the destination will be ORIGIN_PATH or if the ORIGIN_PATH doesn't exist in the archive, the destination will be searched into backup.csv +# | arg: -m, --not_mandatory - Indicate that if the file is missing, the restore process can ignore it. # # examples: # ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf" @@ -297,10 +297,10 @@ ynh_bind_or_cp() { # Calculate and store a file checksum into the app settings # -# $app should be defined when calling this helper -# # usage: ynh_store_file_checksum --file=file -# | arg: -f, --file - The file on which the checksum will performed, then stored. +# | arg: -f, --file= - The file on which the checksum will performed, then stored. +# +# $app should be defined when calling this helper # # Requires YunoHost version 2.6.4 or higher. ynh_store_file_checksum () { @@ -331,7 +331,7 @@ ynh_store_file_checksum () { # modified config files. # # usage: ynh_backup_if_checksum_is_different --file=file -# | arg: -f, --file - The file on which the checksum test will be perfomed. +# | arg: -f, --file= - The file on which the checksum test will be perfomed. # | ret: the name of a backup file, or nothing # # Requires YunoHost version 2.6.4 or higher. @@ -362,10 +362,10 @@ ynh_backup_if_checksum_is_different () { # Delete a file checksum from the app settings # -# $app should be defined when calling this helper +# usage: ynh_delete_file_checksum --file=file +# | arg: -f, --file= - The file for which the checksum will be deleted # -# usage: ynh_remove_file_checksum file -# | arg: -f, --file= - The file for which the checksum will be deleted +# $app should be defined when calling this helper # # Requires YunoHost version 3.3.1 or higher. ynh_delete_file_checksum () { @@ -383,11 +383,11 @@ ynh_delete_file_checksum () { # Make a backup in case of failed upgrade # # usage: -# ynh_backup_before_upgrade -# ynh_clean_setup () { -# ynh_restore_upgradebackup -# } -# ynh_abort_if_errors +# ynh_backup_before_upgrade +# ynh_clean_setup () { +# ynh_restore_upgradebackup +# } +# ynh_abort_if_errors # # Requires YunoHost version 2.7.2 or higher. ynh_backup_before_upgrade () { @@ -432,11 +432,11 @@ ynh_backup_before_upgrade () { # Restore a previous backup if the upgrade process failed # # usage: -# ynh_backup_before_upgrade -# ynh_clean_setup () { -# ynh_restore_upgradebackup -# } -# ynh_abort_if_errors +# ynh_backup_before_upgrade +# ynh_clean_setup () { +# ynh_restore_upgradebackup +# } +# ynh_abort_if_errors # # Requires YunoHost version 2.7.2 or higher. ynh_restore_upgradebackup () { diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index d7e14ccc5..b46edcdd3 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -3,10 +3,11 @@ # Get the total or free amount of RAM+swap on the system # # usage: ynh_get_ram [--free|--total] [--ignore_swap|--only_swap] -# | arg: -f, --free - Count free RAM+swap -# | arg: -t, --total - Count total RAM+swap -# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM -# | arg: -o, --only_swap - Ignore real RAM, consider only swap +# | arg: -f, --free - Count free RAM+swap +# | arg: -t, --total - Count total RAM+swap +# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM +# | arg: -o, --only_swap - Ignore real RAM, consider only swap +# | ret: the amount of free ram ynh_get_ram () { # Declare an array to define the options of this helper. local legacy_args=ftso @@ -67,11 +68,12 @@ ynh_get_ram () { # Return 0 or 1 depending if the system has a given amount of RAM+swap free or total # # usage: ynh_require_ram --required=RAM required in Mb [--free|--total] [--ignore_swap|--only_swap] -# | arg: -r, --required - The amount to require, in Mb -# | arg: -f, --free - Count free RAM+swap -# | arg: -t, --total - Count total RAM+swap -# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM -# | arg: -o, --only_swap - Ignore real RAM, consider only swap +# | arg: -r, --required= - The amount to require, in Mb +# | arg: -f, --free - Count free RAM+swap +# | arg: -t, --total - Count total RAM+swap +# | arg: -s, --ignore_swap - Ignore swap, consider only real RAM +# | arg: -o, --only_swap - Ignore real RAM, consider only swap +# | exit: Return 1 if the ram is under the requirement, 0 otherwise. ynh_require_ram () { # Declare an array to define the options of this helper. local legacy_args=rftso diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 812709921..49374ec1e 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -3,6 +3,8 @@ # Print a message to stderr and exit # # usage: ynh_die --message=MSG [--ret_code=RETCODE] +# | arg: -m, --message= - Message to display +# | arg: -c, --ret_code= - Exit code to exit with # # Requires YunoHost version 2.4.0 or higher. ynh_die() { @@ -21,6 +23,7 @@ ynh_die() { # Display a message in the 'INFO' logging category # # usage: ynh_print_info --message="Some message" +# | arg: -m, --message= - Message to display # # Requires YunoHost version 3.2.0 or higher. ynh_print_info() { @@ -65,7 +68,7 @@ ynh_print_log () { # Print a warning on stderr # # usage: ynh_print_warn --message="Text to print" -# | arg: -m, --message - The text to print +# | arg: -m, --message= - The text to print # # Requires YunoHost version 3.2.0 or higher. ynh_print_warn () { @@ -82,7 +85,7 @@ ynh_print_warn () { # Print an error on stderr # # usage: ynh_print_err --message="Text to print" -# | arg: -m, --message - The text to print +# | arg: -m, --message= - The text to print # # Requires YunoHost version 3.2.0 or higher. ynh_print_err () { @@ -100,13 +103,12 @@ ynh_print_err () { # # usage: ynh_exec_err your_command # usage: ynh_exec_err "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.2.0 or higher. ynh_exec_err () { ynh_print_err "$(eval $@)" @@ -116,13 +118,12 @@ ynh_exec_err () { # # usage: ynh_exec_warn your_command # usage: ynh_exec_warn "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.2.0 or higher. ynh_exec_warn () { ynh_print_warn "$(eval $@)" @@ -132,13 +133,12 @@ ynh_exec_warn () { # # usage: ynh_exec_warn_less your_command # usage: ynh_exec_warn_less "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.2.0 or higher. ynh_exec_warn_less () { eval $@ 2>&1 @@ -148,13 +148,12 @@ ynh_exec_warn_less () { # # usage: ynh_exec_quiet your_command # usage: ynh_exec_quiet "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.2.0 or higher. ynh_exec_quiet () { eval $@ > /dev/null @@ -164,13 +163,12 @@ ynh_exec_quiet () { # # usage: ynh_exec_fully_quiet your_command # usage: ynh_exec_fully_quiet "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.2.0 or higher. ynh_exec_fully_quiet () { eval $@ > /dev/null 2>&1 @@ -216,8 +214,8 @@ base_time=$(date +%s) # usage: ynh_script_progression --message=message [--weight=weight] [--time] # | arg: -m, --message= - The text to print # | arg: -w, --weight= - The weight for this progression. This value is 1 by default. Use a bigger value for a longer part of the script. -# | arg: -t, --time= - Print the execution time since the last call to this helper. Especially usefull to define weights. The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. -# | arg: -l, --last= - Use for the last call of the helper, to fill te progression bar. +# | arg: -t, --time - Print the execution time since the last call to this helper. Especially usefull to define weights. The execution time is given for the duration since the previous call. So the weight should be applied to this previous call. +# | arg: -l, --last - Use for the last call of the helper, to fill te progression bar. # # Requires YunoHost version 3.5.0 or higher. ynh_script_progression () { @@ -365,13 +363,12 @@ ynh_debug () { # # usage: ynh_debug_exec your_command # usage: ynh_debug_exec "your_command | other_command" +# | arg: command - command to execute # # When using pipes, double quotes are required - otherwise, this helper will run the first command, and the whole output will be sent through the next pipe. # # If the command to execute uses double quotes, they have to be escaped or they will be interpreted and removed. # -# | arg: command - command to execute -# # Requires YunoHost version 3.5.0 or higher. ynh_debug_exec () { ynh_debug --message="$(eval $@)" diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index b9af082a6..0fcc63009 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -3,9 +3,9 @@ # Use logrotate to manage the logfile # # usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group] -# | arg: -l, --logfile - absolute path of logfile -# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config. -# | arg: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root. +# | arg: -l, --logfile= - absolute path of logfile +# | arg: -n, --nonappend - (optional) Replace the config file instead of appending this new config. +# | arg: -u, --specific_user= - run logrotate as the specified user and group. If not specified logrotate is runned as root. # # If no --logfile is provided, /var/log/${app} will be used as default. # logfile can be just a directory, or a full path to a logfile : diff --git a/data/helpers.d/mysql b/data/helpers.d/mysql index 7edc633b4..84acc1029 100644 --- a/data/helpers.d/mysql +++ b/data/helpers.d/mysql @@ -4,13 +4,13 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql # Open a connection as a user # -# example: ynh_mysql_connect_as 'user' 'pass' <<< "UPDATE ...;" -# example: ynh_mysql_connect_as 'user' 'pass' < /path/to/file.sql +# example: ynh_mysql_connect_as --user="user" --password="pass" <<< "UPDATE ...;" +# example: ynh_mysql_connect_as --user="user" --password="pass" < /path/to/file.sql # # usage: ynh_mysql_connect_as --user=user --password=password [--database=database] -# | arg: -u, --user - the user name to connect as -# | arg: -p, --password - the user password -# | arg: -d, --database - the database to connect to +# | arg: -u, --user= - the user name to connect as +# | arg: -p, --password= - the user password +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 2.2.4 or higher. ynh_mysql_connect_as() { @@ -30,8 +30,8 @@ ynh_mysql_connect_as() { # Execute a command as root user # # usage: ynh_mysql_execute_as_root --sql=sql [--database=database] -# | arg: -s, --sql - the SQL command to execute -# | arg: -d, --database - the database to connect to +# | arg: -s, --sql= - the SQL command to execute +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 2.2.4 or higher. ynh_mysql_execute_as_root() { @@ -51,8 +51,8 @@ ynh_mysql_execute_as_root() { # Execute a command from a file as root user # # usage: ynh_mysql_execute_file_as_root --file=file [--database=database] -# | arg: -f, --file - the file containing SQL commands -# | arg: -d, --database - the database to connect to +# | arg: -f, --file= - the file containing SQL commands +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 2.2.4 or higher. ynh_mysql_execute_file_as_root() { @@ -114,10 +114,10 @@ ynh_mysql_drop_db() { # Dump a database # -# example: ynh_mysql_dump_db 'roundcube' > ./dump.sql +# example: ynh_mysql_dump_db --database=roundcube > ./dump.sql # # usage: ynh_mysql_dump_db --database=database -# | arg: -d, --database - the database name to dump +# | arg: -d, --database= - the database name to dump # | ret: the mysqldump output # # Requires YunoHost version 2.2.4 or higher. @@ -149,7 +149,8 @@ ynh_mysql_create_user() { # Check if a mysql user exists # # usage: ynh_mysql_user_exists --user=user -# | arg: -u, --user - the user for which to check existence +# | arg: -u, --user= - the user for which to check existence +# | exit: Return 1 if the user doesn't exist, 0 otherwise. # # Requires YunoHost version 2.2.4 or higher. ynh_mysql_user_exists() @@ -183,14 +184,14 @@ ynh_mysql_drop_user() { # Create a database, an user and its password. Then store the password in the app's config # +# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] +# | arg: -u, --db_user= - Owner of the database +# | arg: -n, --db_name= - Name of the database +# | arg: -p, --db_pwd= - Password of the database. If not provided, a password will be generated +# # After executing this helper, the password of the created database will be available in $db_pwd # It will also be stored as "mysqlpwd" into the app settings. # -# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] -# | arg: -u, --db_user - Owner of the database -# | arg: -n, --db_name - Name of the database -# | arg: -p, --db_pwd - Password of the database. If not provided, a password will be generated -# # Requires YunoHost version 2.6.4 or higher. ynh_mysql_setup_db () { # Declare an array to define the options of this helper. @@ -213,8 +214,8 @@ ynh_mysql_setup_db () { # Remove a database if it exists, and the associated user # # usage: ynh_mysql_remove_db --db_user=user --db_name=name -# | arg: -u, --db_user - Owner of the database -# | arg: -n, --db_name - Name of the database +# | arg: -u, --db_user= - Owner of the database +# | arg: -n, --db_name= - Name of the database # # Requires YunoHost version 2.6.4 or higher. ynh_mysql_remove_db () { diff --git a/data/helpers.d/network b/data/helpers.d/network index c8493d7ac..03df04c1e 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -5,7 +5,8 @@ # example: port=$(ynh_find_port --port=8080) # # usage: ynh_find_port --port=begin_port -# | arg: -p, --port - port to start to search +# | arg: -p, --port= - port to start to search +# | ret: the port number # # Requires YunoHost version 2.6.4 or higher. ynh_find_port () { @@ -29,7 +30,8 @@ ynh_find_port () { # example: ynh_port_available --port=1234 || ynh_die "Port 1234 is needs to be available for this app" # # usage: ynh_find_port --port=XYZ -# | arg: -p, --port - port to check +# | arg: -p, --port= - port to check +# | exit: Return 1 if the port is already used by another process. # # Requires YunoHost version 3.7.x or higher. ynh_port_available () { @@ -90,6 +92,7 @@ EOF # example: ynh_validate_ip4 111.222.333.444 # # usage: ynh_validate_ip4 --ip_address=ip_address +# | arg: -i, --ip_address= - the ipv4 address to check # | ret: 0 for valid ipv4 addresses, 1 otherwise # # Requires YunoHost version 2.2.4 or higher. @@ -111,6 +114,7 @@ ynh_validate_ip4() # example: ynh_validate_ip6 2000:dead:beef::1 # # usage: ynh_validate_ip6 --ip_address=ip_address +# | arg: -i, --ip_address= - the ipv6 address to check # | ret: 0 for valid ipv6 addresses, 1 otherwise # # Requires YunoHost version 2.2.4 or higher. diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index cb83e3136..3ede3c8c9 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -54,13 +54,13 @@ ynh_use_nodejs () { # Install a specific version of nodejs # -# n (Node version management) uses the PATH variable to store the path of the version of node it is going to use. -# That's how it changes the version -# # ynh_install_nodejs will install the version of node provided as argument by using n. # # usage: ynh_install_nodejs --nodejs_version=nodejs_version -# | arg: -n, --nodejs_version - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed. +# | arg: -n, --nodejs_version= - Version of node to install. When possible, your should prefer to use major version number (e.g. 8 instead of 8.10.0). The crontab will then handle the update of minor versions when needed. +# +# n (Node version management) uses the PATH variable to store the path of the version of node it is going to use. +# That's how it changes the version # # Requires YunoHost version 2.7.12 or higher. ynh_install_nodejs () { diff --git a/data/helpers.d/php b/data/helpers.d/php index 1bbb6c84b..588bf7177 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -8,16 +8,16 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # Create a dedicated php-fpm config # # usage 1: ynh_add_fpm_config [--phpversion=7.X] [--use_template] [--package=packages] [--dedicated_service] -# | arg: -v, --phpversion - Version of php to use. -# | arg: -t, --use_template - Use this helper in template mode. -# | arg: -p, --package - Additionnal php packages to install -# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one. +# | arg: -v, --phpversion= - Version of php to use. +# | arg: -t, --use_template - Use this helper in template mode. +# | arg: -p, --package= - Additionnal php packages to install +# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one. # # ----------------------------------------------------------------------------- # # usage 2: ynh_add_fpm_config [--phpversion=7.X] --usage=usage --footprint=footprint [--package=packages] [--dedicated_service] -# | arg: -v, --phpversion - Version of php to use. -# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). +# | arg: -v, --phpversion= - Version of php to use. +# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high). # low - Less than 20Mb of ram by pool. # medium - Between 20Mb and 40Mb of ram by pool. # high - More than 40Mb of ram by pool. @@ -25,13 +25,13 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # To have this value, use the following command and stress the service. # watch -n0.5 ps -o user,cmd,%cpu,rss -u APP # -# | arg: -u, --usage - Expected usage of the service (low/medium/high). +# | arg: -u, --usage= - Expected usage of the service (low/medium/high). # low - Personal usage, behind the sso. # medium - Low usage, few people or/and publicly accessible. # high - High usage, frequently visited website. # -# | arg: -p, --package - Additionnal php packages to install for a specific version of php -# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one. +# | arg: -p, --package= - Additionnal php packages to install for a specific version of php +# | arg: -d, --dedicated_service - Use a dedicated php-fpm service instead of the common one. # # # The footprint of the service will be used to defined the maximum footprint we can allow, which is half the maximum RAM. @@ -310,8 +310,8 @@ ynh_remove_fpm_config () { # [internal] # # usage: ynh_install_php --phpversion=phpversion [--package=packages] -# | arg: -v, --phpversion - Version of php to install. -# | arg: -p, --package - Additionnal php packages to install +# | arg: -v, --phpversion= - Version of php to install. +# | arg: -p, --package= - Additionnal php packages to install ynh_install_php () { # Declare an array to define the options of this helper. local legacy_args=vp @@ -401,7 +401,7 @@ ynh_remove_php () { # [internal] # # usage: ynh_get_scalable_phpfpm --usage=usage --footprint=footprint [--print] -# | arg: -f, --footprint - Memory footprint of the service (low/medium/high). +# | arg: -f, --footprint= - Memory footprint of the service (low/medium/high). # low - Less than 20Mb of ram by pool. # medium - Between 20Mb and 40Mb of ram by pool. # high - More than 40Mb of ram by pool. @@ -409,12 +409,12 @@ ynh_remove_php () { # To have this value, use the following command and stress the service. # watch -n0.5 ps -o user,cmd,%cpu,rss -u APP # -# | arg: -u, --usage - Expected usage of the service (low/medium/high). +# | arg: -u, --usage= - Expected usage of the service (low/medium/high). # low - Personal usage, behind the sso. # medium - Low usage, few people or/and publicly accessible. # high - High usage, frequently visited website. # -# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app) +# | arg: -p, --print - Print the result (intended for debug purpose only when packaging the app) ynh_get_scalable_phpfpm () { local legacy_args=ufp # Declare an array to define the options of this helper. diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index f0aa6d0f0..4122deec6 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -9,9 +9,9 @@ PSQL_ROOT_PWD_FILE=/etc/yunohost/psql # ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql # # usage: ynh_psql_connect_as --user=user --password=password [--database=database] -# | arg: -u, --user - the user name to connect as -# | arg: -p, --password - the user password -# | arg: -d, --database - the database to connect to +# | arg: -u, --user= - the user name to connect as +# | arg: -p, --password= - the user password +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 3.5.0 or higher. ynh_psql_connect_as() { @@ -31,8 +31,8 @@ ynh_psql_connect_as() { # Execute a command as root user # # usage: ynh_psql_execute_as_root --sql=sql [--database=database] -# | arg: -s, --sql - the SQL command to execute -# | arg: -d, --database - the database to connect to +# | arg: -s, --sql= - the SQL command to execute +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 3.5.0 or higher. ynh_psql_execute_as_root() { @@ -52,8 +52,8 @@ ynh_psql_execute_as_root() { # Execute a command from a file as root user # # usage: ynh_psql_execute_file_as_root --file=file [--database=database] -# | arg: -f, --file - the file containing SQL commands -# | arg: -d, --database - the database to connect to +# | arg: -f, --file= - the file containing SQL commands +# | arg: -d, --database= - the database to connect to # # Requires YunoHost version 3.5.0 or higher. ynh_psql_execute_file_as_root() { @@ -118,7 +118,7 @@ ynh_psql_drop_db() { # example: ynh_psql_dump_db 'roundcube' > ./dump.sql # # usage: ynh_psql_dump_db --database=database -# | arg: -d, --database - the database name to dump +# | arg: -d, --database= - the database name to dump # | ret: the psqldump output # # Requires YunoHost version 3.5.0 or higher. @@ -151,7 +151,8 @@ ynh_psql_create_user() { # Check if a psql user exists # # usage: ynh_psql_user_exists --user=user -# | arg: -u, --user - the user for which to check existence +# | arg: -u, --user= - the user for which to check existence +# | exit: Return 1 if the user doesn't exist, 0 otherwise ynh_psql_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u @@ -171,7 +172,8 @@ ynh_psql_user_exists() { # Check if a psql database exists # # usage: ynh_psql_database_exists --database=database -# | arg: -d, --database - the database for which to check existence +# | arg: -d, --database= - the database for which to check existence +# | exit: Return 1 if the database doesn't exist, 0 otherwise ynh_psql_database_exists() { # Declare an array to define the options of this helper. local legacy_args=d @@ -202,13 +204,14 @@ ynh_psql_drop_user() { # Create a database, an user and its password. Then store the password in the app's config # +# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] +# | arg: -u, --db_user= - Owner of the database +# | arg: -n, --db_name= - Name of the database +# | arg: -p, --db_pwd= - Password of the database. If not given, a password will be generated +# # After executing this helper, the password of the created database will be available in $db_pwd # It will also be stored as "psqlpwd" into the app settings. # -# usage: ynh_psql_setup_db --db_user=user --db_name=name [--db_pwd=pwd] -# | arg: -u, --db_user - Owner of the database -# | arg: -n, --db_name - Name of the database -# | arg: -p, --db_pwd - Password of the database. If not given, a password will be generated ynh_psql_setup_db() { # Declare an array to define the options of this helper. local legacy_args=unp @@ -234,8 +237,8 @@ ynh_psql_setup_db() { # Remove a database if it exists, and the associated user # # usage: ynh_psql_remove_db --db_user=user --db_name=name -# | arg: -u, --db_user - Owner of the database -# | arg: -n, --db_name - Name of the database +# | arg: -u, --db_user= - Owner of the database +# | arg: -n, --db_name= - Name of the database ynh_psql_remove_db() { # Declare an array to define the options of this helper. local legacy_args=un diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 86634dcc3..00a2a5188 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -3,8 +3,8 @@ # Get an application setting # # usage: ynh_app_setting_get --app=app --key=key -# | arg: -a, --app - the application id -# | arg: -k, --key - the setting to get +# | arg: -a, --app= - the application id +# | arg: -k, --key= - the setting to get # # Requires YunoHost version 2.2.4 or higher. ynh_app_setting_get() { @@ -22,9 +22,9 @@ ynh_app_setting_get() { # Set an application setting # # usage: ynh_app_setting_set --app=app --key=key --value=value -# | arg: -a, --app - the application id -# | arg: -k, --key - the setting name to set -# | arg: -v, --value - the setting value to set +# | arg: -a, --app= - the application id +# | arg: -k, --key= - the setting name to set +# | arg: -v, --value= - the setting value to set # # Requires YunoHost version 2.2.4 or higher. ynh_app_setting_set() { @@ -43,8 +43,8 @@ ynh_app_setting_set() { # Delete an application setting # # usage: ynh_app_setting_delete --app=app --key=key -# | arg: -a, --app - the application id -# | arg: -k, --key - the setting to delete +# | arg: -a, --app= - the application id +# | arg: -k, --key= - the setting to delete # # Requires YunoHost version 2.2.4 or higher. ynh_app_setting_delete() { @@ -117,8 +117,8 @@ EOF # example: ynh_webpath_available --domain=some.domain.tld --path_url=/coffee # # usage: ynh_webpath_available --domain=domain --path_url=path -# | arg: -d, --domain - the domain/host of the url -# | arg: -p, --path_url - the web path to check the availability of +# | arg: -d, --domain= - the domain/host of the url +# | arg: -p, --path_url= - the web path to check the availability of # # Requires YunoHost version 2.6.4 or higher. ynh_webpath_available () { @@ -138,9 +138,9 @@ ynh_webpath_available () { # example: ynh_webpath_register --app=wordpress --domain=some.domain.tld --path_url=/coffee # # usage: ynh_webpath_register --app=app --domain=domain --path_url=path -# | arg: -a, --app - the app for which the domain should be registered -# | arg: -d, --domain - the domain/host of the web path -# | arg: -p, --path_url - the web path to be registered +# | arg: -a, --app= - the app for which the domain should be registered +# | arg: -d, --domain= - the domain/host of the web path +# | arg: -p, --path_url= - the web path to be registered # # Requires YunoHost version 2.6.4 or higher. ynh_webpath_register () { @@ -158,12 +158,12 @@ ynh_webpath_register () { # Create a new permission for the app # -# example: ynh_permission_create --permission admin --url /admin --allowed alice bob +# example: ynh_permission_create --permission=admin --url=/admin --allowed="alice bob" # -# usage: ynh_permission_create --permission "permission" [--url "url"] [--allowed group1 group2] -# | arg: permission - the name for the permission (by default a permission named "main" already exist) -# | arg: url - (optional) URL for which access will be allowed/forbidden -# | arg: allowed - (optional) A list of group/user to allow for the permission +# usage: ynh_permission_create --permission "permission" [--url=url] [--allowed="group1 group2"] +# | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist) +# | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden +# | arg: -a, --allowed= - (optional) A list of group/user to allow for the permission # # If provided, 'url' is assumed to be relative to the app domain/path if they # start with '/'. For example: @@ -202,10 +202,10 @@ ynh_permission_create() { # Remove a permission for the app (note that when the app is removed all permission is automatically removed) # -# example: ynh_permission_delete --permission editors +# example: ynh_permission_delete --permission=editors # -# usage: ynh_permission_delete --permission "permission" -# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) +# usage: ynh_permission_delete --permission="permission" +# | arg: -p, --permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) # # Requires YunoHost version 3.7.0 or higher. ynh_permission_delete() { @@ -221,7 +221,8 @@ ynh_permission_delete() { # Check if a permission exists # # usage: ynh_permission_exists --permission=permission -# | arg: -p, --permission - the permission to check +# | arg: -p, --permission= - the permission to check +# | exit: Return 1 if the permission doesn't exist, 0 otherwise # # Requires YunoHost version 3.7.0 or higher. ynh_permission_exists() { @@ -236,9 +237,9 @@ ynh_permission_exists() { # Redefine the url associated to a permission # -# usage: ynh_permission_url --permission "permission" --url "url" -# | arg: permission - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) -# | arg: url - (optional) URL for which access will be allowed/forbidden +# usage: ynh_permission_url --permission="permission" [--url="url"] +# | arg: -p, --permission= - the name for the permission (by default a permission named "main" is removed automatically when the app is removed) +# | arg: -u, --url= - (optional) URL for which access will be allowed/forbidden # # Requires YunoHost version 3.7.0 or higher. ynh_permission_url() { @@ -262,12 +263,13 @@ ynh_permission_url() { # Update a permission for the app # -# usage: ynh_permission_update --permission "permission" --add "group" ["group" ...] --remove "group" ["group" ...] -# | arg: permission - the name for the permission (by default a permission named "main" already exist) -# | arg: add - the list of group or users to enable add to the permission -# | arg: remove - the list of group or users to remove from the permission +# example: ynh_permission_update --permission admin --add=samdoe --remove=all_users +# +# usage: ynh_permission_update --permission="permission" [--add="group1 group2"] [--remove="group1 group2"] +# | arg: -p, --permission= - the name for the permission (by default a permission named "main" already exist) +# | arg: -a, --add= - the list of group or users to enable add to the permission +# | arg: -r, --remove= - the list of group or users to remove from the permission # -# example: ynh_permission_update --permission admin --add samdoe --remove all_users # Requires YunoHost version 3.7.0 or higher. ynh_permission_update() { # Declare an array to define the options of this helper. @@ -288,14 +290,15 @@ ynh_permission_update() { yunohost user permission update "$app.$permission" ${add:-} ${remove:-} } -# Check if a permission exists -# -# usage: ynh_permission_has_user --permission=permission --user=user -# | arg: -p, --permission - the permission to check -# | arg: -u, --user - the user seek in the permission +# Check if a permission has an user # # example: ynh_permission_has_user --permission=main --user=visitors # +# usage: ynh_permission_has_user --permission=permission --user=user +# | arg: -p, --permission= - the permission to check +# | arg: -u, --user= - the user seek in the permission +# | exit: Return 1 if the permission doesn't have that user or doesn't exist, 0 otherwise +# # Requires YunoHost version 3.7.1 or higher. ynh_permission_has_user() { local legacy_args=pu diff --git a/data/helpers.d/string b/data/helpers.d/string index 7a37f29c3..a0bcdbfaf 100644 --- a/data/helpers.d/string +++ b/data/helpers.d/string @@ -5,7 +5,8 @@ # example: pwd=$(ynh_string_random --length=8) # # usage: ynh_string_random [--length=string_length] -# | arg: -l, --length - the string length to generate (default: 24) +# | arg: -l, --length= - the string length to generate (default: 24) +# | ret: the generated string # # Requires YunoHost version 2.2.4 or higher. ynh_string_random() { @@ -25,9 +26,9 @@ ynh_string_random() { # Substitute/replace a string (or expression) by another in a file # # usage: ynh_replace_string --match_string=match_string --replace_string=replace_string --target_file=target_file -# | arg: -m, --match_string - String to be searched and replaced in the file -# | arg: -r, --replace_string - String that will replace matches -# | arg: -f, --target_file - File in which the string will be replaced. +# | arg: -m, --match_string= - String to be searched and replaced in the file +# | arg: -r, --replace_string= - String that will replace matches +# | arg: -f, --target_file= - File in which the string will be replaced. # # As this helper is based on sed command, regular expressions and # references to sub-expressions can be used @@ -55,9 +56,9 @@ ynh_replace_string () { # Substitute/replace a special string by another in a file # # usage: ynh_replace_special_string --match_string=match_string --replace_string=replace_string --target_file=target_file -# | arg: -m, --match_string - String to be searched and replaced in the file -# | arg: -r, --replace_string - String that will replace matches -# | arg: -t, --target_file - File in which the string will be replaced. +# | arg: -m, --match_string= - String to be searched and replaced in the file +# | arg: -r, --replace_string= - String that will replace matches +# | arg: -t, --target_file= - File in which the string will be replaced. # # This helper will use ynh_replace_string, but as you can use special # characters, you can't use some regular expressions and sub-expressions. @@ -90,7 +91,7 @@ ynh_replace_special_string () { # example: dbname=$(ynh_sanitize_dbid $app) # # usage: ynh_sanitize_dbid --db_name=name -# | arg: -n, --db_name - name to correct/sanitize +# | arg: -n, --db_name= - name to correct/sanitize # | ret: the corrected name # # Requires YunoHost version 2.2.4 or higher. @@ -121,7 +122,7 @@ ynh_sanitize_dbid () { # ynh_normalize_url_path / # -> / # # usage: ynh_normalize_url_path --path_url=path_to_normalize -# | arg: -p, --path_url - URL path to normalize before using it +# | arg: -p, --path_url= - URL path to normalize before using it # # Requires YunoHost version 2.6.4 or higher. ynh_normalize_url_path () { diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 871d6459d..5117aeb99 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -3,8 +3,8 @@ # Create a dedicated systemd config # # usage: ynh_add_systemd_config [--service=service] [--template=template] -# | arg: -s, --service - Service name (optionnal, $app by default) -# | arg: -t, --template - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) +# | arg: -s, --service= - Service name (optionnal, $app by default) +# | arg: -t, --template= - Name of template file (optionnal, this is 'systemd' by default, meaning ./conf/systemd.service will be used as template) # # This will use the template ../conf/.service # to generate a systemd config, by replacing the following keywords @@ -48,7 +48,7 @@ ynh_add_systemd_config () { # Remove the dedicated systemd config # # usage: ynh_remove_systemd_config [--service=service] -# | arg: -s, --service - Service name (optionnal, $app by default) +# | arg: -s, --service= - Service name (optionnal, $app by default) # # Requires YunoHost version 2.7.2 or higher. ynh_remove_systemd_config () { @@ -72,7 +72,7 @@ ynh_remove_systemd_config () { # Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started # -# usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ] +# usage: ynh_systemd_action [--service_name=service_name] [--action=action] [ [--line_match="line to match"] [--log_path=log_path] [--timeout=300] [--length=20] ] # | arg: -n, --service_name= - Name of the service to start. Default : $app # | arg: -a, --action= - Action to perform with systemctl. Default: start # | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot. If not defined it don't wait until the service is completely started. WARNING: When using --line_match, you should always add `ynh_clean_check_starting` into your `ynh_clean_setup` at the beginning of the script. Otherwise, tail will not stop in case of failure of the script. The script will then hang forever. diff --git a/data/helpers.d/user b/data/helpers.d/user index ff6c4e6ea..304658ff8 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -5,7 +5,8 @@ # example: ynh_user_exists 'toto' || exit 1 # # usage: ynh_user_exists --username=username -# | arg: -u, --username - the username to check +# | arg: -u, --username= - the username to check +# | exit: Return 1 if the user doesn't exist, 0 otherwise # # Requires YunoHost version 2.2.4 or higher. ynh_user_exists() { @@ -24,8 +25,8 @@ ynh_user_exists() { # example: mail=$(ynh_user_get_info 'toto' 'mail') # # usage: ynh_user_get_info --username=username --key=key -# | arg: -u, --username - the username to retrieve info from -# | arg: -k, --key - the key to retrieve +# | arg: -u, --username= - the username to retrieve info from +# | arg: -k, --key= - the key to retrieve # | ret: string - the key's value # # Requires YunoHost version 2.2.4 or higher. @@ -57,7 +58,8 @@ ynh_user_list() { # Check if a user exists on the system # # usage: ynh_system_user_exists --username=username -# | arg: -u, --username - the username to check +# | arg: -u, --username= - the username to check +# | exit: Return 1 if the user doesn't exist, 0 otherwise # # Requires YunoHost version 2.2.4 or higher. ynh_system_user_exists() { @@ -74,7 +76,8 @@ ynh_system_user_exists() { # Check if a group exists on the system # # usage: ynh_system_group_exists --group=group -# | arg: -g, --group - the group to check +# | arg: -g, --group= - the group to check +# | exit: Return 1 if the group doesn't exist, 0 otherwise ynh_system_group_exists() { # Declare an array to define the options of this helper. local legacy_args=g @@ -95,9 +98,9 @@ ynh_system_group_exists() { # ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell # # usage: ynh_system_user_create --username=user_name [--home_dir=home_dir] [--use_shell] -# | arg: -u, --username - Name of the system user that will be create -# | arg: -h, --home_dir - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home -# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell +# | arg: -u, --username= - Name of the system user that will be create +# | arg: -h, --home_dir= - Path of the home dir for the user. Usually the final path of the app. If this argument is omitted, the user will be created without home +# | arg: -s, --use_shell - Create a user using the default login shell if present. If this argument is omitted, the user will be created with /usr/sbin/nologin shell # # Requires YunoHost version 2.6.4 or higher. ynh_system_user_create () { @@ -133,7 +136,7 @@ ynh_system_user_create () { # Delete a system user # # usage: ynh_system_user_delete --username=user_name -# | arg: -u, --username - Name of the system user that will be create +# | arg: -u, --username= - Name of the system user that will be create # # Requires YunoHost version 2.6.4 or higher. ynh_system_user_delete () { diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 6b75426fc..46242e634 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -55,6 +55,10 @@ ynh_abort_if_errors () { # Download, check integrity, uncompress and patch the source from app.src # +# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] +# | arg: -d, --dest_dir= - Directory where to setup sources +# | arg: -s, --source_id= - Name of the app, if the package contains more than one app +# # The file conf/app.src need to contains: # # SOURCE_URL=Address to download the app archive @@ -93,11 +97,6 @@ ynh_abort_if_errors () { # Finally, patches named sources/patches/${src_id}-*.patch and extra files in # sources/extra_files/$src_id will be applied to dest_dir # -# -# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id] -# | arg: -d, --dest_dir - Directory where to setup sources -# | arg: -s, --source_id - Name of the app, if the package contains more than one app -# # Requires YunoHost version 2.6.4 or higher. ynh_setup_source () { # Declare an array to define the options of this helper. @@ -204,9 +203,6 @@ ynh_setup_source () { } # Curl abstraction to help with POST requests to local pages (such as installation forms) -# For multiple calls, cookies are persisted between each call for the same app -# -# $domain and $path_url should be defined externally (and correspond to the domain.tld and the /path (of the app?)) # # example: ynh_local_curl "/install.php?installButton" "foo=$var1" "bar=$var2" # @@ -216,6 +212,10 @@ ynh_setup_source () { # | arg: key2=value2 - (Optionnal) Another POST key and corresponding value # | arg: ... - (Optionnal) More POST keys and values # +# For multiple calls, cookies are persisted between each call for the same app +# +# $domain and $path_url should be defined externally (and correspond to the domain.tld and the /path (of the app?)) +# # Requires YunoHost version 2.6.4 or higher. ynh_local_curl () { # Define url of page to curl @@ -306,7 +306,7 @@ properly with chmod/chown." # Remove a file or a directory securely # # usage: ynh_secure_remove --file=path_to_remove -# | arg: -f, --file - File or directory to remove +# | arg: -f, --file= - File or directory to remove # # Requires YunoHost version 2.6.4 or higher. ynh_secure_remove () { @@ -384,9 +384,10 @@ ynh_get_plain_key() { # Read the value of a key in a ynh manifest file # -# usage: ynh_read_manifest manifest key -# | arg: -m, --manifest= - Path of the manifest to read -# | arg: -k, --key= - Name of the key to find +# usage: ynh_read_manifest --manifest="manifest.json" --key="key" +# | arg: -m, --manifest= - Path of the manifest to read +# | arg: -k, --key= - Name of the key to find +# | ret: the value associate to that key # # Requires YunoHost version 3.5.0 or higher. ynh_read_manifest () { @@ -408,14 +409,15 @@ ynh_read_manifest () { # Read the upstream version from the manifest # +# usage: ynh_app_upstream_version [--manifest="manifest.json"] +# | arg: -m, --manifest= - Path of the manifest to read +# | ret: the version number of the upstream app +# # The version number in the manifest is defined by ~ynh # For example : 4.3-2~ynh3 # This include the number before ~ynh # In the last example it return 4.3-2 # -# usage: ynh_app_upstream_version [-m manifest] -# | arg: -m, --manifest= - Path of the manifest to read -# # Requires YunoHost version 3.5.0 or higher. ynh_app_upstream_version () { # Declare an array to define the options of this helper. @@ -432,14 +434,15 @@ ynh_app_upstream_version () { # Read package version from the manifest # +# usage: ynh_app_package_version [--manifest="manifest.json"] +# | arg: -m, --manifest= - Path of the manifest to read +# | ret: the version number of the package +# # The version number in the manifest is defined by ~ynh # For example : 4.3-2~ynh3 # This include the number after ~ynh # In the last example it return 3 # -# usage: ynh_app_package_version [-m manifest] -# | arg: -m, --manifest= - Path of the manifest to read -# # Requires YunoHost version 3.5.0 or higher. ynh_app_package_version () { # Declare an array to define the options of this helper. From 6fb1e62a4c79035c7a0a7d67b985386bad543373 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Mon, 20 Apr 2020 21:00:45 +0200 Subject: [PATCH 193/317] Clean getopts arguments --- data/helpers.d/backup | 15 +++++++-------- data/helpers.d/fail2ban | 5 +++-- data/helpers.d/logging | 3 ++- data/helpers.d/logrotate | 6 +++--- data/helpers.d/setting | 19 ++++++++++++------- data/helpers.d/systemd | 15 +++++++-------- data/helpers.d/utils | 4 ++-- 7 files changed, 36 insertions(+), 31 deletions(-) diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 2fae73ba0..9603ba525 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -53,9 +53,9 @@ ynh_backup() { local not_mandatory # Manage arguments with getopts ynh_handle_getopts_args "$@" - local dest_path="${dest_path:-}" - local is_big="${is_big:-0}" - local not_mandatory="${not_mandatory:-0}" + dest_path="${dest_path:-}" + is_big="${is_big:-0}" + not_mandatory="${not_mandatory:-0}" BACKUP_CORE_ONLY=${BACKUP_CORE_ONLY:-0} test -n "${app:-}" && do_not_backup_data=$(ynh_app_setting_get --app=$app --key=do_not_backup_data) @@ -229,17 +229,16 @@ ynh_restore_file () { local legacy_args=odm local -A args_array=( [o]=origin_path= [d]=dest_path= [m]=not_mandatory ) local origin_path - local archive_path local dest_path local not_mandatory # Manage arguments with getopts ynh_handle_getopts_args "$@" - local origin_path="/${origin_path#/}" - local archive_path="$YNH_CWD${origin_path}" + origin_path="/${origin_path#/}" # Default value for dest_path = /$origin_path - local dest_path="${dest_path:-$origin_path}" - local not_mandatory="${not_mandatory:-0}" + dest_path="${dest_path:-$origin_path}" + not_mandatory="${not_mandatory:-0}" + local archive_path="$YNH_CWD${origin_path}" # If archive_path doesn't exist, search for a corresponding path in CSV if [ ! -d "$archive_path" ] && [ ! -f "$archive_path" ] && [ ! -L "$archive_path" ] then diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 1eef67f5c..54581483d 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -74,9 +74,10 @@ ynh_add_fail2ban_config () { local use_template # Manage arguments with getopts ynh_handle_getopts_args "$@" - use_template="${use_template:-0}" max_retry=${max_retry:-3} ports=${ports:-http,https} + others_var=${others_var:-} + use_template="${use_template:-0}" finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf" finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf" @@ -96,7 +97,7 @@ ynh_add_fail2ban_config () { fi # Replace all other variable given as arguments - for var_to_replace in ${others_var:-} + for var_to_replace in $others_var do # ${var_to_replace^^} make the content of the variable on upper-cases # ${!var_to_replace} get the content of the variable named $var_to_replace diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 49374ec1e..37dfd286c 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -15,9 +15,10 @@ ynh_die() { local ret_code # Manage arguments with getopts ynh_handle_getopts_args "$@" + ret_code=${ret_code:-1} echo "$message" 1>&2 - exit "${ret_code:-1}" + exit "$ret_code" } # Display a message in the 'INFO' logging category diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 0fcc63009..7df954c15 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -26,9 +26,9 @@ ynh_use_logrotate () { local specific_user # Manage arguments with getopts ynh_handle_getopts_args "$@" - local logfile="${logfile:-}" - local nonappend="${nonappend:-0}" - local specific_user="${specific_user:-}" + logfile="${logfile:-}" + nonappend="${nonappend:-0}" + specific_user="${specific_user:-}" # LEGACY CODE - PRE GETOPTS if [ $# -gt 0 ] && [ "$1" == "--non-append" ] diff --git a/data/helpers.d/setting b/data/helpers.d/setting index 00a2a5188..61397151b 100644 --- a/data/helpers.d/setting +++ b/data/helpers.d/setting @@ -185,19 +185,21 @@ ynh_permission_create() { local url local allowed ynh_handle_getopts_args "$@" + url=${url:-} + allowed=${allowed:-} - if [[ -n ${url:-} ]] + if [[ -n $url ]] then url="'$url'" else url="None" fi - if [[ -n ${allowed:-} ]]; then + if [[ -n $allowed ]]; then allowed=",allowed=['${allowed//';'/"','"}']" fi - yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url ${allowed:-} , sync_perm=False)" + yunohost tools shell -c "from yunohost.permission import permission_create; permission_create('$app.$permission', url=$url $allowed , sync_perm=False)" } # Remove a permission for the app (note that when the app is removed all permission is automatically removed) @@ -249,8 +251,9 @@ ynh_permission_url() { local permission local url ynh_handle_getopts_args "$@" + url=${url:-} - if [[ -n ${url:-} ]] + if [[ -n $url ]] then url="'$url'" else @@ -279,15 +282,17 @@ ynh_permission_update() { local add local remove ynh_handle_getopts_args "$@" + add=${add:-} + remove=${remove:-} - if [[ -n ${add:-} ]]; then + if [[ -n $add ]]; then add="--add ${add//';'/" "}" fi - if [[ -n ${remove:-} ]]; then + if [[ -n $remove ]]; then remove="--remove ${remove//';'/" "} " fi - yunohost user permission update "$app.$permission" ${add:-} ${remove:-} + yunohost user permission update "$app.$permission" $add $remove } # Check if a permission has an user diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 5117aeb99..c718e50c2 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -89,18 +89,17 @@ ynh_systemd_action() { local length local log_path local timeout - # Manage arguments with getopts ynh_handle_getopts_args "$@" - - local service_name="${service_name:-$app}" - local action=${action:-start} - local log_path="${log_path:-/var/log/$service_name/$service_name.log}" - local length=${length:-20} - local timeout=${timeout:-300} + service_name="${service_name:-$app}" + action=${action:-start} + line_match=${line_match:-} + length=${length:-20} + log_path="${log_path:-/var/log/$service_name/$service_name.log}" + timeout=${timeout:-300} # Start to read the log - if [[ -n "${line_match:-}" ]] + if [[ -n "$line_match" ]] then local templog="$(mktemp)" # Following the starting of the app in its log diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 46242e634..13d3a5dcd 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -426,8 +426,8 @@ ynh_app_upstream_version () { local manifest # Manage arguments with getopts ynh_handle_getopts_args "$@" - manifest="${manifest:-../manifest.json}" + version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version") echo "${version_key/~ynh*/}" } @@ -451,8 +451,8 @@ ynh_app_package_version () { local manifest # Manage arguments with getopts ynh_handle_getopts_args "$@" - manifest="${manifest:-../manifest.json}" + version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version") echo "${version_key/*~ynh/}" } From 23a083b08770b97adf34903f04b2f5d06008950a Mon Sep 17 00:00:00 2001 From: Kay0u Date: Mon, 20 Apr 2020 23:50:42 +0200 Subject: [PATCH 194/317] YNH_DEFAULT_PHP_VERSION is now readonly --- data/helpers.d/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index d5b17c58f..747d40321 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -1,6 +1,6 @@ #!/bin/bash -YNH_DEFAULT_PHP_VERSION=7.0 +readonly YNH_DEFAULT_PHP_VERSION=7.0 # Declare the actual php version to use. # A packager willing to use another version of php can override the variable into its _common.sh. YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} From b392efdf85f3f9528772ff76dd40ad3239613bef Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 02:42:46 +0200 Subject: [PATCH 195/317] Also anonymize folder name containing %2e instead of dot --- src/yunohost/utils/yunopaste.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/yunohost/utils/yunopaste.py b/src/yunohost/utils/yunopaste.py index 530295735..dc8b6fb8d 100644 --- a/src/yunohost/utils/yunopaste.py +++ b/src/yunohost/utils/yunopaste.py @@ -37,10 +37,18 @@ def yunopaste(data): def anonymize(data): + def anonymize_domain(data, domain, redact): + data = data.replace(domain, redact) + # This stuff appears sometimes because some folder in + # /var/lib/metronome/ have some folders named this way + data = data.replace(domain.replace(".", "%2e"), redact.replace(".", "%2e")) + return data + + # First, let's replace every occurence of the main domain by "domain.tld" # This should cover a good fraction of the info leaked main_domain = _get_maindomain() - data = data.replace(main_domain, "maindomain.tld") + data = anonymize_domain(data, main_domain, "maindomain.tld") # Next, let's replace other domains. We do this in increasing lengths, # because e.g. knowing that the domain is a sub-domain of another domain may @@ -55,7 +63,7 @@ def anonymize(data): for domain in domains: if domain not in data: continue - data = data.replace(domain, "domain%s.tld" % count) + data = anonymize_domain(data, domain, "domain%s.tld" % count) count += 1 # We also want to anonymize the ips From 99ad8cc492de863d86b55a1128635eae8892babd Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 04:45:16 +0200 Subject: [PATCH 196/317] Force-flush the regen-conf for nginx domain conf when adding/removing a domain... --- src/yunohost/domain.py | 32 +++++++++++++++++++++++++++++++- src/yunohost/regenconf.py | 12 ++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index c725b58c9..99f6605f2 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -33,7 +33,7 @@ from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger from yunohost.app import app_ssowatconf -from yunohost.regenconf import regen_conf +from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.utils.network import get_public_ip from yunohost.log import is_unit_operation from yunohost.hook import hook_callback @@ -122,6 +122,17 @@ def domain_add(operation_logger, domain, dyndns=False): # Don't regen these conf if we're still in postinstall if os.path.exists('/etc/yunohost/installed'): + # Sometime we have weird issues with the regenconf where some files + # appears as manually modified even though they weren't touched ... + # There are a few ideas why this happens (like backup/restore nginx + # conf ... which we shouldnt do ...). This in turns creates funky + # situation where the regenconf may refuse to re-create the conf + # (when re-creating a domain..) + # So here we force-clear the has out of the regenconf if it exists. + # This is a pretty ad hoc solution and only applied to nginx + # because it's one of the major service, but in the long term we + # should identify the root of this bug... + _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd']) app_ssowatconf() @@ -186,6 +197,25 @@ def domain_remove(operation_logger, domain, force=False): os.system('rm -rf /etc/yunohost/certs/%s' % domain) + # Sometime we have weird issues with the regenconf where some files + # appears as manually modified even though they weren't touched ... + # There are a few ideas why this happens (like backup/restore nginx + # conf ... which we shouldnt do ...). This in turns creates funky + # situation where the regenconf may refuse to re-create the conf + # (when re-creating a domain..) + # + # So here we force-clear the has out of the regenconf if it exists. + # This is a pretty ad hoc solution and only applied to nginx + # because it's one of the major service, but in the long term we + # should identify the root of this bug... + _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) + # And in addition we even force-delete the file Otherwise, if the file was + # manually modified, it may not get removed by the regenconf which leads to + # catastrophic consequences of nginx breaking because it can't load the + # cert file which disappeared etc.. + if os.path.exists("/etc/nginx/conf.d/%s.conf" % domain): + _process_regen_conf("/etc/nginx/conf.d/%s.conf" % domain, new_conf=None, save=True) + regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix']) app_ssowatconf() diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py index ad84c8164..4062628aa 100644 --- a/src/yunohost/regenconf.py +++ b/src/yunohost/regenconf.py @@ -473,6 +473,18 @@ def _update_conf_hashes(category, hashes): _save_regenconf_infos(categories) +def _force_clear_hashes(paths): + + categories = _get_regenconf_infos() + for path in paths: + for category in categories.keys(): + if path in categories[category]['conffiles']: + logger.debug("force-clearing old conf hash for %s in category %s" % (path, category)) + del categories[category]['conffiles'][path] + + _save_regenconf_infos(categories) + + def _process_regen_conf(system_conf, new_conf=None, save=True): """Regenerate a given system configuration file From 6d42baff38f1876473a88f9a59a9192a81f158ff Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 04:48:13 +0200 Subject: [PATCH 197/317] Be more robust against broken config or service failing to start, show info to help debugging --- data/hooks/conf_regen/15-nginx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index f8b7d8062..86c7c2438 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -27,7 +27,8 @@ do_init_regen() { ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" # Restart nginx if conf looks good, otherwise display error and exit unhappy - nginx -t 2>/dev/null && service nginx restart || (nginx -t && exit 1) + nginx -t 2>/dev/null || { nginx -t; exit 1; } + systemctl restart nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } exit 0 } @@ -125,9 +126,9 @@ do_post_regen() { fi done - - # Reload nginx configuration - pgrep nginx && service nginx reload + # Reload nginx if conf looks good, otherwise display error and exit unhappy + nginx -t 2>/dev/null || { nginx -t; exit 1; } + pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } } FORCE=${2:-0} From 56a1fba297e98d09297d0d2a22faafceace34250 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 04:48:26 +0200 Subject: [PATCH 198/317] Add regenconf tests for previous commits --- src/yunohost/tests/test_regenconf.py | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/yunohost/tests/test_regenconf.py diff --git a/src/yunohost/tests/test_regenconf.py b/src/yunohost/tests/test_regenconf.py new file mode 100644 index 000000000..357f96c88 --- /dev/null +++ b/src/yunohost/tests/test_regenconf.py @@ -0,0 +1,80 @@ +import glob +import os +import pytest +import shutil +import requests + +from conftest import message, raiseYunohostError + +from moulinette import m18n +from moulinette.utils.filesystem import mkdir + +from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list +from yunohost.utils.error import YunohostError +from yunohost.regenconf import manually_modified_files, _get_conf_hashes, _force_clear_hashes + +TEST_DOMAIN = "secondarydomain.test" +TEST_DOMAIN_NGINX_CONFIG = "/etc/nginx/conf.d/secondarydomain.test.conf" + +def setup_function(function): + + _force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG]) + clean() + +def teardown_function(function): + + clean() + _force_clear_hashes([TEST_DOMAIN_NGINX_CONFIG]) + +def clean(): + + assert os.system("pgrep slapd >/dev/null") == 0 + assert os.system("pgrep nginx >/dev/null") == 0 + + if TEST_DOMAIN in domain_list()["domains"]: + domain_remove(TEST_DOMAIN) + assert not os.path.exists(TEST_DOMAIN_NGINX_CONFIG) + + os.system("rm -f %s" % TEST_DOMAIN_NGINX_CONFIG) + + assert os.system("nginx -t 2>/dev/null") == 0 + + assert not os.path.exists(TEST_DOMAIN_NGINX_CONFIG) + assert TEST_DOMAIN_NGINX_CONFIG not in _get_conf_hashes("nginx") + assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files() + + +def test_add_domain(): + + domain_add(TEST_DOMAIN) + + assert TEST_DOMAIN in domain_list()["domains"] + + assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG) + + assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx") + assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files() + + +def test_add_and_edit_domain_conf(): + + domain_add(TEST_DOMAIN) + + assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG) + assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx") + assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files() + + os.system("echo ' ' >> %s" % TEST_DOMAIN_NGINX_CONFIG) + + assert TEST_DOMAIN_NGINX_CONFIG in manually_modified_files() + + +def test_add_domain_conf_already_exists(): + + os.system("echo ' ' >> %s" % TEST_DOMAIN_NGINX_CONFIG) + + domain_add(TEST_DOMAIN) + + assert os.path.exists(TEST_DOMAIN_NGINX_CONFIG) + assert TEST_DOMAIN_NGINX_CONFIG in _get_conf_hashes("nginx") + assert TEST_DOMAIN_NGINX_CONFIG not in manually_modified_files() From 03379007b42bd313325430aa94a89c47b4e9b5b2 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 21 Apr 2020 14:48:52 +0200 Subject: [PATCH 199/317] Update YunoHost version requirements --- data/helpers.d/apt | 10 ++++++++++ data/helpers.d/backup | 2 ++ data/helpers.d/hardware | 4 ++++ data/helpers.d/logrotate | 1 + data/helpers.d/network | 2 +- data/helpers.d/nginx | 1 + data/helpers.d/php | 6 ++++++ data/helpers.d/postgresql | 9 +++++++++ data/helpers.d/systemd | 6 +++++- data/helpers.d/user | 2 ++ data/helpers.d/utils | 1 + 11 files changed, 42 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 50db7613f..9e3f26b90 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -292,6 +292,8 @@ EOF # usage: ynh_add_app_dependencies --package=phpversion [--replace] # | arg: -p, --package= - Packages to add as dependencies for the app. # | arg: -r, --replace - Replace dependencies instead of adding to existing ones. +# +# Requires YunoHost version 3.8.1 or higher. ynh_add_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=pr @@ -338,6 +340,8 @@ ynh_remove_app_dependencies () { # | arg: -p, --package= - The packages to install from this extra repository # | arg: -k, --key= - url to get the public key. # | arg: -n, --name= - Name for the files for this repo, $app as default value. +# +# Requires YunoHost version 3.8.1 or higher. ynh_install_extra_app_dependencies () { # Declare an array to define the options of this helper. local legacy_args=rpkn @@ -376,6 +380,8 @@ ynh_install_extra_app_dependencies () { # | arg: -p, --priority= - Priority for the pin # | arg: -n, --name= - Name for the files for this repo, $app as default value. # | arg: -a, --append - Do not overwrite existing files. +# +# Requires YunoHost version 3.8.1 or higher. ynh_install_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=rkpna @@ -445,6 +451,8 @@ ynh_install_extra_repo () { # # usage: ynh_remove_extra_repo [--name=name] # | arg: -n, --name= - Name for the files for this repo, $app as default value. +# +# Requires YunoHost version 3.8.1 or higher. ynh_remove_extra_repo () { # Declare an array to define the options of this helper. local legacy_args=n @@ -478,6 +486,7 @@ ynh_remove_extra_repo () { # uri suite component # ynh_add_repo --uri=http://forge.yunohost.org/debian/ --suite=stretch --component=stable # +# Requires YunoHost version 3.8.1 or higher. ynh_add_repo () { # Declare an array to define the options of this helper. local legacy_args=uscna @@ -518,6 +527,7 @@ ynh_add_repo () { # # See https://manpages.debian.org/stretch/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities for information about pinning. # +# Requires YunoHost version 3.8.1 or higher. ynh_pin_repo () { # Declare an array to define the options of this helper. local legacy_args=pirna diff --git a/data/helpers.d/backup b/data/helpers.d/backup index 9603ba525..a62f6c104 100644 --- a/data/helpers.d/backup +++ b/data/helpers.d/backup @@ -41,6 +41,7 @@ CAN_BIND=${CAN_BIND:-1} # # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf" # # Requires YunoHost version 2.4.0 or higher. +# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory ynh_backup() { # TODO find a way to avoid injection by file strange naming ! @@ -224,6 +225,7 @@ with open(sys.argv[1], 'r') as backup_file: # /etc/nginx/conf.d/$domain.d/$app.conf # # Requires YunoHost version 2.6.4 or higher. +# Requires YunoHost version 3.5.0 or higher for the argument --not_mandatory ynh_restore_file () { # Declare an array to define the options of this helper. local legacy_args=odm diff --git a/data/helpers.d/hardware b/data/helpers.d/hardware index b46edcdd3..6702a8548 100644 --- a/data/helpers.d/hardware +++ b/data/helpers.d/hardware @@ -8,6 +8,8 @@ # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -o, --only_swap - Ignore real RAM, consider only swap # | ret: the amount of free ram +# +# Requires YunoHost version 3.8.1 or higher. ynh_get_ram () { # Declare an array to define the options of this helper. local legacy_args=ftso @@ -74,6 +76,8 @@ ynh_get_ram () { # | arg: -s, --ignore_swap - Ignore swap, consider only real RAM # | arg: -o, --only_swap - Ignore real RAM, consider only swap # | exit: Return 1 if the ram is under the requirement, 0 otherwise. +# +# Requires YunoHost version 3.8.1 or higher. ynh_require_ram () { # Declare an array to define the options of this helper. local legacy_args=rftso diff --git a/data/helpers.d/logrotate b/data/helpers.d/logrotate index 7df954c15..d5384264c 100644 --- a/data/helpers.d/logrotate +++ b/data/helpers.d/logrotate @@ -16,6 +16,7 @@ # the same logrotate config file. Unless you use the option --non-append # # Requires YunoHost version 2.6.4 or higher. +# Requires YunoHost version 3.2.0 or higher for the argument --specific_user ynh_use_logrotate () { # Declare an array to define the options of this helper. local legacy_args=lnuya diff --git a/data/helpers.d/network b/data/helpers.d/network index 03df04c1e..cb5a9e540 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -33,7 +33,7 @@ ynh_find_port () { # | arg: -p, --port= - port to check # | exit: Return 1 if the port is already used by another process. # -# Requires YunoHost version 3.7.x or higher. +# Requires YunoHost version 3.8.0 or higher. ynh_port_available () { # Declare an array to define the options of this helper. local legacy_args=p diff --git a/data/helpers.d/nginx b/data/helpers.d/nginx index 6b60a3ef7..cd4380f16 100644 --- a/data/helpers.d/nginx +++ b/data/helpers.d/nginx @@ -19,6 +19,7 @@ # __PORT_2__ by $port_2 # # Requires YunoHost version 2.7.2 or higher. +# Requires YunoHost version 2.7.13 or higher for dynamic variables ynh_add_nginx_config () { finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf" local others_var=${1:-} diff --git a/data/helpers.d/php b/data/helpers.d/php index 588bf7177..4ec011217 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -56,6 +56,8 @@ YNH_PHP_VERSION=${YNH_PHP_VERSION:-$YNH_DEFAULT_PHP_VERSION} # children ready to answer. # # Requires YunoHost version 2.7.2 or higher. +# Requires YunoHost version 3.5.1 or higher for the argument --phpversion +# Requires YunoHost version 3.8.1 or higher for the arguments --use_template, --usage, --footprint, --package and --dedicated_service ynh_add_fpm_config () { # Declare an array to define the options of this helper. local legacy_args=vtufpd @@ -312,6 +314,8 @@ ynh_remove_fpm_config () { # usage: ynh_install_php --phpversion=phpversion [--package=packages] # | arg: -v, --phpversion= - Version of php to install. # | arg: -p, --package= - Additionnal php packages to install +# +# Requires YunoHost version 3.8.1 or higher. ynh_install_php () { # Declare an array to define the options of this helper. local legacy_args=vp @@ -364,6 +368,8 @@ ynh_install_php () { # [internal] # # usage: ynh_install_php +# +# Requires YunoHost version 3.8.1 or higher. ynh_remove_php () { # Get the version of php used by this app local phpversion=$(ynh_app_setting_get $app phpversion) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index 4122deec6..4ac9fcbec 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -153,6 +153,8 @@ ynh_psql_create_user() { # usage: ynh_psql_user_exists --user=user # | arg: -u, --user= - the user for which to check existence # | exit: Return 1 if the user doesn't exist, 0 otherwise +# +# Requires YunoHost version 3.5.0 or higher. ynh_psql_user_exists() { # Declare an array to define the options of this helper. local legacy_args=u @@ -174,6 +176,8 @@ ynh_psql_user_exists() { # usage: ynh_psql_database_exists --database=database # | arg: -d, --database= - the database for which to check existence # | exit: Return 1 if the database doesn't exist, 0 otherwise +# +# Requires YunoHost version 3.5.0 or higher. ynh_psql_database_exists() { # Declare an array to define the options of this helper. local legacy_args=d @@ -212,6 +216,7 @@ ynh_psql_drop_user() { # After executing this helper, the password of the created database will be available in $db_pwd # It will also be stored as "psqlpwd" into the app settings. # +# Requires YunoHost version 2.7.13 or higher. ynh_psql_setup_db() { # Declare an array to define the options of this helper. local legacy_args=unp @@ -239,6 +244,8 @@ ynh_psql_setup_db() { # usage: ynh_psql_remove_db --db_user=user --db_name=name # | arg: -u, --db_user= - Owner of the database # | arg: -n, --db_name= - Name of the database +# +# Requires YunoHost version 2.7.13 or higher. ynh_psql_remove_db() { # Declare an array to define the options of this helper. local legacy_args=un @@ -268,6 +275,8 @@ ynh_psql_remove_db() { # Please always call this script in install and restore scripts # # usage: ynh_psql_test_if_first_run +# +# Requires YunoHost version 2.7.13 or higher. ynh_psql_test_if_first_run() { if [ -f "$PSQL_ROOT_PWD_FILE" ] then diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index c718e50c2..5e67baf4d 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -14,7 +14,7 @@ # __APP__ by $app # __FINALPATH__ by $final_path # -# Requires YunoHost version 2.7.2 or higher. +# Requires YunoHost version 2.7.11 or higher. ynh_add_systemd_config () { # Declare an array to define the options of this helper. local legacy_args=st @@ -79,6 +79,8 @@ ynh_remove_systemd_config () { # | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log # | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds. # | arg: -e, --length= - Length of the error log : Default : 20 +# +# Requires YunoHost version 3.5.0 or higher. ynh_systemd_action() { # Declare an array to define the options of this helper. local legacy_args=nalpte @@ -179,6 +181,8 @@ ynh_systemd_action() { # (usually used in ynh_clean_setup scripts) # # usage: ynh_clean_check_starting +# +# Requires YunoHost version 3.5.0 or higher. ynh_clean_check_starting () { if [ -n "$pid_tail" ] then diff --git a/data/helpers.d/user b/data/helpers.d/user index 304658ff8..08b1b1d42 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -78,6 +78,8 @@ ynh_system_user_exists() { # usage: ynh_system_group_exists --group=group # | arg: -g, --group= - the group to check # | exit: Return 1 if the group doesn't exist, 0 otherwise +# +# Requires YunoHost version 3.5.0.2 or higher. ynh_system_group_exists() { # Declare an array to define the options of this helper. local legacy_args=g diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 13d3a5dcd..fb50305ce 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -16,6 +16,7 @@ # # It prints a warning to inform that the script was failed, and execute the ynh_clean_setup function if used in the app script # +# Requires YunoHost version 2.6.4 or higher. ynh_exit_properly () { local exit_code=$? if [ "$exit_code" -eq 0 ]; then From 194a0bb187902e90572fcde1d51afc15f542d750 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 15:46:03 +0200 Subject: [PATCH 200/317] We need that trailing / for the download of files to actually work, c.f. feedback in 3.8 post on the forum --- data/templates/nginx/server.tpl.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/nginx/server.tpl.conf b/data/templates/nginx/server.tpl.conf index f2e9de2de..29af9f532 100644 --- a/data/templates/nginx/server.tpl.conf +++ b/data/templates/nginx/server.tpl.conf @@ -75,7 +75,7 @@ server { root /dev/null; location /upload/ { - alias /var/xmpp-upload/{{ domain }}/upload; + alias /var/xmpp-upload/{{ domain }}/upload/; # Pass all requests to metronome, except for GET and HEAD requests. limit_except GET HEAD { proxy_pass http://localhost:5290; From ba8514fb670367cadc9731d731c02ac27d51b960 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 21 Apr 2020 16:18:04 +0200 Subject: [PATCH 201/317] Fix regressions --- data/helpers.d/php | 2 +- data/helpers.d/systemd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/helpers.d/php b/data/helpers.d/php index 4ec011217..9b23baf25 100644 --- a/data/helpers.d/php +++ b/data/helpers.d/php @@ -96,7 +96,7 @@ ynh_add_fpm_config () { local additionnal_packages="" fi # Install this specific version of php. - ynh_install_php --phpversion=$phpversion "$additionnal_packages" + ynh_install_php --phpversion="$phpversion" "$additionnal_packages" elif [ -n "$package" ] then # Install the additionnal packages from the default repository diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 5e67baf4d..d72744aa0 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -169,7 +169,7 @@ ynh_systemd_action() { ynh_exec_warn journalctl --no-pager --lines=$length --unit=$service_name if [ -e "$log_path" ] then - ynh_print_warn --message="--" + ynh_print_warn --message="\-\-\-" ynh_exec_warn tail --lines=$length "$log_path" fi fi @@ -187,7 +187,7 @@ ynh_clean_check_starting () { if [ -n "$pid_tail" ] then # Stop the execution of tail. - kill --signal 15 $pid_tail 2>&1 + kill -SIGTERM $pid_tail 2>&1 fi if [ -n "$templog" ] then From f72be82429b11787ac2d521ed84d80de9dee9917 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Tue, 21 Apr 2020 16:24:49 +0200 Subject: [PATCH 202/317] Fix getopts with empty parameters --- data/helpers.d/getopts | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/data/helpers.d/getopts b/data/helpers.d/getopts index c8045fa25..5d2bbe896 100644 --- a/data/helpers.d/getopts +++ b/data/helpers.d/getopts @@ -147,26 +147,30 @@ ynh_handle_getopts_args () { break fi else - # Else, add this value to this option - # Each value will be separated by ';' - if [ -n "${!option_var}" ] - then - # If there's already another value for this option, add a ; before adding the new value - eval ${option_var}+="\;" - fi + # Ignore empty parameters + if [ -n "${all_args[$i]}" ] + then + # Else, add this value to this option + # Each value will be separated by ';' + if [ -n "${!option_var}" ] + then + # If there's already another value for this option, add a ; before adding the new value + eval ${option_var}+="\;" + fi - # Remove the \ that escape - at beginning of values. - all_args[i]="${all_args[i]//\\TOBEREMOVED\\/}" + # Remove the \ that escape - at beginning of values. + all_args[i]="${all_args[i]//\\TOBEREMOVED\\/}" - # For the record. - # We're using eval here to get the content of the variable stored itself as simple text in $option_var... - # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var} - # But... ${!option_var} can't be used as left part of an assignation. - # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself. - # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one! + # For the record. + # We're using eval here to get the content of the variable stored itself as simple text in $option_var... + # Other ways to get that content would be to use either ${!option_var} or declare -g ${option_var} + # But... ${!option_var} can't be used as left part of an assignation. + # declare -g ${option_var} will create a local variable (despite -g !) and will not be available for the helper itself. + # So... Stop fucking arguing each time that eval is evil... Go find an other working solution if you can find one! - eval ${option_var}+='"${all_args[$i]}"' - shift_value=$(( shift_value + 1 )) + eval ${option_var}+='"${all_args[$i]}"' + fi + shift_value=$(( shift_value + 1 )) fi done fi From 1a828c725fd43c2a4cc4ae327e05c7eabae7f1e1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 20:20:53 +0200 Subject: [PATCH 203/317] Fix postfix ciphers --- data/templates/postfix/main.cf | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/data/templates/postfix/main.cf b/data/templates/postfix/main.cf index 2642fd8f0..61cbfa2e6 100644 --- a/data/templates/postfix/main.cf +++ b/data/templates/postfix/main.cf @@ -33,14 +33,20 @@ smtpd_tls_cert_file = /etc/yunohost/certs/{{ main_domain }}/crt.pem smtpd_tls_key_file = /etc/yunohost/certs/{{ main_domain }}/key.pem smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1 -smtpd_tls_mandatory_ciphers = medium +# smtpd_tls_mandatory_ciphers = medium # (c.f. below) # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem # not actually 1024 bits, this applies to all DHE >= 1024 bits # smtpd_tls_dh1024_param_file = /path/to/dhparam.pem -tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 +# This custom medium cipherlist recommendation only works if we have a DH ... which we don't, c.f. https://github.com/YunoHost/issues/issues/93 +# On the other hand, the postfix doc strongly discourage tweaking this list ... So whatever, let's keep the mandatory_ciphers to high like we did before applying the Mozilla recommendation ... +#tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 tls_preempt_cipherlist = no + +# Custom Yunohost stuff ... because we can't use the recommendation about medium cipher list ... +smtpd_tls_mandatory_ciphers=high +smtpd_tls_eecdh_grade = ultra ############################################################################### smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtpd_tls_loglevel=1 From cc5dc0e7a7e909348cd1c9174ca2d2d92aeef126 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 22 Apr 2020 02:21:28 +0200 Subject: [PATCH 204/317] How did we not find out about this huge typo earlier :| --- src/yunohost/backup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 8408e7fa3..10a232f38 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -604,7 +604,7 @@ class BackupManager(): ret_succeed = {hook: [path for path, result in infos.items() if result["state"] == "succeed"] for hook, infos in ret.items() if any(result["state"] == "succeed" for result in infos.values())} - ret_failed = {hook: [path for path, result in infos.items.items() if result["state"] == "failed"] + ret_failed = {hook: [path for path, result in infos.items() if result["state"] == "failed"] for hook, infos in ret.items() if any(result["state"] == "failed" for result in infos.values())} From c42f7172f7a4ada26209cac392c844a2d57c6d01 Mon Sep 17 00:00:00 2001 From: pitchum Date: Wed, 22 Apr 2020 10:34:40 +0200 Subject: [PATCH 205/317] Do not include xmpp-upload in certificates of "child" domains Co-Authored-By: Alexandre Aubin --- src/yunohost/certificate.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index c6f520b4e..aa137c784 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -639,13 +639,15 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): # Set the domain csr.get_subject().CN = domain - # Include xmpp-upload subdomain in subject alternate names - subdomain="xmpp-upload." + domain - try: - _dns_ip_match_public_ip(get_public_ip(), subdomain) - csr.add_extensions([crypto.X509Extension("subjectAltName", False, "DNS:" + subdomain)]) - except YunohostError: - logger.warning(m18n.n('certmanager_warning_subdomain_dns_record', subdomain=subdomain, domain=domain)) + from yunohost.domain import domain_list + # For "parent" domains, include xmpp-upload subdomain in subject alternate names + if domain in domain_list(exclude_subdomains=True)["domains"]: + subdomain="xmpp-upload." + domain + try: + _dns_ip_match_public_ip(get_public_ip(), subdomain) + csr.add_extensions([crypto.X509Extension("subjectAltName", False, "DNS:" + subdomain)]) + except YunohostError: + logger.warning(m18n.n('certmanager_warning_subdomain_dns_record', subdomain=subdomain, domain=domain)) # Set the key with open(key_file, 'rt') as f: From 817e45108631f1979e1443584713ea36a7d26643 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 01:27:11 +0200 Subject: [PATCH 206/317] Add regenconf tests to gitlab-ci --- .gitlab-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8e3938ad6..05aafe43b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -92,3 +92,10 @@ test-user-group: script: - cd src/yunohost - py.test tests/test_user-group.py + +test-regenconf: + extends: .tests + stage: tests + script: + - cd src/yunohost + - py.test tests/test_regenconf.py From 9eef8af53d858467ef5b8ef2fd4deb1f21735478 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 04:18:23 +0200 Subject: [PATCH 207/317] Fix improper use of logger.exception in app.py --- src/yunohost/app.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index ed7747b29..b94f57502 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -512,7 +512,7 @@ def app_upgrade(app=[], url=None, file=None): upgrade_failed = True if upgrade_retcode != 0 else False if upgrade_failed: error = m18n.n('app_upgrade_script_failed') - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) if msettings.get('interface') != 'api': dump_app_log_extract_for_debugging(operation_logger) @@ -520,13 +520,13 @@ def app_upgrade(app=[], url=None, file=None): except (KeyboardInterrupt, EOFError): upgrade_retcode = -1 error = m18n.n('operation_interrupted') - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) # Something wrong happened in Yunohost's code (most probably hook_exec) except Exception: import traceback error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) - logger.exception(m18n.n("app_install_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_install_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) finally: # Whatever happened (install success or failure) we check if it broke the system @@ -536,7 +536,7 @@ def app_upgrade(app=[], url=None, file=None): _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e))) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e))) failure_message_with_debug_instructions = operation_logger.error(str(e)) # If upgrade failed or broke the system, @@ -768,20 +768,20 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu install_failed = True if install_retcode != 0 else False if install_failed: error = m18n.n('app_install_script_failed') - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) if msettings.get('interface') != 'api': dump_app_log_extract_for_debugging(operation_logger) # Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception except (KeyboardInterrupt, EOFError): error = m18n.n('operation_interrupted') - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) # Something wrong happened in Yunohost's code (most probably hook_exec) except Exception as e: import traceback error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) finally: # Whatever happened (install success or failure) we check if it broke the system @@ -791,7 +791,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - logger.exception(m18n.n("app_install_failed", app=app_id, error=str(e))) + logger.error(m18n.n("app_install_failed", app=app_id, error=str(e))) failure_message_with_debug_instructions = operation_logger.error(str(e)) # If the install failed or broke the system, we remove it @@ -828,7 +828,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu except (KeyboardInterrupt, EOFError, Exception): remove_retcode = -1 import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) # Remove all permission in LDAP for permission_name in user_permission_list()["permissions"].keys(): @@ -999,7 +999,7 @@ def app_remove(operation_logger, app): except (KeyboardInterrupt, EOFError, Exception): ret = -1 import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) if ret == 0: logger.success(m18n.n('app_removed', app=app)) @@ -1825,7 +1825,7 @@ def _get_app_settings(app_id): if app_id == settings['id']: return settings except (IOError, TypeError, KeyError): - logger.exception(m18n.n('app_not_correctly_installed', + logger.error(m18n.n('app_not_correctly_installed', app=app_id)) return {} From e79f73d4638c0ed100751835789b057c946287a7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 17:02:58 +0200 Subject: [PATCH 208/317] Make sure to return / and not empty string for stuff on domain root --- src/yunohost/app.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index b94f57502..37da3a957 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -239,6 +239,8 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + perm_path = perm_path if perm_path != "" else "/" + return perm_domain, perm_path this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]} @@ -274,7 +276,6 @@ def app_map(app=None, raw=False, user=None): continue perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"]) - if perm_name.endswith(".main"): perm_label = label else: @@ -1105,11 +1106,12 @@ def app_makedefault(operation_logger, app, domain=None): elif domain not in domain_list()['domains']: raise YunohostError('domain_unknown') - operation_logger.start() if '/' in app_map(raw=True)[domain]: raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain, other_app=app_map(raw=True)[domain]["/"]["id"]) + operation_logger.start() + # TODO / FIXME : current trick is to add this to conf.json.persisten # This is really not robust and should be improved # e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the @@ -1267,6 +1269,8 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + perm_path = perm_path if perm_path != "" else "/" + return perm_domain + perm_path # Skipped From 755ba61b326c0eb035e8a8090d66b7b9a3b6b607 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 17:44:01 +0200 Subject: [PATCH 209/317] Moar tests to check the content of app_map --- src/yunohost/tests/test_apps.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/yunohost/tests/test_apps.py b/src/yunohost/tests/test_apps.py index 6bc625a91..7c0861aa1 100644 --- a/src/yunohost/tests/test_apps.py +++ b/src/yunohost/tests/test_apps.py @@ -9,7 +9,7 @@ from conftest import message, raiseYunohostError from moulinette import m18n from moulinette.utils.filesystem import mkdir -from yunohost.app import app_install, app_remove, app_ssowatconf, _is_installed, app_upgrade +from yunohost.app import app_install, app_remove, app_ssowatconf, _is_installed, app_upgrade, app_map from yunohost.domain import _get_maindomain, domain_add, domain_remove, domain_list from yunohost.utils.error import YunohostError from yunohost.tests.test_permission import check_LDAP_db_integrity, check_permission_for_apps @@ -142,6 +142,12 @@ def test_legacy_app_install_main_domain(): install_legacy_app(main_domain, "/legacy") + app_map_ = app_map(raw=True) + assert main_domain in app_map_ + assert '/legacy' in app_map_[main_domain] + assert 'id' in app_map_[main_domain]['/legacy'] + assert app_map_[main_domain]['/legacy']['id'] == 'legacy_app' + assert app_is_installed(main_domain, "legacy_app") assert app_is_exposed_on_http(main_domain, "/legacy", "This is a dummy app") @@ -166,6 +172,12 @@ def test_legacy_app_install_secondary_domain_on_root(secondary_domain): install_legacy_app(secondary_domain, "/") + app_map_ = app_map(raw=True) + assert secondary_domain in app_map_ + assert '/' in app_map_[secondary_domain] + assert 'id' in app_map_[secondary_domain]['/'] + assert app_map_[secondary_domain]['/']['id'] == 'legacy_app' + assert app_is_installed(secondary_domain, "legacy_app") assert app_is_exposed_on_http(secondary_domain, "/", "This is a dummy app") From f68ae4561f23daa2fa1d25e0efea7663facc0e6c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 18:00:46 +0200 Subject: [PATCH 210/317] Patch files earlier to avoid raising an exception is setting folder already exists --- src/yunohost/app.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index b94f57502..8f16198bc 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -489,17 +489,17 @@ def app_upgrade(app=[], url=None, file=None): env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb) - # Start register change on system - related_to = [('app', app_instance_name)] - operation_logger = OperationLogger('app_upgrade', related_to, env=env_dict) - operation_logger.start() - # Attempt to patch legacy helpers ... _patch_legacy_helpers(extracted_app_folder) # Apply dirty patch to make php5 apps compatible with php7 _patch_php5(extracted_app_folder) + # Start register change on system + related_to = [('app', app_instance_name)] + operation_logger = OperationLogger('app_upgrade', related_to, env=env_dict) + operation_logger.start() + # Execute App upgrade script os.system('chown -hR admin: %s' % INSTALL_TMP) @@ -695,6 +695,12 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu # Validate domain / path availability for webapps _validate_and_normalize_webpath(manifest, args_odict, extracted_app_folder) + # Attempt to patch legacy helpers ... + _patch_legacy_helpers(extracted_app_folder) + + # Apply dirty patch to make php5 apps compatible with php7 + _patch_php5(extracted_app_folder) + # Prepare env. var. to pass to script env_dict = _make_environment_dict(args_odict) env_dict["YNH_APP_ID"] = app_id @@ -732,12 +738,6 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu } _set_app_settings(app_instance_name, app_settings) - # Attempt to patch legacy helpers ... - _patch_legacy_helpers(extracted_app_folder) - - # Apply dirty patch to make php5 apps compatible with php7 - _patch_php5(extracted_app_folder) - os.system('chown -R admin: ' + extracted_app_folder) # Execute App install script From cb0a87de256ad54d83725d9c395e940c3f441597 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 18:59:12 +0200 Subject: [PATCH 211/317] Patch usage of old in apps 'yunohost tools diagnosis' --- src/yunohost/app.py | 53 +++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 8f16198bc..ec4e05664 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -2843,29 +2843,46 @@ def _patch_legacy_helpers(app_folder): # sudo yunohost app initdb $db_user -p $db_pwd # by # ynh_mysql_setup_db --db_user=$db_user --db_name=$db_user --db_pwd=$db_pwd - "yunohost app initdb": ( - r"(sudo )?yunohost app initdb \"?(\$\{?\w+\}?)\"?\s+-p\s\"?(\$\{?\w+\}?)\"?", - r"ynh_mysql_setup_db --db_user=\2 --db_name=\2 --db_pwd=\3"), + "yunohost app initdb": { + "pattern": r"(sudo )?yunohost app initdb \"?(\$\{?\w+\}?)\"?\s+-p\s\"?(\$\{?\w+\}?)\"?", + "replace": r"ynh_mysql_setup_db --db_user=\2 --db_name=\2 --db_pwd=\3", + "important": True + }, # Replace # sudo yunohost app checkport whaterver # by # ynh_port_available whatever - "yunohost app checkport": ( - r"(sudo )?yunohost app checkport", - r"ynh_port_available"), + "yunohost app checkport": { + "pattern": r"(sudo )?yunohost app checkport", + "replace": r"ynh_port_available", + "important": True + }, # We can't migrate easily port-available # .. but at the time of writing this code, only two non-working apps are using it. - "yunohost tools port-available": (None, None), + "yunohost tools port-available": {"important":True}, # Replace # yunohost app checkurl "${domain}${path_url}" -a "${app}" # by # ynh_webpath_register --app=${app} --domain=${domain} --path_url=${path_url} - "yunohost app checkurl": ( - r"(sudo )?yunohost app checkurl \"?(\$\{?\w+\}?)\/?(\$\{?\w+\}?)\"?\s+-a\s\"?(\$\{?\w+\}?)\"?", - r"ynh_webpath_register --app=\4 --domain=\2 --path_url=\3"), + "yunohost app checkurl": { + "pattern": r"(sudo )?yunohost app checkurl \"?(\$\{?\w+\}?)\/?(\$\{?\w+\}?)\"?\s+-a\s\"?(\$\{?\w+\}?)\"?", + "replace": r"ynh_webpath_register --app=\4 --domain=\2 --path_url=\3", + "important": True + }, + # Remove + # Automatic diagnosis data from YunoHost + # __PRE_TAG1__$(yunohost tools diagnosis | ...)__PRE_TAG2__" + # + "yunohost tools diagnosis": { + "pattern": r"(Automatic diagnosis data from YunoHost( *\n)*)? *(__\w+__)? *\$\(yunohost tools diagnosis.*\)(__\w+__)?", + "replace": r"", + "important": False + } } - stuff_to_replace_compiled = {h: (re.compile(r[0]), r[1]) if r[0] else (None,None) for h, r in stuff_to_replace.items()} + for helper, infos in stuff_to_replace.items(): + infos["pattern"] = re.compile(infos["pattern"]) if infos.get("pattern") else None + infos["replace"] = infos.get("replace") for filename in files_to_patch: @@ -2875,18 +2892,20 @@ def _patch_legacy_helpers(app_folder): content = read_file(filename) replaced_stuff = False + show_warning = False - for helper, regexes in stuff_to_replace_compiled.items(): - pattern, replace = regexes + for helper, infos in stuff_to_replace.items(): # If helper is used, attempt to patch the file - if helper in content and pattern != "": - content = pattern.sub(replace, content) + if helper in content and infos["pattern"]: + content = infos["pattern"].sub(infos["replace"], content) replaced_stuff = True + if infos["important"]: + show_warning = True # If the helpert is *still* in the content, it means that we # couldn't patch the deprecated helper in the previous lines. In # that case, abort the install or whichever step is performed - if helper in content: + if helper in content and infos["important"]: raise YunohostError("This app is likely pretty old and uses deprecated / outdated helpers that can't be migrated easily. It can't be installed anymore.") if replaced_stuff: @@ -2902,5 +2921,7 @@ def _patch_legacy_helpers(app_folder): # Actually write the new content in the file write_to_file(filename, content) + + if show_warning: # And complain about those damn deprecated helpers logger.error("/!\ Packagers ! This app uses a very old deprecated helpers ... Yunohost automatically patched the helpers to use the new recommended practice, but please do consider fixing the upstream code right now ...") From 5baadd1fa18cc45534a1a66a67af7c61d442af3e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 24 Apr 2020 03:08:31 +0200 Subject: [PATCH 212/317] Be more robust against some situation where archive is corrupted --- locales/en.json | 3 ++- src/yunohost/backup.py | 42 +++++++++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/locales/en.json b/locales/en.json index c2c087031..9207b304b 100644 --- a/locales/en.json +++ b/locales/en.json @@ -74,6 +74,8 @@ "backup_archive_name_exists": "A backup archive with this name already exists.", "backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'", "backup_archive_open_failed": "Could not open the backup archive", + "backup_archive_cant_retrieve_info_json": "Could not load infos for archive '{archive}' ... The info.json cannot be retrieved (or is not a valid json).", + "backup_archive_corrupted": "It looks like the backup archive '{archive}' is corrupted : {error}", "backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup", "backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'", "backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)", @@ -91,7 +93,6 @@ "backup_delete_error": "Could not delete '{path:s}'", "backup_deleted": "Backup deleted", "backup_hook_unknown": "The backup hook '{hook:s}' is unknown", - "backup_invalid_archive": "This is not a backup archive", "backup_method_borg_finished": "Backup into Borg finished", "backup_method_copy_finished": "Backup copy finalized", "backup_method_custom_finished": "Custom backup method '{method:s}' finished", diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 10a232f38..5f24f444f 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -870,7 +870,7 @@ class RestoreManager(): Read the info file from inside an archive Exceptions: - backup_invalid_archive -- Raised if we can't read the info + backup_archive_cant_retrieve_info_json -- Raised if we can't read the info """ # Retrieve backup info info_file = os.path.join(self.work_dir, "info.json") @@ -883,7 +883,7 @@ class RestoreManager(): self.info["system"] = self.info["hooks"] except IOError: logger.debug("unable to load '%s'", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self.archive_path) else: logger.debug("restoring from backup '%s' created on %s", self.name, datetime.utcfromtimestamp(self.info['created_at'])) @@ -891,10 +891,6 @@ class RestoreManager(): def _postinstall_if_needed(self): """ Post install yunohost if needed - - Exceptions: - backup_invalid_archive -- Raised if the current_host isn't in the - archive """ # Check if YunoHost is installed if not os.path.isfile('/etc/yunohost/installed'): @@ -906,7 +902,7 @@ class RestoreManager(): logger.debug("unable to retrieve current_host from the backup", exc_info=1) # FIXME include the current_host by default ? - raise YunohostError('backup_invalid_archive') + raise YunohostError("The main domain name cannot be retrieved from inside the archive, and is needed to perform the postinstall", raw_msg=True) logger.debug("executing the post-install...") tools_postinstall(domain, 'Yunohost', True) @@ -1924,6 +1920,12 @@ class TarBackupMethod(BackupMethod): self._archive_file, exc_info=1) raise YunohostError('backup_archive_open_failed') + try: + files_in_archive = tar.getnames() + print(files_in_archive) + except IOError as e: + raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e)) + # FIXME : Is this really useful to close the archive just to # reopen it right after this with the same options ...? tar.close() @@ -1932,21 +1934,21 @@ class TarBackupMethod(BackupMethod): logger.debug(m18n.n("restore_extracting")) tar = tarfile.open(self._archive_file, "r:gz") - if "info.json" in tar.getnames(): + if "info.json" in files_in_archive: leading_dot = "" tar.extract('info.json', path=self.work_dir) - elif "./info.json" in tar.getnames(): + elif "./info.json" in files_in_archive: leading_dot = "./" tar.extract('./info.json', path=self.work_dir) else: logger.debug("unable to retrieve 'info.json' inside the archive", exc_info=1) tar.close() - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self._archive_file) - if "backup.csv" in tar.getnames(): + if "backup.csv" in files_in_archive: tar.extract('backup.csv', path=self.work_dir) - elif "./backup.csv" in tar.getnames(): + elif "./backup.csv" in files_in_archive: tar.extract('./backup.csv', path=self.work_dir) else: # Old backup archive have no backup.csv file @@ -2288,7 +2290,7 @@ def backup_list(with_info=False, human_readable=False): try: d[a] = backup_info(a, human_readable=human_readable) except YunohostError as e: - logger.warning('%s: %s' % (a, e.strerror)) + logger.warning(str(e)) result = d @@ -2325,17 +2327,23 @@ def backup_info(name, with_details=False, human_readable=False): if not os.path.exists(info_file): tar = tarfile.open(archive_file, "r:gz") info_dir = info_file + '.d' + try: - if "info.json" in tar.getnames(): + files_in_archive = tar.getnames() + except IOError as e: + raise YunohostError("backup_archive_corrupted", archive=archive_file, error=str(e)) + + try: + if "info.json" in files_in_archive: tar.extract('info.json', path=info_dir) - elif "./info.json" in tar.getnames(): + elif "./info.json" in files_in_archive: tar.extract('./info.json', path=info_dir) else: raise KeyError except KeyError: logger.debug("unable to retrieve '%s' inside the archive", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file) else: shutil.move(os.path.join(info_dir, 'info.json'), info_file) finally: @@ -2348,7 +2356,7 @@ def backup_info(name, with_details=False, human_readable=False): info = json.load(f) except: logger.debug("unable to load '%s'", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file) # Retrieve backup size size = info.get('size', 0) From 54cc684a356e7e92cf34c6514c3da48ee2d37b14 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 24 Apr 2020 03:33:59 +0200 Subject: [PATCH 213/317] Keep track of yunohost version a backup was made from, for possible future uses --- src/yunohost/backup.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 10a232f38..3e2f467d1 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -35,9 +35,9 @@ import tempfile from datetime import datetime from glob import glob from collections import OrderedDict +from functools import reduce from moulinette import msignals, m18n, msettings -from yunohost.utils.error import YunohostError from moulinette.utils import filesystem from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file, mkdir, write_to_yaml, read_yaml @@ -51,7 +51,8 @@ from yunohost.hook import ( from yunohost.tools import tools_postinstall from yunohost.regenconf import regen_conf from yunohost.log import OperationLogger -from functools import reduce +from yunohost.utils.error import YunohostError +from yunohost.utils.packages import ynh_packages_version BACKUP_PATH = '/home/yunohost.backup' ARCHIVES_PATH = '%s/archives' % BACKUP_PATH @@ -282,7 +283,8 @@ class BackupManager(): 'size': self.size, 'size_details': self.size_details, 'apps': self.apps_return, - 'system': self.system_return + 'system': self.system_return, + 'from_yunohost_version': ynh_packages_version()["yunohost"]["version"] } @property From b9e226caed6d6fc9f775a9d3121a30ad258c0a70 Mon Sep 17 00:00:00 2001 From: pitchum Date: Fri, 24 Apr 2020 19:07:05 +0200 Subject: [PATCH 214/317] Remove deprecated docstrings. --- src/yunohost/domain.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index a1ac65b81..85d804584 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -46,9 +46,6 @@ def domain_list(exclude_subdomains=False): List domains Keyword argument: - filter -- LDAP filter used to search - offset -- Starting number for domain fetching - limit -- Maximum number of domain fetched exclude_subdomains -- Filter out domains that are subdomains of other declared domains """ From 67785edb1c5e2bf41ea8c8af6e3facb8b185f893 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:45:22 +0200 Subject: [PATCH 215/317] Long arguments for ynh_validate_ip4 Co-Authored-By: Kayou --- data/helpers.d/network | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/network b/data/helpers.d/network index cb5a9e540..e45fe1a5e 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -105,7 +105,7 @@ ynh_validate_ip4() # Manage arguments with getopts ynh_handle_getopts_args "$@" - ynh_validate_ip 4 $ip_address + ynh_validate_ip --family=4 --ip_address=$ip_address } From b3b0aef0477591fcf09ed612a37a442c7046bd81 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:45:43 +0200 Subject: [PATCH 216/317] Long arguments for ynh_validate_ip6 Co-Authored-By: Kayou --- data/helpers.d/network | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/network b/data/helpers.d/network index e45fe1a5e..5618ff377 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -127,5 +127,5 @@ ynh_validate_ip6() # Manage arguments with getopts ynh_handle_getopts_args "$@" - ynh_validate_ip 6 $ip_address + ynh_validate_ip --family=6 --ip_address=$ip_address } From 1decbd242364166134de57952fb65191d3e30e21 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:47:53 +0200 Subject: [PATCH 217/317] Fix ynh_no_log Co-Authored-By: Kayou --- data/helpers.d/logging | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/logging b/data/helpers.d/logging index 37dfd286c..fe0ad70b0 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -54,7 +54,7 @@ ynh_no_log() { eval $@ local exit_code=$? mv ${ynh_cli_log}-move ${ynh_cli_log} - return $? + return $exit_code } # Main printer, just in case in the future we have to change anything about that. From d9aa345ee866c47e7f6792fccd26fc79f280df96 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:51:18 +0200 Subject: [PATCH 218/317] Unfold OR Co-Authored-By: Kayou --- data/helpers.d/nodejs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/nodejs b/data/helpers.d/nodejs index 3ede3c8c9..efb50ae37 100644 --- a/data/helpers.d/nodejs +++ b/data/helpers.d/nodejs @@ -49,7 +49,9 @@ ynh_use_nodejs () { nodejs_path="$node_version_path/$nodejs_version/bin" # Load the path of this version of node in $PATH - [[ :$PATH: == *":$nodejs_path"* ]] || PATH="$nodejs_path:$PATH" + if [[ :$PATH: != *":$nodejs_path"* ]]; then + PATH="$nodejs_path:$PATH" + fi } # Install a specific version of nodejs From defabdbecb3a4ad29702db3f82afce132beecc43 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:56:49 +0200 Subject: [PATCH 219/317] Missing argument Co-Authored-By: Kayou --- data/helpers.d/user | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/user b/data/helpers.d/user index 08b1b1d42..aeac3a9c5 100644 --- a/data/helpers.d/user +++ b/data/helpers.d/user @@ -131,7 +131,7 @@ ynh_system_user_create () { else local shell="--shell /usr/sbin/nologin" fi - useradd $user_home_dir --system --user-group $username $shell || ynh_die "Unable to create $username system account" + useradd $user_home_dir --system --user-group $username $shell || ynh_die --message="Unable to create $username system account" fi } From 1af4d20e1efcd82e60c66c83efd82e030d976435 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Fri, 24 Apr 2020 23:59:59 +0200 Subject: [PATCH 220/317] Typo Co-Authored-By: Kayou --- data/helpers.d/logging | 1 + 1 file changed, 1 insertion(+) diff --git a/data/helpers.d/logging b/data/helpers.d/logging index fe0ad70b0..ec996a7bc 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -230,6 +230,7 @@ ynh_script_progression () { local last # Manage arguments with getopts ynh_handle_getopts_args "$@" + # Re-disable xtrace, ynh_handle_getopts_args set it back set +o xtrace # set +x weight=${weight:-1} time=${time:-0} From 54aa6f891290fff1e709200ebbc93bc08e0d5eb6 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 25 Apr 2020 00:00:57 +0200 Subject: [PATCH 221/317] Typo Co-Authored-By: Kayou --- data/helpers.d/logging | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/logging b/data/helpers.d/logging index ec996a7bc..c79090e25 100644 --- a/data/helpers.d/logging +++ b/data/helpers.d/logging @@ -325,7 +325,7 @@ ynh_debug () { local trace # Manage arguments with getopts ynh_handle_getopts_args "$@" - # Redisable xtrace, ynh_handle_getopts_args set it back + # Re-disable xtrace, ynh_handle_getopts_args set it back set +o xtrace # set +x message=${message:-} trace=${trace:-} From a75af4896c980e0f3e4c5e8bc52b86f8e998dee0 Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 25 Apr 2020 00:35:39 +0200 Subject: [PATCH 222/317] follow=name Co-Authored-By: Kayou --- data/helpers.d/systemd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index d72744aa0..798dfd02a 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -113,7 +113,7 @@ ynh_systemd_action() { local pid_tail=$! else # Read the specified log file - tail --follow --retry --lines=0 "$log_path" > "$templog" 2>&1 & + tail --follow=name --retry --lines=0 "$log_path" > "$templog" 2>&1 & # Get the PID of the tail command local pid_tail=$! fi @@ -195,4 +195,3 @@ ynh_clean_check_starting () { fi } - From b6daf0c448c93cfb21906d15cc938ef3cd8da6db Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sat, 25 Apr 2020 00:38:59 +0200 Subject: [PATCH 223/317] ynh_die instead of false --- data/helpers.d/systemd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 798dfd02a..238f65d93 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -136,7 +136,7 @@ ynh_systemd_action() { ynh_exec_err tail --lines=$length "$log_path" fi # Fail the app script, since the service failed. - false + ynh_die fi # Start the timeout and try to find line_match From dd5699ee404081e95bcf0ec1e60f0e019cfa0a3a Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sat, 25 Apr 2020 01:03:33 +0200 Subject: [PATCH 224/317] use ynh_port_available in ynh_find_port --- data/helpers.d/network | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/network b/data/helpers.d/network index 5618ff377..4f108422b 100644 --- a/data/helpers.d/network +++ b/data/helpers.d/network @@ -18,7 +18,7 @@ ynh_find_port () { ynh_handle_getopts_args "$@" test -n "$port" || ynh_die --message="The argument of ynh_find_port must be a valid port." - while ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$" # Check if the port is free + while ! ynh_port_available --port=$port do port=$((port+1)) # Else, pass to next port done @@ -42,7 +42,7 @@ ynh_port_available () { # Manage arguments with getopts ynh_handle_getopts_args "$@" - if ss --numeric --listening --tcp --udp | grep --quiet --word-regexp :$port + if ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ":$port$" # Check if the port is free then return 1 else From a20fd04955581ce5a261de58bf461ed00b7beb2f Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 01:27:20 +0200 Subject: [PATCH 225/317] Remove tmp debug print() Co-Authored-By: Kayou --- src/yunohost/backup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 5f24f444f..5d64ae5d6 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1922,7 +1922,6 @@ class TarBackupMethod(BackupMethod): try: files_in_archive = tar.getnames() - print(files_in_archive) except IOError as e: raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e)) From 77e124519f14b2fc50d29f1c12a15f993b736121 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sat, 25 Apr 2020 01:54:12 +0200 Subject: [PATCH 226/317] add bad archive test --- src/yunohost/tests/test_backuprestore.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index bcba21bb6..b715aad04 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -574,9 +574,20 @@ def test_restore_archive_with_no_json(mocker): assert "badbackup" in backup_list()["archives"] - with raiseYunohostError(mocker, 'backup_invalid_archive'): + with raiseYunohostError(mocker, 'backup_archive_cant_retrieve_info_json'): backup_restore(name="badbackup", force=True) +@pytest.mark.with_wordpress_archive_from_2p4 +def test_restore_archive_with_bad_archive(mocker): + + # Break the archive + os.system("head -n 1000 /home/yunohost.backup/archives/backup_wordpress_from_2p4.tar.gz > /home/yunohost.backup/archives/backup_wordpress_from_2p4.tar.gz") + + assert "backup_wordpress_from_2p4" in backup_list()["archives"] + + with raiseYunohostError(mocker, 'backup_archive_open_failed'): + backup_restore(name="backup_wordpress_from_2p4", force=True) + def test_backup_binds_are_readonly(mocker, monkeypatch): From 05734dfd7cb221197b065e0cde747721f84bafbe Mon Sep 17 00:00:00 2001 From: Kay0u Date: Sat, 25 Apr 2020 02:28:45 +0200 Subject: [PATCH 227/317] clean tmp backuo dir --- src/yunohost/tests/test_backuprestore.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yunohost/tests/test_backuprestore.py b/src/yunohost/tests/test_backuprestore.py index b715aad04..c7a4f9016 100644 --- a/src/yunohost/tests/test_backuprestore.py +++ b/src/yunohost/tests/test_backuprestore.py @@ -588,6 +588,8 @@ def test_restore_archive_with_bad_archive(mocker): with raiseYunohostError(mocker, 'backup_archive_open_failed'): backup_restore(name="backup_wordpress_from_2p4", force=True) + clean_tmp_backup_directory() + def test_backup_binds_are_readonly(mocker, monkeypatch): From cf32853f810adb4d4a0f674ab887bfbb117703de Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 03:44:26 +0200 Subject: [PATCH 228/317] Fetch all cert-status at once because running a yunohost command takes ~3ish seconds per call --- data/hooks/conf_regen/15-nginx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index f8b7d8062..f1a278440 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -52,6 +52,8 @@ do_pre_regen() { export compatibility="$(yunohost settings get 'security.nginx.compatibility')" ynh_render_template "security.conf.inc" "${nginx_conf_dir}/security.conf.inc" + cert_status=$(yunohost domain cert-status --json) + # add domain conf files for domain in $domain_list; do domain_conf_dir="${nginx_conf_dir}/${domain}.d" @@ -61,7 +63,7 @@ do_pre_regen() { # NGINX server configuration export domain - export domain_cert_ca=$(yunohost domain cert-status $domain --json \ + export domain_cert_ca=$(echo $cert_status \ | jq ".certificates.\"$domain\".CA_type" \ | tr -d '"') From 319898baf7892582e90b5b9b24fccb8234939fe3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 03:49:30 +0200 Subject: [PATCH 229/317] Feed domain list to regen-conf hooks directly through env to avoid having to call 'yunohost domain list' --- data/hooks/conf_regen/12-metronome | 8 +++----- data/hooks/conf_regen/15-nginx | 14 +++++--------- data/hooks/conf_regen/19-postfix | 5 ++--- data/hooks/conf_regen/31-rspamd | 5 +---- data/hooks/conf_regen/43-dnsmasq | 5 ++--- src/yunohost/regenconf.py | 11 +++++++++-- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome index 5a50b2b6e..8aee90212 100755 --- a/data/hooks/conf_regen/12-metronome +++ b/data/hooks/conf_regen/12-metronome @@ -14,7 +14,6 @@ do_pre_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(yunohost domain list --output-as plain --quiet) # install main conf file cat metronome.cfg.lua \ @@ -22,7 +21,7 @@ do_pre_regen() { > "${metronome_dir}/metronome.cfg.lua" # add domain conf files - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do cat domain.tpl.cfg.lua \ | sed "s/{{ domain }}/${domain}/g" \ > "${metronome_conf_dir}/${domain}.cfg.lua" @@ -33,7 +32,7 @@ do_pre_regen() { | awk '/^[^\.]+\.[^\.]+.*\.cfg\.lua$/ { print $1 }') for file in $conf_files; do domain=${file%.cfg.lua} - [[ $domain_list =~ $domain ]] \ + [[ $YNH_DOMAINS =~ $domain ]] \ || touch "${metronome_conf_dir}/${file}" done } @@ -43,10 +42,9 @@ do_post_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(yunohost domain list --output-as plain --quiet) # create metronome directories for domains - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do mkdir -p "/var/lib/metronome/${domain//./%2e}/pep" done # http_upload directory must be writable by metronome and readable by nginx diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index f1a278440..a43107599 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -46,7 +46,6 @@ do_pre_regen() { # retrieve variables main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(yunohost domain list --output-as plain --quiet) # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.nginx.compatibility')" @@ -55,7 +54,7 @@ do_pre_regen() { cert_status=$(yunohost domain cert-status --json) # add domain conf files - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do domain_conf_dir="${nginx_conf_dir}/${domain}.d" mkdir -p "$domain_conf_dir" mail_autoconfig_dir="${pending_dir}/var/www/.well-known/${domain}/autoconfig/mail/" @@ -83,7 +82,7 @@ do_pre_regen() { | awk '/^[^\.]+\.[^\.]+.*\.conf$/ { print $1 }') for file in $conf_files; do domain=${file%.conf} - [[ $domain_list =~ $domain ]] \ + [[ $YNH_DOMAINS =~ $domain ]] \ || touch "${nginx_conf_dir}/${file}" done @@ -91,7 +90,7 @@ do_pre_regen() { autoconfig_files=$(ls -1 /var/www/.well-known/*/autoconfig/mail/config-v1.1.xml 2>/dev/null || true) for file in $autoconfig_files; do domain=$(basename $(readlink -f $(dirname $file)/../..)) - [[ $domain_list =~ $domain ]] \ + [[ $YNH_DOMAINS =~ $domain ]] \ || (mkdir -p "$(dirname ${pending_dir}/${file})" && touch "${pending_dir}/${file}") done @@ -105,16 +104,13 @@ do_post_regen() { [ -z "$regen_conf_files" ] && exit 0 - # retrieve variables - domain_list=$(yunohost domain list --output-as plain --quiet) - # create NGINX conf directories for domains - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do mkdir -p "/etc/nginx/conf.d/${domain}.d" done # Get rid of legacy lets encrypt snippets - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do # If the legacy letsencrypt / acme-challenge domain-specific snippet is still there if [ -e /etc/nginx/conf.d/${domain}.d/000-acmechallenge.conf ] then diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix index 10076b680..68afe4bc9 100755 --- a/data/hooks/conf_regen/19-postfix +++ b/data/hooks/conf_regen/19-postfix @@ -20,18 +20,17 @@ do_pre_regen() { # prepare main.cf conf file main_domain=$(cat /etc/yunohost/current_host) - domain_list=$(yunohost domain list --output-as plain --quiet | tr '\n' ' ') # Support different strategy for security configurations export compatibility="$(yunohost settings get 'security.postfix.compatibility')" export main_domain - export domain_list + export domain_list="$YNH_DOMAINS" ynh_render_template "main.cf" "${postfix_dir}/main.cf" cat postsrsd \ | sed "s/{{ main_domain }}/${main_domain}/g" \ - | sed "s/{{ domain_list }}/${domain_list}/g" \ + | sed "s/{{ domain_list }}/${YNH_DOMAINS}/g" \ > "${default_dir}/postsrsd" # adapt it for IPv4-only hosts diff --git a/data/hooks/conf_regen/31-rspamd b/data/hooks/conf_regen/31-rspamd index 26fea4336..861549e27 100755 --- a/data/hooks/conf_regen/31-rspamd +++ b/data/hooks/conf_regen/31-rspamd @@ -25,11 +25,8 @@ do_post_regen() { mkdir -p /etc/dkim chown _rspamd /etc/dkim - # retrieve domain list - domain_list=$(yunohost domain list --output-as plain --quiet) - # create DKIM key for domains - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do domain_key="/etc/dkim/${domain}.mail.key" [ ! -f "$domain_key" ] && { # We use a 1024 bit size because nsupdate doesn't seem to be able to diff --git a/data/hooks/conf_regen/43-dnsmasq b/data/hooks/conf_regen/43-dnsmasq index 59a1f8a06..8a2985f34 100755 --- a/data/hooks/conf_regen/43-dnsmasq +++ b/data/hooks/conf_regen/43-dnsmasq @@ -26,10 +26,9 @@ do_pre_regen() { ynh_validate_ip4 "$ipv4" || ipv4='127.0.0.1' ipv6=$(curl -s -6 https://ip6.yunohost.org 2>/dev/null || true) ynh_validate_ip6 "$ipv6" || ipv6='' - domain_list=$(yunohost domain list --output-as plain --quiet) # add domain conf files - for domain in $domain_list; do + for domain in $YNH_DOMAINS; do cat domain.tpl \ | sed "s/{{ domain }}/${domain}/g" \ | sed "s/{{ ip }}/${ipv4}/g" \ @@ -42,7 +41,7 @@ do_pre_regen() { conf_files=$(ls -1 /etc/dnsmasq.d \ | awk '/^[^\.]+\.[^\.]+.*$/ { print $1 }') for domain in $conf_files; do - [[ $domain_list =~ $domain ]] \ + [[ $YNH_DOMAINS =~ $domain ]] \ || touch "${dnsmasq_dir}/${domain}" done } diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py index ad84c8164..b81c043ce 100644 --- a/src/yunohost/regenconf.py +++ b/src/yunohost/regenconf.py @@ -141,7 +141,14 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run if "glances" in names: names.remove("glances") - pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call) + # [Optimization] We compute and feed the domain list to the conf regen + # hooks to avoid having to call "yunohost domain list" so many times which + # ends up in wasted time (about 3~5 seconds per call on a RPi2) + from yunohost.domain import domain_list + env = {} + env["YNH_DOMAINS"] = " ".join(domain_list()["domains"]) + + pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call, env=env) # Keep only the hook names with at least one success names = [hook for hook, infos in pre_result.items() @@ -310,7 +317,7 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run regen_conf_files = '' return post_args + [regen_conf_files, ] - hook_callback('conf_regen', names, pre_callback=_pre_call) + hook_callback('conf_regen', names, pre_callback=_pre_call, env=env) operation_logger.success() From b90155423d73614340c9aa9c85d902afd7b0f1e9 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 04:33:08 +0200 Subject: [PATCH 230/317] Add a caching mechanism to get_public_ip to avoid loading requests and calling ip.yunohost.org dozens of time per minute... --- src/yunohost/utils/network.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index 3ae1ba910..92ca2a266 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -21,7 +21,9 @@ import os import re import logging +import time +from moulinette.utils.filesystem import read_file, write_to_file from moulinette.utils.network import download_text from moulinette.utils.process import check_output @@ -29,14 +31,24 @@ logger = logging.getLogger('yunohost.utils.network') def get_public_ip(protocol=4): - """Retrieve the public IP address from ip.yunohost.org""" - if protocol == 4: - url = 'https://ip.yunohost.org' - elif protocol == 6: - url = 'https://ip6.yunohost.org' + assert protocol in [4, 6], "Invalid protocol version for get_public_ip: %s, expected 4 or 6" % protocol + + cache_file = "/var/cache/yunohost/ipv%s" % protocol + cache_duration = 120 # 2 min + if os.path.exists(cache_file) and abs(os.path.getctime(cache_file) - time.time()) < cache_duration: + ip = read_file(cache_file).strip() + ip = ip if ip else None # Empty file (empty string) means there's no IP + logger.debug("Reusing IPv%s from cache: %s" % (protocol, ip)) else: - raise ValueError("invalid protocol version") + ip = get_public_ip_from_remote_server(protocol) + logger.debug("IP fetched: %s" % ip) + write_to_file(cache_file, ip or "") + return ip + + +def get_public_ip_from_remote_server(protocol=4): + """Retrieve the public IP address from ip.yunohost.org""" # We can know that ipv6 is not available directly if this file does not exists if protocol == 6 and not os.path.exists("/proc/net/if_inet6"): @@ -49,6 +61,9 @@ def get_public_ip(protocol=4): logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) return None + url = 'https://ip%s.yunohost.org' % (protocol if protocol != 4 else '') + logger.debug("Fetching IP from %s " % url) + try: return download_text(url, timeout=30).strip() except Exception as e: From 9ef2c60a90e828bd991f6d06e728b4537b9af358 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 05:24:27 +0200 Subject: [PATCH 231/317] Uhoh we can't call domain_list if postinstall ain't done yet --- src/yunohost/regenconf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py index b81c043ce..94883367b 100644 --- a/src/yunohost/regenconf.py +++ b/src/yunohost/regenconf.py @@ -146,7 +146,12 @@ def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run # ends up in wasted time (about 3~5 seconds per call on a RPi2) from yunohost.domain import domain_list env = {} - env["YNH_DOMAINS"] = " ".join(domain_list()["domains"]) + # Well we can only do domain_list() if postinstall is done ... + # ... but hooks that effectively need the domain list are only + # called only after the 'installed' flag is set so that's all good, + # though kinda tight-coupled to the postinstall logic :s + if os.path.exists("/etc/yunohost/installed"): + env["YNH_DOMAINS"] = " ".join(domain_list()["domains"]) pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call, env=env) From cde68cd7ccebc5ae0ebd8c60a35e5389d9164ef4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 23:52:55 +0200 Subject: [PATCH 232/317] Make sure to strip() the path just in case Co-Authored-By: Bram --- src/yunohost/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 37da3a957..a9bcf02fc 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -239,7 +239,7 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path != "" else "/" + perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain, perm_path @@ -1269,7 +1269,7 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path != "" else "/" + perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain + perm_path From 69938c3feb50c2c72d9e7208b8b88c27d6f70174 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 26 Apr 2020 03:43:05 +0200 Subject: [PATCH 233/317] Re-add 'app fetchlist', 'app list -i', 'app list' filter for backward compatibility... --- data/actionsmap/yunohost.yml | 9 +++++++++ src/yunohost/app.py | 24 +++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index e1229352c..d55303d08 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -563,6 +563,9 @@ app: help: Also return a list of app categories action: store_true + fetchlist: + deprecated: true + ### app_list() list: action_help: List installed apps @@ -572,6 +575,12 @@ app: full: --full help: Display all details, including the app manifest and various other infos action: store_true + -i: + full: --installed + help: Dummy argument, does nothing anymore (still there only for backward compatibility) + action: store_true + filter: + nargs: '?' ### app_info() info: diff --git a/src/yunohost/app.py b/src/yunohost/app.py index b94f57502..8dce2ff38 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -110,12 +110,34 @@ def app_catalog(full=False, with_categories=False): return {"apps": catalog["apps"], "categories": catalog["categories"]} -def app_list(full=False): + +# Old legacy function... +def app_fetchlist(): + logger.warning("'yunohost app fetchlist' is deprecated. Please use 'yunohost tools update --apps' instead") + from yunohost.tools import tools_update + tools_update(apps=True) + + +def app_list(full=False, installed=False, filter=None): """ List installed apps """ + + # Old legacy argument ... app_list was a combination of app_list and + # app_catalog before 3.8 ... + if installed: + logger.warning("Argument --installed ain't needed anymore when using 'yunohost app list'. It directly returns the list of installed apps..") + + # Filter is a deprecated option... + if filter: + logger.warning("Using -f $appname in 'yunohost app list' is deprecated. Just use 'yunohost app list | grep -q 'id: $appname' to check a specific app is installed") + out = [] for app_id in sorted(_installed_apps()): + + if filter and not app_id.startswith(filter): + continue + try: app_info_dict = app_info(app_id, full=full) except Exception as e: From 0226ff2fd1f71d82e1e9a6f969f21c09dc464f8c Mon Sep 17 00:00:00 2001 From: xaloc33 Date: Thu, 16 Apr 2020 12:58:13 +0000 Subject: [PATCH 234/317] Translated using Weblate (Catalan) Currently translated at 100.0% (598 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ca/ --- locales/ca.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/locales/ca.json b/locales/ca.json index ff7045d0a..bd071e354 100644 --- a/locales/ca.json +++ b/locales/ca.json @@ -4,7 +4,7 @@ "admin_password_change_failed": "No es pot canviar la contrasenya", "admin_password_changed": "S'ha canviat la contrasenya d'administració", "app_already_installed": "{app:s} ja està instal·lada", - "app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a \"app changeurl\" si està disponible.", + "app_already_installed_cant_change_url": "Aquesta aplicació ja està instal·lada. La URL no és pot canviar únicament amb aquesta funció. Mireu a `app changeurl` si està disponible.", "app_already_up_to_date": "{app:s} ja està actualitzada", "app_argument_choice_invalid": "Utilitzeu una de les opcions «{choices:s}» per l'argument «{name:s}»", "app_argument_invalid": "Escolliu un valor vàlid per l'argument «{name:s}»: {error:s}", @@ -59,7 +59,7 @@ "backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.", "backup_created": "S'ha creat la còpia de seguretat", "aborting": "Avortant.", - "app_not_upgraded": "L'aplicació «{failed_app}» no s'ha pogut actualitzar, i com a conseqüència l'actualització de les següents aplicacions ha estat cancel·lada: {apps}", + "app_not_upgraded": "L'aplicació «{failed_app}» no s'ha pogut actualitzar, i com a conseqüència s'ha cancel·lat l'actualització de les següents aplicacions: {apps}", "app_start_install": "instal·lant l'aplicació «{app}»…", "app_start_remove": "Eliminant l'aplicació «{app}»…", "app_start_backup": "Recuperant els fitxers pels que s'ha de fer una còpia de seguretat per «{app}»…", @@ -167,7 +167,7 @@ "file_does_not_exist": "El camí {path:s} no existeix.", "firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafocs", "firewall_reloaded": "S'ha tornat a carregar el tallafocs", - "firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafocs. Més informació en el registre.", + "firewall_rules_cmd_failed": "Han fallat algunes comandes per aplicar regles del tallafocs. Més informació en el registre.", "global_settings_bad_choice_for_enum": "Opció pel paràmetre {setting:s} incorrecta, s'ha rebut «{choice:s}», però les opcions disponibles són: {available_choices:s}", "global_settings_bad_type_for_setting": "El tipus del paràmetre {setting:s} és incorrecte. S'ha rebut {received_type:s}, però s'esperava {expected_type:s}", "global_settings_cant_open_settings": "No s'ha pogut obrir el fitxer de configuració, raó: {reason:s}", @@ -284,7 +284,7 @@ "migration_0008_root": "• No es podrà connectar com a root a través de SSH. S'haurà d'utilitzar l'usuari admin per fer-ho;", "migration_0008_dsa": "• Es desactivarà la clau DSA. Per tant, es podria haver d'invalidar un missatge esgarrifós del client SSH, i tornar a verificar l'empremta digital del servidor;", "migration_0008_warning": "Si heu entès els avisos i voleu que YunoHost sobreescrigui la configuració actual, comenceu la migració. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", - "migration_0008_no_warning": "Hauria de ser segur sobreescriure la configuració SSH, però no es pot estar del tot segur! Executetu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", + "migration_0008_no_warning": "Hauria de ser segur sobreescriure la configuració SSH, però no es pot estar del tot segur! Executeu la migració per sobreescriure-la. Sinó, podeu saltar-vos la migració, tot i que no està recomanat.", "migration_0009_not_needed": "Sembla que ja s'ha fet aquesta migració… (?) Ometent.", "migrations_cant_reach_migration_file": "No s'ha pogut accedir als fitxers de migració al camí «%s»", "migrations_list_conflict_pending_done": "No es pot utilitzar «--previous» i «--done» al mateix temps.", @@ -596,5 +596,7 @@ "diagnosis_description_web": "Web", "diagnosis_basesystem_hardware_board": "El model de la targeta del servidor és {model}", "diagnosis_basesystem_hardware": "L'arquitectura del maquinari del servidor és {virt} {arch}", - "group_already_exist_on_system_but_removing_it": "El grup {group} ja existeix en els grups del sistema, però YunoHost l'eliminarà…" + "group_already_exist_on_system_but_removing_it": "El grup {group} ja existeix en els grups del sistema, però YunoHost l'eliminarà…", + "certmanager_warning_subdomain_dns_record": "El subdomini «{subdomain:s}» no resol a la mateixa adreça IP que «{domain:s}». Algunes funcions no estaran disponibles fins que no s'hagi arreglat i s'hagi regenerat el certificat.", + "domain_cannot_add_xmpp_upload": "No podeu afegir dominis començant per «xmpp-upload.». Aquest tipus de nom està reservat per a la funció de pujada de XMPP integrada a YunoHost." } From 8fd7456a9be2f069bbf9ea0702023dc7bac16119 Mon Sep 17 00:00:00 2001 From: Zeik0s Date: Wed, 15 Apr 2020 15:38:08 +0000 Subject: [PATCH 235/317] Translated using Weblate (German) Currently translated at 36.1% (216 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/locales/de.json b/locales/de.json index 2369e3bdc..b354f60c5 100644 --- a/locales/de.json +++ b/locales/de.json @@ -15,7 +15,7 @@ "app_removed": "{app:s} wurde entfernt", "app_sources_fetch_failed": "Quelldateien konnten nicht abgerufen werden, ist die URL korrekt?", "app_unknown": "Unbekannte App", - "app_upgrade_failed": "{app:s} konnte nicht aktualisiert werden", + "app_upgrade_failed": "{app:s} konnte nicht aktualisiert werden: {error}", "app_upgraded": "{app:s} aktualisiert", "ask_email": "E-Mail-Adresse", "ask_firstname": "Vorname", @@ -35,7 +35,7 @@ "backup_hook_unknown": "Der Datensicherungshook '{hook:s}' unbekannt", "backup_invalid_archive": "Dies ist kein Backup-Archiv", "backup_nothings_done": "Keine Änderungen zur Speicherung", - "backup_output_directory_forbidden": "Wähle ein anderes Ausgabeverzeichnis. Datensicherung können nicht in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var oder in Unterordnern von /home/yunohost.backup/archives erstellt werden", + "backup_output_directory_forbidden": "Wähle ein anderes Ausgabeverzeichnis. Datensicherungen können nicht in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var oder in Unterordnern von /home/yunohost.backup/archives erstellt werden", "backup_output_directory_not_empty": "Der gewählte Ausgabeordner sollte leer sein", "backup_output_directory_required": "Für die Datensicherung muss ein Zielverzeichnis angegeben werden", "backup_running_hooks": "Datensicherunghook wird ausgeführt…", @@ -213,7 +213,7 @@ "domain_dns_conf_is_just_a_recommendation": "Dieser Befehl zeigt Ihnen, was die * empfohlene * Konfiguration ist. Die DNS-Konfiguration wird NICHT für Sie eingerichtet. Es liegt in Ihrer Verantwortung, Ihre DNS-Zone in Ihrem Registrar gemäß dieser Empfehlung zu konfigurieren.", "dpkg_lock_not_available": "Dieser Befehl kann momentan nicht ausgeführt werden, da anscheinend ein anderes Programm die Sperre von dpkg (dem Systempaket-Manager) verwendet", "confirm_app_install_thirdparty": "WARNUNG! Das Installieren von Anwendungen von Drittanbietern kann die Integrität und Sicherheit Deines Systems beeinträchtigen. Du solltest es wahrscheinlich NICHT installieren, es sei denn, Du weisst, was Du tust. Bist du bereit, dieses Risiko einzugehen? [{answers:s}]", - "confirm_app_install_danger": "WARNUNG! Diese Anwendung ist noch experimentell (wenn nicht ausdrücklich \"not working\"/\"funktioniert nicht\") und es ist wahrscheinlich, dass Dein System Schaden nimmt! Du solltest es wahrscheinlich NICHT installieren, es sei denn, Du weisst, was Du tust. Bist du bereit, dieses Risiko einzugehen? [{answers:s}]", + "confirm_app_install_danger": "WARNUNG! Diese Anwendung ist noch experimentell (wenn nicht ausdrücklich \"not working\"/\"nicht funktionsfähig\")! Du solltest es wahrscheinlich NICHT installieren, es sei denn, du weißt, was du tust. Es wird keine Unterstützung geleistet, falls diese Anwendung nicht funktioniert oder dein System zerstört... Falls du bereit bist, dieses Risiko einzugehen, tippe '{answers:s}'", "confirm_app_install_warning": "Warnung: Diese Anwendung funktioniert möglicherweise, ist jedoch nicht gut in YunoHost integriert. Einige Funktionen wie Single Sign-On und Backup / Restore sind möglicherweise nicht verfügbar. Trotzdem installieren? [{answers:s}] ", "backup_with_no_restore_script_for_app": "Die App {app:s} hat kein Wiederherstellungsskript. Das Backup dieser App kann nicht automatisch wiederhergestellt werden.", "backup_with_no_backup_script_for_app": "Die App {app:s} hat kein Sicherungsskript. Ignoriere es.", @@ -231,7 +231,7 @@ "backup_csv_creation_failed": "Die zur Wiederherstellung erforderliche CSV-Datei kann nicht erstellt werden", "backup_couldnt_bind": "{src:s} konnte nicht an {dest:s} angebunden werden.", "backup_borg_not_implemented": "Die Borg-Sicherungsmethode ist noch nicht implementiert", - "backup_ask_for_copying_if_needed": "Möchten Sie die Sicherung mit {size:s} MB temporär durchführen? (Dieser Weg wird verwendet, da einige Dateien nicht mit einer effizienteren Methode vorbereitet werden konnten).", + "backup_ask_for_copying_if_needed": "Möchten Sie die Sicherung mit {size:s} MB temporär durchführen? (Dieser Weg wird verwendet, da einige Dateien nicht mit einer effizienteren Methode vorbereitet werden konnten.)", "backup_actually_backuping": "Erstellt ein Backup-Archiv aus den gesammelten Dateien …", "ask_new_path": "Neuer Pfad", "ask_new_domain": "Neue Domain", @@ -302,17 +302,40 @@ "app_install_script_failed": "Im Installationsscript ist ein Fehler aufgetreten", "app_remove_after_failed_install": "Entfernen der App nach fehlgeschlagener Installation…", "app_upgrade_script_failed": "Es ist ein Fehler im App-Upgrade-Skript aufgetreten", - "diagnosis_basesystem_host": "Server läuft unter Debian {debian_version}.", + "diagnosis_basesystem_host": "Server läuft unter Debian {debian_version}", "diagnosis_basesystem_kernel": "Server läuft unter Linux-Kernel {kernel_version}", "diagnosis_basesystem_ynh_single_version": "{package} Version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Server läuft YunoHost {main_version} ({repo})", "diagnosis_basesystem_ynh_inconsistent_versions": "Sie verwenden inkonsistente Versionen der YunoHost-Pakete... wahrscheinlich wegen eines fehlgeschlagenen oder teilweisen Upgrades.", "diagnosis_display_tip_web": "Sie können den Abschnitt Diagnose (im Startbildschirm) aufrufen, um die gefundenen Probleme anzuzeigen.", - "apps_catalog_init_success": "Apps-Katalogsystem initialisiert!", - "apps_catalog_updating": "Aktualisierung des Applikationskatalogs...", - "apps_catalog_failed_to_download": "Der {apps_catalog} Apps-Katalog kann nicht heruntergeladen werden: {error}", - "apps_catalog_obsolete_cache": "Der Cache des Apps-Katalogs ist leer oder veraltet.", + "apps_catalog_init_success": "App-Katalogsystem initialisiert!", + "apps_catalog_updating": "Aktualisierung des Applikationskatalogs…", + "apps_catalog_failed_to_download": "Der {apps_catalog} App-Katalog kann nicht heruntergeladen werden: {error}", + "apps_catalog_obsolete_cache": "Der Cache des App-Katalogs ist leer oder veraltet.", "apps_catalog_update_success": "Der Apps-Katalog wurde aktualisiert!", "password_too_simple_1": "Das Passwort muss mindestens 8 Zeichen lang sein", - "diagnosis_display_tip_cli": "Sie können 'yunohost diagnosis show --issues' ausführen, um die gefundenen Probleme anzuzeigen." + "diagnosis_display_tip_cli": "Sie können 'yunohost diagnosis show --issues' ausführen, um die gefundenen Probleme anzuzeigen.", + "diagnosis_everything_ok": "Alles schaut gut aus für {category}!", + "diagnosis_failed": "Kann Diagnose-Ergebnis für die Kategorie '{category}' nicht abrufen: {error}", + "diagnosis_ip_connected_ipv4": "Der Server ist mit dem Internet über IPv4 verbunden!", + "diagnosis_no_cache": "Kein Diagnose Cache aktuell für die Kategorie '{category}'", + "diagnosis_ip_no_ipv4": "Der Server hat kein funktionierendes IPv4.", + "diagnosis_ip_connected_ipv6": "Der Server ist mit dem Internet über IPv6 verbunden!", + "diagnosis_ip_no_ipv6": "Der Server hat kein funktionierendes IPv6.", + "diagnosis_ip_not_connected_at_all": "Der Server scheint überhaupt nicht mit dem Internet verbunden zu sein!?", + "diagnosis_failed_for_category": "Diagnose fehlgeschlagen für die Kategorie '{category}': {error}", + "diagnosis_cache_still_valid": "(Cache noch gültig für {category} Diagnose. Werde keine neue Diagnose durchführen!)", + "diagnosis_cant_run_because_of_dep": "Kann Diagnose für {category} nicht ausführen während wichtige Probleme zu {dep} noch nicht behoben sind.", + "diagnosis_found_errors_and_warnings": "Habe {errors} erhebliche(s) Problem(e) (und {warnings} Warnung(en)) in Verbindung mit {category} gefunden!", + "diagnosis_ip_broken_dnsresolution": "Domänen-Namens-Auflösung scheint aus einem bestimmten Grund nicht zu funktionieren... Blockiert eine Firewall die DNS Anfragen?", + "diagnosis_ip_broken_resolvconf": "Domänen-Namens-Auflösung scheint nicht zu funktionieren, was daran liegen könnte, dass in /etc/resolv.conf kein Eintrag auf 127.0.0.1 zeigt.", + "diagnosis_ip_weird_resolvconf_details": "Stattdessen sollte diese Datei ein Softlink auf /etc/resolvconf/run/resolv.conf sein, die auf sich selbst zu 127.0.0.1 zeigt (dnsmasq). Der eigentlich Auflösende sollte in /etc/resolv.dnsmasq.conf konfiguriert werden.", + "diagnosis_dns_good_conf": "Gute DNS Konfiguration für Domäne {domain} (Kategorie {category})", + "diagnosis_ignored_issues": "(+ {nb_ignored} ignorierte(s) Problem(e))", + "diagnosis_basesystem_hardware": "Server Hardware Architektur ist {virt} {arch}", + "diagnosis_basesystem_hardware_board": "Server Platinen Modell ist {model}", + "diagnosis_found_errors": "Habe {errors} erhebliche(s) Problem(e) in Verbindung mit {category} gefunden!", + "diagnosis_found_warnings": "Habe {warnings} Ding(e) gefunden, die verbessert werden könnten für {category}.", + "diagnosis_ip_dnsresolution_working": "Domänen-Namens-Auflösung funktioniert!", + "diagnosis_ip_weird_resolvconf": "DNS Auflösung scheint zu funktionieren, aber sei vorsichtig wenn du eine eigene /etc/resolv.conf verwendest." } From ced18062562370f9347f930ef2be8876ff8e06e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Wed, 15 Apr 2020 16:45:40 +0000 Subject: [PATCH 236/317] Translated using Weblate (French) Currently translated at 96.2% (575 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 80d9f07dd..ee6aca0a8 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -555,9 +555,8 @@ "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", - "diagnosis_regenconf_manually_modified_details": "C’est probablement OK tant que vous savez ce que vous faites ;) !", + "diagnosis_regenconf_manually_modified_details": "C'est probablement OK tant que vous savez ce que vous faites;) !", "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …", - "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n’a été trouvée.", "apps_catalog_init_success": "Système de catalogue d’applications initialisé !", "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}", "diagnosis_mail_outgoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d’autres serveurs.", From 661735c9d9b59d884469c1e062e4a7e8cfce87a2 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 20 Apr 2020 10:48:16 +0000 Subject: [PATCH 237/317] Translated using Weblate (Esperanto) Currently translated at 90.8% (543 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index f81ea8da6..eb701494d 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -1,6 +1,6 @@ { "admin_password_change_failed": "Ne eblas ŝanĝi pasvorton", - "admin_password_changed": "La pasvorto de administrado ŝanĝiĝis", + "admin_password_changed": "La pasvorto de administrado estis ŝanĝita", "app_already_installed": "{app:s} estas jam instalita", "app_already_up_to_date": "{app:s} estas jam ĝisdata", "app_argument_required": "Parametro {name:s} estas bezonata", @@ -81,7 +81,7 @@ "backup_archive_name_exists": "Rezerva arkivo kun ĉi tiu nomo jam ekzistas.", "backup_applying_method_tar": "Krei la rezervan TAR-ar archiveivon …", "backup_method_custom_finished": "Propra rezerva metodo '{method:s}' finiĝis", - "app_already_installed_cant_change_url": "Ĉi tiu app estas jam instalita. La URL ne povas esti ŝanĝita nur per ĉi tiu funkcio. Rigardu \"app changeurl\" se ĝi haveblas.", + "app_already_installed_cant_change_url": "Ĉi tiu app estas jam instalita. La URL ne povas esti ŝanĝita nur per ĉi tiu funkcio. Kontrolu en `app changeurl` se ĝi haveblas.", "app_not_correctly_installed": "{app:s} ŝajnas esti malĝuste instalita", "app_removed": "{app:s} forigita", "backup_delete_error": "Ne povis forigi '{path:s}'", From 220c62ab4c18e1a66546a9d3af8aebf5ea1c0da8 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 20 Apr 2020 09:54:48 +0000 Subject: [PATCH 238/317] Translated using Weblate (Spanish) Currently translated at 100.0% (598 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/es/ --- locales/es.json | 89 +++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/locales/es.json b/locales/es.json index 15b4b5316..f76d722e6 100644 --- a/locales/es.json +++ b/locales/es.json @@ -2,7 +2,7 @@ "action_invalid": "Acción no válida '{action:s} 1'", "admin_password": "Contraseña administrativa", "admin_password_change_failed": "No se puede cambiar la contraseña", - "admin_password_changed": "La contraseña de administración ha sido cambiada", + "admin_password_changed": "La contraseña de administración fue cambiada", "app_already_installed": "{app:s} ya está instalada", "app_argument_choice_invalid": "Use una de estas opciones «{choices:s}» para el argumento «{name:s}»", "app_argument_invalid": "Elija un valor válido para el argumento «{name:s}»: {error:s}", @@ -41,16 +41,16 @@ "backup_hook_unknown": "El gancho «{hook:s}» de la copia de seguridad es desconocido", "backup_invalid_archive": "Esto no es un archivo de respaldo", "backup_nothings_done": "Nada que guardar", - "backup_output_directory_forbidden": "Elija un directorio de salida diferente. No se pueden crear copias de seguridad en las subcarpetas de /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o /home/yunohost.backup/archives", + "backup_output_directory_forbidden": "Elija un directorio de salida diferente. Las copias de seguridad no se pueden crear en /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o /home/yunohost.backup/archives subcarpetas", "backup_output_directory_not_empty": "Debe elegir un directorio de salida vacío", "backup_output_directory_required": "Debe proporcionar un directorio de salida para la copia de seguridad", "backup_running_hooks": "Ejecutando los hooks de copia de seguridad...", "custom_app_url_required": "Debe proporcionar una URL para actualizar su aplicación personalizada {app:s}", "domain_cert_gen_failed": "No se pudo generar el certificado", "domain_created": "Dominio creado", - "domain_creation_failed": "No se pudo crear el dominio {domain}: {error}", + "domain_creation_failed": "No se puede crear el dominio {domain}: {error}", "domain_deleted": "Dominio eliminado", - "domain_deletion_failed": "No se pudo eliminar el dominio {domain}: {error}", + "domain_deletion_failed": "No se puede eliminar el dominio {domain}: {error}", "domain_dyndns_already_subscribed": "Ya se ha suscrito a un dominio de DynDNS", "domain_dyndns_root_unknown": "Dominio raíz de DynDNS desconocido", "domain_exists": "El dominio ya existe", @@ -117,20 +117,20 @@ "restore_running_app_script": "Restaurando la aplicación «{app:s}»…", "restore_running_hooks": "Ejecutando los ganchos de restauración…", "service_add_failed": "No se pudo añadir el servicio «{service:s}»", - "service_added": "Añadido el servicio «{service:s}»", + "service_added": "Se agregó el servicio '{service:s}'", "service_already_started": "El servicio «{service:s}» ya está funcionando", "service_already_stopped": "El servicio «{service:s}» ya ha sido detenido", "service_cmd_exec_failed": "No se pudo ejecutar la orden «{command:s}»", - "service_disable_failed": "No se pudo desactivar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_disabled": "El servicio «{service:s}» ha sido desactivado", - "service_enable_failed": "No se pudo activar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_enabled": "El servicio «{service:s}» ha sido desactivado", + "service_disable_failed": "No se pudo hacer que el servicio '{service:s}' no se iniciara en el arranque.\n\nRegistros de servicio recientes: {logs:s}", + "service_disabled": "El servicio '{service:s}' ya no se iniciará cuando se inicie el sistema.", + "service_enable_failed": "No se pudo hacer que el servicio '{service:s}' se inicie automáticamente en el arranque.\n\nRegistros de servicio recientes: {logs s}", + "service_enabled": "El servicio '{service:s}' ahora se iniciará automáticamente durante el arranque del sistema.", "service_remove_failed": "No se pudo eliminar el servicio «{service:s}»", - "service_removed": "Eliminado el servicio «{service:s}»", + "service_removed": "Servicio '{service:s}' eliminado", "service_start_failed": "No se pudo iniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_started": "Iniciado el servicio «{service:s}»", + "service_started": "El servicio '{service:s}' comenzó", "service_stop_failed": "No se pudo detener el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_stopped": "El servicio «{service:s}» se detuvo", + "service_stopped": "Servicio '{service:s}' detenido", "service_unknown": "Servicio desconocido '{service:s}'", "ssowat_conf_generated": "Generada la configuración de SSOwat", "ssowat_conf_updated": "Actualizada la configuración de SSOwat", @@ -161,7 +161,7 @@ "yunohost_installing": "Instalando YunoHost…", "yunohost_not_installed": "YunoHost no está correctamente instalado. Ejecute «yunohost tools postinstall»", "ldap_init_failed_to_create_admin": "La inicialización de LDAP no pudo crear el usuario «admin»", - "mailbox_used_space_dovecot_down": "El servicio de correo Dovecot debe estar funcionando si desea obtener el espacio usado por el buzón de correo", + "mailbox_used_space_dovecot_down": "El servicio de buzón Dovecot debe estar activo si desea recuperar el espacio usado del buzón", "certmanager_attempt_to_replace_valid_cert": "Está intentando sobrescribir un certificado correcto y válido para el dominio {domain:s}! (Use --force para omitir este mensaje)", "certmanager_domain_unknown": "Dominio desconocido «{domain:s}»", "certmanager_domain_cert_not_selfsigned": "El certificado para el dominio {domain:s} no es un certificado autofirmado. ¿Está seguro de que quiere reemplazarlo? (Use «--force» para hacerlo)", @@ -170,7 +170,7 @@ "certmanager_attempt_to_renew_valid_cert": "¡El certificado para el dominio «{domain:s}» no está a punto de expirar! (Puede usar --force si sabe lo que está haciendo)", "certmanager_domain_http_not_working": "Parece que no se puede acceder al dominio {domain:s} a través de HTTP. Compruebe que la configuración del DNS y de NGINX es correcta", "certmanager_error_no_A_record": "No se ha encontrado un registro DNS «A» para el dominio {domain:s}. Debe hacer que su nombre de dominio apunte a su máquina para poder instalar un certificado de Let's Encrypt. (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)", - "certmanager_domain_dns_ip_differs_from_public_ip": "El registro «A» del DNS para el dominio «{domain:s}» es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (existen algunos verificadores de propagación de DNS disponibles en línea). (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)", + "certmanager_domain_dns_ip_differs_from_public_ip": "El registro DNS 'A' para el dominio '{dominio:s}' es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (algunos verificadores de propagación de DNS están disponibles en línea). (Si sabe lo que está haciendo, use '--no-checks' para desactivar esos cheques)", "certmanager_cannot_read_cert": "Se ha producido un error al intentar abrir el certificado actual para el dominio {domain:s} (archivo: {file:s}), razón: {reason:s}", "certmanager_cert_install_success_selfsigned": "Instalado correctamente un certificado autofirmado para el dominio «{domain:s}»", "certmanager_cert_install_success": "Instalado correctamente un certificado de Let's Encrypt para el dominio «{domain:s}»", @@ -179,7 +179,7 @@ "certmanager_cert_signing_failed": "No se pudo firmar el nuevo certificado", "certmanager_no_cert_file": "No se pudo leer el certificado para el dominio {domain:s} (archivo: {file:s})", "certmanager_conflicting_nginx_file": "No se pudo preparar el dominio para el desafío ACME: el archivo de configuración de NGINX {filepath:s} está en conflicto y debe ser eliminado primero", - "domain_cannot_remove_main": "No se puede eliminar el dominio principal. Primero debes configurar otro utilizando la linea de comando 'yunohost domain main-domain -n ' donde es parte de esta lista: {other_domains:s}", + "domain_cannot_remove_main": "No puede eliminar '{domain:s}' ya que es el dominio principal, primero debe configurar otro dominio como el dominio principal usando 'yunohost domain main-domain -n '; Aquí está la lista de dominios candidatos: {other_domains:s}", "certmanager_self_ca_conf_file_not_found": "No se pudo encontrar el archivo de configuración para la autoridad de autofirma (archivo: {file:s})", "certmanager_unable_to_parse_self_CA_name": "No se pudo procesar el nombre de la autoridad de autofirma (archivo: {file:s})", "domains_available": "Dominios disponibles:", @@ -189,7 +189,7 @@ "certmanager_couldnt_fetch_intermediate_cert": "Tiempo de espera agotado intentando obtener el certificado intermedio de Let's Encrypt. Cancelada la instalación o renovación del certificado. Vuelva a intentarlo más tarde.", "domain_hostname_failed": "No se pudo establecer un nuevo nombre de anfitrión («hostname»). Esto podría causar problemas más tarde (no es seguro... podría ir bien).", "yunohost_ca_creation_success": "Creada la autoridad de certificación local.", - "app_already_installed_cant_change_url": "Esta aplicación ya está instalada. No se puede cambiar el URL únicamente mediante esta función. Compruebe si está disponible la opción `app changeurl`.", + "app_already_installed_cant_change_url": "Esta aplicación ya está instalada. La URL no se puede cambiar solo con esta función. Marque `app changeurl` si está disponible.", "app_change_url_failed_nginx_reload": "No se pudo recargar NGINX. Esta es la salida de «nginx -t»:\n{nginx_errors:s}", "app_change_url_identical_domains": "El antiguo y nuevo dominio/url_path son idénticos ('{domain:s} {path:s}'), no se realizarán cambios.", "app_change_url_no_script": "La aplicación «{app_name:s}» aún no permite la modificación de URLs. Quizás debería actualizarla.", @@ -222,8 +222,8 @@ "dyndns_could_not_check_provide": "No se pudo verificar si {provider:s} puede ofrecer {domain:s}.", "dyndns_domain_not_provided": "El proveedor de DynDNS {provider:s} no puede proporcionar el dominio {domain:s}.", "experimental_feature": "Aviso : esta funcionalidad es experimental y no se considera estable, no debería usarla a menos que sepa lo que está haciendo.", - "good_practices_about_user_password": "Está a punto de establecer una nueva contraseña de usuario. La contraseña debería de ser de al menos 8 caracteres, aunque es una buena práctica usar una contraseña más extensa (básicamente una frase) y/o usar caracteres de varias clases (mayúsculas, minúsculas, números y caracteres especiales).", - "password_listed": "Esta contraseña es una de las más usadas en el mundo. Elija algo más único.", + "good_practices_about_user_password": "Ahora está a punto de definir una nueva contraseña de usuario. La contraseña debe tener al menos 8 caracteres, aunque es una buena práctica usar una contraseña más larga (es decir, una frase de contraseña) y / o una variación de caracteres (mayúsculas, minúsculas, dígitos y caracteres especiales).", + "password_listed": "Esta contraseña se encuentra entre las contraseñas más utilizadas en el mundo. Por favor, elija algo más único.", "password_too_simple_1": "La contraseña debe tener al menos 8 caracteres de longitud", "password_too_simple_2": "La contraseña tiene que ser de al menos 8 caracteres de longitud e incluir un número y caracteres en mayúsculas y minúsculas", "password_too_simple_3": "La contraseña tiene que ser de al menos 8 caracteres de longitud e incluir un número, mayúsculas, minúsculas y caracteres especiales", @@ -232,7 +232,7 @@ "update_apt_cache_warning": "Algo fue mal durante la actualización de la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}", "update_apt_cache_failed": "No se pudo actualizar la caché de APT (gestor de paquetes de Debian). Aquí tiene un volcado de las líneas de sources.list que podría ayudarle a identificar las líneas problemáticas:\n{sourceslist}", "tools_upgrade_special_packages_completed": "Actualización de paquetes de YunoHost completada.\nPulse [Intro] para regresar a la línea de órdenes", - "tools_upgrade_special_packages_explanation": "Esta acción terminará pero la actualización especial real continuará en segundo plano. No inicie ninguna otra acción en su servidor en aproximadamente 10 minutos (dependiendo de la velocidad de su hardware). Una vez hecho, podría tener que volver a iniciar sesión en la administración web. El registro de actualización estará disponible en Herramientas → Registro (en la página de administración web) o mediante «yunohost log list» (desde la línea de órdenes).", + "tools_upgrade_special_packages_explanation": "La actualización especial continuará en segundo plano. No inicie ninguna otra acción en su servidor durante los próximos 10 minutos (dependiendo de la velocidad del hardware). Después de esto, es posible que deba volver a iniciar sesión en el administrador web. El registro de actualización estará disponible en Herramientas → Registro (en el webadmin) o usando 'yunohost log list' (desde la línea de comandos).", "tools_upgrade_special_packages": "Actualizando ahora paquetes «especiales» (relacionados con YunoHost)…", "tools_upgrade_regular_packages_failed": "No se pudieron actualizar los paquetes: {packages_list}", "tools_upgrade_regular_packages": "Actualizando ahora paquetes «normales» (no relacionados con YunoHost)…", @@ -241,11 +241,11 @@ "tools_upgrade_cant_both": "No se puede actualizar el sistema y las aplicaciones al mismo tiempo", "tools_upgrade_at_least_one": "Especifique «--apps», o «--system»", "this_action_broke_dpkg": "Esta acción rompió dpkg/APT(los gestores de paquetes del sistema)… Puede tratar de solucionar este problema conectando mediante SSH y ejecutando `sudo dpkg --configure -a`.", - "service_reloaded_or_restarted": "El servicio «{service:s}» ha sido recargado o reiniciado", + "service_reloaded_or_restarted": "El servicio '{service:s}' fue recargado o reiniciado", "service_reload_or_restart_failed": "No se pudo recargar o reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_restarted": "Reiniciado el servicio «{service:s}»", + "service_restarted": "Servicio '{service:s}' reiniciado", "service_restart_failed": "No se pudo reiniciar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", - "service_reloaded": "El servicio «{service:s}» ha sido recargado", + "service_reloaded": "Servicio '{service:s}' recargado", "service_reload_failed": "No se pudo recargar el servicio «{service:s}»\n\nRegistro de servicios recientes:{logs:s}", "service_regen_conf_is_deprecated": "¡«yunohost service regen-conf» está obsoleto! Use «yunohost tools regen-conf» en su lugar.", "service_description_yunohost-firewall": "Gestiona los puertos de conexiones abiertos y cerrados a los servicios", @@ -280,7 +280,7 @@ "regenconf_failed": "No se pudo regenerar la configuración para la(s) categoría(s): {categories}", "regenconf_dry_pending_applying": "Comprobando la configuración pendiente que habría sido aplicada para la categoría «{category}»…", "regenconf_would_be_updated": "La configuración habría sido actualizada para la categoría «{category}»", - "regenconf_updated": "Actualizada la configuración para la categoría '{category}'", + "regenconf_updated": "Configuración actualizada para '{category}'", "regenconf_up_to_date": "Ya está actualizada la configuración para la categoría «{category}»", "regenconf_now_managed_by_yunohost": "El archivo de configuración «{conf}» está gestionado ahora por YunoHost (categoría {category}).", "regenconf_file_updated": "Actualizado el archivo de configuración «{conf}»", @@ -345,7 +345,7 @@ "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 está instalado pero no PostgreSQL 9.6. Algo raro podría haber ocurrido en su sistema:(…", "migration_0005_postgresql_94_not_installed": "PostgreSQL no estaba instalado en su sistema. Nada que hacer.", "migration_0003_modified_files": "Tenga en cuenta que se encontró que los siguientes archivos fueron modificados manualmente y podrían ser sobrescritos después de la actualización: {manually_modified_files}", - "migration_0003_problematic_apps_warning": "Tenga en cuenta que las aplicaciones listadas mas abajo fueron detectadas como 'posiblemente problemáticas'. Parece que no fueron instaladas desde una lista de aplicaciones o no estaban etiquetadas como 'funcional'. Así que no hay garantía de que aún funcionen después de la actualización: {problematic_apps}", + "migration_0003_problematic_apps_warning": "Tenga en cuenta que se detectaron las siguientes aplicaciones instaladas posiblemente problemáticas. Parece que no se instalaron desde un catálogo de aplicaciones, o no se marcan como \"en funcionamiento\". En consecuencia, no se puede garantizar que seguirán funcionando después de la actualización: {problematic_apps}", "migration_0003_general_warning": "Tenga en cuenta que esta migración es una operación delicada. El equipo de YunoHost ha hecho todo lo posible para revisarla y probarla, pero la migración aún podría romper parte del sistema o de sus aplicaciones.\n\nPor lo tanto, se recomienda que:\n - Realice una copia de seguridad de cualquier dato crítico o aplicación. Más información en https://yunohost.org/backup;\n - Tenga paciencia tras iniciar la migración: dependiendo de su conexión a Internet y de su hardware, podría tardar unas cuantas horas hasta que todo se actualice.\n\nAdemás, el puerto para SMTP usado por los clientes de correo externos (como Thunderbird o K9-Mail) cambió de 465 (SSL/TLS) a 587 (STARTTLS). El antiguo puerto (465) se cerrará automáticamente y el nuevo puerto (587) se abrirá en el cortafuegos. Todos los usuarios *tendrán* que adaptar la configuración de sus clientes de correo por lo tanto.", "migration_0003_still_on_jessie_after_main_upgrade": "Algo fue mal durante la actualización principal: ⸘el sistema está aún en Jessie‽ Para investigar el problema, vea {log}:s…", "migration_0003_system_not_fully_up_to_date": "Su sistema no está totalmente actualizado. Realice una actualización normal antes de ejecutar la migración a Stretch.", @@ -358,7 +358,7 @@ "migration_0003_start": "Iniciando migración a Stretch. El registro estará disponible en {logfile}.", "migration_description_0012_postgresql_password_to_md5_authentication": "Forzar a la autentificación de PostgreSQL a usar MD5 para las conexiones locales", "migration_description_0011_setup_group_permission": "Configurar grupo de usuario y permisos para aplicaciones y servicios", - "migration_description_0010_migrate_to_apps_json": "Eliminar las listas de aplicaciones («appslists») obsoletas y usar en su lugar la nueva lista unificada «apps.json»", + "migration_description_0010_migrate_to_apps_json": "Elimine los catálogos de aplicaciones obsoletas y use la nueva lista unificada de 'apps.json' en su lugar (desactualizada, reemplazada por la migración 13)", "migration_description_0009_decouple_regenconf_from_services": "Separar el mecanismo «regen-conf» de los servicios", "migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Permitir que la configuración de SSH la gestione YunoHost (paso 2, manual)", "migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Permitir que la configuración de SSH la gestione YunoHost (paso 1, automático)", @@ -422,7 +422,7 @@ "group_deleted": "Eliminado el grupo «{group}»", "group_creation_failed": "No se pudo crear el grupo «{group}»: {error}", "group_created": "Creado el grupo «{group}»", - "good_practices_about_admin_password": "Va a establecer una nueva contraseña de administración. La contraseña debería tener al menos 8 caracteres, aunque es una buena práctica usar una contraseña más extensa (básicamente una frase) y/o usar caracteres de varias clases (mayúsculas, minúsculas, números y caracteres especiales).", + "good_practices_about_admin_password": "Ahora está a punto de definir una nueva contraseña de administración. La contraseña debe tener al menos 8 caracteres, aunque es una buena práctica usar una contraseña más larga (es decir, una frase de contraseña) y / o usar una variación de caracteres (mayúsculas, minúsculas, dígitos y caracteres especiales).", "global_settings_unknown_type": "Situación imprevista, la configuración {setting:s} parece tener el tipo {unknown_type:s} pero no es un tipo compatible con el sistema.", "global_settings_setting_service_ssh_allow_deprecated_dsa_hostkey": "Permitir el uso de la llave (obsoleta) DSA para la configuración del demonio SSH", "global_settings_unknown_setting_from_settings_file": "Clave desconocida en la configuración: «{setting_key:s}», desechada y guardada en /etc/yunohost/settings-unknown.json", @@ -447,8 +447,8 @@ "domain_dns_conf_is_just_a_recommendation": "Esta orden muestra la configuración *recomendada*. No configura el DNS en realidad. Es su responsabilidad configurar la zona de DNS en su registrador según esta recomendación.", "dpkg_lock_not_available": "Esta orden no se puede ejecutar en este momento ,parece que programa está usando el bloqueo de dpkg (el gestor de paquetes del sistema)", "dpkg_is_broken": "No puede hacer esto en este momento porque dpkg/apt (los gestores de paquetes del sistema) parecen estar en un estado roto... Puede tratar de solucionar este problema conectando a través de SSH y ejecutando `sudo dpkg --configure -a`.", - "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de YunoHost. Instalar aplicaciones de terceros podría comprometer la integridad y seguridad de su sistema. Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", - "confirm_app_install_danger": "¡PELIGRO! ¡Esta aplicación es conocida por ser aún experimental (o no funciona explícitamente)! Probablemente NO debería instalarla salvo que sepa lo que está haciendo. No tendrá NINGUNA AYUDA si esta aplicación no funciona o rompe su sistema… Si está dispuesto a aceptar ese riesgo de todas formas, escriba «{answers:s}»", + "confirm_app_install_thirdparty": "¡PELIGRO! Esta aplicación no forma parte del catálogo de aplicaciones de Yunohost. La instalación de aplicaciones de terceros puede comprometer la integridad y la seguridad de su sistema. Probablemente NO debería instalarlo a menos que sepa lo que está haciendo. NO se proporcionará SOPORTE si esta aplicación no funciona o rompe su sistema ... Si de todos modos está dispuesto a correr ese riesgo, escriba '{answers:s}'", + "confirm_app_install_danger": "¡PELIGRO! ¡Se sabe que esta aplicación sigue siendo experimental (si no explícitamente no funciona)! Probablemente NO debería instalarlo a menos que sepa lo que está haciendo. NO se proporcionará SOPORTE si esta aplicación no funciona o rompe su sistema ... Si de todos modos está dispuesto a correr ese riesgo, escriba '{answers:s}'", "confirm_app_install_warning": "Aviso: esta aplicación puede funcionar pero no está bien integrada en YunoHost. Algunas herramientas como la autentificación única y respaldo/restauración podrían no estar disponibles. ¿Instalar de todos modos? [{answers:s}] ", "backup_unable_to_organize_files": "No se pudo usar el método rápido de organización de los archivos en el archivo", "backup_permission": "Permiso de respaldo para la aplicación {app:s}", @@ -467,13 +467,13 @@ "app_start_backup": "Obteniendo archivos para el respaldo de «{app}»…", "app_start_remove": "Eliminando aplicación «{app}»…", "app_start_install": "Instalando aplicación «{app}»…", - "app_not_upgraded": "Error al actualizar la aplicación «{failed_app}» y como consecuencia se han cancelado las actualizaciones de las siguientes aplicaciones: {apps}", + "app_not_upgraded": "La aplicación '{failed_app}' no se pudo actualizar y, como consecuencia, se cancelaron las actualizaciones de las siguientes aplicaciones: {apps}", "app_action_cannot_be_ran_because_required_services_down": "Estos servicios necesarios deberían estar funcionando para ejecutar esta acción: {services}. Pruebe a reiniciarlos para continuar (y posiblemente investigar por qué están caídos).", "already_up_to_date": "Nada que hacer. Todo está actualizado.", "admin_password_too_long": "Elija una contraseña de menos de 127 caracteres", "aborting": "Cancelando.", "app_action_broke_system": "Esta acción parece que ha roto estos servicios importantes: {services}", - "operation_interrupted": "¿Ha sido interrumpida la operación manualmente?", + "operation_interrupted": "¿La operación fue interrumpida manualmente?", "apps_already_up_to_date": "Todas las aplicaciones están ya actualizadas", "dyndns_provider_unreachable": "No se puede conectar con el proveedor de Dyndns {provider}: o su YunoHost no está correctamente conectado a Internet o el servidor dynette está caído.", "group_already_exist": "El grupo {group} ya existe", @@ -488,7 +488,7 @@ "log_user_permission_reset": "Restablecer permiso «{}»", "migration_0011_failed_to_remove_stale_object": "No se pudo eliminar el objeto obsoleto {dn}: {error}", "permission_already_allowed": "El grupo «{group}» ya tiene el permiso «{permission}» activado", - "permission_already_disallowed": "El grupo «{group}» ya tiene el permiso «{permission}» desactivado", + "permission_already_disallowed": "El grupo '{group}' ya tiene el permiso '{permission}' deshabilitado", "permission_cannot_remove_main": "No está permitido eliminar un permiso principal", "user_already_exists": "El usuario «{user}» ya existe", "app_full_domain_unavailable": "Lamentablemente esta aplicación tiene que instalarse en un dominio propio pero ya hay otras aplicaciones instaladas en el dominio «{domain}». Podría usar un subdomino dedicado a esta aplicación en su lugar.", @@ -503,20 +503,20 @@ "permission_currently_allowed_for_all_users": "Este permiso se concede actualmente a todos los usuarios además de los otros grupos. Probablemente quiere o eliminar el permiso de «all_users» o eliminar los otros grupos a los que está otorgado actualmente.", "permission_require_account": "El permiso {permission} solo tiene sentido para usuarios con una cuenta y, por lo tanto, no se puede activar para visitantes.", "app_remove_after_failed_install": "Eliminando la aplicación tras el fallo de instalación…", - "diagnosis_basesystem_host": "El servidor está ejecutando Debian {debian_version}.", + "diagnosis_basesystem_host": "El servidor está ejecutando Debian {debian_version}", "diagnosis_basesystem_kernel": "El servidor está ejecutando el núcleo de Linux {kernel_version}", "diagnosis_basesystem_ynh_single_version": "{package} versión: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "El servidor está ejecutando YunoHost {main_version} ({repo})", - "diagnosis_basesystem_ynh_inconsistent_versions": "Está ejecutando versiones incoherentes de los paquetes de YunoHost... probablemente por una actualización errónea o parcial.", - "diagnosis_failed_for_category": "Diagnóstico fallido para la categoría «{category}» : {error}", + "diagnosis_basesystem_ynh_inconsistent_versions": "Está ejecutando versiones inconsistentes de los paquetes de YunoHost ... probablemente debido a una actualización parcial o fallida.", + "diagnosis_failed_for_category": "Error de diagnóstico para la categoría '{category}': {error}", "diagnosis_cache_still_valid": "(Caché aún válida para el diagnóstico de {category}. ¡Aún no se ha rediagnosticado!)", "diagnosis_found_errors_and_warnings": "¡Encontrado(s) error(es) significativo(s) {errors} (y aviso(s) {warnings}) relacionado(s) con {category}!", "diagnosis_display_tip_web": "Puede ir a la sección de diagnóstico (en la pantalla principal) para ver los problemas encontrados.", "diagnosis_display_tip_cli": "Puede ejecutar «yunohost diagnosis show --issues» para mostrar los problemas encontrados.", "apps_catalog_init_success": "¡Sistema de catálogo de aplicaciones inicializado!", - "apps_catalog_updating": "Actualizando catálogo de aplicaciones...", - "apps_catalog_failed_to_download": "No se pudo descargar el catálogo de aplicaciones {apps_catalog}: {error}", - "apps_catalog_obsolete_cache": "La caché del catálogo de aplicaciones está vacía u obsoleta.", + "apps_catalog_updating": "Actualizando el catálogo de aplicaciones…", + "apps_catalog_failed_to_download": "No se puede descargar el catálogo de aplicaciones {apps_catalog}: {error}", + "apps_catalog_obsolete_cache": "El caché del catálogo de aplicaciones está vacío u obsoleto.", "apps_catalog_update_success": "¡El catálogo de aplicaciones ha sido actualizado!", "diagnosis_cant_run_because_of_dep": "No se puede ejecutar el diagnóstico para {category} mientras haya problemas importantes relacionados con {dep}.", "diagnosis_ignored_issues": "(+ {nb_ignored} problema(s) ignorado(s))", @@ -545,9 +545,9 @@ "diagnosis_diskusage_ok": "¡El almacenamiento {mountpoint} (en el dispositivo {device}) todavía tiene {free} ({free_percent}%) de espacio libre!", "diagnosis_services_conf_broken": "¡Mala configuración para el servicio {service}!", "diagnosis_services_running": "¡El servicio {service} está en ejecución!", - "diagnosis_failed": "No se ha podido obtener el resultado del diagnóstico para la categoría '{category}': {error}", + "diagnosis_failed": "Error al obtener el resultado del diagnóstico para la categoría '{category}': {error}", "diagnosis_ip_connected_ipv4": "¡El servidor está conectado a internet a través de IPv4!", - "diagnosis_security_vulnerable_to_meltdown_details": "Para corregir esto, debieras actualizar y reiniciar tu sistema para cargar el nuevo kernel de Linux (o contacta tu proveedor si esto no funciona). Mas información en https://meltdownattack.com/", + "diagnosis_security_vulnerable_to_meltdown_details": "Para corregir esto, debieras actualizar y reiniciar tu sistema para cargar el nuevo kernel de Linux (o contacta tu proveedor si esto no funciona). Mas información en https://meltdownattack.com/ .", "diagnosis_ram_verylow": "Al sistema le queda solamente {available} ({available_percent}%) de RAM! (De un total de {total})", "diagnosis_ram_low": "Al sistema le queda {available} ({available_percent}%) de RAM de un total de {total}. Cuidado.", "diagnosis_ram_ok": "El sistema aun tiene {available} ({available_percent}%) de RAM de un total de {total}.", @@ -561,7 +561,7 @@ "diagnosis_regenconf_manually_modified_debian": "El archivos de configuración {file} fue modificado manualmente comparado con el valor predeterminado de Debian.", "diagnosis_regenconf_manually_modified_debian_details": "Esto este probablemente BIEN, pero igual no lo pierdas de vista...", "diagnosis_security_all_good": "Ninguna vulnerabilidad critica de seguridad fue encontrada.", - "diagnosis_security_vulnerable_to_meltdown": "Pareces vulnerable a el colapso de vulnerabilidad critica de seguridad.", + "diagnosis_security_vulnerable_to_meltdown": "Pareces vulnerable a el colapso de vulnerabilidad critica de seguridad", "diagnosis_description_basesystem": "Sistema de base", "diagnosis_description_ip": "Conectividad a Internet", "diagnosis_description_dnsrecords": "Registro DNS", @@ -588,15 +588,18 @@ "log_app_action_run": "Inicializa la acción de la aplicación '{}'", "group_already_exist_on_system_but_removing_it": "El grupo {group} ya existe en el grupo de sistema, pero YunoHost lo suprimirá …", "global_settings_setting_pop3_enabled": "Habilita el protocolo POP3 para el servidor de correo electrónico", - "domain_cannot_remove_main_add_new_one": "No se puede remover '{domain:s}' porque es su principal y único dominio. Primero debe agregar un nuevo dominio con la linea de comando 'yunohost domain add ', entonces configurarlo como dominio principal con 'yunohost domain main-domain -n ' y finalmente borrar el dominio '{domain:s}' con 'yunohost domain remove {domain:s}'.", + "domain_cannot_remove_main_add_new_one": "No se puede remover '{domain:s}' porque es su principal y único dominio. Primero debe agregar un nuevo dominio con la linea de comando 'yunohost domain add ', entonces configurarlo como dominio principal con 'yunohost domain main-domain -n ' y finalmente borrar el dominio '{domain:s}' con 'yunohost domain remove {domain:s}'.'", "diagnosis_never_ran_yet": "Este servidor todavía no tiene reportes de diagnostico. Puede iniciar un diagnostico completo desde la interface administrador web o con la linea de comando 'yunohost diagnosis run'.", "diagnosis_unknown_categories": "Las siguientes categorías están desconocidas: {categories}", "diagnosis_http_unreachable": "El dominio {domain} esta fuera de alcance desde internet y a través de HTTP.", "diagnosis_http_bad_status_code": "El sistema de diagnostico no pudo comunicarse con su servidor. Puede ser otra maquina que contesto en lugar del servidor. Debería verificar en su firewall que el re-direccionamiento del puerto 80 esta correcto.", - "diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado,", + "diagnosis_http_connection_error": "Error de conexión: Ne se pudo conectar al dominio solicitado.", "diagnosis_http_timeout": "El intento de contactar a su servidor desde internet corrió fuera de tiempo. Al parece esta incomunicado. Debería verificar que nginx corre en el puerto 80, y que la redireción del puerto 80 no interfiere con en el firewall.", "diagnosis_http_ok": "El Dominio {domain} es accesible desde internet a través de HTTP.", "diagnosis_http_could_not_diagnose": "No se pudo verificar si el dominio es accesible desde internet.", "diagnosis_http_could_not_diagnose_details": "Error: {error}", - "diagnosis_ports_forwarding_tip": "Para solucionar este incidente, debería configurar el \"port forwading\" en su router como especificado en https://yunohost.org/isp_box_config" + "diagnosis_ports_forwarding_tip": "Para solucionar este incidente, debería configurar el \"port forwading\" en su router como especificado en https://yunohost.org/isp_box_config", + "certmanager_warning_subdomain_dns_record": "El subdominio '{subdomain:s}' no se resuelve en la misma dirección IP que '{domain:s}'. Algunas funciones no estarán disponibles hasta que solucione esto y regenere el certificado.", + "domain_cannot_add_xmpp_upload": "No puede agregar dominios que comiencen con 'xmpp-upload'. Este tipo de nombre está reservado para la función de carga XMPP integrada en YunoHost.", + "yunohost_postinstall_end_tip": "¡La post-instalación completada! Para finalizar su configuración, considere:\n - agregar un primer usuario a través de la sección 'Usuarios' del webadmin (o 'yunohost user create ' en la línea de comandos);\n - diagnostique problemas potenciales a través de la sección 'Diagnóstico' de webadmin (o 'ejecución de diagnóstico yunohost' en la línea de comandos);\n - leyendo las partes 'Finalizando su configuración' y 'Conociendo a Yunohost' en la documentación del administrador: https://yunohost.org/admindoc." } From 48329bee03211ef58ceed115e49bec0fe0b646dd Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 20 Apr 2020 07:59:36 +0000 Subject: [PATCH 239/317] Translated using Weblate (French) Currently translated at 100.0% (598 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 53 ++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index ee6aca0a8..7b31f9237 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -41,7 +41,7 @@ "backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu", "backup_invalid_archive": "Archive de sauvegarde invalide", "backup_nothings_done": "Il n’y a rien à sauvegarder", - "backup_output_directory_forbidden": "Dossier de destination interdit. Les sauvegardes ne peuvent être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", + "backup_output_directory_forbidden": "Choisissez un répertoire de sortie différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", "backup_output_directory_not_empty": "Le répertoire de destination n’est pas vide", "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde", "backup_running_hooks": "Exécution des scripts de sauvegarde …", @@ -75,7 +75,7 @@ "field_invalid": "Champ incorrect : '{:s}'", "firewall_reload_failed": "Impossible de recharger le pare-feu", "firewall_reloaded": "Pare-feu rechargé", - "firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Plus d’info dans le journal de log.", + "firewall_rules_cmd_failed": "Certaines commandes de règles de pare-feu ont échoué. Plus d'informations dans le journal.", "hook_exec_failed": "Échec de l’exécution du script : {path:s}", "hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement", "hook_list_by_invalid": "Propriété invalide pour lister les actions par celle-ci", @@ -112,7 +112,7 @@ "restore_complete": "Restauré", "restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]", "restore_failed": "Impossible de restaurer le système", - "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l’est pas non plus dans l’archive", + "restore_hook_unavailable": "Script de restauration pour '{part:s}' non disponible sur votre système et non plus dans l'archive", "restore_nothings_done": "Rien n’a été restauré", "restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}' …", "restore_running_hooks": "Exécution des scripts de restauration …", @@ -168,7 +168,7 @@ "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} n’est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)", "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes", "certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", - "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateurs de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", + "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", "certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}", "certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »", "certmanager_cert_install_success": "Le certificat Let’s Encrypt est maintenant installé pour le domaine « {domain:s} »", @@ -235,7 +235,7 @@ "global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}", "restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire", "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …", - "restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)", + "restore_may_be_not_enough_disk_space": "Votre système ne semble pas avoir suffisamment d'espace (libre: {free_space:d} B, espace nécessaire: {needed_space:d} B, marge de sécurité: {margin:d} B)", "restore_not_enough_disk_space": "Espace disponible insuffisant (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)", "restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système", "backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.", @@ -270,8 +270,8 @@ "migration_0003_patching_sources_list": "Modification du fichier sources.lists …", "migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …", "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …", - "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d’une manière ou d’une autre. La migration va d’abord le réinitialiser à son état initial. Le fichier précédent sera disponible en tant que {backup_dest}.", - "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du paquet YunoHost. La migration se terminera, mais la mise à jour réelle aura lieu immédiatement après. Une fois cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration via le panel web.", + "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d'une manière ou d'une autre. La migration va d'abord le réinitialiser à son état d'origine… Le fichier précédent sera disponible en tant que {backup_dest}.", + "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du package YunoHost… La migration se terminera, mais la mise à niveau réelle aura lieu immédiatement après. Une fois l'opération terminée, vous devrez peut-être vous reconnecter à la page webadmin.", "migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !", "migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer la migration à Stretch.", "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …", @@ -304,7 +304,7 @@ "log_link_to_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en cliquant ici", "backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})", "log_help_to_get_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en utilisant la commande 'yunohost log display {name} --share'", - "log_does_exists": "Il n’existe pas de journal de l’opération ayant pour nom '{log}', utiliser 'yunohost log list' pour voir tous les fichiers de journaux disponibles", + "log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles", "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement", "log_app_change_url": "Changer l’URL de l’application '{}'", "log_app_install": "Installer l’application '{}'", @@ -321,12 +321,12 @@ "log_dyndns_subscribe": "Souscrire au sous-domaine YunoHost '{}'", "log_dyndns_update": "Mettre à jour l’adresse IP associée à votre sous-domaine YunoHost '{}'", "log_letsencrypt_cert_install": "Installer le certificat Let’s Encrypt sur le domaine '{}'", - "log_selfsigned_cert_install": "Installer le certificat auto-signé sur le domaine '{}'", + "log_selfsigned_cert_install": "Installer un certificat auto-signé sur le domaine '{}'", "log_letsencrypt_cert_renew": "Renouveler le certificat Let’s Encrypt de '{}'", "log_user_create": "Ajouter l’utilisateur '{}'", "log_user_delete": "Supprimer l’utilisateur '{}'", "log_user_update": "Mettre à jour les informations de l’utilisateur '{}'", - "log_domain_main_domain": "Faire de '{}' le domaine principal", + "log_domain_main_domain": "Faites de '{}' le domaine principal", "log_tools_migrations_migrate_forward": "Éxecuter les migrations", "log_tools_postinstall": "Faire la post-installation de votre serveur YunoHost", "log_tools_upgrade": "Mettre à jour les paquets du système", @@ -336,15 +336,15 @@ "migration_description_0004_php5_to_php7_pools": "Reconfigurer les espaces utilisateurs PHP pour utiliser PHP 7 au lieu de PHP 5", "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6", "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !", - "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 a été trouvé et installé, mais pas PostgreSQL 9.6 !? Quelque chose d’étrange a dû arriver à votre système… :(", + "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 est installé, mais pas postgresql 9.6‽ Quelque chose de bizarre aurait pu se produire sur votre système: (…", "migration_0005_not_enough_space": "Laissez suffisamment d’espace disponible dans {path} pour exécuter la migration.", "service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX", "users_available": "Liste des utilisateurs disponibles :", - "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d’administration. Le mot de passe doit comporter au moins 8 caractères – bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).", - "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.", + "good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe d'administration. Le mot de passe doit comporter au moins 8 caractères, bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase de passe) et / ou d'utiliser une variation de caractères (majuscule, minuscule, chiffres et caractères spéciaux).", + "good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères, bien qu'il soit recommandé d'utiliser un mot de passe plus long (c'est-à-dire une phrase secrète) et / ou une variation de caractères (majuscule, minuscule, chiffres et caractères spéciaux).", "migration_description_0006_sync_admin_and_root_passwords": "Synchroniser les mots de passe admin et root", "migration_0006_disclaimer": "YunoHost s’attend maintenant à ce que les mots de passe administrateur et racine soient synchronisés. Cette migration remplace votre mot de passe root par le mot de passe administrateur.", - "password_listed": "Ce mot de passe est l’un des mots de passe les plus utilisés dans le monde. Veuillez choisir quelque chose d’un peu plus singulier.", + "password_listed": "Ce mot de passe fait partie des mots de passe les plus utilisés au monde. Veuillez choisir quelque chose de plus unique.", "password_too_simple_1": "Le mot de passe doit comporter au moins 8 caractères", "password_too_simple_2": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules et des minuscules", "password_too_simple_3": "Le mot de passe doit comporter au moins 8 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux", @@ -363,7 +363,7 @@ "backup_mount_archive_for_restore": "Préparation de l’archive pour restauration …", "confirm_app_install_warning": "Avertissement : cette application peut fonctionner mais n’est pas bien intégrée dans YunoHost. Certaines fonctionnalités telles que l’authentification unique et la sauvegarde/restauration peuvent ne pas être disponibles. L’installer quand même ? [{answers:s}] ", "confirm_app_install_danger": "DANGER ! Cette application est connue pour être encore expérimentale (si elle ne fonctionne pas explicitement) ! Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", - "confirm_app_install_thirdparty": "DANGER ! Cette application ne fait pas partie du catalogue d’applications de YunoHost. L’installation d’applications tierces peut compromettre l’intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l’installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système … Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", + "confirm_app_install_thirdparty": "DANGER! Cette application ne fait pas partie du catalogue d'applications de Yunohost. L'installation d'applications tierces peut compromettre l'intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l'installer à moins de savoir ce que vous faites. AUCUN SUPPORT ne sera fourni si cette application ne fonctionne pas ou casse votre système ... Si vous êtes prêt à prendre ce risque de toute façon, tapez '{answers:s}'", "dpkg_is_broken": "Vous ne pouvez pas faire ça maintenant car dpkg/apt (le gestionnaire de paquets du système) semble avoir laissé des choses non configurées. Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a'.", "dyndns_could_not_check_available": "Impossible de vérifier si {domain:s} est disponible chez {provider:s}.", "file_does_not_exist": "Le fichier dont le chemin est {path:s} n’existe pas.", @@ -380,7 +380,7 @@ "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l’utilisateur admin ;", "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d’invalider un avertissement effrayant de votre client SSH afin de revérifier l’empreinte de votre serveur ;", "migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", - "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse pas être promis! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", "migrations_success": "Migration {number} {name} réussie !", "pattern_password_app": "Désolé, les mots de passe ne peuvent pas contenir les caractères suivants : {forbidden_chars}", "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.", @@ -424,9 +424,9 @@ "tools_upgrade_regular_packages_failed": "Impossible de mettre à jour les paquets suivants : {packages_list}", "tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost) …", "tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie !\nPressez [Entrée] pour revenir à la ligne de commande", - "dpkg_lock_not_available": "Cette commande ne peut être exécutée actuellement car un autre programme semble utiliser le verrou de dpkg (gestionnaire de paquets)", + "dpkg_lock_not_available": "Cette commande ne peut pas être exécutée pour le moment car un autre programme semble utiliser le verrou de dpkg (le gestionnaire de package système)", "tools_upgrade_cant_unhold_critical_packages": "Impossible de conserver les paquets critiques…", - "tools_upgrade_special_packages_explanation": "La mise à jour spéciale va continuer en arrière-plan. Veuillez ne pas lancer d’autres actions sur votre serveur pendant environ 10 minutes (en fonction de la vitesse du matériel). Après cela, il vous faudra peut-être vous reconnecter à la webadmin. Le journal de mise à niveau sera disponible dans Outils → Journal (dans la webadmin) ou via \"yunohost log list\" (en ligne de commande).", + "tools_upgrade_special_packages_explanation": "La mise à niveau spéciale se poursuivra en arrière-plan. Veuillez ne pas lancer d'autres actions sur votre serveur pendant les 10 prochaines minutes (selon la vitesse du matériel). Après cela, vous devrez peut-être vous reconnecter à l'administrateur Web. Le journal de mise à niveau sera disponible dans Outils → Journal (dans le webadmin) ou en utilisant la «liste des journaux yunohost» (à partir de la ligne de commande).", "update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "backup_permission": "Permission de sauvegarde pour l’application {app:s}", @@ -457,7 +457,7 @@ "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", "migration_0011_backup_before_migration": "Création d’une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", "permission_not_found": "Autorisation '{permission:s}' introuvable", - "permission_update_failed": "Impossible de mettre à jour la permission '{permission}' : {error}", + "permission_update_failed": "Impossible de mettre à jour l'autorisation '{permission}': {error}", "permission_updated": "Permission '{permission:s}' mise à jour", "permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour", "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur DynDNS {provider}: votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", @@ -518,14 +518,14 @@ "diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}", "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})", - "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost … probablement à cause d’une mise à niveau partielle ou échouée.", + "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... très probablement en raison d'une mise à niveau échouée ou partielle.", "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}", "diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment!)", "diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))", "diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.", "diagnosis_everything_ok": "Tout semble bien pour {category} !", - "diagnosis_failed": "Impossible d’extraire le résultat du diagnostic pour la catégorie '{category}': {error}", + "diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}': {error}", "diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !", "diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d’une adresse IPv4.", "diagnosis_ip_connected_ipv6": "Le serveur est connecté à Internet en IPv6 !", @@ -535,15 +535,6 @@ "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.", "diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})", "diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})", - "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {0} et nom {1} ne correspond pas à la configuration recommandée. Valeur actuelle: {2}. Valeur exceptée: {3}. Vous pouvez consulter https://yunohost.org/dns_config pour plus d’informations.", - "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.", - "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free_abs_GB} Go ({free_percent}%). Faites attention.", - "diagnosis_ram_verylow": "Le système ne dispose plus que de {available_abs_MB} MB ({available_percent}%) ! (sur {total_abs_MB} Mo)", - "diagnosis_ram_low": "Le système n’a plus de {available_abs_MB} MB ({available_percent}%) RAM sur {total_abs_MB} MB. Faites attention.", - "diagnosis_swap_none": "Le système n’a aucun échange. Vous devez envisager d’ajouter au moins 256 Mo de swap pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_notsomuch": "Le système ne dispose que de {total_MB} Mo de swap. Vous devez envisager d’avoir au moins 256 Mo pour éviter les situations où le système manque de mémoire.", - "diagnosis_swap_ok": "Le système dispose de {total_MB} Mo de swap !", "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.", @@ -590,7 +581,7 @@ "diagnosis_services_running": "Le service {service} est en cours de fonctionnement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})", - "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit sur https://yunohost.org/isp_box_config", + "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", From b1dda63385d0bb826adf80b268be91c61a89e1eb Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 20 Apr 2020 09:44:28 +0000 Subject: [PATCH 240/317] Translated using Weblate (Greek) Currently translated at 0.2% (1 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/el/ --- locales/el.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/el.json b/locales/el.json index efa5bf769..b43f11d5d 100644 --- a/locales/el.json +++ b/locales/el.json @@ -1,3 +1,3 @@ { - "password_too_simple_1": "Ο κωδικός πρόσβασης πρέπει να έχει μήκος τουλάχιστον 8 χαρακτήρων" -} \ No newline at end of file + "password_too_simple_1": "Ο κωδικός πρόσβασης πρέπει να έχει τουλάχιστον 8 χαρακτήρες" +} From e35d87f7ed4fe58cfaae0e66f01581deac849749 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Mon, 20 Apr 2020 09:11:59 +0000 Subject: [PATCH 241/317] Translated using Weblate (Nepali) Currently translated at 0.2% (1 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/ne/ --- locales/ne.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/locales/ne.json b/locales/ne.json index 9e26dfeeb..72c4c8537 100644 --- a/locales/ne.json +++ b/locales/ne.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "password_too_simple_1": "पासवर्ड कम्तिमा characters अक्षर लामो हुनु आवश्यक छ" +} From c95c08ef8f792175a02fc226cd38ad1b9a649401 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Tue, 21 Apr 2020 06:16:56 +0000 Subject: [PATCH 242/317] Translated using Weblate (Esperanto) Currently translated at 100.0% (598 of 598 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/eo/ --- locales/eo.json | 75 +++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index eb701494d..22656188d 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -70,7 +70,7 @@ "backup_cant_mount_uncompress_archive": "Ne povis munti la nekompresitan ar archiveivon kiel protektita kontraŭ skribo", "app_action_cannot_be_ran_because_required_services_down": "Ĉi tiuj postulataj servoj devas funkcii por funkciigi ĉi tiun agon: {services}. Provu rekomenci ilin por daŭrigi (kaj eble esploru, kial ili malsupreniras).", "backup_copying_to_organize_the_archive": "Kopiante {size:s} MB por organizi la ar archiveivon", - "backup_output_directory_forbidden": "Elektu malsaman elirejan dosierujon. Sekurkopioj ne povas esti kreitaj en sub-dosierujoj / bin, / boot, / dev, / ktp, / lib, / root, / run, / sbin, / sys, / usr, / var aŭ /home/yunohost.backup/archives", + "backup_output_directory_forbidden": "Elektu malsaman elirejan dosierujon. Sekurkopioj ne povas esti kreitaj en sub-dosierujoj /bin, /boot, /dev, /ktp, /lib, /root, /run, /sbin, /sys, /usr, /var aŭ /home/yunohost.backup/archives", "backup_no_uncompress_archive_dir": "Ne ekzistas tia nekompremita arkiva dosierujo", "password_too_simple_1": "Pasvorto devas esti almenaŭ 8 signojn longa", "app_upgrade_failed": "Ne povis ĝisdatigi {app:s}: {error}", @@ -107,13 +107,13 @@ "app_sources_fetch_failed": "Ne povis akiri fontajn dosierojn, ĉu la URL estas ĝusta?", "ask_new_domain": "Nova domajno", "app_unknown": "Nekonata apliko", - "app_not_upgraded": "La aplikaĵo '{failed_app}' ne ĝisdatigis, kaj pro tio la sekvaj ĝisdatigoj de aplikoj estis nuligitaj: {apps}", + "app_not_upgraded": "La '{failed_app}' de la programo ne sukcesis ĝisdatigi, kaj sekve la nuntempaj plibonigoj de la sekvaj programoj estis nuligitaj: {apps}", "aborting": "Aborti.", "app_upgraded": "{app:s} altgradigita", "backup_deleted": "Rezerva forigita", "backup_csv_addition_failed": "Ne povis aldoni dosierojn al sekurkopio en la CSV-dosiero", "dpkg_lock_not_available": "Ĉi tiu komando ne povas funkcii nun ĉar alia programo uzas la seruron de dpkg (la administrilo de paka sistemo)", - "migration_0003_yunohost_upgrade": "Komenci la ĝisdatigon de YunoHost-pako ... La migrado finiĝos, sed la efektiva ĝisdatigo okazos tuj poste. Post kiam la operacio finiĝos, vi eble devos ensaluti denove sur la retpaĝo.", + "migration_0003_yunohost_upgrade": "Komencante la ĝisdatigon de la pakaĵo YunoHost ... La migrado finiĝos, sed la efektiva ĝisdatigo okazos tuj poste. Post kiam la operacio finiĝos, vi eble devos ensaluti al la retpaĝo.", "domain_dyndns_root_unknown": "Nekonata radika domajno DynDNS", "field_invalid": "Nevalida kampo '{:s}'", "log_app_makedefault": "Faru '{}' la defaŭlta apliko", @@ -124,7 +124,7 @@ "global_settings_setting_security_postfix_compatibility": "Kongruo vs sekureca kompromiso por la Postfix-servilo. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", "group_unknown": "La grupo '{group:s}' estas nekonata", "mailbox_disabled": "Retpoŝto malŝaltita por uzanto {user:s}", - "migration_description_0011_setup_group_permission": "Agordu uzantogrupon kaj starigu permeson por programoj kaj servoj", + "migration_description_0011_setup_group_permission": "Agordu uzantajn grupojn kaj permesojn por programoj kaj servoj", "migration_0011_backup_before_migration": "Krei sekurkopion de LDAP-datumbazo kaj agordojn antaŭ la efektiva migrado.", "migration_0011_migrate_permission": "Migrado de permesoj de agordoj al aplikoj al LDAP…", "migration_0011_migration_failed_trying_to_rollback": "Ne povis migri ... provante redakti la sistemon.", @@ -148,8 +148,8 @@ "log_user_group_delete": "Forigi grupon '{}'", "log_user_group_update": "Ĝisdatigi grupon '{}'", "migration_0005_postgresql_94_not_installed": "PostgreSQL ne estis instalita en via sistemo. Nenio por fari.", - "dyndns_provider_unreachable": "Ne povas atingi Dyndns-provizanton {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dynette-servilo malŝaltiĝas.", - "good_practices_about_user_password": "Vi nun estas por difini novan uzantan pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", + "dyndns_provider_unreachable": "Ne povas atingi la provizanton DynDNS {provider}: ĉu via YunoHost ne estas ĝuste konektita al la interreto aŭ la dyneta servilo malŝaltiĝas.", + "good_practices_about_user_password": "Vi nun estas por difini novan uzantan pasvorton. La pasvorto devas esti almenaŭ 8 signojn - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj/aŭ variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", "group_updated": "Ĝisdatigita \"{group}\" grupo", "group_already_exist": "Grupo {group} jam ekzistas", "group_already_exist_on_system": "Grupo {group} jam ekzistas en la sistemaj grupoj", @@ -172,7 +172,7 @@ "migrations_already_ran": "Tiuj migradoj estas jam faritaj: {ids}", "migrations_no_such_migration": "Estas neniu migrado nomata '{id}'", "permission_already_allowed": "Grupo '{group}' jam havas rajtigitan permeson '{permission}'", - "permission_already_disallowed": "Grupo '{group}' jam havas permeson '{permission}' malebligita'", + "permission_already_disallowed": "Grupo '{group}' jam havas permeson '{permission}' malebligita", "permission_cannot_remove_main": "Forigo de ĉefa permeso ne rajtas", "permission_creation_failed": "Ne povis krei permeson '{permission}': {error}", "user_already_exists": "La uzanto '{user}' jam ekzistas", @@ -186,7 +186,7 @@ "permission_not_found": "Permesita \"{permission:s}\" ne trovita", "restore_not_enough_disk_space": "Ne sufiĉa spaco (spaco: {free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)", "tools_upgrade_regular_packages": "Nun ĝisdatigi 'regulajn' (ne-yunohost-rilatajn) pakojn …", - "tools_upgrade_special_packages_explanation": "La speciala ĝisdatigo daŭros en fono. Bonvolu ne komenci aliajn agojn en via servilo la sekvajn ~ 10 minutojn (depende de la aparata rapideco). Post tio, vi eble devos re-ensaluti sur la retadreso. La ĝisdatiga registro estos havebla en Iloj → Ensaluto (en la retadreso) aŭ uzante 'yunohost-logliston' (el la komandlinio).", + "tools_upgrade_special_packages_explanation": "La speciala ĝisdatigo daŭros en la fono. Bonvolu ne komenci aliajn agojn en via servilo dum la sekvaj ~ 10 minutoj (depende de la aparata rapideco). Post tio, vi eble devos re-ensaluti al la retadreso. La ĝisdatiga registro estos havebla en Iloj → Ensaluto (en la retadreso) aŭ uzante 'yunohost logliston' (el la komandlinio).", "unrestore_app": "App '{app:s}' ne restarigos", "group_created": "Grupo '{group}' kreita", "group_creation_failed": "Ne povis krei la grupon '{group}': {error}", @@ -199,7 +199,7 @@ "log_user_create": "Aldonu uzanton '{}'", "ip6tables_unavailable": "Vi ne povas ludi kun ip6tabloj ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin", "mail_unavailable": "Ĉi tiu retpoŝta adreso estas rezervita kaj aŭtomate estos atribuita al la unua uzanto", - "certmanager_domain_dns_ip_differs_from_public_ip": "La DNS 'A' rekordo por la domajno '{domain:s}' diferencas de ĉi tiu IP-servilo. Se vi lastatempe modifis vian A-registron, bonvolu atendi ĝin propagandi (iuj DNS-disvastigaj kontroliloj estas disponeblaj interrete). (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)", + "certmanager_domain_dns_ip_differs_from_public_ip": "La DNS 'A' rekordo por la domajno '{domain:s}' diferencas de la IP de ĉi tiu servilo. Se vi lastatempe modifis vian A-registron, bonvolu atendi ĝin propagandi (iuj DNS-disvastigaj kontroliloj estas disponeblaj interrete). (Se vi scias, kion vi faras, uzu '--no-checks' por malŝalti tiujn ĉekojn.)", "tools_upgrade_special_packages_completed": "Plenumis la ĝisdatigon de pakaĵoj de YunoHost.\nPremu [Enter] por retrovi la komandlinion", "log_remove_on_failed_install": "Forigu '{}' post malsukcesa instalado", "regenconf_file_manually_modified": "La agorddosiero '{conf}' estis modifita permane kaj ne estos ĝisdatigita", @@ -211,7 +211,7 @@ "migration_description_0006_sync_admin_and_root_passwords": "Sinkronigu admin kaj radikajn pasvortojn", "iptables_unavailable": "Vi ne povas ludi kun iptables ĉi tie. Vi estas en ujo aŭ via kerno ne subtenas ĝin", "global_settings_cant_write_settings": "Ne eblis konservi agordojn, tial: {reason:s}", - "service_added": "La servo '{service:s}' aldonis", + "service_added": "La servo '{service:s}' estis aldonita", "upnp_disabled": "UPnP malŝaltis", "service_started": "Servo '{service:s}' komenciĝis", "port_already_opened": "Haveno {port:d} estas jam malfermita por {ip_version:s} rilatoj", @@ -283,7 +283,7 @@ "log_operation_unit_unclosed_properly": "Operaciumo ne estis fermita ĝuste", "upgrade_complete": "Ĝisdatigo kompleta", "upnp_enabled": "UPnP ŝaltis", - "mailbox_used_space_dovecot_down": "La retpoŝta servo de Dovecot devas funkcii, se vi volas akcepti uzitan poŝtan spacon", + "mailbox_used_space_dovecot_down": "La poŝta servo de Dovecot devas funkcii, se vi volas akcepti uzitan poŝtan keston", "restore_system_part_failed": "Ne povis restarigi la sisteman parton '{part:s}'", "service_stop_failed": "Ne povis maldaŭrigi la servon '{service:s}'\n\nLastatempaj servaj protokoloj: {logs:s}", "unbackup_app": "App '{app:s}' ne konserviĝos", @@ -312,7 +312,7 @@ "package_unknown": "Nekonata pako '{pkgname}'", "domain_unknown": "Nekonata domajno", "global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto", - "restore_may_be_not_enough_disk_space": "Via sistemo ŝajnas ne havi sufiĉe da spaco (free:{free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)", + "restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {libera_spaco:d} B, necesa spaco: {necesa_spaco:d} B, sekureca marĝeno: {rando:d} B)", "log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '", "downloading": "Elŝutante …", "user_deleted": "Uzanto forigita", @@ -323,7 +323,7 @@ "service_description_fail2ban": "Protektas kontraŭ bruta forto kaj aliaj specoj de atakoj de la interreto", "file_does_not_exist": "La dosiero {path:s} ne ekzistas.", "yunohost_not_installed": "YunoHost ne estas ĝuste instalita. Bonvolu prilabori 'yunohost tools postinstall'", - "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 estas instalita, sed ne postgresql 9.6‽ Io stranga eble okazis en via sistemo: (…", + "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 estas instalita, sed ne postgresql 9.6‽ Io stranga eble okazis en via sistemo :(…", "restore_removing_tmp_dir_failed": "Ne povis forigi malnovan provizoran dosierujon", "certmanager_cannot_read_cert": "Io malbona okazis, kiam mi provis malfermi aktualan atestilon por domajno {domain:s} (dosiero: {file:s}), kialo: {reason:s}", "service_removed": "Servo '{service:s}' forigita", @@ -372,7 +372,7 @@ "migration_0003_general_warning": "Bonvolu noti, ke ĉi tiu migrado estas delikata operacio. La teamo de YunoHost faris sian plej bonan revizii kaj testi ĝin, sed la migrado eble ankoraŭ rompos partojn de la sistemo aŭ ĝiaj programoj.\n\nTial oni rekomendas al:\n - Elfari kopion de iuj kritikaj datumoj aŭ app. Pliaj informoj pri https://yunohost.org/backup;\n - Paciencu post lanĉo de la migrado: Depende de via interreta konekto kaj aparataro, eble daŭros kelkaj horoj ĝis ĉio ĝisdatigi.\n\nAldone, la haveno por SMTP, uzata de eksteraj retpoŝtaj klientoj (kiel Thunderbird aŭ K9-Mail) estis ŝanĝita de 465 (SSL / TLS) al 587 (STARTTLS). La malnova haveno (465) aŭtomate fermiĝos, kaj la nova haveno (587) malfermiĝos en la fajrejo. Vi kaj viaj uzantoj * devos adapti la agordon de viaj retpoŝtaj klientoj laŭe.", "global_settings_setting_example_int": "Ekzemple int elekto", "backup_output_symlink_dir_broken": "Via arkiva dosierujo '{path:s}' estas rompita ligilo. Eble vi forgesis restarigi aŭ munti aŭ enŝovi la stokadon, al kiu ĝi notas.", - "good_practices_about_admin_password": "Vi nun estas por difini novan administran pasvorton. La pasvorto devas esti almenaŭ 8 signoj - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj / aŭ uzi variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", + "good_practices_about_admin_password": "Vi nun estas por difini novan administran pasvorton. La pasvorto devas esti almenaŭ 8 signojn - kvankam estas bone praktiki uzi pli longan pasvorton (t.e. pasfrazon) kaj/aŭ uzi variaĵon de signoj (majuskloj, minuskloj, ciferoj kaj specialaj signoj).", "certmanager_attempt_to_renew_valid_cert": "La atestilo por la domajno '{domain:s}' ne finiĝos! (Vi eble uzos --force se vi scias kion vi faras)", "restore_running_hooks": "Kurantaj restarigaj hokoj…", "regenconf_pending_applying": "Aplikante pritraktata agordo por kategorio '{category}'…", @@ -387,12 +387,12 @@ "migrations_list_conflict_pending_done": "Vi ne povas uzi ambaŭ '--previous' kaj '--done' samtempe.", "server_shutdown_confirm": "La servilo haltos tuj, ĉu vi certas? [{answers:s}]", "log_backup_restore_app": "Restarigu '{}' de rezerva ar archiveivo", - "log_does_exists": "Ne estas operacio-registro kun la nomo '{log}', uzu 'yunohost loglist' por vidi ĉiujn disponeblajn operaciojn", + "log_does_exists": "Ne estas operacio kun la nomo '{log}', uzu 'yunohost log list' por vidi ĉiujn disponeblajn operaciojn", "service_add_failed": "Ne povis aldoni la servon '{service:s}'", "pattern_password_app": "Bedaŭrinde, pasvortoj ne povas enhavi jenajn signojn: {forbidden_chars}", "this_action_broke_dpkg": "Ĉi tiu ago rompis dpkg / APT (la administrantoj pri la paka sistemo) ... Vi povas provi solvi ĉi tiun problemon per konekto per SSH kaj funkcianta `sudo dpkg --configure -a`.", "log_regen_conf": "Regeneri sistemajn agordojn '{}'", - "restore_hook_unavailable": "La restariga skripto por '{part:s}' ne haveblas en via sistemo kaj ankaŭ ne en la ar theivo", + "restore_hook_unavailable": "Restariga skripto por '{part:s}' ne haveblas en via sistemo kaj ankaŭ ne en la ar theivo", "log_dyndns_subscribe": "Aboni al YunoHost-subdominio '{}'", "password_too_simple_4": "La pasvorto bezonas almenaŭ 12 signojn kaj enhavas ciferon, majuskle, pli malaltan kaj specialajn signojn", "migration_0003_main_upgrade": "Komencanta ĉefa ĝisdatigo …", @@ -401,7 +401,7 @@ "global_settings_setting_security_nginx_compatibility": "Kongruo vs sekureca kompromiso por la TTT-servilo NGINX. Afektas la ĉifradojn (kaj aliajn aspektojn pri sekureco)", "no_internet_connection": "La servilo ne estas konektita al la interreto", "migration_0008_dsa": "• La DSA-ŝlosilo estos malŝaltita. Tial vi eble bezonos nuligi spuran averton de via SSH-kliento kaj revizii la fingrospuron de via servilo;", - "migration_0003_restoring_origin_nginx_conf": "Fileia dosiero /etc/nginx/nginx.conf estis iel redaktita. La migrado reaperos unue al sia originala stato ... La antaŭa dosiero estos havebla kiel {backup_dest}.", + "migration_0003_restoring_origin_nginx_conf": "Fileia dosiero /etc/nginx/nginx.conf estis iel redaktita. La migrado unue restarigos ĝin al sia originala stato ... La antaŭa dosiero estos havebla kiel {backup_dest}.", "migrate_tsig_end": "Migrado al HMAC-SHA-512 finiĝis", "restore_complete": "Restarigita", "certmanager_couldnt_fetch_intermediate_cert": "Ekvilibrigita kiam vi provis ricevi interajn atestilojn de Let's Encrypt. Atestita instalado / renovigo nuligita - bonvolu reprovi poste.", @@ -432,14 +432,14 @@ "certmanager_cert_install_success": "Ni Ĉifru atestilon nun instalitan por la domajno '{domain:s}'", "global_settings_bad_choice_for_enum": "Malbona elekto por agordo {setting:s}, ricevita '{choice:s}', sed disponeblaj elektoj estas: {available_choices:s}", "server_shutdown": "La servilo haltos", - "log_tools_migrations_migrate_forward": "Migri antaŭen", - "migration_0008_no_warning": "Supersalti vian SSH-agordon estu sekura, kvankam ĉi tio ne povas esti promesita! Ekfunkciu la migradon por superregi ĝin. Alie, vi ankaŭ povas salti la migradon, kvankam ĝi ne rekomendas.", + "log_tools_migrations_migrate_forward": "Kuru migradoj", + "migration_0008_no_warning": "Supersalti vian SSH-agordon estu sekura, kvankam tio ne povas esti promesita! Ekfunkciu la migradon por superregi ĝin. Alie, vi ankaŭ povas salti la migradon, kvankam ĝi ne rekomendas.", "regenconf_now_managed_by_yunohost": "La agorda dosiero '{conf}' nun estas administrata de YunoHost (kategorio {category}).", "server_reboot_confirm": "Ĉu la servilo rekomencos tuj, ĉu vi certas? [{answers:s}]", "log_app_install": "Instalu la aplikon '{}'", "service_description_dnsmasq": "Traktas rezolucion de domajna nomo (DNS)", "global_settings_unknown_type": "Neatendita situacio, la agordo {setting:s} ŝajnas havi la tipon {unknown_type:s} sed ĝi ne estas tipo subtenata de la sistemo.", - "migration_0003_problematic_apps_warning": "Bonvolu noti, ke la sekvaj eventuale problemaj instalitaj programoj estis detektitaj. Ŝajnas, ke tiuj ne estis instalitaj el app_katalogo aŭ ne estas markitaj kiel \"funkciantaj\". Tial ne eblas garantii, ke ili ankoraŭ funkcios post la ĝisdatigo: {problematic_apps}", + "migration_0003_problematic_apps_warning": "Bonvolu noti, ke la sekvaj eventuale problemaj instalitaj programoj estis detektitaj. Ŝajnas, ke tiuj ne estis instalitaj el aplika katalogo aŭ ne estas markitaj kiel \"funkciantaj\". Tial ne eblas garantii, ke ili ankoraŭ funkcios post la ĝisdatigo: {problematic_apps}", "domain_hostname_failed": "Ne povis agordi novan gastigilon. Ĉi tio eble kaŭzos problemon poste (eble bone).", "server_reboot": "La servilo rekomenciĝos", "regenconf_failed": "Ne povis regeneri la agordon por kategorio(j): {categories}", @@ -497,11 +497,11 @@ "app_install_failed": "Ne povis instali {app} : {error}", "app_install_script_failed": "Eraro okazis en la skripto de instalado de la app", "app_remove_after_failed_install": "Forigado de la app post la instala fiasko …", - "diagnosis_basesystem_host": "Servilo funkcias Debian {debian_version}.", + "diagnosis_basesystem_host": "Servilo funkcias Debian {debian_version}", "apps_catalog_init_success": "Aplikoj katalogsistemo inicializita !", - "apps_catalog_updating": "Ĝisdatigante katalogo de aplikoj ...", + "apps_catalog_updating": "Ĝisdatigante katalogo de aplikoj …", "apps_catalog_failed_to_download": "Ne eblas elŝuti la katalogon de {apps_catalog}: {error}", - "apps_catalog_obsolete_cache": "La kaŝmemoro de la katalogo de programoj estas malplena aŭ malaktuala.", + "apps_catalog_obsolete_cache": "La kaŝmemoro de la aplika katalogo estas malplena aŭ malaktuala.", "apps_catalog_update_success": "La aplika katalogo estis ĝisdatigita!", "diagnosis_basesystem_kernel": "Servilo funkcias Linuksan kernon {kernel_version}", "diagnosis_basesystem_ynh_single_version": "{package} versio: {version} ({repo})", @@ -516,9 +516,9 @@ "diagnosis_diskusage_verylow": "Stokado {mountpoint} (sur aparato {device)) restas nur {free} ({free_percent}%) spaco. Vi vere konsideru purigi iom da spaco.", "diagnosis_ram_verylow": "La sistemo nur restas {available} ({available_percent}%) RAM! (el {total})", "diagnosis_mail_outgoing_port_25_blocked": "Eliranta haveno 25 ŝajnas esti blokita. Vi devas provi malŝlosi ĝin en via agorda panelo de provizanto (aŭ gastiganto). Dume la servilo ne povos sendi retpoŝtojn al aliaj serviloj.", - "diagnosis_http_bad_status_code": "Ne povis atingi vian servilon kiel atendite, ĝi redonis malbonan statuskodon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via nginx-agordo ĝisdatigas kaj ke reverso-prokuro ne interbatalas.", + "diagnosis_http_bad_status_code": "La diagnoza sistemo ne povis atingi vian servilon. Povas esti, ke alia maŝino respondis anstataŭ via servilo. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke via agordo de nginx estas ĝisdatigita kaj ke reverso-prokuro ne interbatalas.", "main_domain_changed": "La ĉefa domajno estis ŝanĝita", - "yunohost_postinstall_end_tip": "La post-instalado finiĝis! Por fini vian agordon, bonvolu konsideri:\n - aldonado de unua uzanto tra la sekcio 'Uzantoj' de la retadreso (aŭ 'yunohost user create ' en komandlinio);\n - diagnozi problemojn atendantajn solvi por ke via servilo funkciu kiel eble plej glate tra la sekcio 'Diagnosis' de la retadministrado (aŭ 'yunohost diagnosis run' en komandlinio);\n - legante la partojn 'Finigi vian agordon' kaj 'Ekkoni Yunohost' en la administra dokumentado: https://yunohost.org/admindoc.", + "yunohost_postinstall_end_tip": "La post-instalado finiĝis! Por fini vian agordon, bonvolu konsideri:\n - aldonado de unua uzanto tra la sekcio 'Uzantoj' de la retadreso (aŭ 'uzanto de yunohost kreu ' en komandlinio);\n - diagnozi eblajn problemojn per la sekcio 'Diagnozo' de la reteja administrado (aŭ 'diagnoza yunohost-ekzekuto' en komandlinio);\n - legante la partojn 'Finigi vian agordon' kaj 'Ekkoni Yunohost' en la administra dokumentado: https://yunohost.org/admindoc.", "migration_description_0014_remove_app_status_json": "Forigi heredajn dosierojn", "diagnosis_ip_connected_ipv4": "La servilo estas konektita al la interreto per IPv4 !", "diagnosis_ip_no_ipv4": "La servilo ne havas funkciantan IPv4.", @@ -527,9 +527,9 @@ "diagnosis_ip_not_connected_at_all": "La servilo tute ne ŝajnas esti konektita al la Interreto !?", "diagnosis_ip_dnsresolution_working": "Rezolucio pri domajna nomo funkcias !", "diagnosis_ip_weird_resolvconf": "DNS-rezolucio ŝajnas funkcii, sed atentu, ke vi ŝajnas uzi kutimon /etc/resolv.conf.", - "diagnosis_ip_weird_resolvconf_details": "Anstataŭe, ĉi tiu dosiero estu ligilo kun /etc/resolvconf/run/resolv.conf mem montrante al 127.0.0.1 (dnsmasq). La efektivaj solvantoj devas agordi per /etc/resolv.dnsmasq.conf.", + "diagnosis_ip_weird_resolvconf_details": "Anstataŭe, ĉi tiu dosiero estu ligilo kun /etc/resolvconf/run/resolv.conf mem montrante al 127.0.0.1 (dnsmasq). La efektivaj solvantoj devas agordi en /etc/resolv.dnsmasq.conf.", "diagnosis_dns_good_conf": "Bona DNS-agordo por domajno {domain} (kategorio {category})", - "diagnosis_dns_bad_conf": "Malbona / mankas DNS-agordo por domajno {domain} (kategorio {category})", + "diagnosis_dns_bad_conf": "Malbona aŭ mankas DNS-agordo por domajno {domain} (kategorio {category})", "diagnosis_ram_ok": "La sistemo ankoraŭ havas {available} ({available_percent}%) RAM forlasita de {total}.", "diagnosis_swap_none": "La sistemo tute ne havas interŝanĝon. Vi devus pripensi aldoni almenaŭ {recommended} da interŝanĝo por eviti situaciojn en kiuj la sistemo restas sen memoro.", "diagnosis_swap_notsomuch": "La sistemo havas nur {total}-interŝanĝon. Vi konsideru havi almenaŭ {recommended} por eviti situaciojn en kiuj la sistemo restas sen memoro.", @@ -539,7 +539,7 @@ "diagnosis_security_all_good": "Neniu kritika sekureca vundebleco estis trovita.", "diagnosis_security_vulnerable_to_meltdown": "Vi ŝajnas vundebla al la kritiko-vundebleco de Meltdown", "diagnosis_no_cache": "Neniu diagnoza kaŝmemoro por kategorio '{category}'", - "diagnosis_ip_broken_dnsresolution": "Rezolucio pri domajna nomo rompiĝas pro iu kialo ... Ĉu fajroŝirmilo blokas DNS-petojn ?", + "diagnosis_ip_broken_dnsresolution": "Rezolucio pri domajna nomo rompiĝas pro iu kialo... Ĉu fajroŝirmilo blokas DNS-petojn ?", "diagnosis_ip_broken_resolvconf": "Rezolucio pri domajna nomo ŝajnas esti rompita en via servilo, kiu ŝajnas rilata al /etc/resolv.conf ne notante 127.0.0.1.", "diagnosis_dns_missing_record": "Laŭ la rekomendita DNS-agordo, vi devas aldoni DNS-registron kun\ntipo: {type}\nnomo: {name}\nvaloro: {value}", "diagnosis_dns_discrepancy": "La DNS-registro kun tipo {type} kaj nomo {name} ne kongruas kun la rekomendita agordo.\nNuna valoro: {current}\nEsceptita valoro: {value}", @@ -562,7 +562,7 @@ "diagnosis_description_basesystem": "Baza sistemo", "diagnosis_description_regenconf": "Sistemaj agordoj", "main_domain_change_failed": "Ne eblas ŝanĝi la ĉefan domajnon", - "log_domain_main_domain": "Faru '{}' kiel ĉefa domajno", + "log_domain_main_domain": "Faru de '{}' la ĉefa domajno", "diagnosis_http_timeout": "Tempolimigita dum provado kontakti vian servilon de ekstere. Ĝi ŝajnas esti neatingebla. Vi devus kontroli, ke vi ĝuste redonas la havenon 80, ke nginx funkcias kaj ke fajroŝirmilo ne interbatalas.", "diagnosis_http_connection_error": "Rilata eraro: ne povis konektiĝi al la petita domajno, tre probable ĝi estas neatingebla.", "migration_description_0013_futureproof_apps_catalog_system": "Migru al la nova katalogosistemo pri estontecaj programoj", @@ -576,12 +576,12 @@ "diagnosis_services_running": "Servo {service} funkcias!", "diagnosis_ports_unreachable": "Haveno {port} ne atingeblas de ekstere.", "diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.", - "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por servo {service}", - "diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, plej probable vi devas agordi la plusendon de haveno en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config", + "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por {1} funkcioj (servo {0})", + "diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, vi plej verŝajne bezonas agordi havenon en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config", "diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere.", "diagnosis_http_could_not_diagnose_details": "Eraro: {error}", - "diagnosis_http_ok": "Domajno {domain} atingeblas de ekstere.", - "diagnosis_http_unreachable": "Domajno {domain} estas atingebla per HTTP de ekstere.", + "diagnosis_http_ok": "Domajno {domain} atingebla per HTTP de ekster la loka reto.", + "diagnosis_http_unreachable": "Domajno {domain} ŝajnas neatingebla per HTTP de ekster la loka reto.", "domain_cannot_remove_main_add_new_one": "Vi ne povas forigi '{domain:s}' ĉar ĝi estas la ĉefa domajno kaj via sola domajno, vi devas unue aldoni alian domajnon uzante ''yunohost domain add ', tiam agordi kiel ĉefan domajnon uzante 'yunohost domain main-domain -n ' kaj tiam vi povas forigi la domajnon' {domain:s} 'uzante' yunohost domain remove {domain:s} '.'", "permission_require_account": "Permesilo {permission} nur havas sencon por uzantoj, kiuj havas konton, kaj tial ne rajtas esti ebligitaj por vizitantoj.", "diagnosis_found_warnings": "Trovitaj {warnings} ero (j) kiuj povus esti plibonigitaj por {category}.", @@ -591,5 +591,12 @@ "diagnosis_description_mail": "Retpoŝto", "log_app_action_run": "Funkciigu agon de la apliko '{}'", "log_app_config_show_panel": "Montri la agordan panelon de la apliko '{}'", - "log_app_config_apply": "Apliki agordon al la apliko '{}'" + "log_app_config_apply": "Apliki agordon al la apliko '{}'", + "diagnosis_never_ran_yet": "Ŝajnas, ke ĉi tiu servilo estis instalita antaŭ nelonge kaj estas neniu diagnoza raporto por montri. Vi devas komenci kurante plenan diagnozon, ĉu de la retadministro aŭ uzante 'yunohost diagnosis run' el la komandlinio.", + "certmanager_warning_subdomain_dns_record": "Subdominio '{subdomain:s}' ne solvas al la sama IP-adreso kiel '{domain:s}'. Iuj funkcioj ne estos haveblaj ĝis vi riparos ĉi tion kaj regeneros la atestilon.", + "diagnosis_basesystem_hardware": "Arkitekturo de servila aparataro estas {virt} {arch}", + "diagnosis_basesystem_hardware_board": "Servilo-tabulo-modelo estas {model}", + "diagnosis_description_web": "Reta", + "domain_cannot_add_xmpp_upload": "Vi ne povas aldoni domajnojn per 'xmpp-upload'. Ĉi tiu speco de nomo estas rezervita por la XMPP-alŝuta funkcio integrita en YunoHost.", + "group_already_exist_on_system_but_removing_it": "Grupo {group} jam ekzistas en la sistemaj grupoj, sed YunoHost forigos ĝin …" } From caf41928cc17f665acab3c0fc3decf7d5280fb67 Mon Sep 17 00:00:00 2001 From: amirale qt Date: Tue, 21 Apr 2020 06:58:00 +0000 Subject: [PATCH 243/317] Translated using Weblate (French) Currently translated at 100.0% (632 of 632 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 67 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 7b31f9237..ef60a6956 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -507,10 +507,10 @@ "diagnosis_found_errors": "Trouvé {errors} problème(s) significatif(s) lié(s) à {category} !", "diagnosis_found_errors_and_warnings": "Trouvé {errors} problème(s) significatif(s) (et {warnings} (avertissement(s)) en relation avec {category} !", "diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?", - "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais soyez prudent en utilisant un fichier /etc/resolv.conf personnalisé.", - "diagnosis_ip_weird_resolvconf_details": "Au lieu de cela, ce fichier devrait être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Les résolveurs réels doivent être configurés dans /etc/resolv.dnsmasq.conf.", + "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais il semble que vous utilisez un /etc/resolv.conf personnalisé.", + "diagnosis_ip_weird_resolvconf_details": "Le fichier /etc/resolv.conf doit être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Si vous souhaitez configurer manuellement les résolveurs DNS, veuillez modifier /etc/resolv.dnsmasq.conf.", "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType: {type}\nNom: {name}\nValeur {value}", - "diagnosis_diskusage_ok": "Le stockage {mountpoint} (sur le périphérique {device}) a encore {free} ({free_percent}%) d’espace libre !", + "diagnosis_diskusage_ok": "L'espace de stockage {mountpoint} (sur l'appareil {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", "diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", @@ -532,26 +532,26 @@ "diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d’une adresse IPv6.", "diagnosis_ip_dnsresolution_working": "La résolution de nom de domaine fonctionne !", "diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque … Un pare-feu bloque-t-il les requêtes DNS ?", - "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.", - "diagnosis_dns_good_conf": "Bonne configuration DNS pour le domaine {domain} (catégorie {category})", - "diagnosis_dns_bad_conf": "Configuration DNS incorrecte ou manquante pour le domaine {domain} (catégorie {category})", + "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble être rompue sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas sur 127.0.0.1.", + "diagnosis_dns_good_conf": "Les enregistrements DNS sont correctement configurés pour le domaine {domain} (catégorie {category})", + "diagnosis_dns_bad_conf": "Certains enregistrements DNS sont manquants ou incorrects pour le domaine {domain} (catégorie {category})", "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Vous devriez vraiment envisager de nettoyer un peu d’espace.", - "diagnosis_diskusage_low": "Le stockage {mountpoint} (sur le périphérique {device}) ne dispose que de {free} ({free_percent}%). Faites attention.", + "diagnosis_diskusage_verylow": "L'espace de stockage {mountpoint} (sur l'appareil {device} ) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Vous devriez vraiment envisager de nettoyer de l'espace !", + "diagnosis_diskusage_low": "L'espace de stockage {mountpoint} (sur l'appareil {device}) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Faites attention.", "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", "diagnosis_ram_low": "Le système n’a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", "diagnosis_swap_none": "Le système n’a aucun espace de swap. Vous devriez envisager d’ajouter au moins {recommended} de swap pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_notsomuch": "Le système ne dispose que de {total} de swap. Vous devez envisager d’avoir au moins {recommended} pour éviter les situations où le système manque de mémoire.", "diagnosis_swap_ok": "Le système dispose de {total} de swap !", - "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} a été modifié manuellement.", + "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} semble avoir été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", - "diagnosis_regenconf_manually_modified_details": "C'est probablement OK tant que vous savez ce que vous faites;) !", + "diagnosis_regenconf_manually_modified_details": "C'est probablement OK si vous savez ce que vous faites! YunoHost cessera de mettre à jour ce fichier automatiquement ... Mais attention, les mises à jour de YunoHost pourraient contenir d'importantes modifications recommandées. Si vous le souhaitez, vous pouvez inspecter les différences avec les outils yunohost regen-conf {category} --dry-run --with-diff et forcer la réinitialisation à la configuration recommandée avec les outils yunohost regen-conf {category} --force ", "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …", "apps_catalog_init_success": "Système de catalogue d’applications initialisé !", "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}", "diagnosis_mail_outgoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d’autres serveurs.", - "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal et de votre seul domaine. Vous devez d’abord ajouter un autre domaine à l’aide de 'yunohost domain add ', puis définir comme domaine principal à l’aide de 'yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l’aide de 'yunohost domain remove {domain:s}'.", + "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal et de votre seul domaine. Vous devez d’abord ajouter un autre domaine à l’aide de 'yunohost domain add ', puis définir comme domaine principal à l’aide de 'yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l’aide de 'yunohost domain remove {domain:s}'.'", "diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d’informations.", "diagnosis_description_basesystem": "Système de base", "diagnosis_description_ip": "Connectivité Internet", @@ -581,11 +581,11 @@ "diagnosis_services_running": "Le service {service} est en cours de fonctionnement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})", - "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config", + "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config ", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", - "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service. Si cela ne fonctionne pas, consultez les journaux de service à l’aide de 'yunohost service log {service}' ou de la section 'Services' dans la webadmin.", + "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service, et si cela ne fonctionne pas, consultez les journaux de service dans le webadmin (à partir de la ligne de commande, vous pouvez le faire avec yunohost service restart {service} et yunohost service log {service} ).", "diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", @@ -598,5 +598,44 @@ "diagnosis_basesystem_hardware": "L’architecture du serveur est {virt} {arch}", "group_already_exist_on_system_but_removing_it": "Le groupe {group} est déjà présent dans les groupes du système, mais YunoHost va le supprimer…", "certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.", - "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost." + "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost.", + "diagnosis_mail_outgoing_port_25_ok": "Le serveur de messagerie SMTP peut envoyer des e-mails (le port sortant 25 n'est pas bloqué).", + "diagnosis_mail_outgoing_port_25_blocked_details": "Vous devez d'abord essayer de débloquer le port sortant 25 dans votre interface de routeur Internet ou votre interface d'hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", + "diagnosis_mail_ehlo_bad_answer": "Un service non SMTP a répondu sur le port 25 sur IPv {ipversion}", + "diagnosis_mail_ehlo_bad_answer_details": "Cela peut être dû à un autre répondeur au lieu de votre serveur.", + "diagnosis_mail_ehlo_wrong": "Un autre serveur de messagerie SMTP répond sur IPv{ipversion}. Il ne sera probablement pas en mesure de recevoir des e-mails.", + "diagnosis_mail_ehlo_could_not_diagnose": "Impossible de diagnostiquer si le serveur de messagerie postfix est accessible de l'extérieur pour IPv {ipversion}.", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Erreur: {error}", + "diagnosis_mail_fcrdns_dns_missing": "Aucun DNS inverse n'est défini dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", + "diagnosis_mail_fcrdns_ok": "Votre DNS inversé est correctement configuré !", + "diagnosis_mail_fcrdns_nok_details": "Vous devez d'abord essayer de configurer le DNS inverse avec {ehlo_domain} dans votre interface de routeur Internet ou votre interface d'hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Le DNS inverse n'est pas correctement configuré dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", + "diagnosis_mail_blacklist_ok": "Les adresses IP et les domaines utilisés par ce serveur ne semblent pas être sur liste noire", + "diagnosis_mail_blacklist_reason": "La raison de la liste noire est: {reason}", + "diagnosis_mail_blacklist_website": "Après avoir identifié pourquoi vous êtes répertorié et corrigé, n'hésitez pas à demander la radiation sur {blacklist_website}", + "diagnosis_mail_queue_ok": "{nb_pending} e-mails en attente dans les files d'attente de messagerie", + "diagnosis_mail_queue_unavailable_details": "Erreur: {error}", + "diagnosis_mail_queue_too_big": "Trop d'e-mails en attente dans la file d'attente ({nb_pending} e-mails)", + "global_settings_setting_smtp_allow_ipv6": "Autoriser l'utilisation d'IPv6 pour recevoir et envoyer du courrier", + "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n'a été trouvée.", + "diagnosis_display_tip": "Pour voir les problèmes détectés, vous pouvez accéder à la section Diagnostic du webadmin ou exécuter «yunohost diagnostic show --issues» à partir de la ligne de commande.", + "diagnosis_ip_global": "IP globale: {global} ", + "diagnosis_ip_local": "IP locale: {local} ", + "diagnosis_dns_point_to_doc": "Veuillez consulter la documentation à https://yunohost.org/dns_config si vous avez besoin d'aide pour configurer les enregistrements DNS.", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains fournisseurs ne vous laisseront pas débloquer le port sortant 25 parce qu'ils ne se soucient pas de la neutralité du Net.
- Certains d'entre eux offrent l'alternative de en utilisant un relais de serveur de messagerie bien que cela implique que le relais sera en mesure d'espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type des limites. Voir https://yunohost.org/#/vpn_advantage
- Vous pouvez également envisager de passer à un fournisseur plus respectueux de la neutralité du net ", + "diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des e-mails !", + "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l'extérieur sur IPv {ipversion}. Il ne pourra pas recevoir d'e-mails.", + "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur dans IPv {ipversion}. Il semble inaccessible.
1. La cause la plus courante de ce problème est que le port 25 n'est pas correctement transmis à votre serveur .
2. Vous devez également vous assurer que le suffixe de service est en cours d'exécution.
3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inverse n'interfère.", + "diagnosis_mail_ehlo_wrong_details": "L'EHLO reçu par le diagnostiqueur distant dans IPv {ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu: {right_ehlo}
La cause la plus courante ce problème est que le port 25 n'est pas correctement transmis à votre serveur . Vous pouvez également vous assurer qu'aucun pare-feu ou proxy inverse n'interfère.", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes:
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type de limites. Voir
https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changement de fournisseur ", + "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée ...). Si votre DNS inversé est correctement configuré pour IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'e-mails en exécutant yunohost settings set smtp.allow_ipv6 -v off . Remarque: cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de courriels des quelques serveurs IPv6 uniquement disponibles.", + "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel: {rdns_domain}
Valeur attendue: {ehlo_domain} ", + "diagnosis_mail_blacklist_listed_by": "Votre IP ou domaine {item} est sur liste noire sur {blacklist_name}", + "diagnosis_mail_queue_unavailable": "Impossible de consulter le nombre d'e-mails en attente dans la file d'attente", + "diagnosis_ports_partially_unreachable": "Le port {port} n'est pas accessible de l'extérieur dans IPv {failed}.", + "diagnosis_http_hairpinning_issue": "Votre réseau local ne semble pas avoir activé l'épingle à cheveux.", + "diagnosis_http_hairpinning_issue_details": "C'est probablement à cause de votre box/routeur ISP. Par conséquent, les personnes extérieures à votre réseau local pourront accéder à votre serveur comme prévu, mais pas les personnes internes au réseau local (comme vous, probablement ?). Vous pourrez peut-être améliorer la situation en consultant https://yunohost.org/dns_local_network", + "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible via HTTP depuis l'extérieur du réseau local en IPv {failed}, bien qu'il fonctionne en IPv {passed}.", + "diagnosis_http_nginx_conf_not_up_to_date": "La configuration nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible sur HTTP.", + "diagnosis_http_nginx_conf_not_up_to_date_details": "Pour corriger la situation, inspectez la différence avec la ligne de commande en utilisant les outils yunohost regen-conf nginx --dry-run --with-diff et si vous êtes d'accord, appliquez les modifications avec yunohost tools regen-conf nginx --force." } From 91355274f8c4cee03c63faf9dea3fec278e8e698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Gaspar?= Date: Wed, 22 Apr 2020 10:09:38 +0000 Subject: [PATCH 244/317] Translated using Weblate (French) Currently translated at 100.0% (632 of 632 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/fr/ --- locales/fr.json | 192 ++++++++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index ef60a6956..7bc6b1687 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -12,7 +12,7 @@ "app_install_files_invalid": "Fichiers d’installation incorrects", "app_manifest_invalid": "Manifeste d’application incorrect : {error}", "app_not_correctly_installed": "{app:s} semble être mal installé", - "app_not_installed": "Nous n’avons pas trouvé l’application « {app:s} » dans la liste des applications installées: {all_apps}", + "app_not_installed": "Nous n’avons pas trouvé l’application « {app:s} » dans la liste des applications installées : {all_apps}", "app_not_properly_removed": "{app:s} n’a pas été supprimé correctement", "app_removed": "{app:s} supprimé", "app_requirements_checking": "Vérification des paquets requis pour {app} …", @@ -48,9 +48,9 @@ "custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}", "domain_cert_gen_failed": "Impossible de générer le certificat", "domain_created": "Le domaine a été créé", - "domain_creation_failed": "Impossible de créer le domaine {domain}: {error}", + "domain_creation_failed": "Impossible de créer le domaine {domain} : {error}", "domain_deleted": "Le domaine a été supprimé", - "domain_deletion_failed": "Impossible de supprimer le domaine {domain}:{error}", + "domain_deletion_failed": "Impossible de supprimer le domaine {domain} : {error}", "domain_dyndns_already_subscribed": "Vous avez déjà souscris à un domaine DynDNS", "domain_dyndns_root_unknown": "Domaine DynDNS principal inconnu", "domain_exists": "Le domaine existe déjà", @@ -114,8 +114,8 @@ "restore_failed": "Impossible de restaurer le système", "restore_hook_unavailable": "Script de restauration pour '{part:s}' non disponible sur votre système et non plus dans l'archive", "restore_nothings_done": "Rien n’a été restauré", - "restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}' …", - "restore_running_hooks": "Exécution des scripts de restauration …", + "restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}'…", + "restore_running_hooks": "Exécution des scripts de restauration…", "service_add_failed": "Impossible d’ajouter le service '{service:s}'", "service_added": "Le service '{service:s}' a été ajouté", "service_already_started": "Le service '{service:s}' est déjà en cours d’exécution", @@ -140,25 +140,25 @@ "unexpected_error": "Une erreur inattendue est survenue : {error}", "unlimit": "Pas de quota", "unrestore_app": "L’application '{app:s}' ne sera pas restaurée", - "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système …", + "updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système…", "upgrade_complete": "Mise à jour terminée", - "upgrading_packages": "Mise à jour des paquets en cours …", + "upgrading_packages": "Mise à jour des paquets en cours…", "upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé", "upnp_disabled": "UPnP désactivé", "upnp_enabled": "UPnP activé", "upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP", "user_created": "L’utilisateur créé", - "user_creation_failed": "Impossible de créer l’utilisateur {user}: {error}", + "user_creation_failed": "Impossible de créer l’utilisateur {user} : {error}", "user_deleted": "L’utilisateur supprimé", - "user_deletion_failed": "Impossible de supprimer l’utilisateur {user}: {error}", + "user_deletion_failed": "Impossible de supprimer l’utilisateur {user} : {error}", "user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur", "user_unknown": "L’utilisateur {user:s} est inconnu", - "user_update_failed": "Impossible de mettre à jour l’utilisateur {user}: {error}", + "user_update_failed": "Impossible de mettre à jour l’utilisateur {user} : {error}", "user_updated": "L’utilisateur a été modifié", "yunohost_already_installed": "YunoHost est déjà installé", "yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification", "yunohost_configured": "YunoHost est maintenant configuré", - "yunohost_installing": "L’installation de YunoHost est en cours …", + "yunohost_installing": "L’installation de YunoHost est en cours…", "yunohost_not_installed": "YunoHost n’est pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'", "certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de vouloir remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner cela)", "certmanager_domain_unknown": "Domaine {domain:s} inconnu", @@ -178,7 +178,7 @@ "certmanager_conflicting_nginx_file": "Impossible de préparer le domaine pour le défi ACME : le fichier de configuration NGINX {filepath:s} est en conflit et doit être préalablement retiré", "certmanager_hit_rate_limit": "Trop de certificats ont déjà été émis récemment pour ce même ensemble de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails sur les ratios et limitations", "ldap_init_failed_to_create_admin": "L’initialisation de l’annuaire LDAP n’a pas réussi à créer l’utilisateur admin", - "domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal. Vous devez d’abord définir un autre domaine comme domaine principal à l’aide de 'yunohost domain main-domain -n ', voici la liste des domaines candidats. : {other_domains:s}", + "domain_cannot_remove_main": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal. Vous devez d’abord définir un autre domaine comme domaine principal à l’aide de 'yunohost domain main-domain -n ', voici la liste des domaines candidats : {other_domains:s}", "certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file:s})", "certmanager_unable_to_parse_self_CA_name": "Impossible d’analyser le nom de l’autorité du certificat auto-signé (fichier : {file:s})", "mailbox_used_space_dovecot_down": "Le service de courriel Dovecot doit être démarré si vous souhaitez voir l’espace disque occupé par la messagerie", @@ -187,7 +187,7 @@ "certmanager_acme_not_configured_for_domain": "Le certificat du domaine {domain:s} ne semble pas être correctement installé. Veuillez d’abord exécuter cert-install.", "certmanager_http_check_timeout": "Expiration du délai lorsque le serveur a essayé de se contacter lui-même via HTTP en utilisant l’adresse IP public {ip:s} du domaine {domain:s}. Vous rencontrez peut-être un problème d’hairpinning ou alors le pare-feu/routeur en amont de votre serveur est mal configuré.", "certmanager_couldnt_fetch_intermediate_cert": "Expiration du délai lors de la tentative de récupération du certificat intermédiaire depuis Let’s Encrypt. L’installation ou le renouvellement du certificat a été annulé. Veuillez réessayer plus tard.", - "domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (peut-être que ça n’en causera pas).", + "domain_hostname_failed": "Échec de l’utilisation d’un nouveau nom d’hôte. Cela pourrait causer des soucis plus tard (cela n’en causera peut-être pas).", "yunohost_ca_creation_success": "L’autorité de certification locale créée.", "app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Vérifiez si cela est disponible avec `app changeurl`.", "app_change_url_failed_nginx_reload": "Le redémarrage de Nginx a échoué. Voici la sortie de 'nginx -t' :\n{nginx_errors:s}", @@ -234,8 +234,8 @@ "backup_with_no_restore_script_for_app": "L’application « {app:s} » n’a pas de script de restauration, vous ne pourrez pas restaurer automatiquement la sauvegarde de cette application.", "global_settings_cant_serialize_settings": "Échec de la sérialisation des données de paramétrage car : {reason:s}", "restore_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire", - "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …", - "restore_may_be_not_enough_disk_space": "Votre système ne semble pas avoir suffisamment d'espace (libre: {free_space:d} B, espace nécessaire: {needed_space:d} B, marge de sécurité: {margin:d} B)", + "restore_extracting": "Extraction des fichiers nécessaires depuis l’archive…", + "restore_may_be_not_enough_disk_space": "Votre système ne semble pas avoir suffisamment d’espace (libre : {free_space:d} B, espace nécessaire : {needed_space:d} B, marge de sécurité : {margin:d} B)", "restore_not_enough_disk_space": "Espace disponible insuffisant (L’espace libre est de {free_space:d} octets. Le besoin d’espace nécessaire est de {needed_space:d} octets. En appliquant une marge de sécurité, la quantité d’espace nécessaire est de {margin:d} octets)", "restore_system_part_failed": "Impossible de restaurer la partie '{part:s}' du système", "backup_couldnt_bind": "Impossible de lier {src:s} avec {dest:s}.", @@ -244,7 +244,7 @@ "migrations_loading_migration": "Chargement de la migration {id} …", "migrations_migration_has_failed": "La migration {id} a échoué avec l’exception {exception} : annulation", "migrations_no_migrations_to_run": "Aucune migration à lancer", - "migrations_skip_migration": "Ignorer et passer la migration {id} …", + "migrations_skip_migration": "Ignorer et passer la migration {id}…", "server_shutdown": "Le serveur va s’éteindre", "server_shutdown_confirm": "Le serveur va être éteint immédiatement, le voulez-vous vraiment ? [{answers:s}]", "server_reboot": "Le serveur va redémarrer", @@ -256,7 +256,7 @@ "app_upgrade_app_name": "Mise à jour de l’application {app} …", "backup_output_symlink_dir_broken": "Votre répertoire d’archivage '{path:s}' est un lien symbolique brisé. Peut-être avez-vous oublié de re/monter ou de brancher le support de stockage sur lequel il pointe.", "migrate_tsig_end": "La migration à HMAC-SHA-512 est terminée", - "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à hmac-sha512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}", + "migrate_tsig_failed": "La migration du domaine DynDNS {domain} à HMAC-SHA-512 a échoué. Annulation des modifications. Erreur : {error_code} - {error}", "migrate_tsig_start": "L’algorithme de génération des clefs n’est pas suffisamment sécurisé pour la signature TSIG du domaine '{domain}', lancement de la migration vers HMAC-SHA-512 qui est plus sécurisé", "migrate_tsig_wait": "Attendre trois minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …", "migrate_tsig_wait_2": "2 minutes …", @@ -269,19 +269,19 @@ "migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.", "migration_0003_patching_sources_list": "Modification du fichier sources.lists …", "migration_0003_main_upgrade": "Démarrage de la mise à niveau principale …", - "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de fail2ban …", - "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d'une manière ou d'une autre. La migration va d'abord le réinitialiser à son état d'origine… Le fichier précédent sera disponible en tant que {backup_dest}.", + "migration_0003_fail2ban_upgrade": "Démarrage de la mise à niveau de Fail2Ban …", + "migration_0003_restoring_origin_nginx_conf": "Votre fichier /etc/nginx/nginx.conf a été modifié d'une manière ou d’une autre. La migration va d’abord le réinitialiser à son état d'origine… Le fichier précédent sera disponible en tant que {backup_dest}.", "migration_0003_yunohost_upgrade": "Démarrage de la mise à niveau du package YunoHost… La migration se terminera, mais la mise à niveau réelle aura lieu immédiatement après. Une fois l'opération terminée, vous devrez peut-être vous reconnecter à la page webadmin.", "migration_0003_not_jessie": "La distribution Debian actuelle n’est pas Jessie !", "migration_0003_system_not_fully_up_to_date": "Votre système n’est pas complètement à jour. Veuillez mener une mise à jour classique avant de lancer la migration à Stretch.", "migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est mal passé pendant la mise à niveau principale : le système est toujours sur Debian Jessie !? Pour investiguer sur le problème, veuillez regarder les journaux {log}:s …", "migration_0003_general_warning": "Veuillez noter que cette migration est une opération délicate. Si l’équipe YunoHost a fait de son mieux pour la relire et la tester, la migration pourrait tout de même casser des parties de votre système ou de vos applications.\n\nEn conséquence, nous vous recommandons :\n - de lancer une sauvegarde de vos données ou applications critiques. Plus d’informations sur https://yunohost.org/backup ;\n - d’être patient après avoir lancé la migration : selon votre connexion internet et matériel, cela pourrait prendre jusqu’à quelques heures pour que tout soit à niveau.\n\nEn outre, le port SMTP utilisé par les clients de messagerie externes comme (Thunderbird ou K9-Mail) a été changé de 465 (SSL/TLS) à 587 (STARTTLS). L’ancien port 465 sera automatiquement fermé et le nouveau port 587 sera ouvert dans le pare-feu. Vous et vos utilisateurs *devront* adapter la configuration de vos clients de messagerie en conséquence.", - "migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n’ont pas été installées à partir d’un catalogue d’applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu’ils fonctionneront toujours après la mise à niveau: {problematic_apps}", + "migration_0003_problematic_apps_warning": "Veuillez noter que les applications installées potentiellement problématiques suivantes ont été détectées. Il semble que celles-ci n’ont pas été installées à partir d’un catalogue d’applications, ou ne sont pas marquées comme \"fonctionnelle\". Par conséquent, il ne peut pas être garanti qu’ils fonctionneront toujours après la mise à niveau : {problematic_apps}", "migration_0003_modified_files": "Veuillez noter que les fichiers suivants ont été détectés comme modifiés manuellement et pourraient être écrasés à la fin de la mise à niveau : {manually_modified_files}", "migrations_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.", "migrations_to_be_ran_manually": "La migration {id} doit être lancée manuellement. Veuillez aller dans Outils > Migrations dans l’interface admin, ou lancer `yunohost tools migrations migrate`.", "migrations_need_to_accept_disclaimer": "Pour lancer la migration {id}, vous devez accepter cette clause de non-responsabilité :\n---\n{disclaimer}\n---\nSi vous acceptez de lancer la migration, veuillez relancer la commande avec l’option --accept-disclaimer.", - "service_description_avahi-daemon": "Vous permet d’atteindre votre serveur en utilisant «yunohost.local» sur votre réseau local", + "service_description_avahi-daemon": "Vous permet d’atteindre votre serveur en utilisant « yunohost.local » sur votre réseau local", "service_description_dnsmasq": "Gère la résolution des noms de domaine (DNS)", "service_description_dovecot": "Permet aux clients de messagerie d’accéder/récupérer les courriels (via IMAP et POP3)", "service_description_fail2ban": "Protège contre les attaques brute-force et autres types d’attaques venant d’Internet", @@ -304,7 +304,7 @@ "log_link_to_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en cliquant ici", "backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge PHP 7, vous pourriez ne plus pouvoir restaurer vos applications PHP (cause : {error:s})", "log_help_to_get_failed_log": "L’opération '{desc}' a échoué ! Pour obtenir de l’aide, merci de partager le journal de l’opération en utilisant la commande 'yunohost log display {name} --share'", - "log_does_exists": "Il n'y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d'opérations disponibles", + "log_does_exists": "Il n’y a pas de journal des opérations avec le nom '{log}', utilisez 'yunohost log list' pour voir tous les journaux d’opérations disponibles", "log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement", "log_app_change_url": "Changer l’URL de l’application '{}'", "log_app_install": "Installer l’application '{}'", @@ -327,7 +327,7 @@ "log_user_delete": "Supprimer l’utilisateur '{}'", "log_user_update": "Mettre à jour les informations de l’utilisateur '{}'", "log_domain_main_domain": "Faites de '{}' le domaine principal", - "log_tools_migrations_migrate_forward": "Éxecuter les migrations", + "log_tools_migrations_migrate_forward": "Exécuter les migrations", "log_tools_postinstall": "Faire la post-installation de votre serveur YunoHost", "log_tools_upgrade": "Mettre à jour les paquets du système", "log_tools_shutdown": "Éteindre votre serveur", @@ -336,7 +336,7 @@ "migration_description_0004_php5_to_php7_pools": "Reconfigurer les espaces utilisateurs PHP pour utiliser PHP 7 au lieu de PHP 5", "migration_description_0005_postgresql_9p4_to_9p6": "Migration des bases de données de PostgreSQL 9.4 vers PostgreSQL 9.6", "migration_0005_postgresql_94_not_installed": "PostgreSQL n’a pas été installé sur votre système. Rien à faire !", - "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 est installé, mais pas postgresql 9.6‽ Quelque chose de bizarre aurait pu se produire sur votre système: (…", + "migration_0005_postgresql_96_not_installed": "PostgreSQL 9.4 est installé, mais pas PostgreSQL 9.6 ‽ Quelque chose de bizarre aurait pu se produire sur votre système :(…", "migration_0005_not_enough_space": "Laissez suffisamment d’espace disponible dans {path} pour exécuter la migration.", "service_description_php7.0-fpm": "Exécute des applications écrites en PHP avec NGINX", "users_available": "Liste des utilisateurs disponibles :", @@ -380,7 +380,7 @@ "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l’utilisateur admin ;", "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d’invalider un avertissement effrayant de votre client SSH afin de revérifier l’empreinte de votre serveur ;", "migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", - "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse pas être promis! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse pas être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", "migrations_success": "Migration {number} {name} réussie !", "pattern_password_app": "Désolé, les mots de passe ne peuvent pas contenir les caractères suivants : {forbidden_chars}", "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.", @@ -391,7 +391,7 @@ "service_reload_or_restart_failed": "Impossible de recharger ou de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}", "service_reloaded_or_restarted": "Le service « {service:s} » a été rechargé ou redémarré", "this_action_broke_dpkg": "Cette action a laissé des paquets non configurés par dpkg/apt (les gestionnaires de paquets système). Vous pouvez essayer de résoudre ce problème en vous connectant via SSH et en exécutant `sudo dpkg --configure -a`.", - "app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d’exécution pour exécuter cette action: {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).", + "app_action_cannot_be_ran_because_required_services_down": "Ces services requis doivent être en cours d’exécution pour exécuter cette action : {services}. Essayez de les redémarrer pour continuer (et éventuellement rechercher pourquoi ils sont en panne).", "admin_password_too_long": "Veuillez choisir un mot de passe de moins de 127 caractères", "log_regen_conf": "Régénérer les configurations du système '{}'", "migration_0009_not_needed": "Cette migration semble avoir déjà été jouée ? On l’ignore.", @@ -405,7 +405,7 @@ "regenconf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost (catégorie {category}).", "regenconf_up_to_date": "La configuration est déjà à jour pour la catégorie '{category}'", "already_up_to_date": "Il n’y a rien à faire ! Tout est déjà à jour !", - "global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web nginx. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", + "global_settings_setting_security_nginx_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur web Nginx. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", "global_settings_setting_security_ssh_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur SSH. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", "global_settings_setting_security_postfix_compatibility": "Compatibilité versus compromis sécuritaire pour le serveur Postfix. Affecte les cryptogrammes (et d’autres aspects liés à la sécurité)", "migration_description_0009_decouple_regenconf_from_services": "Dissocier le mécanisme « regen-conf » des services", @@ -413,20 +413,20 @@ "regenconf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par « regen-conf » (catégorie {category}) mais a été conservé.", "regenconf_updated": "La configuration a été mise à jour pour '{category}'", "regenconf_would_be_updated": "La configuration aurait dû être mise à jour pour la catégorie '{category}'", - "regenconf_dry_pending_applying": "Vérification de la configuration en attente qui aurait été appliquée pour la catégorie '{category}' …", + "regenconf_dry_pending_applying": "Vérification de la configuration en attente qui aurait été appliquée pour la catégorie '{category}'…", "regenconf_failed": "Impossible de régénérer la configuration pour la ou les catégorie(s) : '{categories}'", "regenconf_pending_applying": "Applique la configuration en attente pour la catégorie '{category}' …", "service_regen_conf_is_deprecated": "'yunohost service regen-conf' est obsolète ! Veuillez plutôt utiliser 'yunohost tools regen-conf' à la place.", - "tools_upgrade_at_least_one": "Veuillez spécifier '--apps' OU '--system'", + "tools_upgrade_at_least_one": "Veuillez spécifier '--apps' ou '--system'", "tools_upgrade_cant_both": "Impossible de mettre à niveau le système et les applications en même temps", "tools_upgrade_cant_hold_critical_packages": "Impossibilité de maintenir les paquets critiques…", - "tools_upgrade_regular_packages": "Mise à jour des paquets du système (non liés a YunoHost) …", + "tools_upgrade_regular_packages": "Mise à jour des paquets du système (non liés a YunoHost)…", "tools_upgrade_regular_packages_failed": "Impossible de mettre à jour les paquets suivants : {packages_list}", - "tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost) …", + "tools_upgrade_special_packages": "Mise à jour des paquets 'spécifiques' (liés a YunoHost)…", "tools_upgrade_special_packages_completed": "La mise à jour des paquets de YunoHost est finie !\nPressez [Entrée] pour revenir à la ligne de commande", "dpkg_lock_not_available": "Cette commande ne peut pas être exécutée pour le moment car un autre programme semble utiliser le verrou de dpkg (le gestionnaire de package système)", "tools_upgrade_cant_unhold_critical_packages": "Impossible de conserver les paquets critiques…", - "tools_upgrade_special_packages_explanation": "La mise à niveau spéciale se poursuivra en arrière-plan. Veuillez ne pas lancer d'autres actions sur votre serveur pendant les 10 prochaines minutes (selon la vitesse du matériel). Après cela, vous devrez peut-être vous reconnecter à l'administrateur Web. Le journal de mise à niveau sera disponible dans Outils → Journal (dans le webadmin) ou en utilisant la «liste des journaux yunohost» (à partir de la ligne de commande).", + "tools_upgrade_special_packages_explanation": "La mise à niveau spéciale se poursuivra en arrière-plan. Veuillez ne pas lancer d'autres actions sur votre serveur pendant les 10 prochaines minutes (selon la vitesse du matériel). Après cela, vous devrez peut-être vous reconnecter à l'administrateur Web. Le journal de mise à niveau sera disponible dans Outils → Journal (dans le webadmin) ou en utilisant la « liste des journaux yunohost » (à partir de la ligne de commande).", "update_apt_cache_failed": "Impossible de mettre à jour le cache APT (gestionnaire de paquets Debian). Voici un extrait du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "update_apt_cache_warning": "Des erreurs se sont produites lors de la mise à jour du cache APT (gestionnaire de paquets Debian). Voici un extrait des lignes du fichier sources.list qui pourrait vous aider à identifier les lignes problématiques :\n{sourceslist}", "backup_permission": "Permission de sauvegarde pour l’application {app:s}", @@ -435,8 +435,8 @@ "group_unknown": "Le groupe {group:s} est inconnu", "group_updated": "Le groupe '{group}' a été mis à jour", "group_update_failed": "La mise à jour du groupe '{group}' a échoué : {error}", - "group_creation_failed": "Échec de la création du groupe '{group}': {error}", - "group_deletion_failed": "Échec de la suppression du groupe '{group}': {error}", + "group_creation_failed": "Échec de la création du groupe '{group}' : {error}", + "group_deletion_failed": "Échec de la suppression du groupe '{group}' : {error}", "log_user_group_delete": "Supprimer le groupe '{}'", "log_user_group_update": "Mettre à jour '{}' pour le groupe", "mailbox_disabled": "La boîte aux lettres est désactivée pour l’utilisateur {user:s}", @@ -449,23 +449,23 @@ "migrations_pending_cant_rerun": "Ces migrations étant toujours en attente, vous ne pouvez pas les exécuter à nouveau : {ids}", "migration_description_0012_postgresql_password_to_md5_authentication": "Forcer l’authentification PostgreSQL à utiliser MD5 pour les connexions locales", "migrations_exclusive_options": "'auto', '--skip' et '--force-rerun' sont des options mutuellement exclusives.", - "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées: {ids}", - "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n’a pas pu être terminée avant l’échec de la migration. Erreur: {error:s}", - "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP …", + "migrations_not_pending_cant_skip": "Ces migrations ne sont pas en attente et ne peuvent donc pas être ignorées : {ids}", + "migration_0011_can_not_backup_before_migration": "La sauvegarde du système n’a pas pu être terminée avant l’échec de la migration. Erreur : {error:s}", + "migration_0011_migrate_permission": "Migration des autorisations des paramètres des applications vers LDAP…", "migration_0011_migration_failed_trying_to_rollback": "La migration a échoué… Tentative de restauration du système.", "migration_0011_rollback_success": "Système restauré.", "migration_0011_update_LDAP_database": "Mise à jour de la base de données LDAP…", "migration_0011_backup_before_migration": "Création d’une sauvegarde des paramètres de la base de données LDAP et des applications avant la migration.", "permission_not_found": "Autorisation '{permission:s}' introuvable", - "permission_update_failed": "Impossible de mettre à jour l'autorisation '{permission}': {error}", + "permission_update_failed": "Impossible de mettre à jour l’autorisation '{permission}' : {error}", "permission_updated": "Permission '{permission:s}' mise à jour", "permission_update_nothing_to_do": "Aucune autorisation pour mettre à jour", - "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur DynDNS {provider}: votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", - "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP …", + "dyndns_provider_unreachable": "Impossible d’atteindre le fournisseur DynDNS {provider} : votre YunoHost n’est pas correctement connecté à Internet ou le serveur Dynette est en panne.", + "migration_0011_update_LDAP_schema": "Mise à jour du schéma LDAP…", "migrations_already_ran": "Ces migrations sont déjà effectuées : {ids}", "migrations_dependencies_not_satisfied": "Exécutez ces migrations : '{dependencies_id}', avant migration {id}.", - "migrations_failed_to_load_migration": "Impossible de charger la migration {id}: {error}", - "migrations_running_forward": "Exécution de la migration {id} …", + "migrations_failed_to_load_migration": "Impossible de charger la migration {id} : {error}", + "migrations_running_forward": "Exécution de la migration {id}…", "migrations_success_forward": "Migration {id} terminée", "operation_interrupted": "L’opération a été interrompue manuellement ?", "permission_already_exist": "L’autorisation '{permission}' existe déjà", @@ -474,7 +474,7 @@ "permission_deleted": "Permission '{permission:s}' supprimée", "permission_deletion_failed": "Impossible de supprimer la permission '{permission}' : {error}", "migration_description_0011_setup_group_permission": "Initialiser les groupes d’utilisateurs et autorisations pour les applications et les services", - "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur: {error:s}", + "migration_0011_LDAP_update_failed": "Impossible de mettre à jour LDAP. Erreur : {error:s}", "group_already_exist": "Le groupe {group} existe déjà", "group_already_exist_on_system": "Le groupe {group} existe déjà dans les groupes système", "group_cannot_be_deleted": "Le groupe {group} ne peut pas être supprimé manuellement.", @@ -485,20 +485,20 @@ "log_user_group_create": "Créer '{}' groupe", "log_user_permission_update": "Mise à jour des accès pour la permission '{}'", "log_user_permission_reset": "Réinitialiser la permission '{}'", - "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn}: {error}", - "permission_already_allowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' activée", - "permission_already_disallowed": "Le groupe '{group}' a déjà l'autorisation '{permission}' désactivé", - "permission_cannot_remove_main": "Supprimer une autorisation principale n'est pas autorisé", - "user_already_exists": "L'utilisateur '{user}' existe déjà", - "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d'autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", - "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C'est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", - "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C'est un groupe spécial représentant les visiteurs anonymes", - "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C'est le groupe principal destiné à ne contenir qu'un utilisateur spécifique.", - "log_permission_url": "Mise à jour de l'URL associée à l'autorisation '{}'", + "migration_0011_failed_to_remove_stale_object": "Impossible de supprimer un objet périmé {dn} : {error}", + "permission_already_allowed": "Le groupe '{group}' a déjà l’autorisation '{permission}' activée", + "permission_already_disallowed": "Le groupe '{group}' a déjà l’autorisation '{permission}' désactivé", + "permission_cannot_remove_main": "Supprimer une autorisation principale n’est pas autorisé", + "user_already_exists": "L’utilisateur '{user}' existe déjà", + "app_full_domain_unavailable": "Désolé, cette application doit être installée sur un domaine qui lui est propre, mais d’autres applications sont déjà installées sur le domaine '{domain}'. Vous pouvez utiliser un sous-domaine dédié à cette application à la place.", + "group_cannot_edit_all_users": "Le groupe 'all_users' ne peut pas être édité manuellement. C’est un groupe spécial destiné à contenir tous les utilisateurs enregistrés dans YunoHost", + "group_cannot_edit_visitors": "Le groupe 'visiteurs' ne peut pas être édité manuellement. C’est un groupe spécial représentant les visiteurs anonymes", + "group_cannot_edit_primary_group": "Le groupe '{group}' ne peut pas être édité manuellement. C’est le groupe principal destiné à ne contenir qu’un utilisateur spécifique.", + "log_permission_url": "Mise à jour de l’URL associée à l’autorisation '{}'", "migration_0011_slapd_config_will_be_overwritten": "Il semble que vous ayez modifié manuellement la configuration de slapd. Pour cette migration critique, YunoHost doit forcer la mise à jour de la configuration de slapd. Les fichiers originaux seront sauvegardés dans {conf_backup_folder}.", "permission_already_up_to_date": "L’autorisation n’a pas été mise à jour car les demandes d’ajout/suppression correspondent déjà à l’état actuel.", "permission_currently_allowed_for_all_users": "Cette autorisation est actuellement accordée à tous les utilisateurs en plus des autres groupes. Vous voudrez probablement soit supprimer l’autorisation 'all_users', soit supprimer les autres groupes auxquels il est actuellement autorisé.", - "app_install_failed": "Impossible d’installer {app}: {error}", + "app_install_failed": "Impossible d’installer {app} : {error}", "app_install_script_failed": "Une erreur est survenue dans le script d’installation de l’application", "permission_require_account": "Permission {permission} n’a de sens que pour les utilisateurs ayant un compte et ne peut donc pas être activé pour les visiteurs.", "app_remove_after_failed_install": "Supprimer l’application après l’échec de l’installation …", @@ -509,23 +509,23 @@ "diagnosis_ip_not_connected_at_all": "Le serveur ne semble pas du tout connecté à Internet !?", "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais il semble que vous utilisez un /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Le fichier /etc/resolv.conf doit être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Si vous souhaitez configurer manuellement les résolveurs DNS, veuillez modifier /etc/resolv.dnsmasq.conf.", - "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType: {type}\nNom: {name}\nValeur {value}", - "diagnosis_diskusage_ok": "L'espace de stockage {mountpoint} (sur l'appareil {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", + "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType : {type}\nNom : {name}\nValeur : {value}", + "diagnosis_diskusage_ok": "L’espace de stockage {mountpoint} (sur l’appareil {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", "diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", "diagnosis_basesystem_host": "Le serveur utilise Debian {debian_version}", "diagnosis_basesystem_kernel": "Le serveur utilise le noyau Linux {kernel_version}", - "diagnosis_basesystem_ynh_single_version": "{package} version: {version} ({repo})", + "diagnosis_basesystem_ynh_single_version": "{package} version : {version} ({repo})", "diagnosis_basesystem_ynh_main_version": "Le serveur utilise YunoHost {main_version} ({repo})", - "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... très probablement en raison d'une mise à niveau échouée ou partielle.", + "diagnosis_basesystem_ynh_inconsistent_versions": "Vous exécutez des versions incohérentes des packages YunoHost ... très probablement en raison d’une mise à niveau échouée ou partielle.", "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}", "diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment!)", "diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))", "diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.", "diagnosis_everything_ok": "Tout semble bien pour {category} !", - "diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}': {error}", + "diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}' : {error}", "diagnosis_ip_connected_ipv4": "Le serveur est connecté à Internet en IPv4 !", "diagnosis_ip_no_ipv4": "Le serveur ne dispose pas d’une adresse IPv4.", "diagnosis_ip_connected_ipv6": "Le serveur est connecté à Internet en IPv6 !", @@ -535,9 +535,9 @@ "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble être rompue sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas sur 127.0.0.1.", "diagnosis_dns_good_conf": "Les enregistrements DNS sont correctement configurés pour le domaine {domain} (catégorie {category})", "diagnosis_dns_bad_conf": "Certains enregistrements DNS sont manquants ou incorrects pour le domaine {domain} (catégorie {category})", - "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle: {current}\nValeur attendue: {value}", + "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle : {current}\nValeur attendue : {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "L'espace de stockage {mountpoint} (sur l'appareil {device} ) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Vous devriez vraiment envisager de nettoyer de l'espace !", + "diagnosis_diskusage_verylow": "L'espace de stockage {mountpoint} (sur l’appareil {device} ) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Vous devriez vraiment envisager de nettoyer de l’espace !", "diagnosis_diskusage_low": "L'espace de stockage {mountpoint} (sur l'appareil {device}) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Faites attention.", "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", "diagnosis_ram_low": "Le système n’a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", @@ -546,10 +546,10 @@ "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} semble avoir été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", - "diagnosis_regenconf_manually_modified_details": "C'est probablement OK si vous savez ce que vous faites! YunoHost cessera de mettre à jour ce fichier automatiquement ... Mais attention, les mises à jour de YunoHost pourraient contenir d'importantes modifications recommandées. Si vous le souhaitez, vous pouvez inspecter les différences avec les outils yunohost regen-conf {category} --dry-run --with-diff et forcer la réinitialisation à la configuration recommandée avec les outils yunohost regen-conf {category} --force ", + "diagnosis_regenconf_manually_modified_details": "C’est probablement OK si vous savez ce que vous faites ! YunoHost cessera de mettre à jour ce fichier automatiquement ... Mais attention, les mises à jour de YunoHost pourraient contenir d’importantes modifications recommandées. Si vous le souhaitez, vous pouvez inspecter les différences avec les outils yunohost regen-conf {category} --dry-run --with-diff et forcer la réinitialisation à la configuration recommandée avec les outils yunohost regen-conf {category} --force ", "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …", "apps_catalog_init_success": "Système de catalogue d’applications initialisé !", - "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog}:{error}", + "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog} : {error}", "diagnosis_mail_outgoing_port_25_blocked": "Le port sortant 25 semble être bloqué. Vous devriez essayer de le débloquer dans le panneau de configuration de votre fournisseur de services Internet (ou hébergeur). En attendant, le serveur ne pourra pas envoyer de courrier électronique à d’autres serveurs.", "domain_cannot_remove_main_add_new_one": "Vous ne pouvez pas supprimer '{domain:s}' car il s’agit du domaine principal et de votre seul domaine. Vous devez d’abord ajouter un autre domaine à l’aide de 'yunohost domain add ', puis définir comme domaine principal à l’aide de 'yunohost domain main-domain -n ' et vous pouvez ensuite supprimer le domaine '{domain:s}' à l’aide de 'yunohost domain remove {domain:s}'.'", "diagnosis_security_vulnerable_to_meltdown_details": "Pour résoudre ce problème, vous devez mettre à niveau votre système et redémarrer pour charger le nouveau noyau Linux (ou contacter votre fournisseur de serveur si cela ne fonctionne pas). Voir https://meltdownattack.com/ pour plus d’informations.", @@ -562,19 +562,19 @@ "diagnosis_description_regenconf": "Configurations système", "diagnosis_description_security": "Contrôles de sécurité", "diagnosis_ports_could_not_diagnose": "Impossible de diagnostiquer si les ports sont accessibles de l'extérieur.", - "diagnosis_ports_could_not_diagnose_details": "Erreur: {error}", - "apps_catalog_updating": "Mise à jour du catalogue d'applications…", + "diagnosis_ports_could_not_diagnose_details": "Erreur : {error}", + "apps_catalog_updating": "Mise à jour du catalogue d’applications…", "apps_catalog_obsolete_cache": "Le cache du catalogue d'applications est vide ou obsolète.", "apps_catalog_update_success": "Le catalogue des applications a été mis à jour !", "diagnosis_mail_ougoing_port_25_ok": "Le port sortant 25 n’est pas bloqué et le courrier électronique peut être envoyé à d’autres serveurs.", - "diagnosis_description_mail": "Email", + "diagnosis_description_mail": "E-mail", "diagnosis_ports_unreachable": "Le port {port} n’est pas accessible de l’extérieur.", "diagnosis_ports_ok": "Le port {port} est accessible de l’extérieur.", "diagnosis_http_could_not_diagnose": "Impossible de diagnostiquer si le domaine est accessible de l’extérieur.", - "diagnosis_http_could_not_diagnose_details": "Erreur: {error}", + "diagnosis_http_could_not_diagnose_details": "Erreur : {error}", "diagnosis_http_ok": "Le domaine {domain} est accessible en HTTP depuis l’extérieur.", "diagnosis_http_unreachable": "Le domaine {domain} est inaccessible en HTTP depuis l’extérieur.", - "diagnosis_unknown_categories": "Les catégories suivantes sont inconnues: {categories}", + "diagnosis_unknown_categories": "Les catégories suivantes sont inconnues : {categories}", "migration_description_0013_futureproof_apps_catalog_system": "Migrer vers le nouveau système de catalogue d’applications à l’épreuve du temps", "app_upgrade_script_failed": "Une erreur s’est produite durant l’exécution du script de mise à niveau de l’application", "migration_description_0014_remove_app_status_json": "Supprimer les anciens fichiers d’application status.json", @@ -584,10 +584,10 @@ "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config ", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", - "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommendé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande);\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande);\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de Yunohost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", + "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommandé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande) ;\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande) ;\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de YunoHost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service, et si cela ne fonctionne pas, consultez les journaux de service dans le webadmin (à partir de la ligne de commande, vous pouvez le faire avec yunohost service restart {service} et yunohost service log {service} ).", - "diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration nginx est à jour et qu’un reverse-proxy n’interfère pas.", - "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", + "diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration Nginx est à jour et qu’un reverse-proxy n’interfère pas.", + "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que Nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", "log_app_action_run": "Lancer l’action de l’application '{}'", "log_app_config_show_panel": "Montrer le panneau de configuration de l’application '{}'", @@ -600,42 +600,42 @@ "certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.", "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost.", "diagnosis_mail_outgoing_port_25_ok": "Le serveur de messagerie SMTP peut envoyer des e-mails (le port sortant 25 n'est pas bloqué).", - "diagnosis_mail_outgoing_port_25_blocked_details": "Vous devez d'abord essayer de débloquer le port sortant 25 dans votre interface de routeur Internet ou votre interface d'hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", + "diagnosis_mail_outgoing_port_25_blocked_details": "Vous devez d’abord essayer de débloquer le port sortant 25 dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", "diagnosis_mail_ehlo_bad_answer": "Un service non SMTP a répondu sur le port 25 sur IPv {ipversion}", "diagnosis_mail_ehlo_bad_answer_details": "Cela peut être dû à un autre répondeur au lieu de votre serveur.", "diagnosis_mail_ehlo_wrong": "Un autre serveur de messagerie SMTP répond sur IPv{ipversion}. Il ne sera probablement pas en mesure de recevoir des e-mails.", - "diagnosis_mail_ehlo_could_not_diagnose": "Impossible de diagnostiquer si le serveur de messagerie postfix est accessible de l'extérieur pour IPv {ipversion}.", - "diagnosis_mail_ehlo_could_not_diagnose_details": "Erreur: {error}", - "diagnosis_mail_fcrdns_dns_missing": "Aucun DNS inverse n'est défini dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", + "diagnosis_mail_ehlo_could_not_diagnose": "Impossible de diagnostiquer si le serveur de messagerie postfix est accessible de l’extérieur pour IPv {ipversion}.", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Erreur : {error}", + "diagnosis_mail_fcrdns_dns_missing": "Aucun DNS inverse n’est défini dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", "diagnosis_mail_fcrdns_ok": "Votre DNS inversé est correctement configuré !", - "diagnosis_mail_fcrdns_nok_details": "Vous devez d'abord essayer de configurer le DNS inverse avec {ehlo_domain} dans votre interface de routeur Internet ou votre interface d'hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", + "diagnosis_mail_fcrdns_nok_details": "Vous devez d’abord essayer de configurer le DNS inverse avec {ehlo_domain} dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Le DNS inverse n'est pas correctement configuré dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", "diagnosis_mail_blacklist_ok": "Les adresses IP et les domaines utilisés par ce serveur ne semblent pas être sur liste noire", - "diagnosis_mail_blacklist_reason": "La raison de la liste noire est: {reason}", - "diagnosis_mail_blacklist_website": "Après avoir identifié pourquoi vous êtes répertorié et corrigé, n'hésitez pas à demander la radiation sur {blacklist_website}", + "diagnosis_mail_blacklist_reason": "La raison de la liste noire est : {reason}", + "diagnosis_mail_blacklist_website": "Après avoir identifié pourquoi vous êtes répertorié et corrigé, n’hésitez pas à demander la radiation sur {blacklist_website}", "diagnosis_mail_queue_ok": "{nb_pending} e-mails en attente dans les files d'attente de messagerie", - "diagnosis_mail_queue_unavailable_details": "Erreur: {error}", - "diagnosis_mail_queue_too_big": "Trop d'e-mails en attente dans la file d'attente ({nb_pending} e-mails)", - "global_settings_setting_smtp_allow_ipv6": "Autoriser l'utilisation d'IPv6 pour recevoir et envoyer du courrier", - "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n'a été trouvée.", - "diagnosis_display_tip": "Pour voir les problèmes détectés, vous pouvez accéder à la section Diagnostic du webadmin ou exécuter «yunohost diagnostic show --issues» à partir de la ligne de commande.", - "diagnosis_ip_global": "IP globale: {global} ", - "diagnosis_ip_local": "IP locale: {local} ", - "diagnosis_dns_point_to_doc": "Veuillez consulter la documentation à https://yunohost.org/dns_config si vous avez besoin d'aide pour configurer les enregistrements DNS.", - "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains fournisseurs ne vous laisseront pas débloquer le port sortant 25 parce qu'ils ne se soucient pas de la neutralité du Net.
- Certains d'entre eux offrent l'alternative de en utilisant un relais de serveur de messagerie bien que cela implique que le relais sera en mesure d'espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type des limites. Voir https://yunohost.org/#/vpn_advantage
- Vous pouvez également envisager de passer à un fournisseur plus respectueux de la neutralité du net ", + "diagnosis_mail_queue_unavailable_details": "Erreur : {error}", + "diagnosis_mail_queue_too_big": "Trop d’e-mails en attente dans la file d'attente ({nb_pending} e-mails)", + "global_settings_setting_smtp_allow_ipv6": "Autoriser l'utilisation d’IPv6 pour recevoir et envoyer du courrier", + "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n’a été trouvée.", + "diagnosis_display_tip": "Pour voir les problèmes détectés, vous pouvez accéder à la section Diagnostic du webadmin ou exécuter « yunohost diagnostic show --issues » à partir de la ligne de commande.", + "diagnosis_ip_global": "IP globale : {global} ", + "diagnosis_ip_local": "IP locale : {local} ", + "diagnosis_dns_point_to_doc": "Veuillez consulter la documentation à https://yunohost.org/dns_config si vous avez besoin d’aide pour configurer les enregistrements DNS.", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains fournisseurs ne vous laisseront pas débloquer le port sortant 25 parce qu’ils ne se soucient pas de la neutralité du Net.
- Certains d’entre eux offrent l’alternative de en utilisant un relais de serveur de messagerie bien que cela implique que le relais sera en mesure d’espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type des limites. Voir https://yunohost.org/#/vpn_advantage
- Vous pouvez également envisager de passer à un fournisseur plus respectueux de la neutralité du net ", "diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des e-mails !", - "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l'extérieur sur IPv {ipversion}. Il ne pourra pas recevoir d'e-mails.", + "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l’extérieur sur IPv {ipversion}. Il ne pourra pas recevoir d’e-mails.", "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur dans IPv {ipversion}. Il semble inaccessible.
1. La cause la plus courante de ce problème est que le port 25 n'est pas correctement transmis à votre serveur .
2. Vous devez également vous assurer que le suffixe de service est en cours d'exécution.
3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inverse n'interfère.", - "diagnosis_mail_ehlo_wrong_details": "L'EHLO reçu par le diagnostiqueur distant dans IPv {ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu: {right_ehlo}
La cause la plus courante ce problème est que le port 25 n'est pas correctement transmis à votre serveur . Vous pouvez également vous assurer qu'aucun pare-feu ou proxy inverse n'interfère.", - "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes:
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type de limites. Voir
https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changement de fournisseur ", + "diagnosis_mail_ehlo_wrong_details": "L’EHLO reçu par le diagnostiqueur distant dans IPv {ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu : {right_ehlo}
La cause la plus courante ce problème est que le port 25 n’est pas correctement transmis à votre serveur . Vous pouvez également vous assurer qu’aucun pare-feu ou proxy inverse n’interfère.", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes :
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type de limites. Voir
https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changement de fournisseur ", "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée ...). Si votre DNS inversé est correctement configuré pour IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'e-mails en exécutant yunohost settings set smtp.allow_ipv6 -v off . Remarque: cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de courriels des quelques serveurs IPv6 uniquement disponibles.", - "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel: {rdns_domain}
Valeur attendue: {ehlo_domain} ", + "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : {rdns_domain}
Valeur attendue : {ehlo_domain} ", "diagnosis_mail_blacklist_listed_by": "Votre IP ou domaine {item} est sur liste noire sur {blacklist_name}", - "diagnosis_mail_queue_unavailable": "Impossible de consulter le nombre d'e-mails en attente dans la file d'attente", + "diagnosis_mail_queue_unavailable": "Impossible de consulter le nombre d’e-mails en attente dans la file d'attente", "diagnosis_ports_partially_unreachable": "Le port {port} n'est pas accessible de l'extérieur dans IPv {failed}.", - "diagnosis_http_hairpinning_issue": "Votre réseau local ne semble pas avoir activé l'épingle à cheveux.", + "diagnosis_http_hairpinning_issue": "Votre réseau local ne semble pas avoir activé l’épingle à cheveux.", "diagnosis_http_hairpinning_issue_details": "C'est probablement à cause de votre box/routeur ISP. Par conséquent, les personnes extérieures à votre réseau local pourront accéder à votre serveur comme prévu, mais pas les personnes internes au réseau local (comme vous, probablement ?). Vous pourrez peut-être améliorer la situation en consultant https://yunohost.org/dns_local_network", - "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible via HTTP depuis l'extérieur du réseau local en IPv {failed}, bien qu'il fonctionne en IPv {passed}.", - "diagnosis_http_nginx_conf_not_up_to_date": "La configuration nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible sur HTTP.", - "diagnosis_http_nginx_conf_not_up_to_date_details": "Pour corriger la situation, inspectez la différence avec la ligne de commande en utilisant les outils yunohost regen-conf nginx --dry-run --with-diff et si vous êtes d'accord, appliquez les modifications avec yunohost tools regen-conf nginx --force." + "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible via HTTP depuis l’extérieur du réseau local en IPv {failed}, bien qu’il fonctionne en IPv {passed}.", + "diagnosis_http_nginx_conf_not_up_to_date": "La configuration Nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible sur HTTP.", + "diagnosis_http_nginx_conf_not_up_to_date_details": "Pour corriger la situation, inspectez la différence avec la ligne de commande en utilisant les outils yunohost regen-conf nginx --dry-run --with-diff et si vous êtes d’accord, appliquez les modifications avec yunohost tools regen-conf nginx --force." } From 45bbd061904ba2d0900b14e7cfef042e0787cc50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quent=C3=AD?= Date: Thu, 23 Apr 2020 08:39:49 +0000 Subject: [PATCH 245/317] Translated using Weblate (Occitan) Currently translated at 60.0% (379 of 632 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/oc/ --- locales/oc.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/locales/oc.json b/locales/oc.json index 95f581851..cdefd0931 100644 --- a/locales/oc.json +++ b/locales/oc.json @@ -571,5 +571,12 @@ "global_settings_setting_pop3_enabled": "Activar lo protocòl POP3 pel servidor de corrièr", "diagnosis_diskusage_ok": "Lo lòc d’emmagazinatge {mountpoint} (sul periferic {device}) a encara {free} ({free_percent}%) de liure !", "diagnosis_swap_none": "Lo sistèma a pas cap de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria.", - "diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria." + "diagnosis_swap_notsomuch": "Lo sistèma a solament {total} de memòria d’escambi. Auriatz de considerar d’ajustar almens {recommended} d’escambi per evitar las situacions ont lo sistèma manca de memòria.", + "diagnosis_description_web": "Web", + "diagnosis_ip_global": "IP Global  : {global}", + "diagnosis_ip_local": "IP locala : {local}", + "diagnosis_mail_ehlo_could_not_diagnose_details": "Error : {error}", + "diagnosis_mail_queue_unavailable_details": "Error : {error}", + "diagnosis_basesystem_hardware": "L’arquitectura del servidor es {virt} {arch}", + "diagnosis_basesystem_hardware_board": "Lo modèl de carta del servidor es {model}" } From dbcb08a522ba476147fb71e7036e1916132707e3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 24 Apr 2020 01:40:00 +0000 Subject: [PATCH 246/317] Improve wording, fix some weird translation... --- locales/en.json | 8 +++--- locales/fr.json | 72 ++++++++++++++++++++++++------------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/locales/en.json b/locales/en.json index c2c087031..f1906e7c6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -193,8 +193,8 @@ "diagnosis_mail_ehlo_unreachable_details": "Could not open a connection on port 25 to your server in IPv{ipversion}. It appears to be unreachable.
1. The most common cause for this issue is that port 25 is not correctly forwarded to your server.
2. You should also make sure that service postfix is running.
3. On more complex setups: make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_bad_answer": "A non-SMTP service answered on port 25 on IPv{ipversion}", "diagnosis_mail_ehlo_bad_answer_details": "It could be due to an other machine answering instead of your server.", - "diagnosis_mail_ehlo_wrong": "A different SMTP mail server answers on IPv{ipversion}. It will probably not be able to receive emails.", - "diagnosis_mail_ehlo_wrong_details": "The EHLO received by the remote diagnoser in IPv{ipversion} is different from your server's domain.
Received EHLO: {wrong_ehlo}
Expected: {right_ehlo}
The most common cause for this issue is that port 25 is not correctly forwarded to your server. Alternatively, make sure that no firewall or reverse-proxy is interfering.", + "diagnosis_mail_ehlo_wrong": "A different SMTP mail server answers on IPv{ipversion}. Your server will probably not be able to receive emails.", + "diagnosis_mail_ehlo_wrong_details": "The EHLO received by the remote diagnoser in IPv{ipversion} is different from your server's domain.
Received EHLO: {wrong_ehlo}
Expected: {right_ehlo}
The most common cause for this issue is that port 25 is not correctly forwarded to your server. Alternatively, make sure that no firewall or reverse-proxy is interfering.", "diagnosis_mail_ehlo_could_not_diagnose": "Could not diagnose if postfix mail server is reachable from outside in IPv{ipversion}.", "diagnosis_mail_ehlo_could_not_diagnose_details": "Error: {error}", "diagnosis_mail_fcrdns_ok": "Your reverse DNS is correctly configured!", @@ -207,7 +207,7 @@ "diagnosis_mail_blacklist_ok": "The IPs and domains used by this server do not appear to be blacklisted", "diagnosis_mail_blacklist_listed_by": "Your IP or domain {item} is blacklisted on {blacklist_name}", "diagnosis_mail_blacklist_reason": "The blacklist reason is: {reason}", - "diagnosis_mail_blacklist_website": "After identifying why you are listed and fixed it, feel free to ask for delisting on {blacklist_website}", + "diagnosis_mail_blacklist_website": "After identifying why you are listed and fixed it, feel free to ask for your IP or domaine to be removed on {blacklist_website}", "diagnosis_mail_queue_ok": "{nb_pending} pending emails in the mail queues", "diagnosis_mail_queue_unavailable": "Can not consult number of pending emails in queue", "diagnosis_mail_queue_unavailable_details": "Error: {error}", @@ -236,7 +236,7 @@ "diagnosis_ports_needed_by": "Exposing this port is needed for {category} features (service {service})", "diagnosis_ports_forwarding_tip": "To fix this issue, you most probably need to configure port forwarding on your internet router as described in https://yunohost.org/isp_box_config", "diagnosis_http_hairpinning_issue": "Your local network does not seem to have hairpinning enabled.", - "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?). You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", + "diagnosis_http_hairpinning_issue_details": "This is probably because of your ISP box / router. As a result, people from outside your local network will be able to access your server as expected, but not people from inside the local network (like you, probably?) when using the domain name or global IP. You may be able to improve the situation by having a look at https://yunohost.org/dns_local_network", "diagnosis_http_could_not_diagnose": "Could not diagnose if domains are reachable from outside in IPv{ipversion}.", "diagnosis_http_could_not_diagnose_details": "Error: {error}", "diagnosis_http_ok": "Domain {domain} is reachable through HTTP from outside the local network.", diff --git a/locales/fr.json b/locales/fr.json index 7bc6b1687..614733056 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -41,7 +41,7 @@ "backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu", "backup_invalid_archive": "Archive de sauvegarde invalide", "backup_nothings_done": "Il n’y a rien à sauvegarder", - "backup_output_directory_forbidden": "Choisissez un répertoire de sortie différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", + "backup_output_directory_forbidden": "Choisissez un répertoire de destination différent. Les sauvegardes ne peuvent pas être créées dans les sous-dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives", "backup_output_directory_not_empty": "Le répertoire de destination n’est pas vide", "backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde", "backup_running_hooks": "Exécution des scripts de sauvegarde …", @@ -112,7 +112,7 @@ "restore_complete": "Restauré", "restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]", "restore_failed": "Impossible de restaurer le système", - "restore_hook_unavailable": "Script de restauration pour '{part:s}' non disponible sur votre système et non plus dans l'archive", + "restore_hook_unavailable": "Le script de restauration '{part:s}' n’est pas disponible sur votre système, et ne l’est pas non plus dans l’archive", "restore_nothings_done": "Rien n’a été restauré", "restore_running_app_script": "Exécution du script de restauration de l’application '{app:s}'…", "restore_running_hooks": "Exécution des scripts de restauration…", @@ -168,7 +168,7 @@ "certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} n’est pas sur le point d’expirer ! (Vous pouvez utiliser --force si vous savez ce que vous faites)", "certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} ne soit pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et Nginx sont correctes", "certmanager_error_no_A_record": "Aucun enregistrement DNS 'A' n’a été trouvé pour {domain:s}. Vous devez faire pointer votre nom de domaine vers votre machine pour être en mesure d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", - "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (quelques vérificateur de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", + "certmanager_domain_dns_ip_differs_from_public_ip": "L’enregistrement DNS 'A' du domaine {domain:s} est différent de l’adresse IP de ce serveur. Si vous avez récemment modifié votre enregistrement 'A', veuillez attendre sa propagation (des vérificateurs de propagation DNS sont disponibles en ligne). (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)", "certmanager_cannot_read_cert": "Quelque chose s’est mal passé lors de la tentative d’ouverture du certificat actuel pour le domaine {domain:s} (fichier : {file:s}), la cause est : {reason:s}", "certmanager_cert_install_success_selfsigned": "Le certificat auto-signé est maintenant installé pour le domaine « {domain:s} »", "certmanager_cert_install_success": "Le certificat Let’s Encrypt est maintenant installé pour le domaine « {domain:s} »", @@ -326,7 +326,7 @@ "log_user_create": "Ajouter l’utilisateur '{}'", "log_user_delete": "Supprimer l’utilisateur '{}'", "log_user_update": "Mettre à jour les informations de l’utilisateur '{}'", - "log_domain_main_domain": "Faites de '{}' le domaine principal", + "log_domain_main_domain": "Faire de '{}' le domaine principal", "log_tools_migrations_migrate_forward": "Exécuter les migrations", "log_tools_postinstall": "Faire la post-installation de votre serveur YunoHost", "log_tools_upgrade": "Mettre à jour les paquets du système", @@ -380,7 +380,7 @@ "migration_0008_root": "- Vous ne pourrez pas vous connecter en tant que root via SSH. Au lieu de cela, vous devrez utiliser l’utilisateur admin ;", "migration_0008_dsa": "- La clé DSA sera désactivée. Par conséquent, il se peut que vous ayez besoin d’invalider un avertissement effrayant de votre client SSH afin de revérifier l’empreinte de votre serveur ;", "migration_0008_warning": "Si vous comprenez ces avertissements et souhaitez que YunoHost écrase votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", - "migration_0008_no_warning": "Remplacer votre configuration SSH devrait être sûr, bien que cela ne puisse pas être promis ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", + "migration_0008_no_warning": "Remplacer votre configuration SSH ne devrait pas poser de problème, bien qu'il soit difficile de le promettre ! Exécutez la migration pour la remplacer. Sinon, vous pouvez également ignorer la migration, bien que cela ne soit pas recommandé.", "migrations_success": "Migration {number} {name} réussie !", "pattern_password_app": "Désolé, les mots de passe ne peuvent pas contenir les caractères suivants : {forbidden_chars}", "root_password_replaced_by_admin_password": "Votre mot de passe root a été remplacé par votre mot de passe administrateur.", @@ -510,7 +510,7 @@ "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais il semble que vous utilisez un /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Le fichier /etc/resolv.conf doit être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Si vous souhaitez configurer manuellement les résolveurs DNS, veuillez modifier /etc/resolv.dnsmasq.conf.", "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType : {type}\nNom : {name}\nValeur : {value}", - "diagnosis_diskusage_ok": "L’espace de stockage {mountpoint} (sur l’appareil {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", + "diagnosis_diskusage_ok": "L’espace de stockage {mountpoint} (sur le périphérique {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", "diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", @@ -532,12 +532,12 @@ "diagnosis_ip_no_ipv6": "Le serveur ne dispose pas d’une adresse IPv6.", "diagnosis_ip_dnsresolution_working": "La résolution de nom de domaine fonctionne !", "diagnosis_ip_broken_dnsresolution": "La résolution du nom de domaine semble interrompue pour une raison quelconque … Un pare-feu bloque-t-il les requêtes DNS ?", - "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble être rompue sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas sur 127.0.0.1.", + "diagnosis_ip_broken_resolvconf": "La résolution du nom de domaine semble être cassée sur votre serveur, ce qui semble lié au fait que /etc/resolv.conf ne pointe pas vers 127.0.0.1.", "diagnosis_dns_good_conf": "Les enregistrements DNS sont correctement configurés pour le domaine {domain} (catégorie {category})", "diagnosis_dns_bad_conf": "Certains enregistrements DNS sont manquants ou incorrects pour le domaine {domain} (catégorie {category})", "diagnosis_dns_discrepancy": "L’enregistrement DNS de type {type} et nom {name} ne correspond pas à la configuration recommandée.\nValeur actuelle : {current}\nValeur attendue : {value}", "diagnosis_services_bad_status": "Le service {service} est {status} :-(", - "diagnosis_diskusage_verylow": "L'espace de stockage {mountpoint} (sur l’appareil {device} ) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Vous devriez vraiment envisager de nettoyer de l’espace !", + "diagnosis_diskusage_verylow": "L'espace de stockage {mountpoint} (sur l’appareil {device}) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Vous devriez vraiment envisager de nettoyer de l’espace !", "diagnosis_diskusage_low": "L'espace de stockage {mountpoint} (sur l'appareil {device}) ne dispose que de {free} ({free_percent}%) espace restant (sur {total}). Faites attention.", "diagnosis_ram_verylow": "Le système ne dispose plus que de {available} ({available_percent}%)! (sur {total})", "diagnosis_ram_low": "Le système n’a plus de {available} ({available_percent}%) RAM sur {total}. Faites attention.", @@ -546,7 +546,7 @@ "diagnosis_swap_ok": "Le système dispose de {total} de swap !", "diagnosis_regenconf_manually_modified": "Le fichier de configuration {file} semble avoir été modifié manuellement.", "diagnosis_regenconf_manually_modified_debian": "Le fichier de configuration {file} a été modifié manuellement par rapport à celui par défaut de Debian.", - "diagnosis_regenconf_manually_modified_details": "C’est probablement OK si vous savez ce que vous faites ! YunoHost cessera de mettre à jour ce fichier automatiquement ... Mais attention, les mises à jour de YunoHost pourraient contenir d’importantes modifications recommandées. Si vous le souhaitez, vous pouvez inspecter les différences avec les outils yunohost regen-conf {category} --dry-run --with-diff et forcer la réinitialisation à la configuration recommandée avec les outils yunohost regen-conf {category} --force ", + "diagnosis_regenconf_manually_modified_details": "C’est probablement OK si vous savez ce que vous faites ! YunoHost cessera de mettre à jour ce fichier automatiquement ... Mais attention, les mises à jour de YunoHost pourraient contenir d’importantes modifications recommandées. Si vous le souhaitez, vous pouvez inspecter les différences avec yunohost tools regen-conf {category} --dry-run --with-diff et forcer la réinitialisation à la configuration recommandée avec yunohost tools regen-conf {category} --force", "diagnosis_regenconf_manually_modified_debian_details": "Cela peut probablement être OK, mais il faut garder un œil dessus …", "apps_catalog_init_success": "Système de catalogue d’applications initialisé !", "apps_catalog_failed_to_download": "Impossible de télécharger le catalogue des applications {apps_catalog} : {error}", @@ -581,11 +581,11 @@ "diagnosis_services_running": "Le service {service} est en cours de fonctionnement !", "diagnosis_services_conf_broken": "La configuration est cassée pour le service {service} !", "diagnosis_ports_needed_by": "Rendre ce port accessible est nécessaire pour les fonctionnalités de type {category} (service {service})", - "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config ", + "diagnosis_ports_forwarding_tip": "Pour résoudre ce problème, vous devez probablement configurer la redirection de port sur votre routeur Internet comme décrit dans https://yunohost.org/isp_box_config", "diagnosis_http_connection_error": "Erreur de connexion : impossible de se connecter au domaine demandé, il est probablement injoignable.", "diagnosis_no_cache": "Pas encore de cache de diagnostique pour la catégorie « {category} »", "yunohost_postinstall_end_tip": "La post-installation terminée! Pour finaliser votre configuration, il est recommandé de :\n - ajouter un premier utilisateur depuis la section \"Utilisateurs\" de l’interface web (ou \"yunohost user create \" en ligne de commande) ;\n - diagnostiquer les potentiels problèmes dans la section \"Diagnostic\" de l'interface web (ou \"yunohost diagnosis run\" en ligne de commande) ;\n - lire les parties \"Finalisation de votre configuration\" et \"Découverte de YunoHost\" dans le guide de l’administrateur: https://yunohost.org/admindoc.", - "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service, et si cela ne fonctionne pas, consultez les journaux de service dans le webadmin (à partir de la ligne de commande, vous pouvez le faire avec yunohost service restart {service} et yunohost service log {service} ).", + "diagnosis_services_bad_status_tip": "Vous pouvez essayer de redémarrer le service, et si cela ne fonctionne pas, consultez les journaux de service dans le webadmin (à partir de la ligne de commande, vous pouvez le faire avec yunohost service restart {service} et yunohost service log {service} ).", "diagnosis_http_bad_status_code": "Le système de diagnostique n’a pas réussi à contacter votre serveur. Il se peut qu’une autre machine réponde à la place de votre serveur. Vérifiez que le port 80 est correctement redirigé, que votre configuration Nginx est à jour et qu’un reverse-proxy n’interfère pas.", "diagnosis_http_timeout": "Expiration du délai en essayant de contacter votre serveur de l’extérieur. Il semble être inaccessible. Vérifiez que vous transférez correctement le port 80, que Nginx est en cours d’exécution et qu’un pare-feu n’interfère pas.", "global_settings_setting_pop3_enabled": "Activer le protocole POP3 pour le serveur de messagerie", @@ -600,42 +600,42 @@ "certmanager_warning_subdomain_dns_record": "Le sous-domaine '{subdomain:s}' ne résout pas vers la même adresse IP que '{domain:s}'. Certaines fonctionnalités seront indisponibles tant que vous n’aurez pas corrigé cela et regénéré le certificat.", "domain_cannot_add_xmpp_upload": "Vous ne pouvez pas ajouter de domaine commençant par 'xmpp-upload.'. Ce type de nom est réservé à la fonctionnalité d’upload XMPP intégrée dans YunoHost.", "diagnosis_mail_outgoing_port_25_ok": "Le serveur de messagerie SMTP peut envoyer des e-mails (le port sortant 25 n'est pas bloqué).", - "diagnosis_mail_outgoing_port_25_blocked_details": "Vous devez d’abord essayer de débloquer le port sortant 25 dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", - "diagnosis_mail_ehlo_bad_answer": "Un service non SMTP a répondu sur le port 25 sur IPv {ipversion}", - "diagnosis_mail_ehlo_bad_answer_details": "Cela peut être dû à un autre répondeur au lieu de votre serveur.", - "diagnosis_mail_ehlo_wrong": "Un autre serveur de messagerie SMTP répond sur IPv{ipversion}. Il ne sera probablement pas en mesure de recevoir des e-mails.", - "diagnosis_mail_ehlo_could_not_diagnose": "Impossible de diagnostiquer si le serveur de messagerie postfix est accessible de l’extérieur pour IPv {ipversion}.", + "diagnosis_mail_outgoing_port_25_blocked_details": "Vous devez d’abord essayer de débloquer le port sortant 25 dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket de support pour cela).", + "diagnosis_mail_ehlo_bad_answer": "Un service non SMTP a répondu sur le port 25 en IPv{ipversion}", + "diagnosis_mail_ehlo_bad_answer_details": "Cela peut être dû à une autre machine qui répond au lieu de votre serveur.", + "diagnosis_mail_ehlo_wrong": "Un autre serveur de messagerie SMTP répond sur IPv{ipversion}. Votre serveur ne sera probablement pas en mesure de recevoir des e-mails.", + "diagnosis_mail_ehlo_could_not_diagnose": "Impossible de diagnostiquer si le serveur de messagerie postfix est accessible de l’extérieur en IPv{ipversion}.", "diagnosis_mail_ehlo_could_not_diagnose_details": "Erreur : {error}", - "diagnosis_mail_fcrdns_dns_missing": "Aucun DNS inverse n’est défini dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", - "diagnosis_mail_fcrdns_ok": "Votre DNS inversé est correctement configuré !", - "diagnosis_mail_fcrdns_nok_details": "Vous devez d’abord essayer de configurer le DNS inverse avec {ehlo_domain} dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket d'assistance pour cela).", - "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Le DNS inverse n'est pas correctement configuré dans IPv {ipversion}. Certains e-mails peuvent ne pas être livrés ou être signalés comme spam.", + "diagnosis_mail_fcrdns_dns_missing": "Aucun DNS inverse n’est défini pour IPv{ipversion}. Certains e-mails seront peut-être refusés ou considérés comme des spam.", + "diagnosis_mail_fcrdns_ok": "Votre DNS inverse est correctement configuré !", + "diagnosis_mail_fcrdns_nok_details": "Vous devez d’abord essayer de configurer le DNS inverse avec {ehlo_domain} dans votre interface de routeur Internet ou votre interface d’hébergement. (Certains hébergeurs peuvent vous demander de leur envoyer un ticket de support pour cela).", + "diagnosis_mail_fcrdns_different_from_ehlo_domain": "Le DNS inverse n'est pas correctement configuré en IPv{ipversion}. Certains e-mails seront peut-être refusés ou considérés comme des spam.", "diagnosis_mail_blacklist_ok": "Les adresses IP et les domaines utilisés par ce serveur ne semblent pas être sur liste noire", "diagnosis_mail_blacklist_reason": "La raison de la liste noire est : {reason}", - "diagnosis_mail_blacklist_website": "Après avoir identifié pourquoi vous êtes répertorié et corrigé, n’hésitez pas à demander la radiation sur {blacklist_website}", + "diagnosis_mail_blacklist_website": "Après avoir identifié la raison pour laquelle vous êtes répertorié et l'avoir corrigé, n’hésitez pas à demander le retrait de votre IP ou domaine sur {blacklist_website}", "diagnosis_mail_queue_ok": "{nb_pending} e-mails en attente dans les files d'attente de messagerie", "diagnosis_mail_queue_unavailable_details": "Erreur : {error}", "diagnosis_mail_queue_too_big": "Trop d’e-mails en attente dans la file d'attente ({nb_pending} e-mails)", "global_settings_setting_smtp_allow_ipv6": "Autoriser l'utilisation d’IPv6 pour recevoir et envoyer du courrier", "diagnosis_security_all_good": "Aucune vulnérabilité de sécurité critique n’a été trouvée.", "diagnosis_display_tip": "Pour voir les problèmes détectés, vous pouvez accéder à la section Diagnostic du webadmin ou exécuter « yunohost diagnostic show --issues » à partir de la ligne de commande.", - "diagnosis_ip_global": "IP globale : {global} ", - "diagnosis_ip_local": "IP locale : {local} ", - "diagnosis_dns_point_to_doc": "Veuillez consulter la documentation à https://yunohost.org/dns_config si vous avez besoin d’aide pour configurer les enregistrements DNS.", - "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains fournisseurs ne vous laisseront pas débloquer le port sortant 25 parce qu’ils ne se soucient pas de la neutralité du Net.
- Certains d’entre eux offrent l’alternative de en utilisant un relais de serveur de messagerie bien que cela implique que le relais sera en mesure d’espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type des limites. Voir https://yunohost.org/#/vpn_advantage
- Vous pouvez également envisager de passer à un fournisseur plus respectueux de la neutralité du net ", + "diagnosis_ip_global": "IP globale : {global}", + "diagnosis_ip_local": "IP locale : {local}", + "diagnosis_dns_point_to_doc": "Veuillez consulter la documentation sur https://yunohost.org/dns_config si vous avez besoin d’aide pour configurer les enregistrements DNS.", + "diagnosis_mail_outgoing_port_25_blocked_relay_vpn": "Certains fournisseurs ne vous laisseront pas débloquer le port sortant 25 parce qu’ils ne se soucient pas de la neutralité du Net.
- Certains d’entre eux offrent l’alternative d'utiliser un serveur de messagerie relai bien que cela implique que le relai sera en mesure d’espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir https://yunohost.org/#/vpn_advantage
- Vous pouvez également envisager de passer à un fournisseur plus respectueux de la neutralité du net", "diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des e-mails !", - "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l’extérieur sur IPv {ipversion}. Il ne pourra pas recevoir d’e-mails.", - "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur dans IPv {ipversion}. Il semble inaccessible.
1. La cause la plus courante de ce problème est que le port 25 n'est pas correctement transmis à votre serveur .
2. Vous devez également vous assurer que le suffixe de service est en cours d'exécution.
3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inverse n'interfère.", - "diagnosis_mail_ehlo_wrong_details": "L’EHLO reçu par le diagnostiqueur distant dans IPv {ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu : {right_ehlo}
La cause la plus courante ce problème est que le port 25 n’est pas correctement transmis à votre serveur . Vous pouvez également vous assurer qu’aucun pare-feu ou proxy inverse n’interfère.", - "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes :
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN * avec une IP publique dédiée * pour contourner ce type de limites. Voir
https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changement de fournisseur ", - "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée ...). Si votre DNS inversé est correctement configuré pour IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'e-mails en exécutant yunohost settings set smtp.allow_ipv6 -v off . Remarque: cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de courriels des quelques serveurs IPv6 uniquement disponibles.", - "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : {rdns_domain}
Valeur attendue : {ehlo_domain} ", + "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l’extérieur en IPv{ipversion}. Il ne pourra pas recevoir d’e-mails.", + "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur en IPv{ipversion}. Il semble inaccessible.
1. La cause la plus courante de ce problème est que le port 25 n'est pas correctement redirigé vers votre serveur.
2. Vous devez également vous assurer que le service postfix est en cours d'exécution.
3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inversé n'interfère.", + "diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu : {right_ehlo}
La cause la plus courante ce problème est que le port 25 n’est pas correctement redirigé vers votre serveur . Vous pouvez également vous assurer qu’aucun pare-feu ou proxy inversé n’interfère.", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes :
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changer de fournisseur", + "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée ...). Si votre DNS inversé est correctement configuré en IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'e-mails en exécutant yunohost settings set smtp.allow_ipv6 -v off. Remarque: cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de courriels avec les quelques serveurs qui ont uniquement de l'IPv6.", + "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : {rdns_domain}
Valeur attendue : {ehlo_domain}", "diagnosis_mail_blacklist_listed_by": "Votre IP ou domaine {item} est sur liste noire sur {blacklist_name}", "diagnosis_mail_queue_unavailable": "Impossible de consulter le nombre d’e-mails en attente dans la file d'attente", - "diagnosis_ports_partially_unreachable": "Le port {port} n'est pas accessible de l'extérieur dans IPv {failed}.", - "diagnosis_http_hairpinning_issue": "Votre réseau local ne semble pas avoir activé l’épingle à cheveux.", - "diagnosis_http_hairpinning_issue_details": "C'est probablement à cause de votre box/routeur ISP. Par conséquent, les personnes extérieures à votre réseau local pourront accéder à votre serveur comme prévu, mais pas les personnes internes au réseau local (comme vous, probablement ?). Vous pourrez peut-être améliorer la situation en consultant https://yunohost.org/dns_local_network", - "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible via HTTP depuis l’extérieur du réseau local en IPv {failed}, bien qu’il fonctionne en IPv {passed}.", - "diagnosis_http_nginx_conf_not_up_to_date": "La configuration Nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible sur HTTP.", + "diagnosis_ports_partially_unreachable": "Le port {port} n'est pas accessible de l'extérieur en IPv{failed}.", + "diagnosis_http_hairpinning_issue": "Votre réseau local ne semble pas supporter l'hairpinning.", + "diagnosis_http_hairpinning_issue_details": "C'est probablement à cause de la box/routeur de votre fournisseur d'accès internet. Par conséquent, les personnes extérieures à votre réseau local pourront accéder à votre serveur comme prévu, mais pas les personnes internes au réseau local (comme vous, probablement ?) si elles utilisent le nom de domaine ou l'IP globale. Vous pourrez peut-être améliorer la situation en consultant https://yunohost.org/dns_local_network", + "diagnosis_http_partially_unreachable": "Le domaine {domain} semble inaccessible en HTTP depuis l’extérieur du réseau local en IPv{failed}, bien qu’il fonctionne en IPv{passed}.", + "diagnosis_http_nginx_conf_not_up_to_date": "La configuration Nginx de ce domaine semble avoir été modifiée manuellement et empêche YunoHost de diagnostiquer si elle est accessible en HTTP.", "diagnosis_http_nginx_conf_not_up_to_date_details": "Pour corriger la situation, inspectez la différence avec la ligne de commande en utilisant les outils yunohost regen-conf nginx --dry-run --with-diff et si vous êtes d’accord, appliquez les modifications avec yunohost tools regen-conf nginx --force." } From 87cf61dd3e49ed86d2cc5443c6344c9501abf54c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 24 Apr 2020 01:40:59 +0000 Subject: [PATCH 247/317] Fix bad placeholder names... --- locales/eo.json | 4 ++-- locales/es.json | 2 +- locales/fr.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index 22656188d..d778938e9 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -312,7 +312,7 @@ "package_unknown": "Nekonata pako '{pkgname}'", "domain_unknown": "Nekonata domajno", "global_settings_setting_security_password_user_strength": "Uzanto pasvorta forto", - "restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {libera_spaco:d} B, necesa spaco: {necesa_spaco:d} B, sekureca marĝeno: {rando:d} B)", + "restore_may_be_not_enough_disk_space": "Via sistemo ne ŝajnas havi sufiĉe da spaco (libera: {free_space:d} B, necesa spaco: {needed_space:d} B, sekureca marĝeno: {margin:d} B)", "log_corrupted_md_file": "La YAD-metadata dosiero asociita kun protokoloj estas damaĝita: '{md_file}\nEraro: {error} '", "downloading": "Elŝutante …", "user_deleted": "Uzanto forigita", @@ -576,7 +576,7 @@ "diagnosis_services_running": "Servo {service} funkcias!", "diagnosis_ports_unreachable": "Haveno {port} ne atingeblas de ekstere.", "diagnosis_ports_ok": "Haveno {port} atingeblas de ekstere.", - "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por {1} funkcioj (servo {0})", + "diagnosis_ports_needed_by": "Eksponi ĉi tiun havenon necesas por {category} funkcioj (servo {service})", "diagnosis_ports_forwarding_tip": "Por solvi ĉi tiun problemon, vi plej verŝajne bezonas agordi havenon en via interreta enkursigilo kiel priskribite en https://yunohost.org/isp_box_config", "diagnosis_http_could_not_diagnose": "Ne povis diagnozi, ĉu atingeblas domajno de ekstere.", "diagnosis_http_could_not_diagnose_details": "Eraro: {error}", diff --git a/locales/es.json b/locales/es.json index f76d722e6..6d77dd2ef 100644 --- a/locales/es.json +++ b/locales/es.json @@ -170,7 +170,7 @@ "certmanager_attempt_to_renew_valid_cert": "¡El certificado para el dominio «{domain:s}» no está a punto de expirar! (Puede usar --force si sabe lo que está haciendo)", "certmanager_domain_http_not_working": "Parece que no se puede acceder al dominio {domain:s} a través de HTTP. Compruebe que la configuración del DNS y de NGINX es correcta", "certmanager_error_no_A_record": "No se ha encontrado un registro DNS «A» para el dominio {domain:s}. Debe hacer que su nombre de dominio apunte a su máquina para poder instalar un certificado de Let's Encrypt. (Si sabe lo que está haciendo, use «--no-checks» para desactivar esas comprobaciones.)", - "certmanager_domain_dns_ip_differs_from_public_ip": "El registro DNS 'A' para el dominio '{dominio:s}' es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (algunos verificadores de propagación de DNS están disponibles en línea). (Si sabe lo que está haciendo, use '--no-checks' para desactivar esos cheques)", + "certmanager_domain_dns_ip_differs_from_public_ip": "El registro DNS 'A' para el dominio '{domain:s}' es diferente de la IP de este servidor. Si recientemente modificó su registro A, espere a que se propague (algunos verificadores de propagación de DNS están disponibles en línea). (Si sabe lo que está haciendo, use '--no-checks' para desactivar esos cheques)", "certmanager_cannot_read_cert": "Se ha producido un error al intentar abrir el certificado actual para el dominio {domain:s} (archivo: {file:s}), razón: {reason:s}", "certmanager_cert_install_success_selfsigned": "Instalado correctamente un certificado autofirmado para el dominio «{domain:s}»", "certmanager_cert_install_success": "Instalado correctamente un certificado de Let's Encrypt para el dominio «{domain:s}»", diff --git a/locales/fr.json b/locales/fr.json index 614733056..764b6bb10 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -510,7 +510,7 @@ "diagnosis_ip_weird_resolvconf": "La résolution DNS semble fonctionner, mais il semble que vous utilisez un /etc/resolv.conf personnalisé.", "diagnosis_ip_weird_resolvconf_details": "Le fichier /etc/resolv.conf doit être un lien symbolique vers /etc/resolvconf/run/resolv.conf lui-même pointant vers 127.0.0.1 (dnsmasq). Si vous souhaitez configurer manuellement les résolveurs DNS, veuillez modifier /etc/resolv.dnsmasq.conf.", "diagnosis_dns_missing_record": "Selon la configuration DNS recommandée, vous devez ajouter un enregistrement DNS\nType : {type}\nNom : {name}\nValeur : {value}", - "diagnosis_diskusage_ok": "L’espace de stockage {mountpoint} (sur le périphérique {device}) a encore {libre} ({free_percent}%) espace restant (sur {total}) !", + "diagnosis_diskusage_ok": "L’espace de stockage {mountpoint} (sur le périphérique {device}) a encore {free} ({free_percent}%) espace restant (sur {total}) !", "diagnosis_ram_ok": "Le système dispose encore de {available} ({available_percent}%) de RAM sur {total}.", "diagnosis_regenconf_allgood": "Tous les fichiers de configuration sont conformes à la configuration recommandée !", "diagnosis_security_vulnerable_to_meltdown": "Vous semblez vulnérable à la vulnérabilité de sécurité critique de Meltdown", @@ -626,7 +626,7 @@ "diagnosis_mail_ehlo_ok": "Le serveur de messagerie SMTP est accessible de l'extérieur et peut donc recevoir des e-mails !", "diagnosis_mail_ehlo_unreachable": "Le serveur de messagerie SMTP est inaccessible de l’extérieur en IPv{ipversion}. Il ne pourra pas recevoir d’e-mails.", "diagnosis_mail_ehlo_unreachable_details": "Impossible d'ouvrir une connexion sur le port 25 à votre serveur en IPv{ipversion}. Il semble inaccessible.
1. La cause la plus courante de ce problème est que le port 25 n'est pas correctement redirigé vers votre serveur.
2. Vous devez également vous assurer que le service postfix est en cours d'exécution.
3. Sur les configurations plus complexes: assurez-vous qu'aucun pare-feu ou proxy inversé n'interfère.", - "diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur.
EHLO reçu: {bad_ehlo}
Attendu : {right_ehlo}
La cause la plus courante ce problème est que le port 25 n’est pas correctement redirigé vers votre serveur . Vous pouvez également vous assurer qu’aucun pare-feu ou proxy inversé n’interfère.", + "diagnosis_mail_ehlo_wrong_details": "Le EHLO reçu par le serveur de diagnostique distant en IPv{ipversion} est différent du domaine de votre serveur.
EHLO reçu: {wrong_ehlo}
Attendu : {right_ehlo}
La cause la plus courante ce problème est que le port 25 n’est pas correctement redirigé vers votre serveur . Vous pouvez également vous assurer qu’aucun pare-feu ou proxy inversé n’interfère.", "diagnosis_mail_fcrdns_nok_alternatives_4": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée …). Si vous rencontrez des problèmes à cause de cela, envisagez les solutions suivantes :
- Certains FAI fournissent l’alternative de à l’aide d’un relais de serveur de messagerie bien que cela implique que le relais pourra espionner votre trafic de messagerie.
- Une alternative respectueuse de la vie privée consiste à utiliser un VPN *avec une IP publique dédiée* pour contourner ce type de limites. Voir https://yunohost.org/#/vpn_advantage
- Enfin, il est également possible de changer de fournisseur", "diagnosis_mail_fcrdns_nok_alternatives_6": "Certains fournisseurs ne vous laisseront pas configurer votre DNS inversé (ou leur fonctionnalité pourrait être cassée ...). Si votre DNS inversé est correctement configuré en IPv4, vous pouvez essayer de désactiver l'utilisation d'IPv6 lors de l'envoi d'e-mails en exécutant yunohost settings set smtp.allow_ipv6 -v off. Remarque: cette dernière solution signifie que vous ne pourrez pas envoyer ou recevoir de courriels avec les quelques serveurs qui ont uniquement de l'IPv6.", "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "DNS inverse actuel : {rdns_domain}
Valeur attendue : {ehlo_domain}", From e044d20802312323489eea7b4ba7868f97702411 Mon Sep 17 00:00:00 2001 From: Christian Wehrli Date: Fri, 24 Apr 2020 20:50:28 +0000 Subject: [PATCH 248/317] Translated using Weblate (German) Currently translated at 34.8% (220 of 632 strings) Translation: YunoHost/core Translate-URL: https://translate.yunohost.org/projects/yunohost/core/de/ --- locales/de.json | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/locales/de.json b/locales/de.json index b354f60c5..5b372edfc 100644 --- a/locales/de.json +++ b/locales/de.json @@ -165,10 +165,10 @@ "mailbox_used_space_dovecot_down": "Der Dovecot Mailbox Dienst muss gestartet sein, wenn du den von der Mailbox belegten Speicher angezeigen lassen willst", "package_unknown": "Unbekanntes Paket '{pkgname}'", "certmanager_attempt_to_replace_valid_cert": "Du versuchst gerade eine richtiges und gültiges Zertifikat der Domain {domain:s} zu überschreiben! (Benutze --force , um diese Nachricht zu umgehen)", - "certmanager_domain_unknown": "Unbekannte Domain {domain:s}", - "certmanager_domain_cert_not_selfsigned": "Das Zertifikat der Domain {domain:s} is kein selbstsigniertes Zertifikat. Bist du dir sicher, dass du es ersetzen willst? (Benutze --force)", + "certmanager_domain_unknown": "Unbekannte Domain '{domain:s}'", + "certmanager_domain_cert_not_selfsigned": "Das Zertifikat der Domain {domain:s} ist kein selbstsigniertes Zertifikat. Bist du dir sicher, dass du es ersetzen willst? (Benutze dafür '--force')", "certmanager_certificate_fetching_or_enabling_failed": "Es scheint so als wäre die Aktivierung des Zertifikats für die Domain {domain:s} fehlgeschlagen...", - "certmanager_attempt_to_renew_nonLE_cert": "Das Zertifikat der Domain {domain:s} wurde nicht von Let's Encrypt ausgestellt. Es kann nicht automatisch erneuert werden!", + "certmanager_attempt_to_renew_nonLE_cert": "Das Zertifikat der Domain '{domain:s}' wurde nicht von Let's Encrypt ausgestellt. Es kann nicht automatisch erneuert werden!", "certmanager_attempt_to_renew_valid_cert": "Das Zertifikat der Domain {domain:s} läuft nicht in Kürze ab! (Benutze --force um diese Nachricht zu umgehen)", "certmanager_domain_http_not_working": "Es scheint so, dass die Domain {domain:s} nicht über HTTP erreicht werden kann. Bitte überprüfe, ob deine DNS und nginx Konfiguration in Ordnung ist", "certmanager_error_no_A_record": "Kein DNS 'A' Eintrag für die Domain {domain:s} gefunden. Dein Domainname muss auf diese Maschine weitergeleitet werden, um ein Let's Encrypt Zertifikat installieren zu können! (Wenn du weißt was du tust, kannst du --no-checks benutzen, um diese Überprüfung zu überspringen. )", @@ -178,15 +178,15 @@ "certmanager_cert_install_success": "Für die Domain {domain:s} wurde erfolgreich ein Let's Encrypt installiert!", "certmanager_cert_renew_success": "Das Let's Encrypt Zertifikat für die Domain {domain:s} wurde erfolgreich erneuert!", "certmanager_hit_rate_limit": "Es wurden innerhalb kurzer Zeit schon zu viele Zertifikate für die exakt gleiche Domain {domain:s} ausgestellt. Bitte versuche es später nochmal. Besuche https://letsencrypt.org/docs/rate-limits/ für mehr Informationen", - "certmanager_cert_signing_failed": "Signieren des neuen Zertifikats ist fehlgeschlagen", + "certmanager_cert_signing_failed": "Das neue Zertifikat konnte nicht signiert werden", "certmanager_no_cert_file": "Die Zertifikatsdatei für die Domain {domain:s} (Datei: {file:s}) konnte nicht gelesen werden", "certmanager_conflicting_nginx_file": "Die Domain konnte nicht für die ACME challenge vorbereitet werden: Die nginx Konfigurationsdatei {filepath:s} verursacht Probleme und sollte vorher entfernt werden", "domain_cannot_remove_main": "Die primäre Domain konnten nicht entfernt werden. Lege zuerst einen neue primäre Domain fest", "certmanager_self_ca_conf_file_not_found": "Die Konfigurationsdatei der Zertifizierungsstelle für selbstsignierte Zertifikate wurde nicht gefunden (Datei {file:s})", - "certmanager_acme_not_configured_for_domain": "Das Zertifikat für die Domain {domain:s} scheint nicht richtig installiert zu sein. Bitte führe den Befehl cert-install für diese Domain nochmals aus.", + "certmanager_acme_not_configured_for_domain": "Das Zertifikat für die Domain '{domain:s}' scheint nicht richtig installiert zu sein. Bitte führe den Befehl cert-install für diese Domain nochmals aus.", "certmanager_unable_to_parse_self_CA_name": "Der Name der Zertifizierungsstelle für selbstsignierte Zertifikate konnte nicht analysiert werden (Datei: {file:s})", - "certmanager_http_check_timeout": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte sich selbst über HTTP mit der öffentlichen IP (Domain {domain:s} mit der IP {ip:s}) zu erreichen. Möglicherweise ist dafür hairpinning oder eine falsch konfigurierte Firewall/Router deines Servers dafür verantwortlich.", - "certmanager_couldnt_fetch_intermediate_cert": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte die Teilzertifikate von Let's Encrypt zusammenzusetzen. Die Installation/Erneuerung des Zertifikats wurde abgebrochen - bitte versuche es später erneut.", + "certmanager_http_check_timeout": "Eine Zeitüberschreitung ist aufgetreten, als der Server versuchte sich selbst über HTTP mit der öffentlichen IP (Domain '{domain:s}' mit der IP '{ip:s}') zu erreichen. Möglicherweise ist dafür hairpinning oder eine falsch konfigurierte Firewall/Router deines Servers dafür verantwortlich.", + "certmanager_couldnt_fetch_intermediate_cert": "Eine Zeitüberschreitung ist aufgetreten als der Server versuchte die Teilzertifikate von Let's Encrypt zusammenzusetzen. Die Installation/Erneuerung des Zertifikats wurde abgebrochen — bitte versuche es später erneut.", "domain_hostname_failed": "Erstellen des neuen Hostnamens fehlgeschlagen", "yunohost_ca_creation_success": "Die lokale Zertifizierungs-Authorität wurde angelegt.", "app_already_installed_cant_change_url": "Diese Application ist bereits installiert. Die URL kann durch diese Funktion nicht modifiziert werden. Überprüfe ob `app changeurl` verfügbar ist.", @@ -328,7 +328,7 @@ "diagnosis_cant_run_because_of_dep": "Kann Diagnose für {category} nicht ausführen während wichtige Probleme zu {dep} noch nicht behoben sind.", "diagnosis_found_errors_and_warnings": "Habe {errors} erhebliche(s) Problem(e) (und {warnings} Warnung(en)) in Verbindung mit {category} gefunden!", "diagnosis_ip_broken_dnsresolution": "Domänen-Namens-Auflösung scheint aus einem bestimmten Grund nicht zu funktionieren... Blockiert eine Firewall die DNS Anfragen?", - "diagnosis_ip_broken_resolvconf": "Domänen-Namens-Auflösung scheint nicht zu funktionieren, was daran liegen könnte, dass in /etc/resolv.conf kein Eintrag auf 127.0.0.1 zeigt.", + "diagnosis_ip_broken_resolvconf": "Domänen-Namens-Auflösung scheint nicht zu funktionieren, was daran liegen könnte, dass in /etc/resolv.conf kein Eintrag auf 127.0.0.1 zeigt.", "diagnosis_ip_weird_resolvconf_details": "Stattdessen sollte diese Datei ein Softlink auf /etc/resolvconf/run/resolv.conf sein, die auf sich selbst zu 127.0.0.1 zeigt (dnsmasq). Der eigentlich Auflösende sollte in /etc/resolv.dnsmasq.conf konfiguriert werden.", "diagnosis_dns_good_conf": "Gute DNS Konfiguration für Domäne {domain} (Kategorie {category})", "diagnosis_ignored_issues": "(+ {nb_ignored} ignorierte(s) Problem(e))", @@ -337,5 +337,6 @@ "diagnosis_found_errors": "Habe {errors} erhebliche(s) Problem(e) in Verbindung mit {category} gefunden!", "diagnosis_found_warnings": "Habe {warnings} Ding(e) gefunden, die verbessert werden könnten für {category}.", "diagnosis_ip_dnsresolution_working": "Domänen-Namens-Auflösung funktioniert!", - "diagnosis_ip_weird_resolvconf": "DNS Auflösung scheint zu funktionieren, aber sei vorsichtig wenn du eine eigene /etc/resolv.conf verwendest." + "diagnosis_ip_weird_resolvconf": "DNS Auflösung scheint zu funktionieren, aber sei vorsichtig wenn du eine eigene /etc/resolv.conf verwendest.", + "diagnosis_display_tip": "Um die gefundenen Probleme zu sehen, kannst Du zum Diagnose-Bereich des webadmin gehen, oder 'yunohost diagnosis show --issues' in der Kommandozeile ausführen." } From c6c85556ace4e720715ae38f46cc5b2f4f00de35 Mon Sep 17 00:00:00 2001 From: ljf Date: Sun, 19 Apr 2020 21:45:46 +0200 Subject: [PATCH 249/317] [fix] False positive on blacklist due to search in resovconf --- data/hooks/diagnosis/24-mail.py | 30 +++++++++++++++--------------- src/yunohost/utils/network.py | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index 4ced72959..afb88f7cf 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -13,6 +13,7 @@ from moulinette.utils.filesystem import read_yaml from yunohost.diagnosis import Diagnoser from yunohost.domain import _get_maindomain, domain_list from yunohost.settings import settings_get +from yunohost.utils.network import dig DEFAULT_DNS_BLACKLIST = "/usr/share/yunohost/other/dnsbl_list.yml" @@ -155,26 +156,25 @@ class MailDiagnoser(Diagnoser): if not blacklist[item_type]: continue - # Determine if we are listed on this RBL - try: - subdomain = item - if item_type != "domain": - rev = dns.reversename.from_address(item) - subdomain = str(rev.split(3)[0]) - query = subdomain + '.' + blacklist['dns_server'] - # TODO add timeout lifetime - dns.resolver.query(query, "A") - except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, - dns.exception.Timeout): + # Build the query for DNSBL + subdomain = item + if item_type != "domain": + rev = dns.reversename.from_address(item) + subdomain = str(rev.split(3)[0]) + query = subdomain + '.' + blacklist['dns_server'] + + # Do the DNS Query + status, answers = dig(query, 'A') + if status != 'ok': continue # Try to get the reason details = [] - try: - reason = str(dns.resolver.query(query, "TXT")[0]) + status, answers = dig(query, 'TXT') + reason = "-" + if status == 'ok': + reason = ', '.join(answers) details.append("diagnosis_mail_blacklist_reason") - except Exception: - reason = "-" details.append("diagnosis_mail_blacklist_website") diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index 3ae1ba910..6dc4c22a0 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -21,6 +21,7 @@ import os import re import logging +import dns.resolver from moulinette.utils.network import download_text from moulinette.utils.process import check_output @@ -84,6 +85,24 @@ def get_gateway(): return addr.popitem()[1] if len(addr) == 1 else None +def dig(qname, rdtype="A", timeout=5, resolvers=["127.0.0.1"], edns_size=1500): + """ + Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf + """ + + resolver = dns.resolver.Resolver(configure=False) + resolver.use_edns(0, 0, edns_size) + resolver.nameservers = resolvers + resolver.timeout = timeout + try: + answers = resolver.query(qname, rdtype) + except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, + dns.exception.Timeout) as e: + return ("nok", e.__class__.__name__, e) + + return ("ok", [(answer.to_text(), answer) for answer in answers]) + + def _extract_inet(string, skip_netmask=False, skip_loopback=True): """ Extract IP addresses (v4 and/or v6) from a string limited to one From 17d3ec5ad3e083df4920d3550151caee2c1ae7ca Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 27 Apr 2020 17:24:57 +0200 Subject: [PATCH 250/317] Improve new dig() helper, and use it in dnsrecords diagnosis as well --- data/hooks/diagnosis/12-dnsrecords.py | 20 +++++--------- data/hooks/diagnosis/24-mail.py | 2 +- src/yunohost/utils/network.py | 39 +++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 5ed7fc737..53afb2c2d 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -2,9 +2,9 @@ import os -from moulinette.utils.process import check_output from moulinette.utils.filesystem import read_file +from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain @@ -100,20 +100,14 @@ class DNSRecordsDiagnoser(Diagnoser): yield output def get_current_record(self, domain, name, type_): - if name == "@": - command = "dig +short @%s %s %s" % (self.resolver, type_, domain) - else: - command = "dig +short @%s %s %s.%s" % (self.resolver, type_, name, domain) - # FIXME : gotta handle case where this command fails ... - # e.g. no internet connectivity (dependency mechanism to good result from 'ip' diagosis ?) - # or the resolver is unavailable for some reason - output = check_output(command).strip().split("\n") - if len(output) == 0 or not output[0]: + + query = "%s.%s" % (name, domain) if name != "@" else domain + success, answers = dig(query, type_, resolvers="force_external") + + if success != "ok": return None - elif len(output) == 1: - return output[0] else: - return output + return answers[0] if len(answers) == 1 else answers def current_record_match_expected(self, r): if r["value"] is not None and r["current"] is None: diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index afb88f7cf..a60b4f0d4 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -164,7 +164,7 @@ class MailDiagnoser(Diagnoser): query = subdomain + '.' + blacklist['dns_server'] # Do the DNS Query - status, answers = dig(query, 'A') + status, _ = dig(query, 'A') if status != 'ok': continue diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index 6dc4c22a0..23b2310f8 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -25,6 +25,7 @@ import dns.resolver from moulinette.utils.network import download_text from moulinette.utils.process import check_output +from moulinette.utils.filesystem import read_file logger = logging.getLogger('yunohost.utils.network') @@ -85,22 +86,50 @@ def get_gateway(): return addr.popitem()[1] if len(addr) == 1 else None -def dig(qname, rdtype="A", timeout=5, resolvers=["127.0.0.1"], edns_size=1500): +# Lazy dev caching to avoid re-reading the file multiple time when calling +# dig() often during same yunohost operation +external_resolvers_ = [] + + +def external_resolvers(): + + global external_resolvers_ + + if not external_resolvers_: + resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n") + external_resolvers_ = [r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")] + + return external_resolvers_ + + +def dig(qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_answers=False): """ Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf """ + if resolvers == "local": + resolvers = ["127.0.0.1"] + elif resolvers == "force_external": + resolvers = external_resolvers() + else: + assert isinstance(resolvers, list) + resolver = dns.resolver.Resolver(configure=False) resolver.use_edns(0, 0, edns_size) resolver.nameservers = resolvers resolver.timeout = timeout try: answers = resolver.query(qname, rdtype) - except (dns.resolver.NXDOMAIN, dns.resolver.NoNameservers, dns.resolver.NoAnswer, - dns.exception.Timeout) as e: - return ("nok", e.__class__.__name__, e) + except (dns.resolver.NXDOMAIN, + dns.resolver.NoNameservers, + dns.resolver.NoAnswer, + dns.exception.Timeout) as e: + return ("nok", (e.__class__.__name__, e)) - return ("ok", [(answer.to_text(), answer) for answer in answers]) + if not full_answers: + answers = [answer.to_text() for answer in answers] + + return ("ok", answers) def _extract_inet(string, skip_netmask=False, skip_loopback=True): From c1262ab9a93855e241d2c25197de05858547ab36 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 22 Apr 2020 03:09:28 +0200 Subject: [PATCH 251/317] Fix acme challenge code snippet detection for this domain --- locales/en.json | 2 +- src/yunohost/certificate.py | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/locales/en.json b/locales/en.json index c2c087031..b23d3b5c3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -110,7 +110,7 @@ "backup_unable_to_organize_files": "Could not use the quick method to organize files in the archive", "backup_with_no_backup_script_for_app": "The app '{app:s}' has no backup script. Ignoring.", "backup_with_no_restore_script_for_app": "The '{app:s}' has no restoration script, you will not be able to automatically restore the backup of this app.", - "certmanager_acme_not_configured_for_domain": "Certificate for the domain '{domain:s}' does not appear to be correctly installed. Please run 'cert-install' for this domain first.", + "certmanager_acme_not_configured_for_domain": "The ACME challenge cannot be ran for this domain right now because you are missing a code snippet in nginx conf... Please make sure that your nginx configuration is up to date using `yunohost tools regen-conf nginx --dry-run --with-diff`.", "certmanager_attempt_to_renew_nonLE_cert": "The certificate for the domain '{domain:s}' is not issued by Let's Encrypt. Cannot renew it automatically!", "certmanager_attempt_to_renew_valid_cert": "The certificate for the domain '{domain:s}' is not about to expire! (You may use --force if you know what you're doing)", "certmanager_attempt_to_replace_valid_cert": "You are attempting to overwrite a good and valid certificate for domain {domain:s}! (Use --force to bypass)", diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index fd792ccae..89aadce99 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -38,6 +38,7 @@ from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger +from moulinette.utils.filesystem import read_file from yunohost.utils.network import get_public_ip @@ -468,14 +469,15 @@ Subject: %s def _check_acme_challenge_configuration(domain): - # Check nginx conf file exists - nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain - nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder - if not os.path.exists(nginx_conf_file): - return False - else: + domain_conf = "/etc/nginx/conf.d/%s.conf" % domain + if "include /etc/nginx/conf.d/acme-challenge.conf.inc" in read_file(domain_conf): return True + else: + # This is for legacy setups which haven't updated their domain conf to + # the new conf that include the acme snippet... + legacy_acme_conf = "/etc/nginx/conf.d/%s.d/000-acmechallenge.conf" % domain + return os.path.exists(legacy_acme_conf) def _fetch_and_enable_new_certificate(domain, staging=False, no_checks=False): From 32c300e62742da4645e15797da4eb317074a4da5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 22 Apr 2020 03:09:50 +0200 Subject: [PATCH 252/317] Reorganize import, make linter happier --- src/yunohost/certificate.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/yunohost/certificate.py b/src/yunohost/certificate.py index 89aadce99..5558caad5 100644 --- a/src/yunohost/certificate.py +++ b/src/yunohost/certificate.py @@ -34,16 +34,14 @@ import glob from datetime import datetime -from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate - -from yunohost.utils.error import YunohostError +from moulinette import m18n from moulinette.utils.log import getActionLogger from moulinette.utils.filesystem import read_file +from yunohost.vendor.acme_tiny.acme_tiny import get_crt as sign_certificate +from yunohost.utils.error import YunohostError from yunohost.utils.network import get_public_ip -from moulinette import m18n -from yunohost.app import app_ssowatconf from yunohost.service import _run_service_command from yunohost.regenconf import regen_conf from yunohost.log import OperationLogger @@ -597,7 +595,7 @@ def _prepare_certificate_signing_request(domain, key_file, output_folder): from yunohost.domain import _get_maindomain if domain == _get_maindomain(): # Include xmpp-upload subdomain in subject alternate names - subdomain="xmpp-upload." + domain + subdomain = "xmpp-upload." + domain try: _dns_ip_match_public_ip(get_public_ip(), subdomain) csr.add_extensions([crypto.X509Extension("subjectAltName", False, "DNS:" + subdomain)]) From f91eeff9dd3c09f8d8bfcf509541f484c536d340 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 22 Apr 2020 03:49:53 +0200 Subject: [PATCH 253/317] Uhoh we should use {domain}, fix wording.. --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index b23d3b5c3..aa1c4e4f2 100644 --- a/locales/en.json +++ b/locales/en.json @@ -110,7 +110,7 @@ "backup_unable_to_organize_files": "Could not use the quick method to organize files in the archive", "backup_with_no_backup_script_for_app": "The app '{app:s}' has no backup script. Ignoring.", "backup_with_no_restore_script_for_app": "The '{app:s}' has no restoration script, you will not be able to automatically restore the backup of this app.", - "certmanager_acme_not_configured_for_domain": "The ACME challenge cannot be ran for this domain right now because you are missing a code snippet in nginx conf... Please make sure that your nginx configuration is up to date using `yunohost tools regen-conf nginx --dry-run --with-diff`.", + "certmanager_acme_not_configured_for_domain": "The ACME challenge cannot be ran for {domain} right now because its nginx conf lacks the corresponding code snippet... Please make sure that your nginx configuration is up to date using `yunohost tools regen-conf nginx --dry-run --with-diff`.", "certmanager_attempt_to_renew_nonLE_cert": "The certificate for the domain '{domain:s}' is not issued by Let's Encrypt. Cannot renew it automatically!", "certmanager_attempt_to_renew_valid_cert": "The certificate for the domain '{domain:s}' is not about to expire! (You may use --force if you know what you're doing)", "certmanager_attempt_to_replace_valid_cert": "You are attempting to overwrite a good and valid certificate for domain {domain:s}! (Use --force to bypass)", From d6b2275b33a52f978c87770405f7acad44ab0471 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Mon, 27 Apr 2020 18:30:33 +0200 Subject: [PATCH 254/317] [enh] On 2 lines it's better --- data/helpers.d/postgresql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index 1dac6715d..aac223214 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -87,7 +87,8 @@ ynh_psql_create_db() { # grant all privilegies to user if [ -n "$user" ]; then - sql+="ALTER DATABASE ${db} OWNER TO ${user}; GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" + sql+="ALTER DATABASE ${db} OWNER TO ${user};" + sql+="GRANT ALL PRIVILEGES ON DATABASE ${db} TO ${user} WITH GRANT OPTION;" fi ynh_psql_execute_as_root --sql="$sql" From 311835b1b5ccb8a64f8baa3390153524fe402b80 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 27 Apr 2020 23:23:31 +0200 Subject: [PATCH 255/317] Add name of the exceptions that can be raised to docstring.. --- src/yunohost/backup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 5d64ae5d6..c2d2e276a 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1909,6 +1909,8 @@ class TarBackupMethod(BackupMethod): Exceptions: backup_archive_open_failed -- Raised if the archive can't be open + backup_archive_corrupted -- Raised if the archive appears corrupted + backup_archive_cant_retrieve_info_json -- If the info.json file can't be retrieved """ super(TarBackupMethod, self).mount(restore_manager) From a62b127aca961d79188474aa416aff63e0139584 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 04:18:23 +0200 Subject: [PATCH 256/317] Fix improper use of logger.exception in app.py --- src/yunohost/app.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 4e4878f9e..41c2f97a3 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -736,7 +736,7 @@ def app_upgrade(app=[], url=None, file=None): upgrade_failed = True if upgrade_retcode != 0 else False if upgrade_failed: error = m18n.n('app_upgrade_script_failed') - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) if msettings.get('interface') != 'api': dump_app_log_extract_for_debugging(operation_logger) @@ -744,13 +744,13 @@ def app_upgrade(app=[], url=None, file=None): except (KeyboardInterrupt, EOFError): upgrade_retcode = -1 error = m18n.n('operation_interrupted') - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) # Something wrong happened in Yunohost's code (most probably hook_exec) except Exception: import traceback error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) - logger.exception(m18n.n("app_install_failed", app=app_instance_name, error=error)) + logger.error(m18n.n("app_install_failed", app=app_instance_name, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) finally: # Whatever happened (install success or failure) we check if it broke the system @@ -760,7 +760,7 @@ def app_upgrade(app=[], url=None, file=None): _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - logger.exception(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e))) + logger.error(m18n.n("app_upgrade_failed", app=app_instance_name, error=str(e))) failure_message_with_debug_instructions = operation_logger.error(str(e)) # If upgrade failed or broke the system, @@ -1002,20 +1002,20 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu install_failed = True if install_retcode != 0 else False if install_failed: error = m18n.n('app_install_script_failed') - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) if msettings.get('interface') != 'api': dump_app_log_extract_for_debugging(operation_logger) # Script got manually interrupted ... N.B. : KeyboardInterrupt does not inherit from Exception except (KeyboardInterrupt, EOFError): error = m18n.n('operation_interrupted') - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) # Something wrong happened in Yunohost's code (most probably hook_exec) except Exception as e: import traceback error = m18n.n('unexpected_error', error=u"\n" + traceback.format_exc()) - logger.exception(m18n.n("app_install_failed", app=app_id, error=error)) + logger.error(m18n.n("app_install_failed", app=app_id, error=error)) failure_message_with_debug_instructions = operation_logger.error(error) finally: # Whatever happened (install success or failure) we check if it broke the system @@ -1025,7 +1025,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu _assert_system_is_sane_for_app(manifest, "post") except Exception as e: broke_the_system = True - logger.exception(m18n.n("app_install_failed", app=app_id, error=str(e))) + logger.error(m18n.n("app_install_failed", app=app_id, error=str(e))) failure_message_with_debug_instructions = operation_logger.error(str(e)) # If the install failed or broke the system, we remove it @@ -1062,7 +1062,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu except (KeyboardInterrupt, EOFError, Exception): remove_retcode = -1 import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) # Remove all permission in LDAP for permission_name in user_permission_list()["permissions"].keys(): @@ -1234,7 +1234,7 @@ def app_remove(operation_logger, app): except (KeyboardInterrupt, EOFError, Exception): ret = -1 import traceback - logger.exception(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) + logger.error(m18n.n('unexpected_error', error=u"\n" + traceback.format_exc())) if ret == 0: logger.success(m18n.n('app_removed', app=app)) @@ -2197,7 +2197,7 @@ def _get_app_settings(app_id): if app_id == settings['id']: return settings except (IOError, TypeError, KeyError): - logger.exception(m18n.n('app_not_correctly_installed', + logger.error(m18n.n('app_not_correctly_installed', app=app_id)) return {} From 428f0a61fc074a996c982c239d4c6a457076437d Mon Sep 17 00:00:00 2001 From: Maniack Crudelis Date: Sun, 19 Apr 2020 18:15:58 +0200 Subject: [PATCH 257/317] Wait for fail2ban to reload --- data/helpers.d/fail2ban | 2 +- data/helpers.d/systemd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/helpers.d/fail2ban b/data/helpers.d/fail2ban index 58af9ec0b..40f435ecd 100644 --- a/data/helpers.d/fail2ban +++ b/data/helpers.d/fail2ban @@ -130,7 +130,7 @@ EOF ynh_store_file_checksum "$finalfail2banjailconf" ynh_store_file_checksum "$finalfail2banfilterconf" - ynh_systemd_action --service_name=fail2ban --action=reload + ynh_systemd_action --service_name=fail2ban --action=reload --line_match="(Started|Reloaded) Fail2Ban Service" --log_path=systemd local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")" if [[ -n "$fail2ban_error" ]]; then diff --git a/data/helpers.d/systemd b/data/helpers.d/systemd index 960382f8f..2c290ad64 100644 --- a/data/helpers.d/systemd +++ b/data/helpers.d/systemd @@ -133,7 +133,7 @@ ynh_systemd_action() { for i in $(seq 1 $timeout) do # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout - if grep --quiet "$line_match" "$templog" + if grep --extended-regexp --quiet "$line_match" "$templog" then ynh_print_info --message="The service $service_name has correctly started." break From 1ba08be8fb3cc9d177c74bc8620b14678d97eae1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 23 Apr 2020 17:02:58 +0200 Subject: [PATCH 258/317] Make sure to return / and not empty string for stuff on domain root --- src/yunohost/app.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 41c2f97a3..69ea10928 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -455,6 +455,8 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + perm_path = perm_path if perm_path != "" else "/" + return perm_domain, perm_path this_app_perms = {p: i for p, i in permissions.items() if p.startswith(app_id + ".") and i["url"]} @@ -490,7 +492,6 @@ def app_map(app=None, raw=False, user=None): continue perm_domain, perm_path = _sanitized_absolute_url(perm_info["url"]) - if perm_name.endswith(".main"): perm_label = label else: @@ -1362,11 +1363,12 @@ def app_makedefault(operation_logger, app, domain=None): elif domain not in domain_list()['domains']: raise YunohostError('domain_unknown') - operation_logger.start() if '/' in app_map(raw=True)[domain]: raise YunohostError('app_make_default_location_already_used', app=app, domain=app_domain, other_app=app_map(raw=True)[domain]["/"]["id"]) + operation_logger.start() + # TODO / FIXME : current trick is to add this to conf.json.persisten # This is really not robust and should be improved # e.g. have a flag in /etc/yunohost/apps/$app/ to say that this is the @@ -1636,6 +1638,8 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + perm_path = perm_path if perm_path != "" else "/" + return perm_domain + perm_path # Skipped From 794640a6739981560a6221988b4dbf2b5cecd847 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 23:52:55 +0200 Subject: [PATCH 259/317] Make sure to strip() the path just in case Co-Authored-By: Bram --- src/yunohost/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 69ea10928..8c52f4928 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -455,7 +455,7 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path != "" else "/" + perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain, perm_path @@ -1638,7 +1638,7 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path != "" else "/" + perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain + perm_path From d72156b91f95b5c0ee5283bf3c3ee2c9507406ea Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 20 Apr 2020 01:40:37 +0200 Subject: [PATCH 260/317] [enh] Check domain expiration date --- data/hooks/diagnosis/12-dnsrecords.py | 79 +++++++++++++++++++++++++-- debian/control | 2 +- locales/en.json | 5 ++ 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 53afb2c2d..402f5f994 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -1,6 +1,10 @@ #!/usr/bin/env python import os +import re + +from datetime import datetime, timedelta +from subprocess import Popen, PIPE from moulinette.utils.filesystem import read_file @@ -8,6 +12,7 @@ from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain +SMALL_SUFFIX_LIST = ['noho.st', 'nohost.me', 'ynh.fr', 'netlib.re'] class DNSRecordsDiagnoser(Diagnoser): @@ -31,10 +36,12 @@ class DNSRecordsDiagnoser(Diagnoser): is_subdomain = domain.split(".",1)[1] in all_domains for report in self.check_domain(domain, domain == main_domain, is_subdomain=is_subdomain): yield report - - # FIXME : somewhere, should implement a check for reverse DNS ... - - # FIXME / TODO : somewhere, could also implement a check for domain expiring soon + + # Check if a domain buy by the user will expire soon + domains_from_registrar = ['.'.join(domain.split('.')[-2:]) for domain in all_domains] + domains_from_registrar = set(domains_from_registrar) - set(SMALL_SUFFIX_LIST) + for report in self.check_expiration_date(domains_from_registrar): + yield report def check_domain(self, domain, is_main_domain, is_subdomain): @@ -137,5 +144,69 @@ class DNSRecordsDiagnoser(Diagnoser): return r["current"] == r["value"] + def check_expiration_date(self, domains): + """ + Alert if expiration date of a domain is soon + """ + + # FIXME find a way to ignore a specific domain without + # create a report by domain each time. We need something small + details = { + "not_found": [], + "error": [], + "warning": [], + "info": [] + } + + for domain in domains: + expire_date = self.get_domain_expiration(domain) + + if not expire_date: + details["not_found"].append(( + "diagnosis_domain_expiration_date_not_found", + {"domain": domain})) + continue + + expire_in = expire_date - datetime.now() + + alert_type = "info" + if expire_in <= timedelta(7): + alert_type = "error" + elif expire_in <= timedelta(30): + alert_type = "warning" + + args = { + "domain": domain, + "days": expire_in.days - 1, + "expire_date": str(expire_date) + } + details[alert_type].append(("diagnosis_domain_expires_in", args)) + + for alert_type in ["error", "warning", "not_found", "info"]: + if details[alert_type]: + yield dict(meta={"category": "expiration"}, + data={}, + status=alert_type.upper() if alert_type != "not_found" else "INFO", + summary="diagnosis_domain_expiration_" + alert_type, + details=details[alert_type]) + + def get_domain_expiration(self, domain): + """ + Return the expiration datetime of a domain or None + """ + + p1 = Popen(['whois', domain], stdout=PIPE) + p2 = Popen(['grep', 'Expir'], stdin=p1.stdout, stdout=PIPE) + out, err = p2.communicate() + out = out.decode("utf-8").split('\n') + p1.terminate() + #p2.terminate() + + for line in out: + match = re.search(r'\d{4}-\d{2}-\d{2}', line) + if match is not None: + return datetime.strptime(match.group(), '%Y-%m-%d') + return None + def main(args, env, loggers): return DNSRecordsDiagnoser(args, env, loggers).diagnose() diff --git a/debian/control b/debian/control index 5bcd78491..fcffa87f6 100644 --- a/debian/control +++ b/debian/control @@ -29,7 +29,7 @@ Depends: ${python:Depends}, ${misc:Depends} , redis-server , metronome , git, curl, wget, cron, unzip, jq - , lsb-release, haveged, fake-hwclock, equivs, lsof + , lsb-release, haveged, fake-hwclock, equivs, lsof, whois Recommends: yunohost-admin , ntp, inetutils-ping | iputils-ping , bash-completion, rsyslog diff --git a/locales/en.json b/locales/en.json index 3607052e3..7f6d9ce34 100644 --- a/locales/en.json +++ b/locales/en.json @@ -172,6 +172,11 @@ "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.
Type: {type}
Name: {name}
Value: {value}", "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", + "diagnosis_domain_expiration_not_found": "Unable to check the expiration date of some domains", + "diagnosis_domain_expiration_info": "Domains expiration dates", + "diagnosis_domain_expiration_warning": "Some domains expire in less than a month", + "diagnosis_domain_expiration_error": "Some domains expire in less than a week", + "diagnosis_domain_expires_in": "{domain} expires in {days} days.", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", "diagnosis_services_bad_status": "Service {service} is {status} :(", From c0f27c02353d7007f0ae32823213866c6321fa35 Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 20 Apr 2020 01:47:16 +0200 Subject: [PATCH 261/317] [fix] i18n checks --- tests/test_i18n_keys.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 9125c5d52..e3edc4d48 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -119,13 +119,16 @@ def find_expected_string_keys(): for level in ["danger", "thirdparty", "warning"]: yield "confirm_app_install_%s" % level + for errortype in ["not_found", "error", "warning", "info"]: + yield "diagnosis_domain_expiration_" % errortype + for errortype in ["bad_status_code", "connection_error", "timeout"]: yield "diagnosis_http_%s" % errortype yield "password_listed" for i in [1, 2, 3, 4]: yield "password_too_simple_%s" % i - + checks = ["outgoing_port_25_ok", "ehlo_ok", "fcrdns_ok", "blacklist_ok", "queue_ok", "ehlo_bad_answer", "ehlo_unreachable", "ehlo_bad_answer_details", From 6954ca9002c808dab7ad3d3b2b3c27f31661850b Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 20 Apr 2020 01:50:04 +0200 Subject: [PATCH 262/317] [fix] i18n checks --- tests/test_i18n_keys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index e3edc4d48..6dcfd5c70 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -120,7 +120,7 @@ def find_expected_string_keys(): yield "confirm_app_install_%s" % level for errortype in ["not_found", "error", "warning", "info"]: - yield "diagnosis_domain_expiration_" % errortype + yield "diagnosis_domain_expiration_%s" % errortype for errortype in ["bad_status_code", "connection_error", "timeout"]: yield "diagnosis_http_%s" % errortype From d98d753f521def498bd8300294a3ff7b21b0f16a Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 27 Apr 2020 17:07:38 +0200 Subject: [PATCH 263/317] [fix] Bad i18n key --- data/hooks/diagnosis/12-dnsrecords.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 402f5f994..b6d87aed0 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -163,7 +163,7 @@ class DNSRecordsDiagnoser(Diagnoser): if not expire_date: details["not_found"].append(( - "diagnosis_domain_expiration_date_not_found", + "diagnosis_domain_expiration_not_found", {"domain": domain})) continue From cdb917e5652bc3782ef861272be9ae3acf32d0db Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 27 Apr 2020 18:09:07 +0200 Subject: [PATCH 264/317] [enh] Explain why domain expiration not found --- data/hooks/diagnosis/12-dnsrecords.py | 47 +++++++++++++++------------ locales/en.json | 2 ++ tests/test_i18n_keys.py | 3 +- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index b6d87aed0..f03e92df3 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -14,6 +14,7 @@ from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain SMALL_SUFFIX_LIST = ['noho.st', 'nohost.me', 'ynh.fr', 'netlib.re'] + class DNSRecordsDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] @@ -33,12 +34,13 @@ class DNSRecordsDiagnoser(Diagnoser): all_domains = domain_list()["domains"] for domain in all_domains: self.logger_debug("Diagnosing DNS conf for %s" % domain) - is_subdomain = domain.split(".",1)[1] in all_domains + is_subdomain = domain.split(".", 1)[1] in all_domains for report in self.check_domain(domain, domain == main_domain, is_subdomain=is_subdomain): yield report - + # Check if a domain buy by the user will expire soon domains_from_registrar = ['.'.join(domain.split('.')[-2:]) for domain in all_domains] + domains_from_registrar = ['ynh.local', 'grimaud.me', 'netlib.re', 'arn-fai.net'] domains_from_registrar = set(domains_from_registrar) - set(SMALL_SUFFIX_LIST) for report in self.check_expiration_date(domains_from_registrar): yield report @@ -74,7 +76,6 @@ class DNSRecordsDiagnoser(Diagnoser): results[id_] = "WRONG" discrepancies.append(("diagnosis_dns_discrepancy", r)) - def its_important(): # Every mail DNS records are important for main domain # For other domain, we only report it as a warning for now... @@ -135,7 +136,7 @@ class DNSRecordsDiagnoser(Diagnoser): if r["name"] == "@": current = {part for part in current if not part.startswith("ip4:") and not part.startswith("ip6:")} return expected == current - elif r["type"] == "MX": + elif r["type"] == "MX": # For MX, we want to ignore the priority expected = r["value"].split()[-1] current = r["current"].split()[-1] @@ -143,14 +144,11 @@ class DNSRecordsDiagnoser(Diagnoser): else: return r["current"] == r["value"] - def check_expiration_date(self, domains): """ Alert if expiration date of a domain is soon """ - # FIXME find a way to ignore a specific domain without - # create a report by domain each time. We need something small details = { "not_found": [], "error": [], @@ -161,9 +159,9 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in domains: expire_date = self.get_domain_expiration(domain) - if not expire_date: + if isinstance(expire_date, str): details["not_found"].append(( - "diagnosis_domain_expiration_not_found", + "diagnosis_%s_details" % (expire_date), {"domain": domain})) continue @@ -184,9 +182,17 @@ class DNSRecordsDiagnoser(Diagnoser): for alert_type in ["error", "warning", "not_found", "info"]: if details[alert_type]: - yield dict(meta={"category": "expiration"}, + if alert_type == "not_found": + meta = {"test": "domain_not_found"} + else: + meta = {"test": "domain_expiration"} + # Allow to ignor specifically a single domain + if len(details[alert_type]) == 1: + meta["domain"] = details[alert_type][0][1]["domain"] + meta["domain"] = details[alert_type][0][1]["domain"] + yield dict(meta=meta, data={}, - status=alert_type.upper() if alert_type != "not_found" else "INFO", + status=alert_type.upper() if alert_type != "not_found" else "WARNING", summary="diagnosis_domain_expiration_" + alert_type, details=details[alert_type]) @@ -194,19 +200,20 @@ class DNSRecordsDiagnoser(Diagnoser): """ Return the expiration datetime of a domain or None """ + # "echo failed" avoid to trigger CalledProcessError + command = "whois -H %s || echo failed" % (domain) + out = check_output(command).strip().split("\n") - p1 = Popen(['whois', domain], stdout=PIPE) - p2 = Popen(['grep', 'Expir'], stdin=p1.stdout, stdout=PIPE) - out, err = p2.communicate() - out = out.decode("utf-8").split('\n') - p1.terminate() - #p2.terminate() + # If there is less 5 lines, it's NOT FOUND response + if len(out) <= 4: + return "domain_not_found" for line in out: - match = re.search(r'\d{4}-\d{2}-\d{2}', line) + match = re.search(r'Expir.+(\d{4}-\d{2}-\d{2})', line) if match is not None: - return datetime.strptime(match.group(), '%Y-%m-%d') - return None + return datetime.strptime(match.group(1), '%Y-%m-%d') + return "domain_expiration_not_found" + def main(args, env, loggers): return DNSRecordsDiagnoser(args, env, loggers).diagnose() diff --git a/locales/en.json b/locales/en.json index 7f6d9ce34..a0e7454f1 100644 --- a/locales/en.json +++ b/locales/en.json @@ -173,6 +173,8 @@ "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", "diagnosis_domain_expiration_not_found": "Unable to check the expiration date of some domains", + "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database !", + "diagnosis_domain_expiration_not_found_details": "The WHOIS returns some info about the domain {domain} but we are not able to found the expiration date inside those info.", "diagnosis_domain_expiration_info": "Domains expiration dates", "diagnosis_domain_expiration_warning": "Some domains expire in less than a month", "diagnosis_domain_expiration_error": "Some domains expire in less than a week", diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 6dcfd5c70..6ddfa9c4a 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -119,8 +119,9 @@ def find_expected_string_keys(): for level in ["danger", "thirdparty", "warning"]: yield "confirm_app_install_%s" % level - for errortype in ["not_found", "error", "warning", "info"]: + for errortype in ["not_found", "error", "warning", "info", "not_found_details"]: yield "diagnosis_domain_expiration_%s" % errortype + yield "diagnosis_domain_not_found_details" for errortype in ["bad_status_code", "connection_error", "timeout"]: yield "diagnosis_http_%s" % errortype From c347e368fc8913e2042ae62589a6775746c6e3e9 Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 27 Apr 2020 18:22:22 +0200 Subject: [PATCH 265/317] [fix] Remove this damn test --- data/hooks/diagnosis/12-dnsrecords.py | 1 - 1 file changed, 1 deletion(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index f03e92df3..003c19cfb 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -40,7 +40,6 @@ class DNSRecordsDiagnoser(Diagnoser): # Check if a domain buy by the user will expire soon domains_from_registrar = ['.'.join(domain.split('.')[-2:]) for domain in all_domains] - domains_from_registrar = ['ynh.local', 'grimaud.me', 'netlib.re', 'arn-fai.net'] domains_from_registrar = set(domains_from_registrar) - set(SMALL_SUFFIX_LIST) for report in self.check_expiration_date(domains_from_registrar): yield report From d1b694447a15e799cd514eb106623e33e86db87b Mon Sep 17 00:00:00 2001 From: ljf Date: Mon, 27 Apr 2020 23:37:45 +0200 Subject: [PATCH 266/317] [enh] Use publicsuffix list to avoid alert on dyndns domain --- data/hooks/diagnosis/12-dnsrecords.py | 40 ++++++++++++++++++--------- debian/control | 2 +- locales/en.json | 2 +- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 003c19cfb..c92c2648e 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -4,15 +4,16 @@ import os import re from datetime import datetime, timedelta -from subprocess import Popen, PIPE +from publicsuffix import PublicSuffixList from moulinette.utils.filesystem import read_file from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain +from yunohost.utils.network import dig -SMALL_SUFFIX_LIST = ['noho.st', 'nohost.me', 'ynh.fr', 'netlib.re'] +PENDING_SUFFIX_LIST = ['ynh.fr', 'netlib.re'] class DNSRecordsDiagnoser(Diagnoser): @@ -39,8 +40,11 @@ class DNSRecordsDiagnoser(Diagnoser): yield report # Check if a domain buy by the user will expire soon - domains_from_registrar = ['.'.join(domain.split('.')[-2:]) for domain in all_domains] - domains_from_registrar = set(domains_from_registrar) - set(SMALL_SUFFIX_LIST) + psl = PublicSuffixList() + all_domains = ["grimaud.me", "reflexlibre.net", "netlib.re", "noho.st", "nohost.me", "ynh.fr", "test.noho.st", "hub.netlib.re", "sans-nuage.fr", "yunohost.org", "yunohost.local", "free.fr"] + domains_from_registrar = [psl.get_public_suffix(domain) for domain in all_domains] + domains_from_registrar = [domain for domain in domains_from_registrar if "." in domain] + domains_from_registrar = set(domains_from_registrar) - set(PENDING_SUFFIX_LIST) for report in self.check_expiration_date(domains_from_registrar): yield report @@ -159,9 +163,12 @@ class DNSRecordsDiagnoser(Diagnoser): expire_date = self.get_domain_expiration(domain) if isinstance(expire_date, str): - details["not_found"].append(( - "diagnosis_%s_details" % (expire_date), - {"domain": domain})) + status_ns, _ = dig(domain, "NS", resolvers="force_external") + status_a, _ = dig(domain, "A", resolvers="force_external") + if "ok" not in [status_ns, status_a]: + details["not_found"].append(( + "diagnosis_domain_%s_details" % (expire_date), + {"domain": domain})) continue expire_in = expire_date - datetime.now() @@ -199,19 +206,26 @@ class DNSRecordsDiagnoser(Diagnoser): """ Return the expiration datetime of a domain or None """ - # "echo failed" avoid to trigger CalledProcessError - command = "whois -H %s || echo failed" % (domain) + command = "whois -H %s" % (domain) + + # Reduce output to determine if whois answer is equivalent to NOT FOUND out = check_output(command).strip().split("\n") + filtered_out = [line for line in out + if re.search(r'^\w{4,25}:', line, re.IGNORECASE) and + not re.match(r'>>> Last update of whois', line, re.IGNORECASE) and + not re.match(r'^NOTICE:', line, re.IGNORECASE) and + not re.match(r'^%%', line, re.IGNORECASE) and + not re.match(r'"https?:"', line, re.IGNORECASE)] # If there is less 5 lines, it's NOT FOUND response - if len(out) <= 4: - return "domain_not_found" + if len(filtered_out) <= 6: + return "not_found" for line in out: - match = re.search(r'Expir.+(\d{4}-\d{2}-\d{2})', line) + match = re.search(r'Expir.+(\d{4}-\d{2}-\d{2})', line, re.IGNORECASE) if match is not None: return datetime.strptime(match.group(1), '%Y-%m-%d') - return "domain_expiration_not_found" + return "expiration_not_found" def main(args, env, loggers): diff --git a/debian/control b/debian/control index fcffa87f6..5061ad4f2 100644 --- a/debian/control +++ b/debian/control @@ -29,7 +29,7 @@ Depends: ${python:Depends}, ${misc:Depends} , redis-server , metronome , git, curl, wget, cron, unzip, jq - , lsb-release, haveged, fake-hwclock, equivs, lsof, whois + , lsb-release, haveged, fake-hwclock, equivs, lsof, whois, python-publicsuffix Recommends: yunohost-admin , ntp, inetutils-ping | iputils-ping , bash-completion, rsyslog diff --git a/locales/en.json b/locales/en.json index a0e7454f1..3f957c702 100644 --- a/locales/en.json +++ b/locales/en.json @@ -173,7 +173,7 @@ "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", "diagnosis_domain_expiration_not_found": "Unable to check the expiration date of some domains", - "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database !", + "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired !", "diagnosis_domain_expiration_not_found_details": "The WHOIS returns some info about the domain {domain} but we are not able to found the expiration date inside those info.", "diagnosis_domain_expiration_info": "Domains expiration dates", "diagnosis_domain_expiration_warning": "Some domains expire in less than a month", From 01a6aa13719bf99ed7cf6210b6fa669ee15725ce Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 04:45:16 +0200 Subject: [PATCH 267/317] Force-flush the regen-conf for nginx domain conf when adding/removing a domain... --- src/yunohost/domain.py | 32 +++++++++++++++++++++++++++++++- src/yunohost/regenconf.py | 12 ++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 18c4bd8e2..5ef6ef650 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -33,7 +33,7 @@ from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger from yunohost.app import app_ssowatconf -from yunohost.regenconf import regen_conf +from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.utils.network import get_public_ip from yunohost.log import is_unit_operation from yunohost.hook import hook_callback @@ -119,6 +119,17 @@ def domain_add(operation_logger, domain, dyndns=False): # Don't regen these conf if we're still in postinstall if os.path.exists('/etc/yunohost/installed'): + # Sometime we have weird issues with the regenconf where some files + # appears as manually modified even though they weren't touched ... + # There are a few ideas why this happens (like backup/restore nginx + # conf ... which we shouldnt do ...). This in turns creates funky + # situation where the regenconf may refuse to re-create the conf + # (when re-creating a domain..) + # So here we force-clear the has out of the regenconf if it exists. + # This is a pretty ad hoc solution and only applied to nginx + # because it's one of the major service, but in the long term we + # should identify the root of this bug... + _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd']) app_ssowatconf() @@ -176,6 +187,25 @@ def domain_remove(operation_logger, domain, force=False): os.system('rm -rf /etc/yunohost/certs/%s' % domain) + # Sometime we have weird issues with the regenconf where some files + # appears as manually modified even though they weren't touched ... + # There are a few ideas why this happens (like backup/restore nginx + # conf ... which we shouldnt do ...). This in turns creates funky + # situation where the regenconf may refuse to re-create the conf + # (when re-creating a domain..) + # + # So here we force-clear the has out of the regenconf if it exists. + # This is a pretty ad hoc solution and only applied to nginx + # because it's one of the major service, but in the long term we + # should identify the root of this bug... + _force_clear_hashes(["/etc/nginx/conf.d/%s.conf" % domain]) + # And in addition we even force-delete the file Otherwise, if the file was + # manually modified, it may not get removed by the regenconf which leads to + # catastrophic consequences of nginx breaking because it can't load the + # cert file which disappeared etc.. + if os.path.exists("/etc/nginx/conf.d/%s.conf" % domain): + _process_regen_conf("/etc/nginx/conf.d/%s.conf" % domain, new_conf=None, save=True) + regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix']) app_ssowatconf() diff --git a/src/yunohost/regenconf.py b/src/yunohost/regenconf.py index b7a42dd9d..fea6dbea7 100644 --- a/src/yunohost/regenconf.py +++ b/src/yunohost/regenconf.py @@ -463,6 +463,18 @@ def _update_conf_hashes(category, hashes): _save_regenconf_infos(categories) +def _force_clear_hashes(paths): + + categories = _get_regenconf_infos() + for path in paths: + for category in categories.keys(): + if path in categories[category]['conffiles']: + logger.debug("force-clearing old conf hash for %s in category %s" % (path, category)) + del categories[category]['conffiles'][path] + + _save_regenconf_infos(categories) + + def _process_regen_conf(system_conf, new_conf=None, save=True): """Regenerate a given system configuration file From 34fd4e90bd3ffcdf5ac067159c16251896dcfc7c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 21 Apr 2020 04:48:13 +0200 Subject: [PATCH 268/317] Be more robust against broken config or service failing to start, show info to help debugging --- data/hooks/conf_regen/15-nginx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx index 55a5494b2..87cc9b5b9 100755 --- a/data/hooks/conf_regen/15-nginx +++ b/data/hooks/conf_regen/15-nginx @@ -26,7 +26,8 @@ do_init_regen() { ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf" # Restart nginx if conf looks good, otherwise display error and exit unhappy - nginx -t 2>/dev/null && service nginx restart || (nginx -t && exit 1) + nginx -t 2>/dev/null || { nginx -t; exit 1; } + systemctl restart nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } exit 0 } @@ -109,8 +110,9 @@ do_post_regen() { mkdir -p "/etc/nginx/conf.d/${domain}.d" done - # Reload nginx configuration - pgrep nginx && service nginx reload + # Reload nginx if conf looks good, otherwise display error and exit unhappy + nginx -t 2>/dev/null || { nginx -t; exit 1; } + pgrep nginx && systemctl reload nginx || { journalctl --no-pager --lines=10 -u nginx >&2; exit 1; } } FORCE=${2:-0} From 176d0176db3b3b90a1e86eaa9e0ed370fc1f1187 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 24 Apr 2020 03:08:31 +0200 Subject: [PATCH 269/317] Be more robust against some situation where archive is corrupted --- locales/en.json | 3 ++- src/yunohost/backup.py | 42 +++++++++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/locales/en.json b/locales/en.json index 6a2af5e41..9ffa35ab6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -88,6 +88,8 @@ "backup_archive_name_exists": "A backup archive with this name already exists.", "backup_archive_name_unknown": "Unknown local backup archive named '{name:s}'", "backup_archive_open_failed": "Could not open the backup archive", + "backup_archive_cant_retrieve_info_json": "Could not load infos for archive '{archive}' ... The info.json cannot be retrieved (or is not a valid json).", + "backup_archive_corrupted": "It looks like the backup archive '{archive}' is corrupted : {error}", "backup_archive_system_part_not_available": "System part '{part:s}' unavailable in this backup", "backup_archive_writing_error": "Could not add the files '{source:s}' (named in the archive '{dest:s}') to be backed up into the compressed archive '{archive:s}'", "backup_ask_for_copying_if_needed": "Do you want to perform the backup using {size:s} MB temporarily? (This way is used since some files could not be prepared using a more efficient method.)", @@ -105,7 +107,6 @@ "backup_delete_error": "Could not delete '{path:s}'", "backup_deleted": "Backup deleted", "backup_hook_unknown": "The backup hook '{hook:s}' is unknown", - "backup_invalid_archive": "This is not a backup archive", "backup_method_borg_finished": "Backup into Borg finished", "backup_method_copy_finished": "Backup copy finalized", "backup_method_custom_finished": "Custom backup method '{method:s}' finished", diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 3344d2807..5e90bce6c 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -871,7 +871,7 @@ class RestoreManager(): Read the info file from inside an archive Exceptions: - backup_invalid_archive -- Raised if we can't read the info + backup_archive_cant_retrieve_info_json -- Raised if we can't read the info """ # Retrieve backup info info_file = os.path.join(self.work_dir, "info.json") @@ -884,7 +884,7 @@ class RestoreManager(): self.info["system"] = self.info["hooks"] except IOError: logger.debug("unable to load '%s'", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self.archive_path) else: logger.debug("restoring from backup '%s' created on %s", self.name, datetime.utcfromtimestamp(self.info['created_at'])) @@ -892,10 +892,6 @@ class RestoreManager(): def _postinstall_if_needed(self): """ Post install yunohost if needed - - Exceptions: - backup_invalid_archive -- Raised if the current_host isn't in the - archive """ # Check if YunoHost is installed if not os.path.isfile('/etc/yunohost/installed'): @@ -907,7 +903,7 @@ class RestoreManager(): logger.debug("unable to retrieve current_host from the backup", exc_info=1) # FIXME include the current_host by default ? - raise YunohostError('backup_invalid_archive') + raise YunohostError("The main domain name cannot be retrieved from inside the archive, and is needed to perform the postinstall", raw_msg=True) logger.debug("executing the post-install...") tools_postinstall(domain, 'Yunohost', True) @@ -1924,6 +1920,12 @@ class TarBackupMethod(BackupMethod): self._archive_file, exc_info=1) raise YunohostError('backup_archive_open_failed') + try: + files_in_archive = tar.getnames() + print(files_in_archive) + except IOError as e: + raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e)) + # FIXME : Is this really useful to close the archive just to # reopen it right after this with the same options ...? tar.close() @@ -1932,21 +1934,21 @@ class TarBackupMethod(BackupMethod): logger.debug(m18n.n("restore_extracting")) tar = tarfile.open(self._archive_file, "r:gz") - if "info.json" in tar.getnames(): + if "info.json" in files_in_archive: leading_dot = "" tar.extract('info.json', path=self.work_dir) - elif "./info.json" in tar.getnames(): + elif "./info.json" in files_in_archive: leading_dot = "./" tar.extract('./info.json', path=self.work_dir) else: logger.debug("unable to retrieve 'info.json' inside the archive", exc_info=1) tar.close() - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=self._archive_file) - if "backup.csv" in tar.getnames(): + if "backup.csv" in files_in_archive: tar.extract('backup.csv', path=self.work_dir) - elif "./backup.csv" in tar.getnames(): + elif "./backup.csv" in files_in_archive: tar.extract('./backup.csv', path=self.work_dir) else: # Old backup archive have no backup.csv file @@ -2288,7 +2290,7 @@ def backup_list(with_info=False, human_readable=False): try: d[a] = backup_info(a, human_readable=human_readable) except YunohostError as e: - logger.warning('%s: %s' % (a, e.strerror)) + logger.warning(str(e)) result = d @@ -2325,17 +2327,23 @@ def backup_info(name, with_details=False, human_readable=False): if not os.path.exists(info_file): tar = tarfile.open(archive_file, "r:gz") info_dir = info_file + '.d' + try: - if "info.json" in tar.getnames(): + files_in_archive = tar.getnames() + except IOError as e: + raise YunohostError("backup_archive_corrupted", archive=archive_file, error=str(e)) + + try: + if "info.json" in files_in_archive: tar.extract('info.json', path=info_dir) - elif "./info.json" in tar.getnames(): + elif "./info.json" in files_in_archive: tar.extract('./info.json', path=info_dir) else: raise KeyError except KeyError: logger.debug("unable to retrieve '%s' inside the archive", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file) else: shutil.move(os.path.join(info_dir, 'info.json'), info_file) finally: @@ -2348,7 +2356,7 @@ def backup_info(name, with_details=False, human_readable=False): info = json.load(f) except: logger.debug("unable to load '%s'", info_file, exc_info=1) - raise YunohostError('backup_invalid_archive') + raise YunohostError('backup_archive_cant_retrieve_info_json', archive=archive_file) # Retrieve backup size size = info.get('size', 0) From aea8b97993084b61fb63f9e8d2a56772bd473de7 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 25 Apr 2020 01:27:20 +0200 Subject: [PATCH 270/317] Remove tmp debug print() Co-Authored-By: Kayou --- src/yunohost/backup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/yunohost/backup.py b/src/yunohost/backup.py index 5e90bce6c..452d87361 100644 --- a/src/yunohost/backup.py +++ b/src/yunohost/backup.py @@ -1922,7 +1922,6 @@ class TarBackupMethod(BackupMethod): try: files_in_archive = tar.getnames() - print(files_in_archive) except IOError as e: raise YunohostError("backup_archive_corrupted", archive=self._archive_file, error=str(e)) From d91966ca98a2b4829695560cb4cb99dd46ea61ca Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 27 Apr 2020 23:48:46 +0200 Subject: [PATCH 271/317] Update changelog for 3.7.1.2 --- debian/changelog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/debian/changelog b/debian/changelog index 6245bb4b0..fcef69c4f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +yunohost (3.7.1.2) stable; urgency=low + + - [fix] Be more robust against some situation where some archives are corrupted + - [fix] Make nginx regen-conf more robust against broken config or service failing to start, show info to help debugging + - [fix] Force-flush the regen-conf for nginx domain conf when adding/removing a domain... + - [fix] app_map : Make sure to return / and not empty string for stuff on domain root + - [fix] Improve ynh_systemd_action to wait for fail2ban to reload + - [fix] Improper use of logger.exception in app.py leading to infamous weird "KeyError: label" + + -- Alexandre Aubin Mon, 27 Apr 2020 23:50:00 +0000 + yunohost (3.7.1.1) stable; urgency=low - [fix] lxc uid number is limited to 65536 by default (0c9a4509) From 575aa674015d3a5c343a102d31d807fb4f04a5dd Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 28 Apr 2020 00:30:38 +0200 Subject: [PATCH 272/317] [fix] whois on co.uk --- data/hooks/diagnosis/12-dnsrecords.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index c92c2648e..d47e33d33 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -7,11 +7,11 @@ from datetime import datetime, timedelta from publicsuffix import PublicSuffixList from moulinette.utils.filesystem import read_file +from moulinette.utils.process import check_output from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain -from yunohost.utils.network import dig PENDING_SUFFIX_LIST = ['ynh.fr', 'netlib.re'] @@ -41,7 +41,6 @@ class DNSRecordsDiagnoser(Diagnoser): # Check if a domain buy by the user will expire soon psl = PublicSuffixList() - all_domains = ["grimaud.me", "reflexlibre.net", "netlib.re", "noho.st", "nohost.me", "ynh.fr", "test.noho.st", "hub.netlib.re", "sans-nuage.fr", "yunohost.org", "yunohost.local", "free.fr"] domains_from_registrar = [psl.get_public_suffix(domain) for domain in all_domains] domains_from_registrar = [domain for domain in domains_from_registrar if "." in domain] domains_from_registrar = set(domains_from_registrar) - set(PENDING_SUFFIX_LIST) @@ -211,7 +210,7 @@ class DNSRecordsDiagnoser(Diagnoser): # Reduce output to determine if whois answer is equivalent to NOT FOUND out = check_output(command).strip().split("\n") filtered_out = [line for line in out - if re.search(r'^\w{4,25}:', line, re.IGNORECASE) and + if re.search(r'^[a-zA-Z0-9 ]{4,25}:', line, re.IGNORECASE) and not re.match(r'>>> Last update of whois', line, re.IGNORECASE) and not re.match(r'^NOTICE:', line, re.IGNORECASE) and not re.match(r'^%%', line, re.IGNORECASE) and @@ -225,6 +224,11 @@ class DNSRecordsDiagnoser(Diagnoser): match = re.search(r'Expir.+(\d{4}-\d{2}-\d{2})', line, re.IGNORECASE) if match is not None: return datetime.strptime(match.group(1), '%Y-%m-%d') + + match = re.search(r'Expir.+(\d{2}-\w{3}-\d{4})', line, re.IGNORECASE) + if match is not None: + return datetime.strptime(match.group(1), '%d-%b-%Y') + return "expiration_not_found" From b241c2fa1d552c719e83181940893092bef53316 Mon Sep 17 00:00:00 2001 From: ljf Date: Tue, 28 Apr 2020 00:53:23 +0200 Subject: [PATCH 273/317] [enh] Whois not working --- data/hooks/diagnosis/12-dnsrecords.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index d47e33d33..7ff791823 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -3,6 +3,7 @@ import os import re +from subprocess import CalledProcessError from datetime import datetime, timedelta from publicsuffix import PublicSuffixList @@ -161,13 +162,15 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in domains: expire_date = self.get_domain_expiration(domain) - if isinstance(expire_date, str): + if isinstance(expire_date, str) and expire_date != "not_working": status_ns, _ = dig(domain, "NS", resolvers="force_external") status_a, _ = dig(domain, "A", resolvers="force_external") if "ok" not in [status_ns, status_a]: details["not_found"].append(( "diagnosis_domain_%s_details" % (expire_date), {"domain": domain})) + else: + self.logger_debug("Dyndns domain: %s" % (domain)) continue expire_in = expire_date - datetime.now() @@ -207,8 +210,13 @@ class DNSRecordsDiagnoser(Diagnoser): """ command = "whois -H %s" % (domain) + try: + out = check_output(command).strip().split("\n") + except CalledProcessError as e: + self.logger_warning("Unable to get whois data for %s . Could be due to a rate limit on whois. Error: %s" % (domain, str(e))) + return "not_working" + # Reduce output to determine if whois answer is equivalent to NOT FOUND - out = check_output(command).strip().split("\n") filtered_out = [line for line in out if re.search(r'^[a-zA-Z0-9 ]{4,25}:', line, re.IGNORECASE) and not re.match(r'>>> Last update of whois', line, re.IGNORECASE) and @@ -216,7 +224,7 @@ class DNSRecordsDiagnoser(Diagnoser): not re.match(r'^%%', line, re.IGNORECASE) and not re.match(r'"https?:"', line, re.IGNORECASE)] - # If there is less 5 lines, it's NOT FOUND response + # If there is less than 7 lines, it's NOT FOUND response if len(filtered_out) <= 6: return "not_found" From 196a3d4d477f7cb168e2748715e06ddec74737d3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 28 Apr 2020 05:36:11 +0200 Subject: [PATCH 274/317] Refactor check about apps being installed on domain when trying to remove a domain --- src/yunohost/domain.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/yunohost/domain.py b/src/yunohost/domain.py index 82cbbc322..f1dcefba9 100644 --- a/src/yunohost/domain.py +++ b/src/yunohost/domain.py @@ -25,14 +25,13 @@ """ import os import re -import yaml from moulinette import m18n, msettings from moulinette.core import MoulinetteError from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger -from yunohost.app import app_ssowatconf +from yunohost.app import app_ssowatconf, _installed_apps, _get_app_settings from yunohost.regenconf import regen_conf, _force_clear_hashes, _process_regen_conf from yunohost.utils.network import get_public_ip from yunohost.log import is_unit_operation @@ -180,15 +179,9 @@ def domain_remove(operation_logger, domain, force=False): raise YunohostError('domain_cannot_remove_main_add_new_one', domain=domain) # Check if apps are installed on the domain - for app in os.listdir('/etc/yunohost/apps/'): - with open('/etc/yunohost/apps/' + app + '/settings.yml') as f: - try: - app_domain = yaml.load(f)['domain'] - except: - continue - else: - if app_domain == domain: - raise YunohostError('domain_uninstall_app_first') + app_settings = [_get_app_settings(app) for app in _installed_apps()] + if any(s["domain"] == domain for s in app_settings): + raise YunohostError('domain_uninstall_app_first') operation_logger.start() ldap = _get_ldap_interface() From 2c7a059f1903aeb5cf623af2c83883bc9c12c010 Mon Sep 17 00:00:00 2001 From: "ljf (zamentur)" Date: Tue, 28 Apr 2020 17:01:11 +0200 Subject: [PATCH 275/317] [enh] Add a small comments to explain the pending suffix list --- data/hooks/diagnosis/12-dnsrecords.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 7ff791823..8d59538dc 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -14,6 +14,8 @@ from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain +# We put here domains we know has dyndns provider, but that are not yet +# registered in the public suffix list PENDING_SUFFIX_LIST = ['ynh.fr', 'netlib.re'] From ba73bd03b4b563c9a0ea4b7992db070bac0bb167 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 28 Apr 2020 17:18:25 +0200 Subject: [PATCH 276/317] Update postgresql --- data/helpers.d/postgresql | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/postgresql b/data/helpers.d/postgresql index a4cb50393..954f44d0b 100644 --- a/data/helpers.d/postgresql +++ b/data/helpers.d/postgresql @@ -276,7 +276,13 @@ ynh_psql_test_if_first_run() { local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf local logfile=/var/log/postgresql/postgresql-9.6-main.log else - ynh_die "postgresql shoud be 9.4 or 9.6 or it could be a problem of locale see https://serverfault.com/questions/426989/postgresql-etc-postgresql-doesnt-exist" + if dpkg --list | grep -q "ii postgresql-9." + then + ynh_die "It looks like postgresql was not properly configured ? /etc/postgresql/9.* is missing ... Could be due to a locale issue, c.f.https://serverfault.com/questions/426989/postgresql-etc-postgresql-doesnt-exist" + else + ynh_die "postgresql shoud be 9.4 or 9.6 or " + fi + fi ynh_systemd_action --service_name=postgresql --action=start From ae98ec1aa7548f13cf99318bdcfdf89853bb2b52 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 28 Apr 2020 18:55:39 +0200 Subject: [PATCH 277/317] Trailing slash in ssowat uris cause issues to access app installed on root, we only need it for app_map ... --- src/yunohost/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 25f856c10..f7e4fd435 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -261,6 +261,8 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + # N.B. : having '/' instead of empty string is needed in app_map + # but should *not* be done in app_ssowatconf (yeah :[) perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain, perm_path @@ -1291,8 +1293,6 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path.strip() != "" else "/" - return perm_domain + perm_path # Skipped From 3582a5a389d1ffff31d5feb28901364ceb857a56 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 28 Apr 2020 18:55:39 +0200 Subject: [PATCH 278/317] Trailing slash in ssowat uris cause issues to access app installed on root, we only need it for app_map ... --- src/yunohost/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 8c52f4928..94e453b1d 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -455,6 +455,8 @@ def app_map(app=None, raw=False, user=None): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") + # N.B. : having '/' instead of empty string is needed in app_map + # but should *not* be done in app_ssowatconf (yeah :[) perm_path = perm_path if perm_path.strip() != "" else "/" return perm_domain, perm_path @@ -1638,8 +1640,6 @@ def app_ssowatconf(): perm_domain, perm_path = perm_url.split("/", 1) perm_path = "/" + perm_path.rstrip("/") - perm_path = perm_path if perm_path.strip() != "" else "/" - return perm_domain + perm_path # Skipped From 3c234c7895e8ed82dddff204e6d54db9fdcccd9a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Tue, 28 Apr 2020 18:59:19 +0200 Subject: [PATCH 279/317] Update changelog for 3.7.1.3 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index fcef69c4f..eb7af8f4d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.7.1.3) stable; urgency=low + + - [fix] Fix the hotfix about trailing slash, it was breaking access to app installed on domain root.. + + -- Alexandre Aubin Thu, 28 Apr 2020 19:00:00 +0000 + yunohost (3.7.1.2) stable; urgency=low - [fix] Be more robust against some situation where some archives are corrupted From 4e84b6368851e0bb03632378a05abec78ca56792 Mon Sep 17 00:00:00 2001 From: ljf Date: Wed, 29 Apr 2020 00:23:33 +0200 Subject: [PATCH 280/317] [fix] Who is the creator of whois ? #consistency --- data/hooks/diagnosis/12-dnsrecords.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 7ff791823..90dc2e04b 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -162,7 +162,7 @@ class DNSRecordsDiagnoser(Diagnoser): for domain in domains: expire_date = self.get_domain_expiration(domain) - if isinstance(expire_date, str) and expire_date != "not_working": + if isinstance(expire_date, str): status_ns, _ = dig(domain, "NS", resolvers="force_external") status_a, _ = dig(domain, "A", resolvers="force_external") if "ok" not in [status_ns, status_a]: @@ -208,13 +208,8 @@ class DNSRecordsDiagnoser(Diagnoser): """ Return the expiration datetime of a domain or None """ - command = "whois -H %s" % (domain) - - try: - out = check_output(command).strip().split("\n") - except CalledProcessError as e: - self.logger_warning("Unable to get whois data for %s . Could be due to a rate limit on whois. Error: %s" % (domain, str(e))) - return "not_working" + command = "whois -H %s || echo failed" % (domain) + out = check_output(command).strip().split("\n") # Reduce output to determine if whois answer is equivalent to NOT FOUND filtered_out = [line for line in out From 76de0bb2e9bfd8b0a26ba0123eb6ce754fac0439 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 02:42:23 +0200 Subject: [PATCH 281/317] Remove stale code --- data/hooks/diagnosis/12-dnsrecords.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 9db6f88bc..ef720928b 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -3,18 +3,16 @@ import os import re -from subprocess import CalledProcessError from datetime import datetime, timedelta from publicsuffix import PublicSuffixList -from moulinette.utils.filesystem import read_file from moulinette.utils.process import check_output from yunohost.utils.network import dig from yunohost.diagnosis import Diagnoser from yunohost.domain import domain_list, _build_dns_conf, _get_maindomain -# We put here domains we know has dyndns provider, but that are not yet +# We put here domains we know has dyndns provider, but that are not yet # registered in the public suffix list PENDING_SUFFIX_LIST = ['ynh.fr', 'netlib.re'] @@ -27,12 +25,6 @@ class DNSRecordsDiagnoser(Diagnoser): def run(self): - resolvers = read_file("/etc/resolv.dnsmasq.conf").split("\n") - ipv4_resolvers = [r.split(" ")[1] for r in resolvers if r.startswith("nameserver") and ":" not in r] - # FIXME some day ... handle ipv4-only and ipv6-only servers. For now we assume we have at least ipv4 - assert ipv4_resolvers != [], "Uhoh, need at least one IPv4 DNS resolver ..." - - self.resolver = ipv4_resolvers[0] main_domain = _get_maindomain() all_domains = domain_list()["domains"] From f22ac67468ea35a29c42328e16b4298610370d6a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 02:43:37 +0200 Subject: [PATCH 282/317] Success for domains not about to expire --- data/hooks/diagnosis/12-dnsrecords.py | 9 ++++----- tests/test_i18n_keys.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index ef720928b..60efcdf9f 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -150,7 +150,7 @@ class DNSRecordsDiagnoser(Diagnoser): "not_found": [], "error": [], "warning": [], - "info": [] + "success": [] } for domain in domains: @@ -169,7 +169,7 @@ class DNSRecordsDiagnoser(Diagnoser): expire_in = expire_date - datetime.now() - alert_type = "info" + alert_type = "success" if expire_in <= timedelta(7): alert_type = "error" elif expire_in <= timedelta(30): @@ -182,16 +182,15 @@ class DNSRecordsDiagnoser(Diagnoser): } details[alert_type].append(("diagnosis_domain_expires_in", args)) - for alert_type in ["error", "warning", "not_found", "info"]: + for alert_type in ["success", "error", "warning", "not_found"]: if details[alert_type]: if alert_type == "not_found": meta = {"test": "domain_not_found"} else: meta = {"test": "domain_expiration"} - # Allow to ignor specifically a single domain + # Allow to ignore specifically a single domain if len(details[alert_type]) == 1: meta["domain"] = details[alert_type][0][1]["domain"] - meta["domain"] = details[alert_type][0][1]["domain"] yield dict(meta=meta, data={}, status=alert_type.upper() if alert_type != "not_found" else "WARNING", diff --git a/tests/test_i18n_keys.py b/tests/test_i18n_keys.py index 6ddfa9c4a..874794e11 100644 --- a/tests/test_i18n_keys.py +++ b/tests/test_i18n_keys.py @@ -119,7 +119,7 @@ def find_expected_string_keys(): for level in ["danger", "thirdparty", "warning"]: yield "confirm_app_install_%s" % level - for errortype in ["not_found", "error", "warning", "info", "not_found_details"]: + for errortype in ["not_found", "error", "warning", "success", "not_found_details"]: yield "diagnosis_domain_expiration_%s" % errortype yield "diagnosis_domain_not_found_details" From b528336fd05f0490a0409940afc186d2ddc68c4a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 02:43:58 +0200 Subject: [PATCH 283/317] Update / improve strings --- locales/en.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/locales/en.json b/locales/en.json index 3f957c702..da37f144c 100644 --- a/locales/en.json +++ b/locales/en.json @@ -172,12 +172,12 @@ "diagnosis_dns_missing_record": "According to the recommended DNS configuration, you should add a DNS record with the following info.
Type: {type}
Name: {name}
Value: {value}", "diagnosis_dns_discrepancy": "The following DNS record does not seem to follow the recommended configuration:
Type: {type}
Name: {name}
Current value: {current}
Excepted value: {value}", "diagnosis_dns_point_to_doc": "Please check the documentation at https://yunohost.org/dns_config if you need help about configuring DNS records.", - "diagnosis_domain_expiration_not_found": "Unable to check the expiration date of some domains", - "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired !", - "diagnosis_domain_expiration_not_found_details": "The WHOIS returns some info about the domain {domain} but we are not able to found the expiration date inside those info.", - "diagnosis_domain_expiration_info": "Domains expiration dates", - "diagnosis_domain_expiration_warning": "Some domains expire in less than a month", - "diagnosis_domain_expiration_error": "Some domains expire in less than a week", + "diagnosis_domain_expiration_not_found": "Unable to check the expiration date for some domains", + "diagnosis_domain_not_found_details": "The domain {domain} doesn't exist in WHOIS database or is expired!", + "diagnosis_domain_expiration_not_found_details": "The WHOIS information for domain {domain} doesn't seem to contain the information about the expiration date?", + "diagnosis_domain_expiration_success": "Your domains are registered and not going to expire anytime soon.", + "diagnosis_domain_expiration_warning": "Some domains will expire soon!", + "diagnosis_domain_expiration_error": "Some domains will expire VERY SOON!", "diagnosis_domain_expires_in": "{domain} expires in {days} days.", "diagnosis_services_running": "Service {service} is running!", "diagnosis_services_conf_broken": "Configuration is broken for service {service}!", From 415e805f74cc312ca9752c6075f858a64fe00831 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 02:44:39 +0200 Subject: [PATCH 284/317] Change threshold to warn earlier about soon-to-expire domain --- data/hooks/diagnosis/12-dnsrecords.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/12-dnsrecords.py b/data/hooks/diagnosis/12-dnsrecords.py index 60efcdf9f..560127bb0 100644 --- a/data/hooks/diagnosis/12-dnsrecords.py +++ b/data/hooks/diagnosis/12-dnsrecords.py @@ -170,9 +170,9 @@ class DNSRecordsDiagnoser(Diagnoser): expire_in = expire_date - datetime.now() alert_type = "success" - if expire_in <= timedelta(7): + if expire_in <= timedelta(15): alert_type = "error" - elif expire_in <= timedelta(30): + elif expire_in <= timedelta(45): alert_type = "warning" args = { From c04d3c38069d79abbec5ee060291624fabfcbd13 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 17:13:47 +0200 Subject: [PATCH 285/317] Remove comment about old lines that got replaced --- data/helpers.d/apt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/helpers.d/apt b/data/helpers.d/apt index 9e3f26b90..82e3ab40c 100644 --- a/data/helpers.d/apt +++ b/data/helpers.d/apt @@ -188,12 +188,10 @@ ynh_package_install_from_equivs () { (cd "$TMPDIR" LC_ALL=C equivs-build ./control 1> /dev/null dpkg --force-depends --install "./${pkgname}_${pkgversion}_all.deb" 2>&1) - # If install fails we use "apt-get check" to try to debug and diagnose possible unmet dependencies - # Note the use of { } which allows to group commands without starting a subshell (otherwise the ynh_die wouldn't exit the current shell). - # Be careful with the syntax : the semicolon + space at the end is important! ynh_package_install --fix-broken || \ - { # If the installation failed + { # If the installation failed + # (the following is ran inside { } to not start a subshell otherwise ynh_die wouldnt exit the original process) # Get the list of dependencies from the deb local dependencies="$(dpkg --info "$TMPDIR/${pkgname}_${pkgversion}_all.deb" | grep Depends | \ sed 's/^ Depends: //' | sed 's/,//g')" From b78d72278501641c6f93b1d1d6b55103ccc4624c Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 18:01:40 +0200 Subject: [PATCH 286/317] Dirty hack to automatically find custom SSH port --- src/yunohost/service.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index b6c93b5ae..a593aac4f 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -24,6 +24,7 @@ Manage services """ import os +import re import time import yaml import subprocess @@ -33,11 +34,12 @@ from datetime import datetime from moulinette import m18n from yunohost.utils.error import YunohostError -from moulinette.utils import log, filesystem +from moulinette.utils.log import getActionLogger +from moulinette.utils.filesystem import read_file MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock" -logger = log.getActionLogger('yunohost.service') +logger = getActionLogger('yunohost.service') def service_add(name, description=None, log=None, log_type="file", test_status=None, test_conf=None, needs_exposed_ports=None, need_lock=False, status=None): @@ -552,7 +554,7 @@ def _give_lock(action, service, p): def _remove_lock(PID_to_remove): # FIXME ironically not concurrency safe because it's not atomic... - PIDs = filesystem.read_file(MOULINETTE_LOCK).split("\n") + PIDs = read_file(MOULINETTE_LOCK).split("\n") 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)) @@ -574,6 +576,11 @@ def _get_services(): if value is None: del services[key] + # Dirty hack to automatically find custom SSH port ... + ssh_port_line = re.findall(r"\bPort *([0-9]{2,5})\b", read_file("/etc/ssh/sshd_config")) + if len(ssh_port_line) == 1: + services["ssh"]["needs_exposed_ports"] = [int(ssh_port_line[0])] + # Stupid hack for postgresql which ain't an official service ... Can't # really inject that info otherwise. Real service we want to check for # status and log is in fact postgresql@x.y-main (x.y being the version) @@ -654,8 +661,6 @@ def _find_previous_log_file(file): """ Find the previous log file """ - import re - splitext = os.path.splitext(file) if splitext[1] == '.gz': file = splitext[0] From e236a2872a0ef54e7cac365ed7e1ba090ec6aa7b Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 18:22:38 +0200 Subject: [PATCH 287/317] Lul I fuckedup import refactoring --- src/yunohost/service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index a593aac4f..7c6b28b10 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -35,7 +35,7 @@ from datetime import datetime from moulinette import m18n from yunohost.utils.error import YunohostError from moulinette.utils.log import getActionLogger -from moulinette.utils.filesystem import read_file +from moulinette.utils.filesystem import read_file, append_to_file, write_to_file MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock" @@ -546,7 +546,7 @@ def _give_lock(action, service, p): # Append the PID to the lock file logger.debug("Giving a lock to PID %s for service %s !" % (str(son_PID), service)) - filesystem.append_to_file(MOULINETTE_LOCK, "\n%s" % str(son_PID)) + append_to_file(MOULINETTE_LOCK, "\n%s" % str(son_PID)) return son_PID @@ -556,7 +556,7 @@ def _remove_lock(PID_to_remove): PIDs = read_file(MOULINETTE_LOCK).split("\n") 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)) + write_to_file(MOULINETTE_LOCK, '\n'.join(PIDs_to_keep)) def _get_services(): From 0b75f5d437af69c9777f47489ef2f6dfabd277c3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 19:20:29 +0200 Subject: [PATCH 288/317] IPv6 resolvers make everything super slow on IPv4-only servers --- data/hooks/diagnosis/10-ip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index c0d35278c..ac867efb5 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -73,7 +73,7 @@ class IPDiagnoser(Diagnoser): network_interfaces = get_network_interfaces() def get_local_ip(version): - local_ip = {iface:addr[version].split("/")[0] + local_ip = {iface: addr[version].split("/")[0] for iface, addr in network_interfaces.items() if version in addr} if not local_ip: return None @@ -92,7 +92,7 @@ class IPDiagnoser(Diagnoser): data={"global": ipv6, "local": get_local_ip("ipv6")}, status="SUCCESS" if ipv6 else "WARNING", summary="diagnosis_ip_connected_ipv6" if ipv6 else "diagnosis_ip_no_ipv6", - details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 else None) + details=["diagnosis_ip_global", "diagnosis_ip_local"] if ipv6 else ["diagnosis_ip_no_ipv6_tip"]) # TODO / FIXME : add some attempt to detect ISP (using whois ?) ? From 426d93825d5e0afaf5bec24e9e056cbe6e1c11e6 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 19:20:54 +0200 Subject: [PATCH 289/317] Add a tip about not having IPv6 --- locales/en.json | 1 + src/yunohost/utils/network.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index fcc603f41..1bf83469e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -159,6 +159,7 @@ "diagnosis_ip_no_ipv4": "The server does not have working IPv4.", "diagnosis_ip_connected_ipv6": "The server is connected to the Internet through IPv6 !", "diagnosis_ip_no_ipv6": "The server does not have working IPv6.", + "diagnosis_ip_no_ipv6_tip": "Having a working IPv6 is not mandatory for your server to work, but it is better for the health of the Internet as a whole. IPv6 should usually be automatically configured by the system or your provider if it's available. Otherwise, you might need to configure a few things manually as explained in the documentation here: https://yunohost.org/#/ipv6. If you cannot enable IPv6 or if it seems too technical for you, you can also safely ignore this warning.", "diagnosis_ip_global": "Global IP: {global}", "diagnosis_ip_local": "Local IP: {local}", "diagnosis_ip_not_connected_at_all": "The server does not seem to be connected to the Internet at all!?", diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index ef6378692..2da758886 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -27,7 +27,6 @@ import dns.resolver from moulinette.utils.filesystem import read_file, write_to_file from moulinette.utils.network import download_text from moulinette.utils.process import check_output -from moulinette.utils.filesystem import read_file logger = logging.getLogger('yunohost.utils.network') @@ -113,6 +112,10 @@ def external_resolvers(): if not external_resolvers_: resolv_dnsmasq_conf = read_file("/etc/resolv.dnsmasq.conf").split("\n") external_resolvers_ = [r.split(" ")[1] for r in resolv_dnsmasq_conf if r.startswith("nameserver")] + # We keep only ipv4 resolvers, otherwise on IPv4-only instances, IPv6 + # will be tried anyway resulting in super-slow dig requests that'll wait + # until timeout... + external_resolvers_ = [r for r in external_resolvers_ if ":" not in r] return external_resolvers_ From fd47e45df3589cfbdf5fd9165f29ce4493793c6a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 19:39:46 +0200 Subject: [PATCH 290/317] Wording --- locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.json b/locales/en.json index 1bf83469e..25712e8cd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -209,7 +209,7 @@ "diagnosis_mail_fcrdns_ok": "Your reverse DNS is correctly configured!", "diagnosis_mail_fcrdns_dns_missing": "No reverse DNS is defined in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.", "diagnosis_mail_fcrdns_nok_details": "You should first try to configure the reverse DNS with {ehlo_domain} in your internet router interface or your hosting provider interface. (Some hosting provider may require you to send them a support ticket for this).", - "diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If you are experiencing issues because of this, consider the following solutions:
- Some ISP provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Finally, it's also possible to change of provider", + "diagnosis_mail_fcrdns_nok_alternatives_4": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If you are experiencing issues because of this, consider the following solutions:
- Some ISP provide the alternative of using a mail server relay though it implies that the relay will be able to spy on your email traffic.
- A privacy-friendly alternative is to use a VPN *with a dedicated public IP* to bypass this kind of limits. See https://yunohost.org/#/vpn_advantage
- Or it's possible to switch to a different provider", "diagnosis_mail_fcrdns_nok_alternatives_6": "Some providers won't let you configure your reverse DNS (or their feature might be broken...). If your reverse DNS is correctly configured for IPv4, you can try disabling the use of IPv6 when sending emails by running yunohost settings set smtp.allow_ipv6 -v off. Note: this last solution means that you won't be able to send or receive emails from the few IPv6-only servers out there.", "diagnosis_mail_fcrdns_different_from_ehlo_domain": "The reverse DNS is not correctly configured in IPv{ipversion}. Some emails may fail to get delivered or may get flagged as spam.", "diagnosis_mail_fcrdns_different_from_ehlo_domain_details": "Current reverse DNS: {rdns_domain}
Expected value: {ehlo_domain}", From 822c731086ec18a57f192295cb89ebdf5b11ba07 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 21:48:22 +0200 Subject: [PATCH 291/317] Improve default IPv6 route check to cover stuff happening on internet cube --- src/yunohost/utils/network.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index 2da758886..ce2356fcf 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -58,7 +58,13 @@ def get_public_ip_from_remote_server(protocol=4): # If we are indeed connected in ipv4 or ipv6, we should find a default route routes = check_output("ip -%s route" % protocol).split("\n") - if not any(r.startswith("default") for r in routes): + def is_default_route(r): + # Typically the default route starts with "default" + # But of course IPv6 is more complex ... e.g. on internet cube there's + # no default route but a /3 which acts as a default-like route... + # e.g. 2000:/3 dev tun0 ... + return r.startswith("default") or (":" in r and re.match(r".*/[0-3]$", r.split()[0])) + if not any(is_default_route(r) for r in routes): logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) return None From 3d4ef03ad27f8f2c81b6dc305821ca01816373e3 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 22:03:58 +0200 Subject: [PATCH 292/317] Dirty hack to check status of ynh-vpnclient for real --- src/yunohost/service.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 7c6b28b10..2f45e28c3 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -581,6 +581,14 @@ def _get_services(): if len(ssh_port_line) == 1: services["ssh"]["needs_exposed_ports"] = [int(ssh_port_line[0])] + # Dirty hack to check the status of ynh-vpnclient + if "ynh-vpnclient" in services: + status_check = "systemctl is-active openvpn@client.service" + if "test_status" not in services["ynh-vpnclient"]: + services["ynh-vpnclient"]["test_status"] = status_check + if "log" not in services["ynh-vpnclient"]: + services["ynh-vpnclient"]["log"] = ["/var/log/ynh-vpnclient.log"] + # Stupid hack for postgresql which ain't an official service ... Can't # really inject that info otherwise. Real service we want to check for # status and log is in fact postgresql@x.y-main (x.y being the version) From 645ed9c211ae026705db4dd1c00be365ea30955a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Wed, 29 Apr 2020 23:16:39 +0200 Subject: [PATCH 293/317] Update changelog for 3.8.2 --- debian/changelog | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/debian/changelog b/debian/changelog index abf42446e..37a945919 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,38 @@ +yunohost (3.8.2) testing; urgency=low + + ### Diagnosis + + - [fix] Some DNS queries triggered false negatives about CNAME/A record and email blacklisting (#943) + - [enh] Add a check about domain expiration (#944) + - [enh] Dirty hack to automatically find custom SSH port and diagnose it instead of 22 (b78d722) + - [enh] Add a tip / explanation when IPv6 ain't working / available (426d938) + - [fix] Small false-negative about not having IPv6 when it's actually working (822c731) + + ### Helpers + + - [fix] When setting up a new db, corresponding user should be declared as owner (#813) + - [enh] Add dynamic variables to systemd helper (#937) + - [enh] Clean helpers (#947) + - [fix] getopts behaved in weird way when fed empty parameters (#948) + - [fix] Use ynh_port_available in ynh_find_port (#957) + + ### Others + + - [enh] Setup all XMPP components for each "parent" domains (#916) + - [fix] Previous change in Postfix ciphers broke TLS (#949) + - [fix] Update ACME snippet detection following previous change (#950) + - [fix] Trying to install apps with unpatchable legacy helpers was breaking stuff (#954) + - [fix] Patch usage of old 'yunohost tools diagnosis' (#954) + - [enh] Misc optimizations to speed up regen-conf and other things (#958) + - [enh] When sharing logs, also anonymize folder name containing %2e instead of dot (b392efd) + - [enh] Keep track of yunohost version a backup was made from (54cc684) + - [fix] Re-add 'app fetchlist', 'app list -i', 'app list' filter for backward compatibility... (69938c3) + - [i18n] Improve translations for Catalan, German, French, Esperanto, Spanish, Greek, Nepali, Occitan + + Thanks to all contributors <3 ! (Bram, C. Wehrli, Kay0u, Maniack C., Quentí, Zeik0s, amirale qt, ljf, pitchum, tituspijean, xaloc33, Éric G.) + + -- Alexandre Aubin Wed, 29 Apr 2020 23:15:00 +0000 + yunohost (3.8.1.1) testing; urgency=low - [fix] Stupid issue about path in debian/install ... From 7ce56cd867b0939aabf95fcbab344c3f01083a5e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 00:18:12 +0200 Subject: [PATCH 294/317] Bad french translation --- locales/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/fr.json b/locales/fr.json index 764b6bb10..e9402730d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -522,7 +522,7 @@ "diagnosis_display_tip_cli": "Vous pouvez exécuter 'yunohost diagnosis show --issues' pour afficher les problèmes détectés.", "diagnosis_failed_for_category": "Échec du diagnostic pour la catégorie '{category}': {error}", "diagnosis_cache_still_valid": "(Le cache est encore valide pour le diagnostic {category}. Il ne sera pas re-diagnostiqué pour le moment!)", - "diagnosis_ignored_issues": "(+ {nb_ignored} questions ignorée(s))", + "diagnosis_ignored_issues": "(+ {nb_ignored} problèmes ignorée(s))", "diagnosis_found_warnings": "Trouvé {warnings} objet(s) pouvant être amélioré(s) pour {category}.", "diagnosis_everything_ok": "Tout semble bien pour {category} !", "diagnosis_failed": "Échec de la récupération du résultat du diagnostic pour la catégorie '{category}' : {error}", From 4f8aa5e338537f211aa459d142b97cfe3585b628 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 02:38:27 +0200 Subject: [PATCH 295/317] Propagate route check to ip diagnoser as well :/ --- data/hooks/diagnosis/10-ip.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index ac867efb5..d4c203e7e 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -106,8 +106,15 @@ class IPDiagnoser(Diagnoser): # If we are indeed connected in ipv4 or ipv6, we should find a default route routes = check_output("ip -%s route" % protocol).split("\n") - if not any(r.startswith("default") for r in routes): - return False + def is_default_route(r): + # Typically the default route starts with "default" + # But of course IPv6 is more complex ... e.g. on internet cube there's + # no default route but a /3 which acts as a default-like route... + # e.g. 2000:/3 dev tun0 ... + return r.startswith("default") or (":" in r and re.match(r".*/[0-3]$", r.split()[0])) + if not any(is_default_route(r) for r in routes): + logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) + return None # We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping resolver_file = "/usr/share/yunohost/templates/dnsmasq/plain/resolv.dnsmasq.conf" From aaccb547750076694af33656126eb04bdf0a3ff5 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 02:40:22 +0200 Subject: [PATCH 296/317] Hmf, comparison return a warning if swap is exactly 512.. --- data/hooks/diagnosis/50-systemresources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/50-systemresources.py b/data/hooks/diagnosis/50-systemresources.py index 417b88ae7..5007f8ede 100644 --- a/data/hooks/diagnosis/50-systemresources.py +++ b/data/hooks/diagnosis/50-systemresources.py @@ -47,7 +47,7 @@ class SystemResourcesDiagnoser(Diagnoser): if swap.total <= 1 * MB: item["status"] = "ERROR" item["summary"] = "diagnosis_swap_none" - elif swap.total <= 512 * MB: + elif swap.total < 500 * MB: item["status"] = "WARNING" item["summary"] = "diagnosis_swap_notsomuch" else: From 8de8d0ad6fdefafdb641b5aad83396476a7af3ff Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 30 Apr 2020 02:44:51 +0200 Subject: [PATCH 297/317] [fix] Reverse DNS check --- data/hooks/diagnosis/24-mail.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index a60b4f0d4..f325c72da 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -2,7 +2,6 @@ import os import dns.resolver -import socket import re from subprocess import CalledProcessError @@ -118,15 +117,25 @@ class MailDiagnoser(Diagnoser): details = ["diagnosis_mail_fcrdns_nok_details", "diagnosis_mail_fcrdns_nok_alternatives_4"] - try: - rdns_domain, _, _ = socket.gethostbyaddr(ip) - except socket.herror: + rev = dns.reversename.from_address(ip) + subdomain = str(rev.split(3)[0]) + query = subdomain + if ipversion == 4: + query += '.in-addr.arpa' + else: + query += '.ip6.arpa' + + # Do the DNS Query + status, value = dig(query, 'PTR') + if status == "nok": yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion}, data={"ip": ip, "ehlo_domain": self.ehlo_domain}, status="ERROR", summary="diagnosis_mail_fcrdns_dns_missing", details=details) continue + + rdns_domain = value[0] if len(value) > 0 else '' if rdns_domain != self.ehlo_domain: details = ["diagnosis_mail_fcrdns_different_from_ehlo_domain_details"] + details yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion}, From 1cb330823d3e1348fc1e350105729d6604890648 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sun, 26 Apr 2020 20:49:09 +0200 Subject: [PATCH 298/317] Try to show smarter / more useful logs by filtering irrelevant lines like 'set +x' etc --- data/actionsmap/yunohost.yml | 4 ++++ src/yunohost/app.py | 17 +++++++++++++++++ src/yunohost/log.py | 19 +++++++++++++++++-- src/yunohost/service.py | 10 +++++++++- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 0ad1268f2..6ccd5ebfe 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1659,6 +1659,10 @@ log: --share: help: Share the full log using yunopaste action: store_true + -f: + full: --filter-irrelevant + help: Do not show some lines deemed not relevant (like set +x or helper argument parsing) + action: store_true ############################# diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 8a29f9dbb..ba3ac4c01 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -914,6 +914,19 @@ def dump_app_log_extract_for_debugging(operation_logger): with open(operation_logger.log_path, "r") as f: lines = f.readlines() + filters = [ + r"set [+-]x$", + r"local \w+$", + r"local legacy_args=.*$", + r".*Helper used in legacy mode.*", + r"args_array=.*$", + r"declare -Ar args_array$", + r"ynh_handle_getopts_args", + r"ynh_script_progression" + ] + + filters = [re.compile(f) for f in filters] + lines_to_display = [] for line in lines: @@ -924,6 +937,10 @@ def dump_app_log_extract_for_debugging(operation_logger): # 2019-10-19 16:10:27,611: DEBUG - + mysql -u piwigo --password=********** -B piwigo # And we just want the part starting by "DEBUG - " line = line.strip().split(": ", 1)[1] + + if any(filter_.search(line) for filter_ in filters): + continue + lines_to_display.append(line) if line.endswith("+ ynh_exit_properly") or " + ynh_die " in line: diff --git a/src/yunohost/log.py b/src/yunohost/log.py index cd08bdfe0..523a10f76 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -122,7 +122,7 @@ def log_list(category=[], limit=None, with_details=False): return result -def log_display(path, number=None, share=False): +def log_display(path, number=None, share=False, filter_irrelevant=False): """ Display a log file enriched with metadata if any. @@ -202,9 +202,24 @@ def log_display(path, number=None, share=False): # Display logs if exist if os.path.exists(log_path): + + if filter_irrelevant: + filters = [ + r"set [+-]x$", + r"local \w+$", + r"local legacy_args=.*$", + r".*Helper used in legacy mode.*", + r"args_array=.*$", + r"declare -Ar args_array$", + r"ynh_handle_getopts_args", + r"ynh_script_progression" + ] + else: + filters = [] + from yunohost.service import _tail if number: - logs = _tail(log_path, int(number)) + logs = _tail(log_path, int(number), filters=filters) else: logs = read_file(log_path) infos['log_path'] = log_path diff --git a/src/yunohost/service.py b/src/yunohost/service.py index 2f45e28c3..c17eb04c2 100644 --- a/src/yunohost/service.py +++ b/src/yunohost/service.py @@ -23,6 +23,8 @@ Manage services """ + +import re import os import re import time @@ -616,7 +618,7 @@ def _save_services(services): raise -def _tail(file, n): +def _tail(file, n, filters=[]): """ Reads a n lines from f with an offset of offset lines. The return value is a tuple in the form ``(lines, has_more)`` where `has_more` is @@ -627,6 +629,9 @@ def _tail(file, n): avg_line_length = 74 to_read = n + if filters: + filters = [re.compile(f) for f in filters] + try: if file.endswith(".gz"): import gzip @@ -647,6 +652,9 @@ def _tail(file, n): pos = f.tell() lines = f.read().splitlines() + for filter_ in filters: + lines = [l for l in lines if not filter_.search(l)] + if len(lines) >= to_read: return lines[-to_read:] From 9a7b9b0b321bb99babc033cc9a3c5b1e8c10a0e4 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 27 Apr 2020 02:24:50 +0200 Subject: [PATCH 299/317] declare -Ar -> local -A --- src/yunohost/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index ba3ac4c01..7d5eccd30 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -920,7 +920,7 @@ def dump_app_log_extract_for_debugging(operation_logger): r"local legacy_args=.*$", r".*Helper used in legacy mode.*", r"args_array=.*$", - r"declare -Ar args_array$", + r"local -A args_array$", r"ynh_handle_getopts_args", r"ynh_script_progression" ] From a51478dc40f3b17ffc73692029a3003970b89d8e Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Mon, 27 Apr 2020 02:25:14 +0200 Subject: [PATCH 300/317] declare -Ar -> local -A --- src/yunohost/log.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/log.py b/src/yunohost/log.py index 523a10f76..b15a65943 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -210,7 +210,7 @@ def log_display(path, number=None, share=False, filter_irrelevant=False): r"local legacy_args=.*$", r".*Helper used in legacy mode.*", r"args_array=.*$", - r"declare -Ar args_array$", + r"local -A args_array$", r"ynh_handle_getopts_args", r"ynh_script_progression" ] From e9f359e5f0bb3682d9a286aa2e39c7ac9296e8d1 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 05:14:29 +0200 Subject: [PATCH 301/317] Call exit 1 directly instead of ynh_die to avoid a full arg parse just to exit.. --- data/helpers.d/utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index fb50305ce..0a2967363 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -35,7 +35,7 @@ ynh_exit_properly () { ynh_clean_setup # Call the function to do specific cleaning for the app. fi - ynh_die # Exit with error status + exit 1 # Exit with error status } # Exits if an error occurs during the execution of the script. From bb82c41db64e7a341e4cbcceb52bfb972f59128d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 05:21:42 +0200 Subject: [PATCH 302/317] Apparently set +x is set +o xtrace now ;P --- src/yunohost/app.py | 1 + src/yunohost/log.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/yunohost/app.py b/src/yunohost/app.py index 7d5eccd30..e2df6ba78 100644 --- a/src/yunohost/app.py +++ b/src/yunohost/app.py @@ -916,6 +916,7 @@ def dump_app_log_extract_for_debugging(operation_logger): filters = [ r"set [+-]x$", + r"set [+-]o xtrace$", r"local \w+$", r"local legacy_args=.*$", r".*Helper used in legacy mode.*", diff --git a/src/yunohost/log.py b/src/yunohost/log.py index b15a65943..de84280f0 100644 --- a/src/yunohost/log.py +++ b/src/yunohost/log.py @@ -206,6 +206,7 @@ def log_display(path, number=None, share=False, filter_irrelevant=False): if filter_irrelevant: filters = [ r"set [+-]x$", + r"set [+-]o xtrace$", r"local \w+$", r"local legacy_args=.*$", r".*Helper used in legacy mode.*", From be883c3aef92a207277a1221516b4fea9ffa55bf Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 05:23:23 +0200 Subject: [PATCH 303/317] Let's have the short option be -i instead of -f --- data/actionsmap/yunohost.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 6ccd5ebfe..a748e4533 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -1659,7 +1659,7 @@ log: --share: help: Share the full log using yunopaste action: store_true - -f: + -i: full: --filter-irrelevant help: Do not show some lines deemed not relevant (like set +x or helper argument parsing) action: store_true From 65d54ba6b90d95d15eb7f01f671248f0f840e7d5 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 30 Apr 2020 17:15:48 +0200 Subject: [PATCH 304/317] [fix] Blacklist false positive --- src/yunohost/utils/network.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/yunohost/utils/network.py b/src/yunohost/utils/network.py index ce2356fcf..ccd938fd4 100644 --- a/src/yunohost/utils/network.py +++ b/src/yunohost/utils/network.py @@ -131,6 +131,12 @@ def dig(qname, rdtype="A", timeout=5, resolvers="local", edns_size=1500, full_an Do a quick DNS request and avoid the "search" trap inside /etc/resolv.conf """ + # It's very important to do the request with a qname ended by . + # If we don't and the domain fail, dns resolver try a second request + # by concatenate the qname with the end of the "hostname" + if not qname.endswith("."): + qname += "." + if resolvers == "local": resolvers = ["127.0.0.1"] elif resolvers == "force_external": From c33e61ab2ede8a467019d347edae8a99d19ec36a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 17:32:29 +0200 Subject: [PATCH 305/317] Update changelog for 3.8.2.1 --- debian/changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index 37a945919..d79900fae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +yunohost (3.8.2.1) testing; urgency=low + + - [fix] Make sure DNS queries are dong using absolute names to avoid stupid issues + - [fix] More reliable way to fetch PTR record / reverse DNS + - [fix] Propagate IPv6 default route check to ip diagnoser code as well + + Thanks to ljf for the tests and fixes ! + + -- Alexandre Aubin Thu, 30 Apr 2020 17:30:00 +0000 + yunohost (3.8.2) testing; urgency=low ### Diagnosis From 86810fb68a1729a069b1ac3175790ca2727fcf6d Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 18:03:44 +0200 Subject: [PATCH 306/317] Goddamit Aleks, check your damn code before release yo --- data/hooks/diagnosis/10-ip.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/10-ip.py b/data/hooks/diagnosis/10-ip.py index d4c203e7e..fe4993935 100644 --- a/data/hooks/diagnosis/10-ip.py +++ b/data/hooks/diagnosis/10-ip.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import re import os import random @@ -10,6 +11,7 @@ from moulinette.utils.filesystem import read_file from yunohost.diagnosis import Diagnoser from yunohost.utils.network import get_network_interfaces + class IPDiagnoser(Diagnoser): id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1] @@ -72,6 +74,7 @@ class IPDiagnoser(Diagnoser): ipv6 = self.get_public_ip(6) if can_ping_ipv6 else None network_interfaces = get_network_interfaces() + def get_local_ip(version): local_ip = {iface: addr[version].split("/")[0] for iface, addr in network_interfaces.items() if version in addr} @@ -106,6 +109,7 @@ class IPDiagnoser(Diagnoser): # If we are indeed connected in ipv4 or ipv6, we should find a default route routes = check_output("ip -%s route" % protocol).split("\n") + def is_default_route(r): # Typically the default route starts with "default" # But of course IPv6 is more complex ... e.g. on internet cube there's @@ -113,7 +117,7 @@ class IPDiagnoser(Diagnoser): # e.g. 2000:/3 dev tun0 ... return r.startswith("default") or (":" in r and re.match(r".*/[0-3]$", r.split()[0])) if not any(is_default_route(r) for r in routes): - logger.debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) + self.logger_debug("No default route for IPv%s, so assuming there's no IP address for that version" % protocol) return None # We use the resolver file as a list of well-known, trustable (ie not google ;)) IPs that we can ping From 15807c411c3cea86743ac3177de694ad4c182ccc Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 17:45:39 +0200 Subject: [PATCH 307/317] Bad parenthesis positioning --- src/yunohost/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/yunohost/tools.py b/src/yunohost/tools.py index 3208bda60..abfc3b7af 100644 --- a/src/yunohost/tools.py +++ b/src/yunohost/tools.py @@ -598,8 +598,8 @@ def tools_upgrade(operation_logger, apps=None, system=False): ) returncode = call_async_output(dist_upgrade, callbacks, shell=True) if returncode != 0: - logger.warning(m18n.n('tools_upgrade_regular_packages_failed'), - packages_list=', '.join(noncritical_packages_upgradable)) + logger.warning(m18n.n('tools_upgrade_regular_packages_failed', + packages_list=', '.join(noncritical_packages_upgradable))) operation_logger.error(m18n.n('packages_upgrade_failed')) raise YunohostError(m18n.n('packages_upgrade_failed')) From f358bdde19ab0a0f9678a1d43bb8fcd49caaa51a Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Thu, 30 Apr 2020 18:04:35 +0200 Subject: [PATCH 308/317] Update changelog for 3.8.2.2 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index d79900fae..c119d57e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +yunohost (3.8.2.2) testing; urgency=low + + Aleks broke everything /again/ *.* + + -- Alexandre Aubin Thu, 30 Apr 2020 18:05:00 +0000 + yunohost (3.8.2.1) testing; urgency=low - [fix] Make sure DNS queries are dong using absolute names to avoid stupid issues From 572feafc805165419065b1687366a32b3cd4a620 Mon Sep 17 00:00:00 2001 From: ljf Date: Thu, 30 Apr 2020 20:06:43 +0200 Subject: [PATCH 309/317] [fix] Remove point in reverse DNS --- data/hooks/diagnosis/24-mail.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/hooks/diagnosis/24-mail.py b/data/hooks/diagnosis/24-mail.py index f325c72da..bc159c3b7 100644 --- a/data/hooks/diagnosis/24-mail.py +++ b/data/hooks/diagnosis/24-mail.py @@ -135,7 +135,9 @@ class MailDiagnoser(Diagnoser): details=details) continue - rdns_domain = value[0] if len(value) > 0 else '' + rdns_domain = '' + if len(value) > 0: + rdns_domain = value[0][:-1] if value[0].endswith('.') else value[0] if rdns_domain != self.ehlo_domain: details = ["diagnosis_mail_fcrdns_different_from_ehlo_domain_details"] + details yield dict(meta={"test": "mail_fcrdns", "ipversion": ipversion}, From d6095a3c0f79c44826539ededdbedf2a3e4db8a3 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 30 Apr 2020 20:10:20 +0200 Subject: [PATCH 310/317] Add linter --- .gitlab-ci.yml | 83 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 05aafe43b..6aac589c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,9 +1,25 @@ stages: - postinstall - tests + - lint -.tests: +######################################## +# POSTINSTALL +######################################## + +postinstall: + image: before-postinstall + stage: postinstall + script: + - yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns + +######################################## +# TESTS +######################################## + +.test-stage: image: after-postinstall + stage: tests before_script: - apt-get install python-pip -y - mkdir -p .pip @@ -25,77 +41,90 @@ stages: - src/yunohost/tests/apps key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" -postinstall: - image: before-postinstall - stage: postinstall - script: - - yunohost tools postinstall -d domain.tld -p the_password --ignore-dyndns - root-tests: - extends: .tests - stage: tests + extends: .test-stage script: - py.test tests test-apps: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_apps.py test-appscatalog: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_appscatalog.py test-appurl: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_appurl.py test-backuprestore: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_backuprestore.py test-changeurl: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_changeurl.py test-permission: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_permission.py test-settings: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_settings.py test-user-group: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_user-group.py test-regenconf: - extends: .tests - stage: tests + extends: .test-stage script: - cd src/yunohost - py.test tests/test_regenconf.py + +######################################## +# LINTER +######################################## + +.lint-stage: + image: before-postinstall + stage: lint + before_script: + - apt-get install python-pip -y + - mkdir -p .pip + - pip install -U pip + - hash -d pip + - pip --cache-dir=.pip install flake8 blake + cache: + paths: + - .pip + - src/yunohost/tests/apps + key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" + +lint: + extends: .lint-stage + script: + - flake8 src tests data + +format-check: + extends: .lint-stage + script: + - black {posargs:--check --diff} src tests data \ No newline at end of file From 18580803e61b09ace3ba9b8279538a7b5cb63241 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Thu, 30 Apr 2020 23:40:58 +0200 Subject: [PATCH 311/317] use python3 for linter --- .gitlab-ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6aac589c1..bd5a320e7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,15 +108,14 @@ test-regenconf: image: before-postinstall stage: lint before_script: - - apt-get install python-pip -y - - mkdir -p .pip - - pip install -U pip - - hash -d pip - - pip --cache-dir=.pip install flake8 blake + - apt-get install python3-pip -y + - mkdir -p .pip3 + - pip3 install -U pip + - hash -d pip3 + - pip3 --cache-dir=.pip3 install flake8 black cache: paths: - - .pip - - src/yunohost/tests/apps + - .pip3 key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" lint: From 81bdb3382465e30c1d44b9bbbcdf5aabe112d453 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Fri, 1 May 2020 00:41:50 +0200 Subject: [PATCH 312/317] disable black until buster --- .gitlab-ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bd5a320e7..8248d6caf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -112,7 +112,7 @@ test-regenconf: - mkdir -p .pip3 - pip3 install -U pip - hash -d pip3 - - pip3 --cache-dir=.pip3 install flake8 black + - pip3 --cache-dir=.pip3 install flake8 # black cache: paths: - .pip3 @@ -123,7 +123,8 @@ lint: script: - flake8 src tests data -format-check: - extends: .lint-stage - script: - - black {posargs:--check --diff} src tests data \ No newline at end of file +# Disabled, waiting for buster +#format-check: +# extends: .lint-stage +# script: +# - black {posargs:--check --diff} src tests data \ No newline at end of file From 4dccab981971052b16bc8776e57527cf3f09c7f5 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Fri, 1 May 2020 00:45:13 +0200 Subject: [PATCH 313/317] linter on all the repo --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8248d6caf..d55b02d3a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -121,10 +121,10 @@ test-regenconf: lint: extends: .lint-stage script: - - flake8 src tests data + - flake8 # Disabled, waiting for buster #format-check: # extends: .lint-stage # script: -# - black {posargs:--check --diff} src tests data \ No newline at end of file +# - black --check --diff \ No newline at end of file From 3b93ba47721d0a3234e88b06f6c320ac98405ae7 Mon Sep 17 00:00:00 2001 From: Kay0u Date: Fri, 1 May 2020 01:27:31 +0200 Subject: [PATCH 314/317] use tox --- .gitlab-ci.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d55b02d3a..7459ae982 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,20 +108,22 @@ test-regenconf: image: before-postinstall stage: lint before_script: - - apt-get install python3-pip -y - - mkdir -p .pip3 - - pip3 install -U pip - - hash -d pip3 - - pip3 --cache-dir=.pip3 install flake8 # black + - apt-get install python-pip -y + - mkdir -p .pip + - pip install -U pip + - hash -d pip + - pip --cache-dir=.pip install tox cache: paths: - - .pip3 + - .pip + - .tox key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" lint: extends: .lint-stage + allow_failure: true script: - - flake8 + - tox -e lint # Disabled, waiting for buster #format-check: From 6bd7eb64bd3aa4d57e3656afa6d519174138c455 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Fri, 1 May 2020 17:53:07 +0200 Subject: [PATCH 315/317] Assert slapd is running to avoid miserably crashing with weird ldap errors --- src/yunohost/utils/ldap.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/yunohost/utils/ldap.py b/src/yunohost/utils/ldap.py index 22e95ad07..b7111a6cd 100644 --- a/src/yunohost/utils/ldap.py +++ b/src/yunohost/utils/ldap.py @@ -19,8 +19,10 @@ """ +import os import atexit from moulinette.authenticators import ldap +from yunohost.utils.error import YunohostError # We use a global variable to do some caching # to avoid re-authenticating in case we call _get_ldap_authenticator multiple times @@ -32,6 +34,8 @@ def _get_ldap_interface(): if _ldap_interface is None: + assert_slapd_is_running() + conf = { "vendor": "ldap", "name": "as-root", "parameters": { 'uri': 'ldapi://%2Fvar%2Frun%2Fslapd%2Fldapi', @@ -45,6 +49,13 @@ def _get_ldap_interface(): return _ldap_interface +def assert_slapd_is_running(): + + # Assert slapd is running... + if not os.system("pgrep slapd >dev/null") == 0: + raise YunohostError("Service slapd is not running but is required to perform this action ... You can try to investigate what's happening with 'systemctl status slapd'") + + # We regularly want to extract stuff like 'bar' in ldap path like # foo=bar,dn=users.example.org,ou=example.org,dc=org so this small helper allow # to do this without relying of dozens of mysterious string.split()[0] From acba1c4bc82203b9f6fa1b5b168f36e6ce45bcfb Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 2 May 2020 02:13:09 +0200 Subject: [PATCH 316/317] Comment about why not using ynh_die --- data/helpers.d/utils | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data/helpers.d/utils b/data/helpers.d/utils index 0a2967363..bad157fe1 100644 --- a/data/helpers.d/utils +++ b/data/helpers.d/utils @@ -35,7 +35,10 @@ ynh_exit_properly () { ynh_clean_setup # Call the function to do specific cleaning for the app. fi - exit 1 # Exit with error status + # Exit with error status + # We don't call ynh_die basically to avoid unecessary 10-ish + # debug lines about parsing args and stuff just to exit 1.. + exit 1 } # Exits if an error occurs during the execution of the script. From e85a29fbf3ee64ce3018a4eb77aa956e5dfd2b28 Mon Sep 17 00:00:00 2001 From: Alexandre Aubin Date: Sat, 2 May 2020 02:34:28 +0200 Subject: [PATCH 317/317] Typo zblerg ~.~ --- src/yunohost/utils/ldap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yunohost/utils/ldap.py b/src/yunohost/utils/ldap.py index b7111a6cd..fd984ce56 100644 --- a/src/yunohost/utils/ldap.py +++ b/src/yunohost/utils/ldap.py @@ -52,7 +52,7 @@ def _get_ldap_interface(): def assert_slapd_is_running(): # Assert slapd is running... - if not os.system("pgrep slapd >dev/null") == 0: + if not os.system("pgrep slapd >/dev/null") == 0: raise YunohostError("Service slapd is not running but is required to perform this action ... You can try to investigate what's happening with 'systemctl status slapd'")