mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'stretch-unstable' into migrate_to_apps_json
This commit is contained in:
commit
935f103b91
59 changed files with 2646 additions and 1189 deletions
|
@ -1623,6 +1623,32 @@ tools:
|
||||||
full: --force
|
full: --force
|
||||||
action: store_true
|
action: store_true
|
||||||
|
|
||||||
|
### tools_regen_conf()
|
||||||
|
regen-conf:
|
||||||
|
action_help: Regenerate the configuration file(s)
|
||||||
|
api: PUT /tools/regenconf
|
||||||
|
arguments:
|
||||||
|
names:
|
||||||
|
help: Categories to regenerate configuration of (all by default)
|
||||||
|
nargs: "*"
|
||||||
|
metavar: NAME
|
||||||
|
-d:
|
||||||
|
full: --with-diff
|
||||||
|
help: Show differences in case of configuration changes
|
||||||
|
action: store_true
|
||||||
|
-f:
|
||||||
|
full: --force
|
||||||
|
help: Override all manual modifications in configuration files
|
||||||
|
action: store_true
|
||||||
|
-n:
|
||||||
|
full: --dry-run
|
||||||
|
help: Show what would have been regenerated
|
||||||
|
action: store_true
|
||||||
|
-p:
|
||||||
|
full: --list-pending
|
||||||
|
help: List pending configuration files and exit
|
||||||
|
action: store_true
|
||||||
|
|
||||||
subcategories:
|
subcategories:
|
||||||
|
|
||||||
migrations:
|
migrations:
|
||||||
|
|
|
@ -3,17 +3,19 @@
|
||||||
# Use logrotate to manage the logfile
|
# Use logrotate to manage the logfile
|
||||||
#
|
#
|
||||||
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
|
# usage: ynh_use_logrotate [--logfile=/log/file] [--nonappend] [--specific_user=user/group]
|
||||||
# | arg: -l, --logfile= - absolute path of logfile
|
# | arg: -l, --logfile - absolute path of logfile
|
||||||
# | arg: -n, --nonappend - (Option) Replace the config file instead of appending this new config.
|
# | 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: -u, --specific_user : run logrotate as the specified user and group. If not specified logrotate is runned as root.
|
||||||
#
|
#
|
||||||
# If no argument provided, a standard directory will be use. /var/log/${app}
|
# If no --logfile is provided, /var/log/${app} will be used as default.
|
||||||
# You can provide a path with the directory only or with the logfile.
|
# logfile can be just a directory, or a full path to a logfile :
|
||||||
# /parentdir/logdir
|
# /parentdir/logdir
|
||||||
# /parentdir/logdir/logfile.log
|
# /parentdir/logdir/logfile.log
|
||||||
#
|
#
|
||||||
# It's possible to use this helper several times, each config will be added to the same logrotate config file.
|
# It's possible to use this helper multiple times, each config will be added to
|
||||||
# Unless you use the option --non-append
|
# the same logrotate config file. Unless you use the option --non-append
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_use_logrotate () {
|
ynh_use_logrotate () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=lnuya
|
local legacy_args=lnuya
|
||||||
|
@ -92,6 +94,8 @@ EOF
|
||||||
# Remove the app's logrotate config.
|
# Remove the app's logrotate config.
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_logrotate
|
# usage: ynh_remove_logrotate
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_remove_logrotate () {
|
ynh_remove_logrotate () {
|
||||||
if [ -e "/etc/logrotate.d/$app" ]; then
|
if [ -e "/etc/logrotate.d/$app" ]; then
|
||||||
sudo rm "/etc/logrotate.d/$app"
|
sudo rm "/etc/logrotate.d/$app"
|
||||||
|
@ -112,6 +116,7 @@ ynh_remove_logrotate () {
|
||||||
# __APP__ by $app
|
# __APP__ by $app
|
||||||
# __FINALPATH__ by $final_path
|
# __FINALPATH__ by $final_path
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_add_systemd_config () {
|
ynh_add_systemd_config () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=st
|
local legacy_args=st
|
||||||
|
@ -147,6 +152,7 @@ ynh_add_systemd_config () {
|
||||||
# usage: ynh_remove_systemd_config [--service=service]
|
# 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 () {
|
ynh_remove_systemd_config () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=s
|
local legacy_args=s
|
||||||
|
@ -158,10 +164,10 @@ ynh_remove_systemd_config () {
|
||||||
|
|
||||||
local finalsystemdconf="/etc/systemd/system/$service.service"
|
local finalsystemdconf="/etc/systemd/system/$service.service"
|
||||||
if [ -e "$finalsystemdconf" ]; then
|
if [ -e "$finalsystemdconf" ]; then
|
||||||
sudo systemctl stop $service
|
ynh_systemd_action --service_name=$service --action=stop
|
||||||
sudo systemctl disable $service
|
systemctl disable $service
|
||||||
ynh_secure_remove --file="$finalsystemdconf"
|
ynh_secure_remove --file="$finalsystemdconf"
|
||||||
sudo systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,8 +175,7 @@ ynh_remove_systemd_config () {
|
||||||
#
|
#
|
||||||
# usage: ynh_add_nginx_config "list of others variables to replace"
|
# usage: ynh_add_nginx_config "list of others variables to replace"
|
||||||
#
|
#
|
||||||
# | arg: list of others variables to replace separeted by a space
|
# | arg: list - (Optional) list of others variables to replace separated by spaces. For example : 'path_2 port_2 ...'
|
||||||
# | for example : 'path_2 port_2 ...'
|
|
||||||
#
|
#
|
||||||
# This will use a template in ../conf/nginx.conf
|
# This will use a template in ../conf/nginx.conf
|
||||||
# __PATH__ by $path_url
|
# __PATH__ by $path_url
|
||||||
|
@ -183,6 +188,7 @@ ynh_remove_systemd_config () {
|
||||||
# __PATH_2__ by $path_2
|
# __PATH_2__ by $path_2
|
||||||
# __PORT_2__ by $port_2
|
# __PORT_2__ by $port_2
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_add_nginx_config () {
|
ynh_add_nginx_config () {
|
||||||
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
finalnginxconf="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
local others_var=${1:-}
|
local others_var=${1:-}
|
||||||
|
@ -227,24 +233,38 @@ ynh_add_nginx_config () {
|
||||||
|
|
||||||
ynh_store_file_checksum --file="$finalnginxconf"
|
ynh_store_file_checksum --file="$finalnginxconf"
|
||||||
|
|
||||||
sudo systemctl reload nginx
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the dedicated nginx config
|
# Remove the dedicated nginx config
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_nginx_config
|
# usage: ynh_remove_nginx_config
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_remove_nginx_config () {
|
ynh_remove_nginx_config () {
|
||||||
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
ynh_secure_remove --file="/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
sudo systemctl reload nginx
|
ynh_systemd_action --service_name=nginx --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a dedicated php-fpm config
|
# Create a dedicated php-fpm config
|
||||||
#
|
#
|
||||||
# usage: ynh_add_fpm_config
|
# usage: ynh_add_fpm_config [--phpversion=7.X]
|
||||||
|
# | arg: -v, --phpversion - Version of php to use.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_add_fpm_config () {
|
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 phpversion
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
# Configure PHP-FPM 7.0 by default
|
# Configure PHP-FPM 7.0 by default
|
||||||
local fpm_config_dir="/etc/php/7.0/fpm"
|
phpversion="${phpversion:-7.0}"
|
||||||
local fpm_service="php7.0-fpm"
|
|
||||||
|
local fpm_config_dir="/etc/php/$phpversion/fpm"
|
||||||
|
local fpm_service="php${phpversion}-fpm"
|
||||||
# Configure PHP-FPM 5 on Debian Jessie
|
# Configure PHP-FPM 5 on Debian Jessie
|
||||||
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
|
if [ "$(ynh_get_debian_release)" == "jessie" ]; then
|
||||||
fpm_config_dir="/etc/php5/fpm"
|
fpm_config_dir="/etc/php5/fpm"
|
||||||
|
@ -258,6 +278,7 @@ ynh_add_fpm_config () {
|
||||||
ynh_replace_string --match_string="__NAMETOCHANGE__" --replace_string="$app" --target_file="$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="__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="__USER__" --replace_string="$app" --target_file="$finalphpconf"
|
||||||
|
ynh_replace_string --match_string="__PHPVERSION__" --replace_string="$phpversion" --target_file="$finalphpconf"
|
||||||
sudo chown root: "$finalphpconf"
|
sudo chown root: "$finalphpconf"
|
||||||
ynh_store_file_checksum --file="$finalphpconf"
|
ynh_store_file_checksum --file="$finalphpconf"
|
||||||
|
|
||||||
|
@ -270,12 +291,14 @@ ynh_add_fpm_config () {
|
||||||
sudo chown root: "$finalphpini"
|
sudo chown root: "$finalphpini"
|
||||||
ynh_store_file_checksum "$finalphpini"
|
ynh_store_file_checksum "$finalphpini"
|
||||||
fi
|
fi
|
||||||
sudo systemctl reload $fpm_service
|
ynh_systemd_action --service_name=$fpm_service --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove the dedicated php-fpm config
|
# Remove the dedicated php-fpm config
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_fpm_config
|
# usage: ynh_remove_fpm_config
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_remove_fpm_config () {
|
ynh_remove_fpm_config () {
|
||||||
local fpm_config_dir=$(ynh_app_setting_get --app=$app --key=fpm_config_dir)
|
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 fpm_service=$(ynh_app_setting_get --app=$app --key=fpm_service)
|
||||||
|
@ -286,7 +309,7 @@ ynh_remove_fpm_config () {
|
||||||
fi
|
fi
|
||||||
ynh_secure_remove --file="$fpm_config_dir/pool.d/$app.conf"
|
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_secure_remove --file="$fpm_config_dir/conf.d/20-$app.ini" 2>&1
|
||||||
sudo systemctl reload $fpm_service
|
ynh_systemd_action --service_name=$fpm_service --action=reload
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a dedicated fail2ban config (jail and filter conf files)
|
# Create a dedicated fail2ban config (jail and filter conf files)
|
||||||
|
@ -350,8 +373,10 @@ ynh_remove_fpm_config () {
|
||||||
# To validate your regex you can test with this command:
|
# To validate your regex you can test with this command:
|
||||||
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
|
# fail2ban-regex /var/log/YOUR_LOG_FILE_PATH /etc/fail2ban/filter.d/YOUR_APP.conf
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_add_fail2ban_config () {
|
ynh_add_fail2ban_config () {
|
||||||
# Declare an array to define the options of this helper.
|
# 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=)
|
declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= [t]=use_template [v]=others_var=)
|
||||||
local logpath
|
local logpath
|
||||||
local failregex
|
local failregex
|
||||||
|
@ -429,6 +454,8 @@ EOF
|
||||||
# Remove the dedicated fail2ban config (jail and filter conf files)
|
# Remove the dedicated fail2ban config (jail and filter conf files)
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_fail2ban_config
|
# usage: ynh_remove_fail2ban_config
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_remove_fail2ban_config () {
|
ynh_remove_fail2ban_config () {
|
||||||
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
|
ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
|
||||||
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
|
ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# usage: ynh_debug [--message=message] [--trace=1/0]
|
# usage: ynh_debug [--message=message] [--trace=1/0]
|
||||||
# | arg: -m, --message= - The text to print
|
# | arg: -m, --message= - The text to print
|
||||||
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
|
# | arg: -t, --trace= - Turn on or off the trace of the script. Usefull to trace nonly a small part of a script.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_debug () {
|
ynh_debug () {
|
||||||
# Disable set xtrace for the helper itself, to not pollute the debug log
|
# Disable set xtrace for the helper itself, to not pollute the debug log
|
||||||
set +x
|
set +x
|
||||||
|
@ -35,6 +37,8 @@ ynh_debug () {
|
||||||
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
|
PS4='$(basename ${BASH_SOURCE[0]})-L${LINENO}: '
|
||||||
# Force xtrace to stderr
|
# Force xtrace to stderr
|
||||||
BASH_XTRACEFD=2
|
BASH_XTRACEFD=2
|
||||||
|
# Force stdout to stderr
|
||||||
|
exec 1>&2
|
||||||
fi
|
fi
|
||||||
if [ "$trace" == "0" ]
|
if [ "$trace" == "0" ]
|
||||||
then
|
then
|
||||||
|
@ -42,6 +46,8 @@ ynh_debug () {
|
||||||
set +x
|
set +x
|
||||||
# Put xtrace back to its original fild descriptor
|
# Put xtrace back to its original fild descriptor
|
||||||
BASH_XTRACEFD=$old_bash_xtracefd
|
BASH_XTRACEFD=$old_bash_xtracefd
|
||||||
|
# Restore stdout
|
||||||
|
exec 1>&1
|
||||||
fi
|
fi
|
||||||
# Renable set xtrace
|
# Renable set xtrace
|
||||||
set -x
|
set -x
|
||||||
|
@ -54,6 +60,8 @@ ynh_debug () {
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
||||||
#
|
#
|
||||||
# | arg: command - command to execute
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_debug_exec () {
|
ynh_debug_exec () {
|
||||||
ynh_debug --message="$(eval $@)"
|
ynh_debug --message="$(eval $@)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,13 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
# If DEST is ended by a slash it complete this path with the basename of SRC.
|
# 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]
|
# 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
|
# | arg: -s, --src_path - file or directory to bind or symlink or copy. it shouldn't be in the backup dir.
|
||||||
# the backup dir.
|
# | arg: -d, --dest_path - destination file or directory inside 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: -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: -m, --not_mandatory - Indicate that if the file is missing, the backup can ignore it.
|
||||||
# | arg: arg - Deprecated arg
|
# | arg: arg - Deprecated arg
|
||||||
#
|
#
|
||||||
# example:
|
# Example in the context of a wordpress app
|
||||||
# # Wordpress app context
|
|
||||||
#
|
#
|
||||||
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
|
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf"
|
||||||
# # => This line will be added into CSV file
|
# # => This line will be added into CSV file
|
||||||
|
@ -46,6 +43,7 @@ CAN_BIND=${CAN_BIND:-1}
|
||||||
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
|
# ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" "/conf/"
|
||||||
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
|
# # => "/etc/nginx/conf.d/$domain.d/$app.conf","apps/wordpress/conf/$app.conf"
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.4.0 or higher.
|
||||||
ynh_backup() {
|
ynh_backup() {
|
||||||
# TODO find a way to avoid injection by file strange naming !
|
# TODO find a way to avoid injection by file strange naming !
|
||||||
|
|
||||||
|
@ -79,7 +77,7 @@ ynh_backup() {
|
||||||
echo "Source path '${src_path}' does not exist" >&2
|
echo "Source path '${src_path}' does not exist" >&2
|
||||||
if [ "$not_mandatory" == "0" ]
|
if [ "$not_mandatory" == "0" ]
|
||||||
then
|
then
|
||||||
echo "Source path '${SRC_PATH}' does not exist" >&2
|
echo "Source path '${src_path}' does not exist" >&2
|
||||||
|
|
||||||
# This is a temporary fix for fail2ban config files missing after the migration to stretch.
|
# This is a temporary fix for fail2ban config files missing after the migration to stretch.
|
||||||
if echo "${src_path}" | grep --quiet "/etc/fail2ban"
|
if echo "${src_path}" | grep --quiet "/etc/fail2ban"
|
||||||
|
@ -158,6 +156,7 @@ ynh_backup() {
|
||||||
#
|
#
|
||||||
# usage: ynh_restore
|
# usage: ynh_restore
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_restore () {
|
ynh_restore () {
|
||||||
# Deduce the relative path of $YNH_CWD
|
# Deduce the relative path of $YNH_CWD
|
||||||
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
|
local REL_DIR="${YNH_CWD#$YNH_BACKUP_DIR/}"
|
||||||
|
@ -196,29 +195,27 @@ with open(sys.argv[1], 'r') as backup_file:
|
||||||
# Restore a file or a directory
|
# Restore a file or a directory
|
||||||
#
|
#
|
||||||
# Use the registered path in backup_list by ynh_backup to restore the file at
|
# Use the registered path in backup_list by ynh_backup to restore the file at
|
||||||
# the good place.
|
# the right place.
|
||||||
#
|
#
|
||||||
# usage: ynh_restore_file --origin_path=origin_path [--dest_path=dest_path] [--not_mandatory]
|
# 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
|
# | 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
|
||||||
# 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: -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: -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"
|
||||||
|
# # You can also use relative paths:
|
||||||
|
# ynh_restore_file "conf/nginx.conf"
|
||||||
|
#
|
||||||
# If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in
|
# If DEST_PATH already exists and is lighter than 500 Mo, a backup will be made in
|
||||||
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed.
|
# /home/yunohost.conf/backup/. Otherwise, the existing file is removed.
|
||||||
#
|
#
|
||||||
# examples:
|
# if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
|
||||||
# ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf"
|
# /etc/nginx/conf.d/$domain.d/$app.conf
|
||||||
# # if apps/wordpress/etc/nginx/conf.d/$domain.d/$app.conf exists, restore it into
|
# if no, search for a match in the csv (eg: conf/nginx.conf) and restore it into
|
||||||
# # /etc/nginx/conf.d/$domain.d/$app.conf
|
# /etc/nginx/conf.d/$domain.d/$app.conf
|
||||||
# # if no, search a correspondance in the csv (eg: conf/nginx.conf) and restore it into
|
|
||||||
# # /etc/nginx/conf.d/$domain.d/$app.conf
|
|
||||||
#
|
|
||||||
# # DON'T GIVE THE ARCHIVE PATH:
|
|
||||||
# ynh_restore_file "conf/nginx.conf"
|
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_restore_file () {
|
ynh_restore_file () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=odm
|
local legacy_args=odm
|
||||||
|
@ -313,6 +310,8 @@ properly with chmod/chown." >&2
|
||||||
#
|
#
|
||||||
# usage: ynh_store_file_checksum --file=file
|
# 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.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_store_file_checksum () {
|
ynh_store_file_checksum () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
|
@ -343,8 +342,9 @@ ynh_store_file_checksum () {
|
||||||
#
|
#
|
||||||
# usage: ynh_backup_if_checksum_is_different --file=file
|
# 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
|
||||||
#
|
#
|
||||||
# | ret: Return the name a the backup file, or nothing
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_backup_if_checksum_is_different () {
|
ynh_backup_if_checksum_is_different () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
|
@ -376,6 +376,8 @@ ynh_backup_if_checksum_is_different () {
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_file_checksum file
|
# usage: ynh_remove_file_checksum file
|
||||||
# | arg: -f, --file= - The file for which the checksum will be deleted
|
# | arg: -f, --file= - The file for which the checksum will be deleted
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.3.1 or higher.
|
||||||
ynh_delete_file_checksum () {
|
ynh_delete_file_checksum () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
|
@ -392,6 +394,8 @@ ynh_delete_file_checksum () {
|
||||||
#
|
#
|
||||||
# usage: ynh_secure_remove --file=path_to_remove
|
# 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 () {
|
ynh_secure_remove () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=f
|
local legacy_args=f
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
# To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments.
|
# To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments.
|
||||||
# The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array.
|
# The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array.
|
||||||
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
|
# e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.2 or higher.
|
||||||
ynh_handle_getopts_args () {
|
ynh_handle_getopts_args () {
|
||||||
# Manage arguments only if there's some provided
|
# Manage arguments only if there's some provided
|
||||||
set +x
|
set +x
|
||||||
|
@ -150,10 +152,15 @@ ynh_handle_getopts_args () {
|
||||||
# If there's already another value for this option, add a ; before adding the new value
|
# If there's already another value for this option, add a ; before adding the new value
|
||||||
eval ${option_var}+="\;"
|
eval ${option_var}+="\;"
|
||||||
fi
|
fi
|
||||||
# Escape double quote to prevent any interpretation during the eval
|
|
||||||
all_args[$i]="${all_args[$i]//\"/\\\"}"
|
|
||||||
|
|
||||||
eval ${option_var}+=\"${all_args[$i]}\"
|
# 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 ))
|
shift_value=$(( shift_value + 1 ))
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -191,12 +198,9 @@ ynh_handle_getopts_args () {
|
||||||
# The variable name will be stored in 'option_var'
|
# The variable name will be stored in 'option_var'
|
||||||
local option_var="${args_array[$option_flag]%=}"
|
local option_var="${args_array[$option_flag]%=}"
|
||||||
|
|
||||||
# Escape double quote to prevent any interpretation during the eval
|
|
||||||
arguments[$i]="${arguments[$i]//\"/\\\"}"
|
|
||||||
|
|
||||||
# Store each value given as argument in the corresponding variable
|
# Store each value given as argument in the corresponding variable
|
||||||
# The values will be stored in the same order than $args_array
|
# The values will be stored in the same order than $args_array
|
||||||
eval ${option_var}+=\"${arguments[$i]}\"
|
eval ${option_var}+='"${arguments[$i]}"'
|
||||||
done
|
done
|
||||||
unset legacy_args
|
unset legacy_args
|
||||||
else
|
else
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#
|
#
|
||||||
# example: ynh_validate_ip 4 111.222.333.444
|
# example: ynh_validate_ip 4 111.222.333.444
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip()
|
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
|
||||||
|
@ -40,6 +41,7 @@ EOF
|
||||||
# usage: ynh_validate_ip4 --ip_address=ip_address
|
# usage: ynh_validate_ip4 --ip_address=ip_address
|
||||||
# | ret: 0 for valid ipv4 addresses, 1 otherwise
|
# | ret: 0 for valid ipv4 addresses, 1 otherwise
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip4()
|
ynh_validate_ip4()
|
||||||
{
|
{
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
|
@ -60,6 +62,7 @@ ynh_validate_ip4()
|
||||||
# usage: ynh_validate_ip6 --ip_address=ip_address
|
# usage: ynh_validate_ip6 --ip_address=ip_address
|
||||||
# | ret: 0 for valid ipv6 addresses, 1 otherwise
|
# | ret: 0 for valid ipv6 addresses, 1 otherwise
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_validate_ip6()
|
ynh_validate_ip6()
|
||||||
{
|
{
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
|
|
|
@ -11,6 +11,8 @@ MYSQL_ROOT_PWD_FILE=/etc/yunohost/mysql
|
||||||
# | arg: -u, --user - the user name to connect as
|
# | arg: -u, --user - the user name to connect as
|
||||||
# | arg: -p, --password - the user password
|
# | arg: -p, --password - the user password
|
||||||
# | arg: -d, --database - the database to connect to
|
# | arg: -d, --database - the database to connect to
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_connect_as() {
|
ynh_mysql_connect_as() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=upd
|
local legacy_args=upd
|
||||||
|
@ -30,6 +32,8 @@ ynh_mysql_connect_as() {
|
||||||
# usage: ynh_mysql_execute_as_root --sql=sql [--database=database]
|
# usage: ynh_mysql_execute_as_root --sql=sql [--database=database]
|
||||||
# | arg: -s, --sql - the SQL command to execute
|
# | arg: -s, --sql - the SQL command to execute
|
||||||
# | arg: -d, --database - the database to connect to
|
# | arg: -d, --database - the database to connect to
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_execute_as_root() {
|
ynh_mysql_execute_as_root() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=sd
|
local legacy_args=sd
|
||||||
|
@ -49,6 +53,8 @@ ynh_mysql_execute_as_root() {
|
||||||
# usage: ynh_mysql_execute_file_as_root --file=file [--database=database]
|
# usage: ynh_mysql_execute_file_as_root --file=file [--database=database]
|
||||||
# | arg: -f, --file - the file containing SQL commands
|
# | arg: -f, --file - the file containing SQL commands
|
||||||
# | arg: -d, --database - the database to connect to
|
# | arg: -d, --database - the database to connect to
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_execute_file_as_root() {
|
ynh_mysql_execute_file_as_root() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=fd
|
local legacy_args=fd
|
||||||
|
@ -71,6 +77,8 @@ ynh_mysql_execute_file_as_root() {
|
||||||
# | arg: db - the database name to create
|
# | arg: db - the database name to create
|
||||||
# | arg: user - the user to grant privilegies
|
# | arg: user - the user to grant privilegies
|
||||||
# | arg: pwd - the password to identify user by
|
# | arg: pwd - the password to identify user by
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_create_db() {
|
ynh_mysql_create_db() {
|
||||||
local db=$1
|
local db=$1
|
||||||
|
|
||||||
|
@ -95,6 +103,8 @@ ynh_mysql_create_db() {
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_drop_db db
|
# usage: ynh_mysql_drop_db db
|
||||||
# | arg: db - the database name to drop
|
# | arg: db - the database name to drop
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_drop_db() {
|
ynh_mysql_drop_db() {
|
||||||
ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};"
|
ynh_mysql_execute_as_root --sql="DROP DATABASE ${1};"
|
||||||
}
|
}
|
||||||
|
@ -106,6 +116,8 @@ ynh_mysql_drop_db() {
|
||||||
# usage: ynh_mysql_dump_db --database=database
|
# 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
|
# | ret: the mysqldump output
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_dump_db() {
|
ynh_mysql_dump_db() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=d
|
local legacy_args=d
|
||||||
|
@ -124,6 +136,8 @@ ynh_mysql_dump_db() {
|
||||||
# usage: ynh_mysql_create_user user pwd [host]
|
# usage: ynh_mysql_create_user user pwd [host]
|
||||||
# | arg: user - the user name to create
|
# | arg: user - the user name to create
|
||||||
# | arg: pwd - the password to identify user by
|
# | arg: pwd - the password to identify user by
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_create_user() {
|
ynh_mysql_create_user() {
|
||||||
ynh_mysql_execute_as_root \
|
ynh_mysql_execute_as_root \
|
||||||
--sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';"
|
--sql="CREATE USER '${1}'@'localhost' IDENTIFIED BY '${2}';"
|
||||||
|
@ -133,6 +147,8 @@ ynh_mysql_create_user() {
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_user_exists --user=user
|
# 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
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_user_exists()
|
ynh_mysql_user_exists()
|
||||||
{
|
{
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
|
@ -156,6 +172,8 @@ ynh_mysql_user_exists()
|
||||||
#
|
#
|
||||||
# usage: ynh_mysql_drop_user user
|
# usage: ynh_mysql_drop_user user
|
||||||
# | arg: user - the user name to drop
|
# | arg: user - the user name to drop
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_mysql_drop_user() {
|
ynh_mysql_drop_user() {
|
||||||
ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';"
|
ynh_mysql_execute_as_root --sql="DROP USER '${1}'@'localhost';"
|
||||||
}
|
}
|
||||||
|
@ -168,7 +186,9 @@ ynh_mysql_drop_user() {
|
||||||
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
# usage: ynh_mysql_setup_db --db_user=user --db_name=name [--db_pwd=pwd]
|
||||||
# | arg: -u, --db_user - Owner of the database
|
# | arg: -u, --db_user - Owner of the database
|
||||||
# | arg: -n, --db_name - Name 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
|
# | 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 () {
|
ynh_mysql_setup_db () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=unp
|
local legacy_args=unp
|
||||||
|
@ -180,7 +200,7 @@ ynh_mysql_setup_db () {
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
local new_db_pwd=$(ynh_string_random) # Generate a random password
|
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
|
# If $db_pwd is not provided, use new_db_pwd instead for db_pwd
|
||||||
db_pwd="${db_pwd:-$new_db_pwd}"
|
db_pwd="${db_pwd:-$new_db_pwd}"
|
||||||
|
|
||||||
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
|
ynh_mysql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
|
||||||
|
@ -192,6 +212,8 @@ ynh_mysql_setup_db () {
|
||||||
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
|
# usage: ynh_mysql_remove_db --db_user=user --db_name=name
|
||||||
# | arg: -u, --db_user - Owner of the database
|
# | arg: -u, --db_user - Owner of the database
|
||||||
# | arg: -n, --db_name - Name of the database
|
# | arg: -n, --db_name - Name of the database
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_mysql_remove_db () {
|
ynh_mysql_remove_db () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=un
|
local legacy_args=un
|
||||||
|
@ -223,6 +245,8 @@ ynh_mysql_remove_db () {
|
||||||
# usage: ynh_sanitize_dbid --db_name=name
|
# 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
|
# | ret: the corrected name
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_sanitize_dbid () {
|
ynh_sanitize_dbid () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=n
|
local legacy_args=n
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Normalize the url path syntax
|
# Normalize the url path syntax
|
||||||
|
#
|
||||||
# Handle the slash at the beginning of path and its absence at ending
|
# Handle the slash at the beginning of path and its absence at ending
|
||||||
# Return a normalized url path
|
# Return a normalized url path
|
||||||
#
|
#
|
||||||
# example: url_path=$(ynh_normalize_url_path $url_path)
|
# examples:
|
||||||
# ynh_normalize_url_path example -> /example
|
# url_path=$(ynh_normalize_url_path $url_path)
|
||||||
# ynh_normalize_url_path /example -> /example
|
# ynh_normalize_url_path example # -> /example
|
||||||
# ynh_normalize_url_path /example/ -> /example
|
# ynh_normalize_url_path /example # -> /example
|
||||||
# ynh_normalize_url_path / -> /
|
# ynh_normalize_url_path /example/ # -> /example
|
||||||
|
# ynh_normalize_url_path / # -> /
|
||||||
#
|
#
|
||||||
# usage: ynh_normalize_url_path --path_url=path_to_normalize
|
# 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 () {
|
ynh_normalize_url_path () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
|
@ -36,6 +40,8 @@ ynh_normalize_url_path () {
|
||||||
#
|
#
|
||||||
# usage: ynh_find_port --port=begin_port
|
# usage: ynh_find_port --port=begin_port
|
||||||
# | arg: -p, --port - port to start to search
|
# | arg: -p, --port - port to start to search
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_find_port () {
|
ynh_find_port () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
|
@ -59,6 +65,8 @@ ynh_find_port () {
|
||||||
# usage: ynh_webpath_available --domain=domain --path_url=path
|
# usage: ynh_webpath_available --domain=domain --path_url=path
|
||||||
# | arg: -d, --domain - the domain/host of the url
|
# | arg: -d, --domain - the domain/host of the url
|
||||||
# | arg: -p, --path_url - the web path to check the availability of
|
# | arg: -p, --path_url - the web path to check the availability of
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_webpath_available () {
|
ynh_webpath_available () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=dp
|
local legacy_args=dp
|
||||||
|
@ -79,6 +87,8 @@ ynh_webpath_available () {
|
||||||
# | arg: -a, --app - the app for which the domain should 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: -d, --domain - the domain/host of the web path
|
||||||
# | arg: -p, --path_url - the web path to be registered
|
# | arg: -p, --path_url - the web path to be registered
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_webpath_register () {
|
ynh_webpath_register () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=adp
|
local legacy_args=adp
|
||||||
|
|
|
@ -10,6 +10,8 @@ export N_PREFIX="$n_install_dir"
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_install_n
|
# usage: ynh_install_n
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_install_n () {
|
ynh_install_n () {
|
||||||
echo "Installation of N - Node.js version management" >&2
|
echo "Installation of N - Node.js version management" >&2
|
||||||
# Build an app.src for n
|
# Build an app.src for n
|
||||||
|
@ -36,6 +38,8 @@ SOURCE_SUM=2ba3c9d4dd3c7e38885b37e02337906a1ee91febe6d5c9159d89a9050f2eea8f" > "
|
||||||
# That's means it has to be added to any systemd script.
|
# That's means it has to be added to any systemd script.
|
||||||
#
|
#
|
||||||
# usage: ynh_use_nodejs
|
# usage: ynh_use_nodejs
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_use_nodejs () {
|
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)
|
||||||
|
|
||||||
|
@ -59,6 +63,8 @@ ynh_use_nodejs () {
|
||||||
# | arg: -n, --nodejs_version - Version of node to install.
|
# | arg: -n, --nodejs_version - Version of node to install.
|
||||||
# If possible, prefer to use major version number (e.g. 8 instead of 8.10.0).
|
# If possible, prefer to use major version number (e.g. 8 instead of 8.10.0).
|
||||||
# The crontab will handle the update of minor versions when needed.
|
# The crontab will handle the update of minor versions when needed.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_install_nodejs () {
|
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
|
||||||
|
|
||||||
|
@ -117,7 +123,7 @@ ynh_install_nodejs () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Store the ID of this app and the version of node requested for it
|
# Store the ID of this app and the version of node requested for it
|
||||||
echo "$YNH_APP_ID:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
echo "$YNH_APP_INSTANCE_NAME:$nodejs_version" | tee --append "$n_install_dir/ynh_app_version"
|
||||||
|
|
||||||
# Store nodejs_version into the config of this app
|
# Store nodejs_version into the config of this app
|
||||||
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
|
ynh_app_setting_set --app=$app --key=nodejs_version --value=$nodejs_version
|
||||||
|
@ -135,11 +141,13 @@ ynh_install_nodejs () {
|
||||||
# If no other app uses node, n will be also removed.
|
# If no other app uses node, n will be also removed.
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_nodejs
|
# usage: ynh_remove_nodejs
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_remove_nodejs () {
|
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
|
# Remove the line for this app
|
||||||
sed --in-place "/$YNH_APP_ID:$nodejs_version/d" "$n_install_dir/ynh_app_version"
|
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 no other app uses this version of nodejs, remove it.
|
||||||
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"
|
if ! grep --quiet "$nodejs_version" "$n_install_dir/ynh_app_version"
|
||||||
|
@ -164,6 +172,8 @@ ynh_remove_nodejs () {
|
||||||
# This cron will check and update all minor node versions used by your apps.
|
# This cron will check and update all minor node versions used by your apps.
|
||||||
#
|
#
|
||||||
# usage: ynh_cron_upgrade_node
|
# usage: ynh_cron_upgrade_node
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_cron_upgrade_node () {
|
ynh_cron_upgrade_node () {
|
||||||
# Build the update script
|
# Build the update script
|
||||||
cat > "$n_install_dir/node_update.sh" << EOF
|
cat > "$n_install_dir/node_update.sh" << EOF
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_wait_dpkg_free
|
# usage: ynh_wait_dpkg_free
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.3.1 or higher.
|
||||||
ynh_wait_dpkg_free() {
|
ynh_wait_dpkg_free() {
|
||||||
local try
|
local try
|
||||||
# With seq 1 17, timeout will be almost 30 minutes
|
# With seq 1 17, timeout will be almost 30 minutes
|
||||||
|
@ -44,6 +46,8 @@ ynh_wait_dpkg_free() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_is_installed --package=name
|
# 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() {
|
ynh_package_is_installed() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
|
@ -64,6 +68,8 @@ ynh_package_is_installed() {
|
||||||
# usage: ynh_package_version --package=name
|
# 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
|
# | ret: the version or an empty string
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_version() {
|
ynh_package_version() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=p
|
local legacy_args=p
|
||||||
|
@ -84,6 +90,8 @@ ynh_package_version() {
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
# usage: ynh_apt update
|
# usage: ynh_apt update
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.4.0.3 or higher.
|
||||||
ynh_apt() {
|
ynh_apt() {
|
||||||
ynh_wait_dpkg_free
|
ynh_wait_dpkg_free
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get -y $@
|
DEBIAN_FRONTEND=noninteractive apt-get -y $@
|
||||||
|
@ -92,6 +100,8 @@ ynh_apt() {
|
||||||
# Update package index files
|
# Update package index files
|
||||||
#
|
#
|
||||||
# usage: ynh_package_update
|
# usage: ynh_package_update
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_update() {
|
ynh_package_update() {
|
||||||
ynh_apt update
|
ynh_apt update
|
||||||
}
|
}
|
||||||
|
@ -100,6 +110,8 @@ ynh_package_update() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_install name [name [...]]
|
# usage: ynh_package_install name [name [...]]
|
||||||
# | arg: name - the package name to install
|
# | arg: name - the package name to install
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_install() {
|
ynh_package_install() {
|
||||||
ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \
|
ynh_apt --no-remove -o Dpkg::Options::=--force-confdef \
|
||||||
-o Dpkg::Options::=--force-confold install $@
|
-o Dpkg::Options::=--force-confold install $@
|
||||||
|
@ -109,6 +121,8 @@ ynh_package_install() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_remove name [name [...]]
|
# usage: ynh_package_remove name [name [...]]
|
||||||
# | arg: name - the package name to remove
|
# | arg: name - the package name to remove
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_remove() {
|
ynh_package_remove() {
|
||||||
ynh_apt remove $@
|
ynh_apt remove $@
|
||||||
}
|
}
|
||||||
|
@ -117,6 +131,8 @@ ynh_package_remove() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_autoremove name [name [...]]
|
# usage: ynh_package_autoremove name [name [...]]
|
||||||
# | arg: name - the package name to remove
|
# | arg: name - the package name to remove
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_autoremove() {
|
ynh_package_autoremove() {
|
||||||
ynh_apt autoremove $@
|
ynh_apt autoremove $@
|
||||||
}
|
}
|
||||||
|
@ -125,6 +141,8 @@ ynh_package_autoremove() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_autopurge name [name [...]]
|
# usage: ynh_package_autopurge name [name [...]]
|
||||||
# | arg: name - the package name to autoremove and purge
|
# | arg: name - the package name to autoremove and purge
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_package_autopurge() {
|
ynh_package_autopurge() {
|
||||||
ynh_apt autoremove --purge $@
|
ynh_apt autoremove --purge $@
|
||||||
}
|
}
|
||||||
|
@ -139,6 +157,8 @@ ynh_package_autopurge() {
|
||||||
#
|
#
|
||||||
# usage: ynh_package_install_from_equivs controlfile
|
# usage: ynh_package_install_from_equivs controlfile
|
||||||
# | arg: controlfile - path of the equivs control file
|
# | arg: controlfile - path of the equivs control file
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_package_install_from_equivs () {
|
ynh_package_install_from_equivs () {
|
||||||
local controlfile=$1
|
local controlfile=$1
|
||||||
|
|
||||||
|
@ -181,6 +201,8 @@ ynh_package_install_from_equivs () {
|
||||||
# You can give a choice between some package with this syntax : "dep1|dep2"
|
# You can give a choice between some package with this syntax : "dep1|dep2"
|
||||||
# Example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
|
# Example : ynh_install_app_dependencies dep1 dep2 "dep3|dep4|dep5"
|
||||||
# This mean in the dependence tree : dep1 & dep2 & (dep3 | dep4 | dep5)
|
# This mean in the dependence tree : dep1 & dep2 & (dep3 | dep4 | dep5)
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_install_app_dependencies () {
|
ynh_install_app_dependencies () {
|
||||||
local dependencies=$@
|
local dependencies=$@
|
||||||
local dependencies=${dependencies// /, }
|
local dependencies=${dependencies// /, }
|
||||||
|
@ -217,6 +239,8 @@ EOF
|
||||||
# Dependencies will removed only if no other package need them.
|
# Dependencies will removed only if no other package need them.
|
||||||
#
|
#
|
||||||
# usage: ynh_remove_app_dependencies
|
# usage: ynh_remove_app_dependencies
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_remove_app_dependencies () {
|
ynh_remove_app_dependencies () {
|
||||||
local dep_app=${app//_/-} # Replace all '_' by '-'
|
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.
|
ynh_package_autopurge ${dep_app}-ynh-deps # Remove the fake package and its dependencies if they not still used.
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
# Print a message to stderr and exit
|
# Print a message to stderr and exit
|
||||||
# usage: ynh_die --message=MSG [--ret_code=RETCODE]
|
# usage: ynh_die --message=MSG [--ret_code=RETCODE]
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.4.0 or higher.
|
||||||
ynh_die() {
|
ynh_die() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mc
|
local legacy_args=mc
|
||||||
|
@ -18,6 +20,8 @@ ynh_die() {
|
||||||
# Display a message in the 'INFO' logging category
|
# Display a message in the 'INFO' logging category
|
||||||
#
|
#
|
||||||
# usage: ynh_print_info --message="Some message"
|
# usage: ynh_print_info --message="Some message"
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_info() {
|
ynh_print_info() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
|
@ -37,6 +41,8 @@ ynh_print_info() {
|
||||||
#
|
#
|
||||||
# Simply duplicate the log, execute the yunohost command and replace the log without the result of this command
|
# Simply duplicate the log, execute the yunohost command and replace the log without the result of this command
|
||||||
# It's a very badly hack...
|
# It's a very badly hack...
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_no_log() {
|
ynh_no_log() {
|
||||||
local ynh_cli_log=/var/log/yunohost/yunohost-cli.log
|
local ynh_cli_log=/var/log/yunohost/yunohost-cli.log
|
||||||
sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move
|
sudo cp -a ${ynh_cli_log} ${ynh_cli_log}-move
|
||||||
|
@ -50,6 +56,7 @@ ynh_no_log() {
|
||||||
#
|
#
|
||||||
# [internal]
|
# [internal]
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_log () {
|
ynh_print_log () {
|
||||||
echo -e "${1}"
|
echo -e "${1}"
|
||||||
}
|
}
|
||||||
|
@ -58,6 +65,8 @@ ynh_print_log () {
|
||||||
#
|
#
|
||||||
# usage: ynh_print_warn --message="Text to print"
|
# 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 () {
|
ynh_print_warn () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
|
@ -73,6 +82,8 @@ ynh_print_warn () {
|
||||||
#
|
#
|
||||||
# usage: ynh_print_err --message="Text to print"
|
# 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 () {
|
ynh_print_err () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=m
|
local legacy_args=m
|
||||||
|
@ -89,8 +100,11 @@ ynh_print_err () {
|
||||||
# usage: ynh_exec_err command to execute
|
# usage: ynh_exec_err command to execute
|
||||||
# usage: ynh_exec_err "command to execute | following command"
|
# usage: ynh_exec_err "command to execute | following command"
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to 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
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_err () {
|
ynh_exec_err () {
|
||||||
ynh_print_err "$(eval $@)"
|
ynh_print_err "$(eval $@)"
|
||||||
}
|
}
|
||||||
|
@ -100,8 +114,11 @@ ynh_exec_err () {
|
||||||
# usage: ynh_exec_warn command to execute
|
# usage: ynh_exec_warn command to execute
|
||||||
# usage: ynh_exec_warn "command to execute | following command"
|
# usage: ynh_exec_warn "command to execute | following command"
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to 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
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn () {
|
ynh_exec_warn () {
|
||||||
ynh_print_warn "$(eval $@)"
|
ynh_print_warn "$(eval $@)"
|
||||||
}
|
}
|
||||||
|
@ -111,8 +128,11 @@ ynh_exec_warn () {
|
||||||
# usage: ynh_exec_warn_less command to execute
|
# usage: ynh_exec_warn_less command to execute
|
||||||
# usage: ynh_exec_warn_less "command to execute | following command"
|
# usage: ynh_exec_warn_less "command to execute | following command"
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to 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
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_warn_less () {
|
ynh_exec_warn_less () {
|
||||||
eval $@ 2>&1
|
eval $@ 2>&1
|
||||||
}
|
}
|
||||||
|
@ -122,8 +142,11 @@ ynh_exec_warn_less () {
|
||||||
# usage: ynh_exec_quiet command to execute
|
# usage: ynh_exec_quiet command to execute
|
||||||
# usage: ynh_exec_quiet "command to execute | following command"
|
# usage: ynh_exec_quiet "command to execute | following command"
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to 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
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_quiet () {
|
ynh_exec_quiet () {
|
||||||
eval $@ > /dev/null
|
eval $@ > /dev/null
|
||||||
}
|
}
|
||||||
|
@ -133,8 +156,11 @@ ynh_exec_quiet () {
|
||||||
# usage: ynh_exec_fully_quiet command to execute
|
# usage: ynh_exec_fully_quiet command to execute
|
||||||
# usage: ynh_exec_fully_quiet "command to execute | following command"
|
# usage: ynh_exec_fully_quiet "command to execute | following command"
|
||||||
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to the next pipe.
|
# In case of use of pipes, you have to use double quotes. Otherwise, this helper will be executed with the first command, then be sent to 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
|
# | arg: command - command to execute
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_exec_fully_quiet () {
|
ynh_exec_fully_quiet () {
|
||||||
eval $@ > /dev/null 2>&1
|
eval $@ > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
@ -143,6 +169,8 @@ ynh_exec_fully_quiet () {
|
||||||
#
|
#
|
||||||
# usage: ynh_print_OFF
|
# usage: ynh_print_OFF
|
||||||
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
|
# WARNING: You should be careful with this helper, and never forget to use ynh_print_ON as soon as possible to restore the logging.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_OFF () {
|
ynh_print_OFF () {
|
||||||
set +x
|
set +x
|
||||||
}
|
}
|
||||||
|
@ -150,6 +178,8 @@ ynh_print_OFF () {
|
||||||
# Restore the logging after ynh_print_OFF
|
# Restore the logging after ynh_print_OFF
|
||||||
#
|
#
|
||||||
# usage: ynh_print_ON
|
# usage: ynh_print_ON
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.2.0 or higher.
|
||||||
ynh_print_ON () {
|
ynh_print_ON () {
|
||||||
set -x
|
set -x
|
||||||
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
|
# Print an echo only for the log, to be able to know that ynh_print_ON has been called.
|
||||||
|
@ -162,13 +192,17 @@ ynh_print_ON () {
|
||||||
# | arg: -m, --message= - The text to print
|
# | 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: -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.
|
# | 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: -l, --last= - Use for the last call of the helper, to fill te progression bar.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
increment_progression=0
|
increment_progression=0
|
||||||
previous_weight=0
|
previous_weight=0
|
||||||
# Define base_time when the file is sourced
|
# Define base_time when the file is sourced
|
||||||
base_time=$(date +%s)
|
base_time=$(date +%s)
|
||||||
ynh_script_progression () {
|
ynh_script_progression () {
|
||||||
# Declare an array to define the options of this helper.
|
# 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 )
|
declare -Ar args_array=( [m]=message= [w]=weight= [t]=time [l]=last )
|
||||||
local message
|
local message
|
||||||
local weight
|
local weight
|
||||||
|
@ -190,9 +224,9 @@ ynh_script_progression () {
|
||||||
local weight_calls=$(grep --perl-regexp --count "^[^#]*ynh_script_progression.*(--weight|-w )" $0)
|
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
|
# 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')"
|
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
|
# 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')"
|
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.
|
# Each value will be on a different line.
|
||||||
# Remove each 'end of line' and replace it by a '+' to sum the values.
|
# 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 ))
|
local weight_values=$(( $(echo "$weight_valuesA" | tr '\n' '+') + $(echo "$weight_valuesB" | tr '\n' '+') 0 ))
|
||||||
|
|
|
@ -1,21 +1,277 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PSQL_ROOT_PWD_FILE=/etc/yunohost/psql
|
||||||
|
|
||||||
|
# Open a connection as a user
|
||||||
|
#
|
||||||
|
# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"
|
||||||
|
# example: 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
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
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 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
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 sql
|
||||||
|
local database
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
database="${database:-}"
|
||||||
|
|
||||||
|
ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
|
||||||
|
--database="$database" <<<"$sql"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
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 file
|
||||||
|
local database
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
database="${database:-}"
|
||||||
|
|
||||||
|
ynh_psql_connect_as --user="postgres" --password="$(sudo cat $PSQL_ROOT_PWD_FILE)" \
|
||||||
|
--database="$database" <"$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a database and grant optionnaly privilegies to a user
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_psql_create_db db [user]
|
||||||
|
# | arg: db - the database name to create
|
||||||
|
# | arg: user - the user to grant privilegies
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
ynh_psql_create_db() {
|
||||||
|
local db=$1
|
||||||
|
local user=${2:-}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ynh_psql_execute_as_root --sql="$sql"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Drop a database
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# If you intend to drop the database *and* the associated user,
|
||||||
|
# consider using ynh_psql_remove_db instead.
|
||||||
|
#
|
||||||
|
# usage: ynh_psql_drop_db db
|
||||||
|
# | arg: db - the database name to drop
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
ynh_psql_drop_db() {
|
||||||
|
local db=$1
|
||||||
|
sudo --login --user=postgres dropdb $db
|
||||||
|
}
|
||||||
|
|
||||||
|
# Dump a database
|
||||||
|
#
|
||||||
|
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
|
||||||
|
#
|
||||||
|
# usage: ynh_psql_dump_db --database=database
|
||||||
|
# | arg: -d, --database - the database name to dump
|
||||||
|
# | ret: the psqldump output
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
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 database
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
sudo --login --user=postgres pg_dump "$database"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a user
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_psql_create_user user pwd
|
||||||
|
# | arg: user - the user name to create
|
||||||
|
# | arg: pwd - the password to identify user by
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? 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'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a psql user exists
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
declare -Ar args_array=([u]=user=)
|
||||||
|
local user
|
||||||
|
# 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
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a psql database 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
|
||||||
|
declare -Ar args_array=([d]=database=)
|
||||||
|
local database
|
||||||
|
# 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
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Drop a user
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
# usage: ynh_psql_drop_user user
|
||||||
|
# | arg: user - the user name to drop
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
|
ynh_psql_drop_user() {
|
||||||
|
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
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
declare -Ar 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}"
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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 db_user
|
||||||
|
local db_name
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
local psql_root_password=$(sudo cat $PSQL_ROOT_PWD_FILE)
|
||||||
|
if ynh_psql_database_exists --database=$db_name; then # Check if the database exists
|
||||||
|
echo "Removing database $db_name" >&2
|
||||||
|
ynh_psql_drop_db $db_name # Remove the database
|
||||||
|
else
|
||||||
|
echo "Database $db_name not found" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove psql user if it exists
|
||||||
|
if ynh_psql_user_exists --user=$db_user; then
|
||||||
|
echo "Removing user $db_user" >&2
|
||||||
|
ynh_psql_drop_user $db_user
|
||||||
|
else
|
||||||
|
echo "User $db_user not found" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Create a master password and set up global settings
|
# Create a master password and set up global settings
|
||||||
# Please always call this script in install and restore scripts
|
# Please always call this script in install and restore scripts
|
||||||
#
|
#
|
||||||
# usage: ynh_psql_test_if_first_run
|
# usage: ynh_psql_test_if_first_run
|
||||||
ynh_psql_test_if_first_run() {
|
ynh_psql_test_if_first_run() {
|
||||||
if [ -f /etc/yunohost/psql ];
|
if [ -f "$PSQL_ROOT_PWD_FILE" ]; then
|
||||||
then
|
|
||||||
echo "PostgreSQL is already installed, no need to create master password"
|
echo "PostgreSQL is already installed, no need to create master password"
|
||||||
else
|
else
|
||||||
local pgsql="$(ynh_string_random)"
|
local pgsql="$(ynh_string_random)"
|
||||||
echo "$pgsql" > /etc/yunohost/psql
|
echo "$pgsql" >/etc/yunohost/psql
|
||||||
|
|
||||||
if [ -e /etc/postgresql/9.4/ ]
|
if [ -e /etc/postgresql/9.4/ ]; then
|
||||||
then
|
|
||||||
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
|
local pg_hba=/etc/postgresql/9.4/main/pg_hba.conf
|
||||||
elif [ -e /etc/postgresql/9.6/ ]
|
local logfile=/var/log/postgresql/postgresql-9.4-main.log
|
||||||
then
|
elif [ -e /etc/postgresql/9.6/ ]; then
|
||||||
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
|
local pg_hba=/etc/postgresql/9.6/main/pg_hba.conf
|
||||||
|
local logfile=/var/log/postgresql/postgresql-9.6-main.log
|
||||||
else
|
else
|
||||||
ynh_die "postgresql shoud be 9.4 or 9.6"
|
ynh_die "postgresql shoud be 9.4 or 9.6"
|
||||||
fi
|
fi
|
||||||
|
@ -27,122 +283,12 @@ ynh_psql_test_if_first_run() {
|
||||||
# https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
|
# https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html#EXAMPLE-PG-HBA.CONF
|
||||||
# Note: we can't use peer since YunoHost create users with nologin
|
# Note: we can't use peer since YunoHost create users with nologin
|
||||||
# See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
|
# See: https://github.com/YunoHost/yunohost/blob/unstable/data/helpers.d/user
|
||||||
sed -i '/local\s*all\s*all\s*peer/i \
|
ynh_replace_string --match_string="local\(\s*\)all\(\s*\)all\(\s*\)peer" --replace_string="local\1all\2all\3password" --target_file="$pg_hba"
|
||||||
local all all password' "$pg_hba"
|
|
||||||
|
# Advertise service in admin panel
|
||||||
|
yunohost service add postgresql --log "$logfile"
|
||||||
|
|
||||||
systemctl enable postgresql
|
systemctl enable postgresql
|
||||||
systemctl reload postgresql
|
systemctl reload postgresql
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Open a connection as a user
|
|
||||||
#
|
|
||||||
# example: ynh_psql_connect_as 'user' 'pass' <<< "UPDATE ...;"
|
|
||||||
# example: ynh_psql_connect_as 'user' 'pass' < /path/to/file.sql
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_connect_as user pwd [db]
|
|
||||||
# | arg: user - the user name to connect as
|
|
||||||
# | arg: pwd - the user password
|
|
||||||
# | arg: db - the database to connect to
|
|
||||||
ynh_psql_connect_as() {
|
|
||||||
local user="$1"
|
|
||||||
local pwd="$2"
|
|
||||||
local db="$3"
|
|
||||||
sudo --login --user=postgres PGUSER="$user" PGPASSWORD="$pwd" psql "$db"
|
|
||||||
}
|
|
||||||
|
|
||||||
# # Execute a command as root user
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_execute_as_root sql [db]
|
|
||||||
# | arg: sql - the SQL command to execute
|
|
||||||
ynh_psql_execute_as_root () {
|
|
||||||
local sql="$1"
|
|
||||||
sudo --login --user=postgres psql <<< "$sql"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Execute a command from a file as root user
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_execute_file_as_root file [db]
|
|
||||||
# | arg: file - the file containing SQL commands
|
|
||||||
# | arg: db - the database to connect to
|
|
||||||
ynh_psql_execute_file_as_root() {
|
|
||||||
local file="$1"
|
|
||||||
local db="$2"
|
|
||||||
sudo --login --user=postgres psql "$db" < "$file"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create a database, an user and its password. Then store the password in the app's config
|
|
||||||
#
|
|
||||||
# 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 user name [pwd]
|
|
||||||
# | arg: user - Owner of the database
|
|
||||||
# | arg: name - Name of the database
|
|
||||||
# | arg: pwd - Password of the database. If not given, a password will be generated
|
|
||||||
ynh_psql_setup_db () {
|
|
||||||
local db_user="$1"
|
|
||||||
local db_name="$2"
|
|
||||||
local new_db_pwd=$(ynh_string_random) # Generate a random password
|
|
||||||
# If $3 is not given, use new_db_pwd instead for db_pwd.
|
|
||||||
local db_pwd="${3:-$new_db_pwd}"
|
|
||||||
ynh_psql_create_db "$db_name" "$db_user" "$db_pwd" # Create the database
|
|
||||||
ynh_app_setting_set "$app" psqlpwd "$db_pwd" # Store the password in the app's config
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create a database and grant privilegies to a user
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_create_db db [user [pwd]]
|
|
||||||
# | arg: db - the database name to create
|
|
||||||
# | arg: user - the user to grant privilegies
|
|
||||||
# | arg: pwd - the user password
|
|
||||||
ynh_psql_create_db() {
|
|
||||||
local db="$1"
|
|
||||||
local user="$2"
|
|
||||||
local pwd="$3"
|
|
||||||
ynh_psql_create_user "$user" "$pwd"
|
|
||||||
sudo --login --user=postgres createdb --owner="$user" "$db"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Drop a database
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_drop_db db
|
|
||||||
# | arg: db - the database name to drop
|
|
||||||
# | arg: user - the user to drop
|
|
||||||
ynh_psql_remove_db() {
|
|
||||||
local db="$1"
|
|
||||||
local user="$2"
|
|
||||||
sudo --login --user=postgres dropdb "$db"
|
|
||||||
ynh_psql_drop_user "$user"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Dump a database
|
|
||||||
#
|
|
||||||
# example: ynh_psql_dump_db 'roundcube' > ./dump.sql
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_dump_db db
|
|
||||||
# | arg: db - the database name to dump
|
|
||||||
# | ret: the psqldump output
|
|
||||||
ynh_psql_dump_db() {
|
|
||||||
local db="$1"
|
|
||||||
sudo --login --user=postgres pg_dump "$db"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Create a user
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_create_user user pwd [host]
|
|
||||||
# | arg: user - the user name to create
|
|
||||||
ynh_psql_create_user() {
|
|
||||||
local user="$1"
|
|
||||||
local pwd="$2"
|
|
||||||
sudo --login --user=postgres psql -c"CREATE USER $user WITH PASSWORD '$pwd'" postgres
|
|
||||||
}
|
|
||||||
|
|
||||||
# Drop a user
|
|
||||||
#
|
|
||||||
# usage: ynh_psql_drop_user user
|
|
||||||
# | arg: user - the user name to drop
|
|
||||||
ynh_psql_drop_user() {
|
|
||||||
local user="$1"
|
|
||||||
sudo --login --user=postgres dropuser "$user"
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# usage: ynh_app_setting_get --app=app --key=key
|
# usage: ynh_app_setting_get --app=app --key=key
|
||||||
# | arg: -a, --app - the application id
|
# | arg: -a, --app - the application id
|
||||||
# | arg: -k, --key - the setting to get
|
# | arg: -k, --key - the setting to get
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_app_setting_get() {
|
ynh_app_setting_get() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ak
|
local legacy_args=ak
|
||||||
|
@ -14,7 +16,7 @@ ynh_app_setting_get() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
sudo yunohost app setting "$app" "$key" --output-as plain --quiet
|
ynh_app_setting "get" "$app" "$key"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set an application setting
|
# Set an application setting
|
||||||
|
@ -23,6 +25,8 @@ ynh_app_setting_get() {
|
||||||
# | arg: -a, --app - the application id
|
# | arg: -a, --app - the application id
|
||||||
# | arg: -k, --key - the setting name to set
|
# | arg: -k, --key - the setting name to set
|
||||||
# | arg: -v, --value - the setting value to set
|
# | arg: -v, --value - the setting value to set
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_app_setting_set() {
|
ynh_app_setting_set() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=akv
|
local legacy_args=akv
|
||||||
|
@ -33,7 +37,7 @@ ynh_app_setting_set() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
sudo yunohost app setting "$app" "$key" --value="$value" --quiet
|
ynh_app_setting "set" "$app" "$key" "$value"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Delete an application setting
|
# Delete an application setting
|
||||||
|
@ -41,6 +45,8 @@ ynh_app_setting_set() {
|
||||||
# usage: ynh_app_setting_delete --app=app --key=key
|
# usage: ynh_app_setting_delete --app=app --key=key
|
||||||
# | arg: -a, --app - the application id
|
# | arg: -a, --app - the application id
|
||||||
# | arg: -k, --key - the setting to delete
|
# | arg: -k, --key - the setting to delete
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_app_setting_delete() {
|
ynh_app_setting_delete() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ak
|
local legacy_args=ak
|
||||||
|
@ -50,5 +56,38 @@ ynh_app_setting_delete() {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
sudo yunohost app setting -d "$app" "$key" --quiet
|
ynh_app_setting "delete" "$app" "$key"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Small "hard-coded" interface to avoid calling "yunohost app" directly each
|
||||||
|
# time dealing with a setting is needed (which may be so slow on ARM boards)
|
||||||
|
#
|
||||||
|
# [internal]
|
||||||
|
#
|
||||||
|
ynh_app_setting()
|
||||||
|
{
|
||||||
|
ACTION="$1" APP="$2" KEY="$3" VALUE="${4:-}" python - <<EOF
|
||||||
|
import os, yaml
|
||||||
|
app, action = os.environ['APP'], os.environ['ACTION'].lower()
|
||||||
|
key, value = os.environ['KEY'], os.environ.get('VALUE', None)
|
||||||
|
setting_file = "/etc/yunohost/apps/%s/settings.yml" % app
|
||||||
|
assert os.path.exists(setting_file), "Setting file %s does not exists ?" % setting_file
|
||||||
|
with open(setting_file) as f:
|
||||||
|
settings = yaml.load(f)
|
||||||
|
if action == "get":
|
||||||
|
if key in settings:
|
||||||
|
print(settings[key])
|
||||||
|
else:
|
||||||
|
if action == "delete":
|
||||||
|
if key in settings:
|
||||||
|
del settings[key]
|
||||||
|
elif action == "set":
|
||||||
|
if key in ['redirected_urls', 'redirected_regex']:
|
||||||
|
value = yaml.load(value)
|
||||||
|
settings[key] = value
|
||||||
|
else:
|
||||||
|
raise ValueError("action should either be get, set or delete")
|
||||||
|
with open(setting_file, "w") as f:
|
||||||
|
yaml.safe_dump(settings, f, default_flow_style=False)
|
||||||
|
EOF
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#
|
#
|
||||||
# usage: ynh_string_random [--length=string_length]
|
# 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)
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_string_random() {
|
ynh_string_random() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=l
|
local legacy_args=l
|
||||||
|
@ -30,6 +32,8 @@ ynh_string_random() {
|
||||||
# As this helper is based on sed command, regular expressions and
|
# As this helper is based on sed command, regular expressions and
|
||||||
# references to sub-expressions can be used
|
# references to sub-expressions can be used
|
||||||
# (see sed manual page for more information)
|
# (see sed manual page for more information)
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_replace_string () {
|
ynh_replace_string () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mrf
|
local legacy_args=mrf
|
||||||
|
@ -57,6 +61,8 @@ ynh_replace_string () {
|
||||||
#
|
#
|
||||||
# This helper will use ynh_replace_string, but as you can use special
|
# This helper will use ynh_replace_string, but as you can use special
|
||||||
# characters, you can't use some regular expressions and sub-expressions.
|
# characters, you can't use some regular expressions and sub-expressions.
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.7 or higher.
|
||||||
ynh_replace_special_string () {
|
ynh_replace_special_string () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=mrf
|
local legacy_args=mrf
|
||||||
|
|
|
@ -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
|
# 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 () {
|
ynh_exit_properly () {
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
if [ "$exit_code" -eq 0 ]; then
|
if [ "$exit_code" -eq 0 ]; then
|
||||||
|
@ -43,6 +44,7 @@ ynh_exit_properly () {
|
||||||
# immediately and a call to `ynh_clean_setup` is triggered if it has been
|
# immediately and a call to `ynh_clean_setup` is triggered if it has been
|
||||||
# defined by your script.
|
# defined by your script.
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_abort_if_errors () {
|
ynh_abort_if_errors () {
|
||||||
set -eu # Exit if a command fail, and if a variable is used unset.
|
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
|
trap ynh_exit_properly EXIT # Capturing exit signals on shell script
|
||||||
|
@ -52,17 +54,129 @@ ynh_abort_if_errors () {
|
||||||
#
|
#
|
||||||
# usage: ynh_get_debian_release
|
# usage: ynh_get_debian_release
|
||||||
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
|
# | ret: The Debian release codename (i.e. jessie, stretch, ...)
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.7.12 or higher.
|
||||||
ynh_get_debian_release () {
|
ynh_get_debian_release () {
|
||||||
echo $(lsb_release --codename --short)
|
echo $(lsb_release --codename --short)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 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] ]
|
||||||
|
# | 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.
|
||||||
|
# | 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
|
||||||
|
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 service_name
|
||||||
|
local action
|
||||||
|
local line_match
|
||||||
|
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}
|
||||||
|
|
||||||
|
# Start to read the log
|
||||||
|
if [[ -n "${line_match:-}" ]]
|
||||||
|
then
|
||||||
|
local templog="$(mktemp)"
|
||||||
|
# Following the starting of the app in its log
|
||||||
|
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
|
||||||
|
local pid_tail=$!
|
||||||
|
else
|
||||||
|
# Read the specified log file
|
||||||
|
tail -F -n0 "$log_path" > "$templog" 2>&1 &
|
||||||
|
# Get the PID of the tail command
|
||||||
|
local pid_tail=$!
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ynh_print_info --message="${action^} the service $service_name"
|
||||||
|
|
||||||
|
# Use reload-or-restart instead of reload. So it wouldn't fail if the service isn't running.
|
||||||
|
if [ "$action" == "reload" ]; then
|
||||||
|
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 )
|
||||||
|
|
||||||
|
# Start the timeout and try to find line_match
|
||||||
|
if [[ -n "${line_match:-}" ]]
|
||||||
|
then
|
||||||
|
local i=0
|
||||||
|
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"
|
||||||
|
then
|
||||||
|
ynh_print_info --message="The service $service_name has correctly started."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if [ $i -eq 3 ]; then
|
||||||
|
echo -n "Please wait, the service $service_name is ${action}ing" >&2
|
||||||
|
fi
|
||||||
|
if [ $i -ge 3 ]; then
|
||||||
|
echo -n "." >&2
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
if [ $i -ge 3 ]; then
|
||||||
|
echo "" >&2
|
||||||
|
fi
|
||||||
|
if [ $i -eq $timeout ]
|
||||||
|
then
|
||||||
|
ynh_print_warn --message="The service $service_name didn't fully started 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
|
||||||
|
fi
|
||||||
|
ynh_clean_check_starting
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean temporary process and file used by ynh_check_starting
|
||||||
|
# (usually used in ynh_clean_setup scripts)
|
||||||
|
#
|
||||||
|
# usage: ynh_clean_check_starting
|
||||||
|
ynh_clean_check_starting () {
|
||||||
|
# Stop the execution of tail.
|
||||||
|
kill -s 15 $pid_tail 2>&1
|
||||||
|
ynh_secure_remove "$templog" 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
# Read the value of a key in a ynh manifest file
|
# Read the value of a key in a ynh manifest file
|
||||||
#
|
#
|
||||||
# usage: ynh_read_manifest manifest key
|
# usage: ynh_read_manifest manifest key
|
||||||
# | arg: -m, --manifest= - Path of the manifest to read
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
# | arg: -k, --key= - Name of the key to find
|
# | arg: -k, --key= - Name of the key to find
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_read_manifest () {
|
ynh_read_manifest () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
|
local legacy_args=mk
|
||||||
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
|
declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
|
||||||
local manifest
|
local manifest
|
||||||
local manifest_key
|
local manifest_key
|
||||||
|
@ -85,7 +199,11 @@ ynh_read_manifest () {
|
||||||
#
|
#
|
||||||
# usage: ynh_app_upstream_version [-m manifest]
|
# usage: ynh_app_upstream_version [-m manifest]
|
||||||
# | arg: -m, --manifest= - Path of the manifest to read
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_app_upstream_version () {
|
ynh_app_upstream_version () {
|
||||||
|
# Declare an array to define the options of this helper.
|
||||||
|
local legacy_args=m
|
||||||
declare -Ar args_array=( [m]=manifest= )
|
declare -Ar args_array=( [m]=manifest= )
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -104,7 +222,11 @@ ynh_app_upstream_version () {
|
||||||
#
|
#
|
||||||
# usage: ynh_app_package_version [-m manifest]
|
# usage: ynh_app_package_version [-m manifest]
|
||||||
# | arg: -m, --manifest= - Path of the manifest to read
|
# | arg: -m, --manifest= - Path of the manifest to read
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_app_package_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= )
|
declare -Ar args_array=( [m]=manifest= )
|
||||||
local manifest
|
local manifest
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
|
@ -119,7 +241,7 @@ ynh_app_package_version () {
|
||||||
# - UPGRADE_APP if the upstream app version has changed
|
# - UPGRADE_APP if the upstream app version has changed
|
||||||
# - UPGRADE_PACKAGE if only the YunoHost package has changed
|
# - UPGRADE_PACKAGE if only the YunoHost package has changed
|
||||||
#
|
#
|
||||||
## It stops the current script without error if the package is up-to-date
|
# It stops the current script without error if the package is up-to-date
|
||||||
#
|
#
|
||||||
# This helper should be used to avoid an upgrade of an app, or the upstream part
|
# This helper should be used to avoid an upgrade of an app, or the upstream part
|
||||||
# of it, when it's not needed
|
# of it, when it's not needed
|
||||||
|
@ -129,6 +251,8 @@ ynh_app_package_version () {
|
||||||
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
|
# example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
|
||||||
#
|
#
|
||||||
# usage: ynh_check_app_version_changed
|
# usage: ynh_check_app_version_changed
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 3.?.? or higher.
|
||||||
ynh_check_app_version_changed () {
|
ynh_check_app_version_changed () {
|
||||||
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
|
local force_upgrade=${YNH_FORCE_UPGRADE:-0}
|
||||||
local package_check=${PACKAGE_CHECK_EXEC:-0}
|
local package_check=${PACKAGE_CHECK_EXEC:-0}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#
|
#
|
||||||
# usage: ynh_user_exists --username=username
|
# usage: ynh_user_exists --username=username
|
||||||
# | arg: -u, --username - the username to check
|
# | arg: -u, --username - the username to check
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_user_exists() {
|
ynh_user_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
|
@ -25,6 +27,8 @@ ynh_user_exists() {
|
||||||
# | arg: -u, --username - the username to retrieve info from
|
# | arg: -u, --username - the username to retrieve info from
|
||||||
# | arg: -k, --key - the key to retrieve
|
# | arg: -k, --key - the key to retrieve
|
||||||
# | ret: string - the key's value
|
# | ret: string - the key's value
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_user_get_info() {
|
ynh_user_get_info() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uk
|
local legacy_args=uk
|
||||||
|
@ -43,6 +47,8 @@ ynh_user_get_info() {
|
||||||
#
|
#
|
||||||
# usage: ynh_user_list
|
# usage: ynh_user_list
|
||||||
# | ret: string - one username per line
|
# | ret: string - one username per line
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.4.0 or higher.
|
||||||
ynh_user_list() {
|
ynh_user_list() {
|
||||||
sudo yunohost user list --output-as plain --quiet \
|
sudo yunohost user list --output-as plain --quiet \
|
||||||
| awk '/^##username$/{getline; print}'
|
| awk '/^##username$/{getline; print}'
|
||||||
|
@ -52,6 +58,8 @@ ynh_user_list() {
|
||||||
#
|
#
|
||||||
# usage: ynh_system_user_exists --username=username
|
# usage: ynh_system_user_exists --username=username
|
||||||
# | arg: -u, --username - the username to check
|
# | arg: -u, --username - the username to check
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_system_user_exists() {
|
ynh_system_user_exists() {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
|
@ -63,19 +71,35 @@ ynh_system_user_exists() {
|
||||||
getent passwd "$username" &>/dev/null
|
getent passwd "$username" &>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Check if a group exists on the system
|
||||||
|
#
|
||||||
|
# usage: ynh_system_group_exists --group=group
|
||||||
|
# | arg: -g, --group - the group to check
|
||||||
|
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 group
|
||||||
|
# Manage arguments with getopts
|
||||||
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
|
getent group "$group" &>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
# Create a system user
|
# Create a system user
|
||||||
#
|
#
|
||||||
# examples:
|
# examples:
|
||||||
# - ynh_system_user_create --username=nextcloud -> creates a nextcloud user with
|
# # Create a nextcloud user with no home directory and /usr/sbin/nologin login shell (hence no login capability)
|
||||||
# no home directory and /usr/sbin/nologin login shell (hence no login capability)
|
# ynh_system_user_create --username=nextcloud
|
||||||
# - ynh_system_user_create --username=discourse --home_dir=/var/www/discourse --use_shell --> creates a
|
# # Create a discourse user using /var/www/discourse as home directory and the default login shell
|
||||||
# discourse user using /var/www/discourse as home directory and the default login shell
|
# 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]
|
# 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: -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: -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.
|
# | 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
|
||||||
# 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 () {
|
ynh_system_user_create () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=uhs
|
local legacy_args=uhs
|
||||||
|
@ -108,6 +132,8 @@ ynh_system_user_create () {
|
||||||
#
|
#
|
||||||
# usage: ynh_system_user_delete --username=user_name
|
# 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 () {
|
ynh_system_user_delete () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=u
|
local legacy_args=u
|
||||||
|
@ -116,11 +142,19 @@ ynh_system_user_delete () {
|
||||||
# Manage arguments with getopts
|
# Manage arguments with getopts
|
||||||
ynh_handle_getopts_args "$@"
|
ynh_handle_getopts_args "$@"
|
||||||
|
|
||||||
if ynh_system_user_exists "$username" # Check if the user exists on the system
|
# Check if the user exists on the system
|
||||||
|
if ynh_system_user_exists "$username"
|
||||||
then
|
then
|
||||||
echo "Remove the user $username" >&2
|
echo "Remove the user $username" >&2
|
||||||
sudo userdel $username
|
deluser $username
|
||||||
else
|
else
|
||||||
echo "The user $username was not found" >&2
|
echo "The user $username was not found" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check if the group exists on the system
|
||||||
|
if ynh_system_group_exists "$username"
|
||||||
|
then
|
||||||
|
echo "Remove the group $username" >&2
|
||||||
|
delgroup $username
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#
|
#
|
||||||
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
|
# usage: ynh_get_plain_key key [subkey [subsubkey ...]]
|
||||||
# | ret: string - the key's value
|
# | ret: string - the key's value
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.2.4 or higher.
|
||||||
ynh_get_plain_key() {
|
ynh_get_plain_key() {
|
||||||
local prefix="#"
|
local prefix="#"
|
||||||
local founded=0
|
local founded=0
|
||||||
|
@ -36,6 +38,7 @@ ynh_get_plain_key() {
|
||||||
# }
|
# }
|
||||||
# ynh_abort_if_errors
|
# ynh_abort_if_errors
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_restore_upgradebackup () {
|
ynh_restore_upgradebackup () {
|
||||||
echo "Upgrade failed." >&2
|
echo "Upgrade failed." >&2
|
||||||
local app_bck=${app//_/-} # Replace all '_' by '-'
|
local app_bck=${app//_/-} # Replace all '_' by '-'
|
||||||
|
@ -67,6 +70,7 @@ ynh_restore_upgradebackup () {
|
||||||
# }
|
# }
|
||||||
# ynh_abort_if_errors
|
# ynh_abort_if_errors
|
||||||
#
|
#
|
||||||
|
# Requires YunoHost version 2.7.2 or higher.
|
||||||
ynh_backup_before_upgrade () {
|
ynh_backup_before_upgrade () {
|
||||||
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
|
if [ ! -e "/etc/yunohost/apps/$app/scripts/backup" ]
|
||||||
then
|
then
|
||||||
|
@ -150,6 +154,8 @@ ynh_backup_before_upgrade () {
|
||||||
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
|
# usage: ynh_setup_source --dest_dir=dest_dir [--source_id=source_id]
|
||||||
# | arg: -d, --dest_dir - Directory where to setup sources
|
# | 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
|
# | 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 () {
|
ynh_setup_source () {
|
||||||
# Declare an array to define the options of this helper.
|
# Declare an array to define the options of this helper.
|
||||||
local legacy_args=ds
|
local legacy_args=ds
|
||||||
|
@ -255,6 +261,8 @@ ynh_setup_source () {
|
||||||
# | arg: key1=value1 - (Optionnal) POST key and corresponding value
|
# | arg: key1=value1 - (Optionnal) POST key and corresponding value
|
||||||
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
|
# | arg: key2=value2 - (Optionnal) Another POST key and corresponding value
|
||||||
# | arg: ... - (Optionnal) More POST keys and values
|
# | arg: ... - (Optionnal) More POST keys and values
|
||||||
|
#
|
||||||
|
# Requires YunoHost version 2.6.4 or higher.
|
||||||
ynh_local_curl () {
|
ynh_local_curl () {
|
||||||
# Define url of page to curl
|
# Define url of page to curl
|
||||||
local local_page=$(ynh_normalize_url_path $1)
|
local local_page=$(ynh_normalize_url_path $1)
|
||||||
|
|
|
@ -23,6 +23,9 @@ do_pre_regen() {
|
||||||
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
|
ssh_keys="$ssh_keys $(ls /etc/ssh/ssh_host_dsa_key 2>/dev/null || true)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Support different strategy for security configurations
|
||||||
|
export compatibility="$(yunohost settings get 'security.ssh.compatibility')"
|
||||||
|
|
||||||
export ssh_keys
|
export ssh_keys
|
||||||
export ipv6_enabled
|
export ipv6_enabled
|
||||||
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
|
ynh_render_template "sshd_config" "${pending_dir}/etc/ssh/sshd_config"
|
||||||
|
|
|
@ -10,7 +10,25 @@ do_init_regen() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
do_pre_regen ""
|
cd /usr/share/yunohost/templates/nginx
|
||||||
|
|
||||||
|
nginx_dir="/etc/nginx"
|
||||||
|
nginx_conf_dir="${nginx_dir}/conf.d"
|
||||||
|
mkdir -p "$nginx_conf_dir"
|
||||||
|
|
||||||
|
# install plain conf files
|
||||||
|
cp plain/* "$nginx_conf_dir"
|
||||||
|
|
||||||
|
# probably run with init: just disable default site, restart NGINX and exit
|
||||||
|
rm -f "${nginx_dir}/sites-enabled/default"
|
||||||
|
|
||||||
|
export compatibility="intermediate"
|
||||||
|
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)
|
||||||
|
|
||||||
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
do_pre_regen() {
|
do_pre_regen() {
|
||||||
|
@ -22,20 +40,16 @@ do_pre_regen() {
|
||||||
nginx_conf_dir="${nginx_dir}/conf.d"
|
nginx_conf_dir="${nginx_dir}/conf.d"
|
||||||
mkdir -p "$nginx_conf_dir"
|
mkdir -p "$nginx_conf_dir"
|
||||||
|
|
||||||
# install plain conf files
|
# install / update plain conf files
|
||||||
cp plain/* "$nginx_conf_dir"
|
cp plain/* "$nginx_conf_dir"
|
||||||
|
|
||||||
# probably run with init: just disable default site, restart NGINX and exit
|
|
||||||
if [[ -z "$pending_dir" ]]; then
|
|
||||||
rm -f "${nginx_dir}/sites-enabled/default"
|
|
||||||
service nginx restart
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# retrieve variables
|
# retrieve variables
|
||||||
main_domain=$(cat /etc/yunohost/current_host)
|
main_domain=$(cat /etc/yunohost/current_host)
|
||||||
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
|
domain_list=$(sudo yunohost domain list --output-as plain --quiet)
|
||||||
|
|
||||||
|
# Support different strategy for security configurations
|
||||||
|
export compatibility="$(yunohost settings get 'security.nginx.compatibility')"
|
||||||
|
|
||||||
# add domain conf files
|
# add domain conf files
|
||||||
for domain in $domain_list; do
|
for domain in $domain_list; do
|
||||||
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
|
domain_conf_dir="${nginx_conf_dir}/${domain}.d"
|
||||||
|
@ -58,6 +72,8 @@ do_pre_regen() {
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
ynh_render_template "yunohost_admin.conf" "${nginx_conf_dir}/yunohost_admin.conf"
|
||||||
|
|
||||||
# remove old domain conf files
|
# remove old domain conf files
|
||||||
conf_files=$(ls -1 /etc/nginx/conf.d \
|
conf_files=$(ls -1 /etc/nginx/conf.d \
|
||||||
| awk '/^[^\.]+\.[^\.]+.*\.conf$/ { print $1 }')
|
| awk '/^[^\.]+\.[^\.]+.*\.conf$/ { print $1 }')
|
||||||
|
|
|
@ -9,25 +9,37 @@
|
||||||
|
|
||||||
# (FR) FDN
|
# (FR) FDN
|
||||||
nameserver 80.67.169.12
|
nameserver 80.67.169.12
|
||||||
|
nameserver 2001:910:800::12
|
||||||
nameserver 80.67.169.40
|
nameserver 80.67.169.40
|
||||||
|
nameserver 2001:910:800::40
|
||||||
# (FR) LDN
|
# (FR) LDN
|
||||||
nameserver 80.67.188.188
|
nameserver 80.67.188.188
|
||||||
|
nameserver 2001:913::8
|
||||||
# (FR) ARN
|
# (FR) ARN
|
||||||
nameserver 89.234.141.66
|
nameserver 89.234.141.66
|
||||||
|
nameserver 2a00:5881:8100:1000::3
|
||||||
# (FR) Aquilenet
|
# (FR) Aquilenet
|
||||||
nameserver 185.233.100.100
|
nameserver 185.233.100.100
|
||||||
|
nameserver 2a0c:e300::100
|
||||||
nameserver 185.233.100.101
|
nameserver 185.233.100.101
|
||||||
|
nameserver 2a0c:e300::101
|
||||||
# (FR) gozmail / grifon
|
# (FR) gozmail / grifon
|
||||||
nameserver 80.67.190.200
|
nameserver 80.67.190.200
|
||||||
|
nameserver 2a00:5884:8218::1
|
||||||
# (DE) FoeBud / Digital Courage
|
# (DE) FoeBud / Digital Courage
|
||||||
nameserver 85.214.20.141
|
nameserver 85.214.20.141
|
||||||
# (DE) CCC Berlin
|
# (DE) CCC Berlin
|
||||||
nameserver 195.160.173.53
|
nameserver 195.160.173.53
|
||||||
# (DE) AS250
|
# (DE) AS250
|
||||||
nameserver 194.150.168.168
|
nameserver 194.150.168.168
|
||||||
|
nameserver 2001:4ce8::53
|
||||||
# (DE) Ideal-Hosting
|
# (DE) Ideal-Hosting
|
||||||
nameserver 84.200.69.80
|
nameserver 84.200.69.80
|
||||||
|
nameserver 2001:1608:10:25::1c04:b12f
|
||||||
nameserver 84.200.70.40
|
nameserver 84.200.70.40
|
||||||
|
nameserver 2001:1608:10:25::9249:d69b
|
||||||
# (DK) censurfridns
|
# (DK) censurfridns
|
||||||
nameserver 91.239.100.100
|
nameserver 91.239.100.100
|
||||||
|
nameserver 2001:67c:28a4::
|
||||||
nameserver 89.233.43.71
|
nameserver 89.233.43.71
|
||||||
|
nameserver 2002:d596:2a92:1:71:53::
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
server_tokens off;
|
server_tokens off;
|
||||||
gzip_types text/css text/javascript application/javascript;
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Insert YunoHost panel
|
# Insert YunoHost button + portal overlay
|
||||||
sub_filter </head> '<script type="text/javascript" src="/ynhpanel.js"></script></head>';
|
sub_filter </head> '<script type="text/javascript" src="/ynh_portal.js"></script><link type="text/css" rel="stylesheet" href="/ynh_overlay.css"></link><script type="text/javascript" src="/ynhtheme/custom_portal.js"></script><link type="text/css" rel="stylesheet" href="/ynhtheme/custom_overlay.css"></link></head>';
|
||||||
sub_filter_once on;
|
sub_filter_once on;
|
||||||
# Apply to other mime types than text/html
|
# Apply to other mime types than text/html
|
||||||
sub_filter_types application/xhtml+xml;
|
sub_filter_types application/xhtml+xml;
|
||||||
# Prevent YunoHost panel files from being blocked by specific app rules
|
# Prevent YunoHost panel files from being blocked by specific app rules
|
||||||
location ~ ynhpanel\.(js|json|css) {
|
location ~ (ynh_portal.js|ynh_overlay.css|ynh_userinfo.json) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,14 @@ server {
|
||||||
ssl_session_timeout 5m;
|
ssl_session_timeout 5m;
|
||||||
ssl_session_cache shared:SSL:50m;
|
ssl_session_cache shared:SSL:50m;
|
||||||
|
|
||||||
|
{% 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
|
# 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_ecdh_curve secp521r1:secp384r1:prime256v1;
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers on;
|
||||||
|
@ -38,15 +46,10 @@ server {
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
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';
|
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';
|
||||||
|
|
||||||
# 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
|
|
||||||
# Uncomment the following to 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';
|
|
||||||
|
|
||||||
# Uncomment the following directive after DH generation
|
# Uncomment the following directive after DH generation
|
||||||
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
|
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
|
||||||
#ssl_dhparam /etc/ssl/private/dh2048.pem;
|
#ssl_dhparam /etc/ssl/private/dh2048.pem;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
|
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
|
||||||
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
||||||
|
@ -71,6 +74,10 @@ server {
|
||||||
resolver_timeout 5s;
|
resolver_timeout 5s;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
# Disable gzip to protect against BREACH
|
||||||
|
# Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!)
|
||||||
|
gzip off;
|
||||||
|
|
||||||
access_by_lua_file /usr/share/ssowat/access.lua;
|
access_by_lua_file /usr/share/ssowat/access.lua;
|
||||||
|
|
||||||
include /etc/nginx/conf.d/{{ domain }}.d/*.conf;
|
include /etc/nginx/conf.d/{{ domain }}.d/*.conf;
|
||||||
|
|
|
@ -20,6 +20,14 @@ server {
|
||||||
ssl_session_timeout 5m;
|
ssl_session_timeout 5m;
|
||||||
ssl_session_cache shared:SSL:50m;
|
ssl_session_cache shared:SSL:50m;
|
||||||
|
|
||||||
|
{% 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
|
||||||
|
# Uncomment the following to 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
|
# 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_ecdh_curve secp521r1:secp384r1:prime256v1;
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers on;
|
||||||
|
@ -29,15 +37,10 @@ server {
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
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';
|
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';
|
||||||
|
|
||||||
# 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
|
|
||||||
# Uncomment the following to 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';
|
|
||||||
|
|
||||||
# Uncomment the following directive after DH generation
|
# Uncomment the following directive after DH generation
|
||||||
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
|
# > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048
|
||||||
#ssl_dhparam /etc/ssl/private/dh2048.pem;
|
#ssl_dhparam /etc/ssl/private/dh2048.pem;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
|
# Follows the Web Security Directives from the Mozilla Dev Lab and the Mozilla Obervatory + Partners
|
||||||
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
# https://wiki.mozilla.org/Security/Guidelines/Web_Security
|
||||||
|
@ -51,6 +54,10 @@ server {
|
||||||
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
|
more_set_headers "X-Permitted-Cross-Domain-Policies : none";
|
||||||
more_set_headers "X-Frame-Options : SAMEORIGIN";
|
more_set_headers "X-Frame-Options : SAMEORIGIN";
|
||||||
|
|
||||||
|
# Disable gzip to protect against BREACH
|
||||||
|
# Read https://trac.nginx.org/nginx/ticket/1720 (text/html cannot be disabled!)
|
||||||
|
gzip off;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
return 302 https://$http_host/yunohost/admin;
|
return 302 https://$http_host/yunohost/admin;
|
||||||
}
|
}
|
|
@ -15,10 +15,17 @@ HostKey {{ key }}{% endfor %}
|
||||||
# https://infosec.mozilla.org/guidelines/openssh
|
# https://infosec.mozilla.org/guidelines/openssh
|
||||||
# ##############################################
|
# ##############################################
|
||||||
|
|
||||||
# Keys, ciphers and MACS
|
{% if compatibility == "intermediate" %}
|
||||||
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
|
KexAlgorithms diffie-hellman-group-exchange-sha256
|
||||||
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
Ciphers aes256-ctr,aes192-ctr,aes128-ctr
|
||||||
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
|
MACs hmac-sha2-512,hmac-sha2-256
|
||||||
|
{% else %}
|
||||||
|
# By default use "modern" Mozilla configuration
|
||||||
|
# Keys, ciphers and MACS
|
||||||
|
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
|
||||||
|
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
||||||
|
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
# Use kernel sandbox mechanisms where possible in unprivileged processes
|
# Use kernel sandbox mechanisms where possible in unprivileged processes
|
||||||
UsePrivilegeSeparation sandbox
|
UsePrivilegeSeparation sandbox
|
||||||
|
|
|
@ -20,8 +20,6 @@ mysql:
|
||||||
glances: {}
|
glances: {}
|
||||||
ssh:
|
ssh:
|
||||||
log: /var/log/auth.log
|
log: /var/log/auth.log
|
||||||
ssl:
|
|
||||||
status: null
|
|
||||||
metronome:
|
metronome:
|
||||||
log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err]
|
log: [/var/log/metronome/metronome.log,/var/log/metronome/metronome.err]
|
||||||
slapd:
|
slapd:
|
||||||
|
@ -34,10 +32,9 @@ yunohost-firewall:
|
||||||
need_lock: true
|
need_lock: true
|
||||||
nslcd:
|
nslcd:
|
||||||
log: /var/log/syslog
|
log: /var/log/syslog
|
||||||
nsswitch:
|
nsswitch: null
|
||||||
status: null
|
ssl: null
|
||||||
yunohost:
|
yunohost: null
|
||||||
status: null
|
|
||||||
bind9: null
|
bind9: null
|
||||||
tahoe-lafs: null
|
tahoe-lafs: null
|
||||||
memcached: null
|
memcached: null
|
||||||
|
|
116
debian/changelog
vendored
116
debian/changelog
vendored
|
@ -1,3 +1,119 @@
|
||||||
|
yunohost (3.5.2.2) stable; urgency=low
|
||||||
|
|
||||||
|
- Hotfix for ynh_psql_remove_db (from ljf)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 18 Apr 2019 17:32:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.2.1) stable; urgency=low
|
||||||
|
|
||||||
|
- [fix] Fresh install was broken because of yunohost_admin.conf initialization
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 11 Apr 2019 14:38:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.2) stable; urgency=low
|
||||||
|
|
||||||
|
- Release as stable !
|
||||||
|
- [doc] Update script to automatically generate helper doc
|
||||||
|
- [i18n] Update translations for Catalan, Arabic, Italian
|
||||||
|
|
||||||
|
Thanks to all contributors: Aleks, xaloc, BoF, silkevicious ! <3
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 10 Apr 2019 01:53:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.1.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] enabled/disabled status for sysv services
|
||||||
|
- [fix] Nodejs helpers : use YNH_APP_INSTANCE_NAME instead of YNH_APP_ID (#700)
|
||||||
|
- [fix] nginx diagnosis when there's an error throwing a huge useless traceback. Use Popen instead to display the real error
|
||||||
|
- [fix] service_status returns different type of data if you ask for one or multiple services
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 03 Apr 2019 17:28:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] Fix the dbus interface to get info for services (#698)
|
||||||
|
- [mod] Use ask key for display_text instead and support i18n (#697)
|
||||||
|
- [fix] Rework tools update (#695)
|
||||||
|
- [enh] Nginx conf tweaks for theme (#689)
|
||||||
|
- [fix] Fix argument escaping in getopts (#685, #683)
|
||||||
|
- [enh] Support php versions in ynh_add_fpm_config (#674)
|
||||||
|
- [enh] Check that required services are up before running app install and upgrade (#670)
|
||||||
|
- [doc] Add min version for all helpers (#664)
|
||||||
|
- [enh] Add a setting to control compatibility/security tradeoff for nginx and ssh configurations (#640)
|
||||||
|
- [enh] Hooks to allow apps to extend the recommended DNS configuration (#517)
|
||||||
|
- Misc technical fixes / improvements (0bd781b, fad3edf, 1268872, 847ceca, 26e77b7, b6cff68)
|
||||||
|
- [i18n] Update translation for French, Catalan, Esperanto, Occitan
|
||||||
|
|
||||||
|
Thanks to all contributors: Aleks, Bram, Gabriel Corona, Jibec, Josue, Maniack C, Mélanie C., Quentí, Romuald du Song, ljf, ppr, Xaloc ! <3
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 03 Apr 2019 02:13:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.0.2) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] Make sure that `ynh_system_user_delete` also deletes the group (#680)
|
||||||
|
- [enh] `ynh_systemd_action` : reload-or-restart instead of just reload (#681)
|
||||||
|
|
||||||
|
Last minute fixes by Maniack ;)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 14 Mar 2019 03:45:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.0.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [fix] #675 introduced a bug in nginx conf ...
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 13 Mar 2019 19:23:00 +0000
|
||||||
|
|
||||||
|
yunohost (3.5.0) testing; urgency=low
|
||||||
|
|
||||||
|
Core
|
||||||
|
----
|
||||||
|
|
||||||
|
- [fix] Disable gzip entirely to avoid BREACH attacks (#675)
|
||||||
|
- [fix] Backup tests were broken (#673)
|
||||||
|
- [fix] Backup fails because output directory not empty (#672)
|
||||||
|
- [fix] Reject app password if they contains { or } (#671)
|
||||||
|
- [enh] Allow `display_text` 'fake' argument in manifest.json (#669)
|
||||||
|
- [fix] Optimize dyndns requests (#662)
|
||||||
|
- [enh] Don't add Strict-Transport-Security header in nginx conf if using a selfsigned cert (#661)
|
||||||
|
- [enh] Add apt-transport-https to dependencies (#658)
|
||||||
|
- [enh] Cache results from meltdown vulnerability checker (#656)
|
||||||
|
- [enh] Ensure the tar file is closed during the backup (#655)
|
||||||
|
- [enh] Be able to define hook to trigger when changing a setting (#654)
|
||||||
|
- [enh] Assert dpkg is not broken before app install (#652)
|
||||||
|
- [fix] Loading only one helper file leads to errors because missing getopts (#651)
|
||||||
|
- [enh] Improve / add some messages to improve UX (#650)
|
||||||
|
- [enh] Reload fail2ban instead of restart (#649)
|
||||||
|
- [enh] Add IPv6 resolvers from diyisp.org to resolv.dnsmasq.conf (#639)
|
||||||
|
- [fix] Remove old SMTP port (465) from fail2ban jail.conf (#637)
|
||||||
|
- [enh] Improve protection against indexation from the robots. (#622)
|
||||||
|
- [enh] Allow hooks to return data (#526)
|
||||||
|
- [fix] Do not make version number available from web API to unauthenticated users (#291)
|
||||||
|
- [i18n] Improve Russian and Chinese (Mandarin) translations
|
||||||
|
|
||||||
|
App helpers
|
||||||
|
-----------
|
||||||
|
|
||||||
|
- [enh] Optimize app setting helpers (#663, #676)
|
||||||
|
- [enh] Handle `ynh_install_nodejs` for arm64 / aarch64 (#660)
|
||||||
|
- [enh] Update postgresql helpers (#657)
|
||||||
|
- [enh] Print diff of files when backup by `ynh_backup_if_checksum_is_different` (#648)
|
||||||
|
- [enh] Add app debugger helper (#647)
|
||||||
|
- [fix] Escape double quote before eval in getopts (#646)
|
||||||
|
- [fix] `ynh_local_curl` not using the right url in some cases (#644)
|
||||||
|
- [fix] Get rid of annoying 'unable to initialize frontend' messages (#643)
|
||||||
|
- [enh] Check if dpkg is not broken when calling `ynh_wait_dpkg_free` (#638)
|
||||||
|
- [enh] Warn the packager that `ynh_secure_remove` should be used with only one arg… (#635, #642)
|
||||||
|
- [enh] Add `ynh_script_progression` helper (#634)
|
||||||
|
- [enh] Add `ynh_systemd_action` helper (#633)
|
||||||
|
- [enh] Allow to dig deeper into an archive with `ynh_setup_source` (#630)
|
||||||
|
- [enh] Use getops (#561)
|
||||||
|
- [enh] Add `ynh_check_app_version_changed` helper (#521)
|
||||||
|
- [enh] Add fail2ban helpers (#364)
|
||||||
|
|
||||||
|
Contributors: Alexandre Aubin, Jimmy Monin, Josué Tille, Kayou, Laurent Peuch, Lukas Fülling, Maniack Crudelis, Taekiro, frju365, ljf, opi, yalh76, Алексей
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 13 Mar 2019 16:10:00 +0000
|
||||||
|
|
||||||
yunohost (3.4.2.4) stable; urgency=low
|
yunohost (3.4.2.4) stable; urgency=low
|
||||||
|
|
||||||
- [fix] Meltdown vulnerability checker something outputing trash instead of pure json
|
- [fix] Meltdown vulnerability checker something outputing trash instead of pure json
|
||||||
|
|
2
debian/postinst
vendored
2
debian/postinst
vendored
|
@ -12,7 +12,7 @@ do_configure() {
|
||||||
bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
|
bash /usr/share/yunohost/hooks/conf_regen/15-nginx init
|
||||||
else
|
else
|
||||||
echo "Regenerating configuration, this might take a while..."
|
echo "Regenerating configuration, this might take a while..."
|
||||||
yunohost service regen-conf --output-as none
|
yunohost tools regen-conf --output-as none
|
||||||
|
|
||||||
echo "Launching migrations.."
|
echo "Launching migrations.."
|
||||||
yunohost tools migrations migrate --auto
|
yunohost tools migrations migrate --auto
|
||||||
|
|
|
@ -4,7 +4,12 @@ import os
|
||||||
import glob
|
import glob
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
def render(data):
|
def render(helpers):
|
||||||
|
|
||||||
|
data = { "helpers": helpers,
|
||||||
|
"date": datetime.datetime.now().strftime("%m/%d/%Y"),
|
||||||
|
"version": open("../debian/changelog").readlines()[0].split()[1].strip("()")
|
||||||
|
}
|
||||||
|
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
from ansi2html import Ansi2HTMLConverter
|
from ansi2html import Ansi2HTMLConverter
|
||||||
|
@ -103,7 +108,6 @@ class Parser():
|
||||||
b["usage"] = ""
|
b["usage"] = ""
|
||||||
b["args"] = []
|
b["args"] = []
|
||||||
b["ret"] = ""
|
b["ret"] = ""
|
||||||
b["example"] = ""
|
|
||||||
|
|
||||||
subblocks = '\n'.join(b["comments"]).split("\n\n")
|
subblocks = '\n'.join(b["comments"]).split("\n\n")
|
||||||
|
|
||||||
|
@ -114,17 +118,29 @@ class Parser():
|
||||||
b["brief"] = subblock
|
b["brief"] = subblock
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif subblock.startswith("example"):
|
elif subblock.startswith("example:"):
|
||||||
b["example"] = " ".join(subblock.split()[1:])
|
b["example"] = " ".join(subblock.split()[1:])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
elif subblock.startswith("examples:"):
|
||||||
|
b["examples"] = subblock.split("\n")[1:]
|
||||||
|
continue
|
||||||
|
|
||||||
elif subblock.startswith("usage"):
|
elif subblock.startswith("usage"):
|
||||||
for line in subblock.split("\n"):
|
for line in subblock.split("\n"):
|
||||||
|
|
||||||
if line.startswith("| arg"):
|
if line.startswith("| arg"):
|
||||||
argname = line.split()[2]
|
linesplit = line.split()
|
||||||
argdescr = " ".join(line.split()[4:])
|
argname = linesplit[2]
|
||||||
b["args"].append((argname, argdescr))
|
# Detect that there's a long argument version (-f, --foo - Some description)
|
||||||
|
if argname.endswith(",") and linesplit[3].startswith("--"):
|
||||||
|
argname = argname.strip(",")
|
||||||
|
arglongname = linesplit[3]
|
||||||
|
argdescr = " ".join(linesplit[5:])
|
||||||
|
b["args"].append((argname, arglongname, argdescr))
|
||||||
|
else:
|
||||||
|
argdescr = " ".join(linesplit[4:])
|
||||||
|
b["args"].append((argname, argdescr))
|
||||||
elif line.startswith("| ret"):
|
elif line.startswith("| ret"):
|
||||||
b["ret"] = " ".join(line.split()[2:])
|
b["ret"] = " ".join(line.split()[2:])
|
||||||
else:
|
else:
|
||||||
|
@ -136,9 +152,17 @@ class Parser():
|
||||||
elif subblock.startswith("| arg"):
|
elif subblock.startswith("| arg"):
|
||||||
for line in subblock.split("\n"):
|
for line in subblock.split("\n"):
|
||||||
if line.startswith("| arg"):
|
if line.startswith("| arg"):
|
||||||
argname = line.split()[2]
|
linesplit = line.split()
|
||||||
argdescr = line.split()[4:]
|
argname = linesplit[2]
|
||||||
b["args"].append((argname, argdescr))
|
# Detect that there's a long argument version (-f, --foo - Some description)
|
||||||
|
if argname.endswith(",") and linesplit[3].startswith("--"):
|
||||||
|
argname = argname.strip(",")
|
||||||
|
arglongname = linesplit[3]
|
||||||
|
argdescr = " ".join(linesplit[5:])
|
||||||
|
b["args"].append((argname, arglongname, argdescr))
|
||||||
|
else:
|
||||||
|
argdescr = " ".join(linesplit[4:])
|
||||||
|
b["args"].append((argname, argdescr))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<h1>App helpers</h1>
|
<h1>App helpers</h1>
|
||||||
|
|
||||||
{% for category, helpers in data %}
|
{% for category, helpers in data.helpers %}
|
||||||
|
|
||||||
<h3 style="text-transform: uppercase; font-weight: bold">{{ category }}</h3>
|
<h3 style="text-transform: uppercase; font-weight: bold">{{ category }}</h3>
|
||||||
|
|
||||||
|
@ -27,8 +27,12 @@
|
||||||
<p>
|
<p>
|
||||||
<strong>Arguments</strong>:
|
<strong>Arguments</strong>:
|
||||||
<ul>
|
<ul>
|
||||||
{% for name, descr in h.args %}
|
{% for infos in h.args %}
|
||||||
<li><code>{{ name }}</code> : {{ descr }}</li>
|
{% if infos|length == 2 %}
|
||||||
|
<li><code>{{ infos[0] }}</code> : {{ infos[1] }}</li>
|
||||||
|
{% else %}
|
||||||
|
<li><code>{{ infos[0] }}</code>, <code>{{ infos[1] }}</code> : {{ infos[2] }}</li>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
@ -38,11 +42,25 @@
|
||||||
<strong>Returns</strong>: {{ h.ret }}
|
<strong>Returns</strong>: {{ h.ret }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if h.example %}
|
{% if "example" in h.keys() %}
|
||||||
<p>
|
<p>
|
||||||
<strong>Example</strong>: <code class="helper-code">{{ h.example }}</code>
|
<strong>Example</strong>: <code class="helper-code">{{ h.example }}</code>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if "examples" in h.keys() %}
|
||||||
|
<p>
|
||||||
|
<strong>Examples</strong>:<ul>
|
||||||
|
{% for example in h.examples %}
|
||||||
|
{% if not example.strip().startswith("# ") %}
|
||||||
|
<code class="helper-code">{{ example }}</code>
|
||||||
|
{% else %}
|
||||||
|
{{ example.strip("# ") }}
|
||||||
|
{% endif %}
|
||||||
|
<br>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
{% if h.details %}
|
{% if h.details %}
|
||||||
<p>
|
<p>
|
||||||
<strong>Details</strong>:
|
<strong>Details</strong>:
|
||||||
|
@ -63,6 +81,8 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<p>Generated by <a href="https://github.com/YunoHost/yunohost/blob/stretch-unstable/doc/generate_helper_doc.py">this script</a> on {{data.date}} (Yunohost version {{data.version}})</p>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/*=================================================
|
/*=================================================
|
||||||
|
|
|
@ -29,13 +29,13 @@
|
||||||
"app_not_properly_removed": "لم يتم حذف تطبيق {app:s} بشكلٍ جيّد",
|
"app_not_properly_removed": "لم يتم حذف تطبيق {app:s} بشكلٍ جيّد",
|
||||||
"app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes",
|
"app_package_need_update": "The app {app} package needs to be updated to follow YunoHost changes",
|
||||||
"app_removed": "تمت إزالة تطبيق {app:s}",
|
"app_removed": "تمت إزالة تطبيق {app:s}",
|
||||||
"app_requirements_checking": "جار فحص الحزم اللازمة لـ {app} ...",
|
"app_requirements_checking": "جار فحص الحزم اللازمة لـ {app}…",
|
||||||
"app_requirements_failed": "Unable to meet requirements for {app}: {error}",
|
"app_requirements_failed": "Unable to meet requirements for {app}: {error}",
|
||||||
"app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}",
|
"app_requirements_unmeet": "Requirements are not met for {app}, the package {pkgname} ({version}) must be {spec}",
|
||||||
"app_sources_fetch_failed": "تعذرت عملية جلب مصادر الملفات",
|
"app_sources_fetch_failed": "تعذرت عملية جلب مصادر الملفات",
|
||||||
"app_unknown": "برنامج مجهول",
|
"app_unknown": "برنامج مجهول",
|
||||||
"app_unsupported_remote_type": "Unsupported remote type used for the app",
|
"app_unsupported_remote_type": "Unsupported remote type used for the app",
|
||||||
"app_upgrade_app_name": "جارٍ تحديث برنامج {app}...",
|
"app_upgrade_app_name": "جارٍ تحديث تطبيق {app}…",
|
||||||
"app_upgrade_failed": "تعذرت عملية ترقية {app:s}",
|
"app_upgrade_failed": "تعذرت عملية ترقية {app:s}",
|
||||||
"app_upgrade_some_app_failed": "تعذرت عملية ترقية بعض البرمجيات",
|
"app_upgrade_some_app_failed": "تعذرت عملية ترقية بعض البرمجيات",
|
||||||
"app_upgraded": "تم تحديث التطبيق {app:s}",
|
"app_upgraded": "تم تحديث التطبيق {app:s}",
|
||||||
|
@ -413,5 +413,18 @@
|
||||||
"service_description_mysql": "يقوم بتخزين بيانات التطبيقات (قواعد بيانات SQL)",
|
"service_description_mysql": "يقوم بتخزين بيانات التطبيقات (قواعد بيانات SQL)",
|
||||||
"service_description_rspamd": "يقوم بتصفية البريد المزعج و إدارة ميزات أخرى للبريد",
|
"service_description_rspamd": "يقوم بتصفية البريد المزعج و إدارة ميزات أخرى للبريد",
|
||||||
"service_description_yunohost-firewall": "يريد فتح و غلق منافذ الإتصال إلى الخدمات",
|
"service_description_yunohost-firewall": "يريد فتح و غلق منافذ الإتصال إلى الخدمات",
|
||||||
"users_available": "المستخدمون المتوفرون:"
|
"users_available": "المستخدمون المتوفرون:",
|
||||||
|
"aborting": "إلغاء.",
|
||||||
|
"admin_password_too_long": "يرجى اختيار كلمة سرية أقصر مِن 127 حرف",
|
||||||
|
"app_not_upgraded": "لم يتم تحديث التطبيقات التالية: {apps}",
|
||||||
|
"app_start_install": "جارٍ تثبيت التطبيق {app}…",
|
||||||
|
"app_start_remove": "جارٍ حذف التطبيق {app}…",
|
||||||
|
"app_start_restore": "جارٍ استرجاع التطبيق {app}…",
|
||||||
|
"app_upgrade_several_apps": "سوف يتم تحديث التطبيقات التالية: {apps}",
|
||||||
|
"ask_new_domain": "نطاق جديد",
|
||||||
|
"ask_new_path": "مسار جديد",
|
||||||
|
"global_settings_setting_security_password_admin_strength": "قوة الكلمة السرية الإدارية",
|
||||||
|
"global_settings_setting_security_password_user_strength": "قوة الكلمة السرية للمستخدم",
|
||||||
|
"log_app_addaccess": "إضافة ترخيص بالنفاذ إلى '{}'",
|
||||||
|
"password_too_simple_1": "يجب أن يكون طول الكلمة السرية على الأقل 8 حروف"
|
||||||
}
|
}
|
||||||
|
|
1
locales/bn_BD.json
Normal file
1
locales/bn_BD.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
190
locales/ca.json
190
locales/ca.json
|
@ -21,5 +21,193 @@
|
||||||
"app_location_already_used": "L'aplicació '{app}' ja està instal·lada en aquest camí ({path})",
|
"app_location_already_used": "L'aplicació '{app}' ja està instal·lada en aquest camí ({path})",
|
||||||
"app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'",
|
"app_make_default_location_already_used": "No es pot fer l'aplicació '{app}' per defecte en el domini {domain} ja que ja és utilitzat per una altra aplicació '{other_app}'",
|
||||||
"app_location_install_failed": "No s'ha pogut instal·lar l'aplicació en aquest camí ja que entra en conflicte amb l'aplicació '{other_app}' ja instal·lada a '{other_path}'",
|
"app_location_install_failed": "No s'ha pogut instal·lar l'aplicació en aquest camí ja que entra en conflicte amb l'aplicació '{other_app}' ja instal·lada a '{other_path}'",
|
||||||
"app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}"
|
"app_location_unavailable": "Aquesta url no està disponible o entra en conflicte amb aplicacions ja instal·lades:\n{apps:s}",
|
||||||
|
"app_manifest_invalid": "Manifest d'aplicació incorrecte: {error}",
|
||||||
|
"app_no_upgrade": "No hi ha cap aplicació per actualitzar",
|
||||||
|
"app_not_correctly_installed": "{app:s} sembla estar mal instal·lada",
|
||||||
|
"app_not_installed": "{app:s} no està instal·lada",
|
||||||
|
"app_not_properly_removed": "{app:s} no s'ha pogut suprimir correctament",
|
||||||
|
"app_package_need_update": "El paquet de l'aplicació {app} ha de ser actualitzat per poder seguir els canvis de YunoHost",
|
||||||
|
"app_removed": "{app:s} ha estat suprimida",
|
||||||
|
"app_requirements_checking": "Verificació dels paquets requerits per {app}…",
|
||||||
|
"app_requirements_failed": "No es poden satisfer els requeriments per {app}: {error}",
|
||||||
|
"app_requirements_unmeet": "No es compleixen els requeriments per {app}, el paquet {pkgname} ({version}) ha de ser {spec}",
|
||||||
|
"app_sources_fetch_failed": "No s'han pogut carregar els fitxers font",
|
||||||
|
"app_unknown": "Aplicació desconeguda",
|
||||||
|
"app_unsupported_remote_type": "El tipus remot utilitzat per l'aplicació no està suportat",
|
||||||
|
"app_upgrade_app_name": "Actualitzant l'aplicació {app}…",
|
||||||
|
"app_upgrade_failed": "No s'ha pogut actualitzar {app:s}",
|
||||||
|
"app_upgrade_some_app_failed": "No s'han pogut actualitzar algunes aplicacions",
|
||||||
|
"app_upgraded": "{app:s} ha estat actualitzada",
|
||||||
|
"appslist_corrupted_json": "No s'han pogut carregar les llistes d'aplicacions. Sembla que {filename:s} està danyat.",
|
||||||
|
"appslist_could_not_migrate": "No s'ha pogut migrar la llista d'aplicacions {appslist:s}! No s'ha pogut analitzar la URL... L'antic cronjob s'ha guardat a {bkp_file:s}.",
|
||||||
|
"appslist_fetched": "S'ha descarregat la llista d'aplicacions {appslist:s} correctament",
|
||||||
|
"appslist_migrating": "Migrant la llista d'aplicacions {appslist:s}…",
|
||||||
|
"appslist_name_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb el nom {name:s}.",
|
||||||
|
"appslist_removed": "S'ha eliminat la llista d'aplicacions {appslist:s}",
|
||||||
|
"appslist_retrieve_bad_format": "L'arxiu obtingut per la llista d'aplicacions {appslist:s} no és vàlid",
|
||||||
|
"appslist_retrieve_error": "No s'ha pogut obtenir la llista d'aplicacions remota {appslist:s}: {error:s}",
|
||||||
|
"appslist_unknown": "La llista d'aplicacions {appslist:s} es desconeguda.",
|
||||||
|
"appslist_url_already_tracked": "Ja hi ha una llista d'aplicacions registrada amb al URL {url:s}.",
|
||||||
|
"ask_current_admin_password": "Contrasenya d'administrador actual",
|
||||||
|
"ask_email": "Correu electrònic",
|
||||||
|
"ask_firstname": "Nom",
|
||||||
|
"ask_lastname": "Cognom",
|
||||||
|
"ask_list_to_remove": "Llista per a suprimir",
|
||||||
|
"ask_main_domain": "Domini principal",
|
||||||
|
"ask_new_admin_password": "Nova contrasenya d'administrador",
|
||||||
|
"ask_password": "Contrasenya",
|
||||||
|
"ask_path": "Camí",
|
||||||
|
"backup_abstract_method": "Encara no s'ha implementat aquest mètode de copia de seguretat",
|
||||||
|
"backup_action_required": "S'ha d'especificar què s'ha de guardar",
|
||||||
|
"backup_app_failed": "No s'ha pogut fer la còpia de seguretat de l'aplicació \"{app:s}\"",
|
||||||
|
"backup_applying_method_borg": "Enviant tots els fitxers de la còpia de seguretat al repositori borg-backup…",
|
||||||
|
"backup_applying_method_copy": "Còpia de tots els fitxers a la còpia de seguretat…",
|
||||||
|
"backup_applying_method_custom": "Crida del mètode de còpia de seguretat personalitzat \"{method:s}\"…",
|
||||||
|
"backup_applying_method_tar": "Creació de l'arxiu tar de la còpia de seguretat…",
|
||||||
|
"backup_archive_app_not_found": "L'aplicació \"{app:s}\" no es troba dins l'arxiu de la còpia de seguretat",
|
||||||
|
"backup_archive_broken_link": "No s'ha pogut accedir a l'arxiu de la còpia de seguretat (enllaç invàlid cap a {path:s})",
|
||||||
|
"backup_archive_mount_failed": "No s'ha pogut carregar l'arxiu de la còpia de seguretat",
|
||||||
|
"backup_archive_name_exists": "Ja hi ha una còpia de seguretat amb aquest nom",
|
||||||
|
"backup_archive_name_unknown": "Còpia de seguretat local \"{name:s}\" desconeguda",
|
||||||
|
"backup_archive_open_failed": "No s'ha pogut obrir l'arxiu de la còpia de seguretat",
|
||||||
|
"backup_archive_system_part_not_available": "La part \"{part:s}\" del sistema no està disponible en aquesta copia de seguretat",
|
||||||
|
"backup_archive_writing_error": "No es poden afegir arxius a l'arxiu comprimit de la còpia de seguretat",
|
||||||
|
"backup_ask_for_copying_if_needed": "Alguns fitxers no s'han pogut preparar per la còpia de seguretat utilitzant el mètode que evita malgastar espai del sistema temporalment. Per fer la còpia de seguretat, s'han d'utilitzar {size:s}MB temporalment. Hi esteu d'acord?",
|
||||||
|
"backup_borg_not_implemented": "El mètode de còpia de seguretat Borg encara no està implementat",
|
||||||
|
"backup_cant_mount_uncompress_archive": "No es pot carregar en mode de lectura només el directori de l'arxiu descomprimit",
|
||||||
|
"backup_cleaning_failed": "No s'ha pogut netejar el directori temporal de la còpia de seguretat",
|
||||||
|
"backup_copying_to_organize_the_archive": "Copiant {size:s}MB per organitzar l'arxiu",
|
||||||
|
"backup_couldnt_bind": "No es pot lligar {src:s} amb {dest:s}.",
|
||||||
|
"backup_created": "S'ha creat la còpia de seguretat",
|
||||||
|
"backup_creating_archive": "Creant l'arxiu de la còpia de seguretat…",
|
||||||
|
"aborting": "Avortant.",
|
||||||
|
"app_not_upgraded": "Les següents aplicacions no s'han actualitzat: {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}…",
|
||||||
|
"app_start_restore": "Recuperant l'aplicació {app}…",
|
||||||
|
"app_upgrade_several_apps": "S'actualitzaran les següents aplicacions: {apps}",
|
||||||
|
"ask_new_domain": "Nou domini",
|
||||||
|
"ask_new_path": "Nou camí",
|
||||||
|
"backup_actually_backuping": "S'està creant un arxiu de còpia de seguretat a partir dels fitxers recuperats…",
|
||||||
|
"backup_creation_failed": "Ha fallat la creació de la còpia de seguretat",
|
||||||
|
"backup_csv_addition_failed": "No s'han pogut afegir fitxers per a fer-ne la còpia de seguretat al fitxer CSV",
|
||||||
|
"backup_csv_creation_failed": "No s'ha pogut crear el fitxer CSV necessari per a futures operacions de recuperació",
|
||||||
|
"backup_custom_backup_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"backup\"",
|
||||||
|
"backup_custom_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"mount\"",
|
||||||
|
"backup_custom_need_mount_error": "El mètode de còpia de seguretat personalitzat ha fallat a l'etapa \"need_mount\"",
|
||||||
|
"backup_delete_error": "No s'ha pogut suprimir \"{path:s}\"",
|
||||||
|
"backup_deleted": "S'ha suprimit la còpia de seguretat",
|
||||||
|
"backup_extracting_archive": "Extraient l'arxiu de la còpia de seguretat…",
|
||||||
|
"backup_hook_unknown": "Script de còpia de seguretat \"{hook:s}\" desconegut",
|
||||||
|
"backup_invalid_archive": "Arxiu de còpia de seguretat no vàlid",
|
||||||
|
"backup_method_borg_finished": "La còpia de seguretat a borg ha acabat",
|
||||||
|
"backup_method_copy_finished": "La còpia de la còpia de seguretat ha acabat",
|
||||||
|
"backup_method_custom_finished": "El mètode de còpia de seguretat personalitzat \"{method:s}\" ha acabat",
|
||||||
|
"backup_method_tar_finished": "S'ha creat l'arxiu de còpia de seguretat tar",
|
||||||
|
"backup_mount_archive_for_restore": "Preparant l'arxiu per la restauració…",
|
||||||
|
"good_practices_about_user_password": "Esteu a punt de definir una nova contrasenya d'usuari. La contrasenya ha de tenir un mínim de 8 caràcters ; tot i que és de bona pràctica utilitzar una contrasenya més llarga (és a dir una frase de contrasenya) i/o utilitzar diferents tipus de caràcters (majúscules, minúscules, dígits i caràcters especials).",
|
||||||
|
"password_listed": "Aquesta contrasenya és una de les més utilitzades en el món. Si us plau utilitzeu-ne una més única.",
|
||||||
|
"password_too_simple_1": "La contrasenya ha de tenir un mínim de 8 caràcters",
|
||||||
|
"password_too_simple_2": "La contrasenya ha de tenir un mínim de 8 caràcters i ha de contenir dígits, majúscules i minúscules",
|
||||||
|
"password_too_simple_3": "La contrasenya ha de tenir un mínim de 8 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
|
||||||
|
"password_too_simple_4": "La contrasenya ha de tenir un mínim de 12 caràcters i tenir dígits, majúscules, minúscules i caràcters especials",
|
||||||
|
"backup_no_uncompress_archive_dir": "El directori de l'arxiu descomprimit no existeix",
|
||||||
|
"backup_nothings_done": "No hi ha res a guardar",
|
||||||
|
"backup_output_directory_forbidden": "Directori de sortida no permès. Les còpies de seguretat no es poden crear ni dins els directoris /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ni dins els subdirectoris /home/yunohost.backup/archives",
|
||||||
|
"backup_output_directory_not_empty": "El directori de sortida no està buit",
|
||||||
|
"backup_output_directory_required": "Heu d'especificar un directori de sortida per la còpia de seguretat",
|
||||||
|
"backup_output_symlink_dir_broken": "Teniu un enllaç simbòlic trencat en lloc del directori dels arxius '{path:s}'. Pot ser teniu una configuració per la còpia de seguretat específica en un altre sistema de fitxers, si és el cas segurament heu oblidat muntar o connectar el disc dur o la clau USB.",
|
||||||
|
"backup_php5_to_php7_migration_may_fail": "No s'ha pogut convertir l'arxiu per suportar php7, la restauració de les vostres aplicacions pot fallar (raó: {error:s})",
|
||||||
|
"backup_running_hooks": "Executant els scripts de la còpia de seguretat…",
|
||||||
|
"backup_system_part_failed": "No s'ha pogut fer la còpia de seguretat de la part \"{part:s}\" del sistema",
|
||||||
|
"backup_unable_to_organize_files": "No s'han pogut organitzar els fitxers dins de l'arxiu amb el mètode ràpid",
|
||||||
|
"backup_with_no_backup_script_for_app": "L'aplicació {app:s} no té un script de còpia de seguretat. Serà ignorat.",
|
||||||
|
"backup_with_no_restore_script_for_app": "L'aplicació {app:s} no té un script de restauració, no podreu restaurar automàticament la còpia de seguretat d'aquesta aplicació.",
|
||||||
|
"certmanager_acme_not_configured_for_domain": "El certificat pel domini {domain:s} sembla que no està instal·lat correctament. Si us plau executeu primer cert-install per aquest domini.",
|
||||||
|
"certmanager_attempt_to_renew_nonLE_cert": "El certificat pel domini {domain:s} no ha estat emès per Let's Encrypt. No es pot renovar automàticament!",
|
||||||
|
"certmanager_attempt_to_renew_valid_cert": "El certificat pel domini {domain:s} està a punt de caducar! Utilitzeu --force per ometre",
|
||||||
|
"certmanager_attempt_to_replace_valid_cert": "Esteu intentant sobreescriure un certificat correcte i vàlid pel domini {domain:s}! (Utilitzeu --force per ometre)",
|
||||||
|
"certmanager_cannot_read_cert": "S'ha produït un error al intentar obrir el certificat actual pel domini {domain:s} (arxiu: {file:s}), raó: {reason:s}",
|
||||||
|
"certmanager_cert_install_success": "S'ha instal·lat correctament un certificat Let's Encrypt pel domini {domain:s}!",
|
||||||
|
"certmanager_cert_install_success_selfsigned": "S'ha instal·lat correctament un certificat auto-signat pel domini {domain:s}!",
|
||||||
|
"certmanager_cert_renew_success": "S'ha renovat correctament el certificat Let's Encrypt pel domini {domain:s}!",
|
||||||
|
"certmanager_cert_signing_failed": "No s'ha pogut firmar el nou certificat",
|
||||||
|
"certmanager_certificate_fetching_or_enabling_failed": "Sembla que l'activació del nou certificat per {domain:s} ha fallat…",
|
||||||
|
"certmanager_conflicting_nginx_file": "No s'ha pogut preparar el domini per al desafiament ACME: l'arxiu de configuració nginx {filepath:s} entra en conflicte i s'ha d'eliminar primer",
|
||||||
|
"certmanager_couldnt_fetch_intermediate_cert": "S'ha exhaurit el temps d'esperar al intentar recollir el certificat intermedi des de Let's Encrypt. La instal·lació/renovació del certificat s'ha cancel·lat - torneu a intentar-ho més tard.",
|
||||||
|
"certmanager_domain_cert_not_selfsigned": "El certificat pel domini {domain:s} no és auto-signat Esteu segur de voler canviar-lo? (Utilitzeu --force per fer-ho)",
|
||||||
|
"certmanager_domain_dns_ip_differs_from_public_ip": "El registre DNS \"A\" pel domini {domain:s} és diferent a l'adreça IP d'aquest servidor. Si heu modificat recentment el registre A, si us plau espereu a que es propagui (hi ha eines per verificar la propagació disponibles a internet). (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
|
||||||
|
"certmanager_domain_http_not_working": "Sembla que el domini {domain:s} no és accessible via HTTP. Si us plau verifiqueu que les configuracions DNS i nginx siguin correctes",
|
||||||
|
"certmanager_domain_not_resolved_locally": "El domini {domain:s} no es pot resoldre dins del vostre servidor YunoHost. Això pot passar si heu modificat recentment el registre DNS. Si és així, si us plau espereu unes hores per a que es propagui. Si el problema continua, considereu afegir {domain:s} a /etc/hosts. (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
|
||||||
|
"certmanager_domain_unknown": "Domini desconegut {domain:s}",
|
||||||
|
"certmanager_error_no_A_record": "No s'ha trobat cap registre DNS \"A\" per {domain:s}. Heu de fer que el vostre nom de domini apunti cap a la vostra màquina per tal de poder instal·lar un certificat Let's Encrypt! (Si sabeu el que esteu fent, podeu utilitzar --no-checks per desactivar aquestes comprovacions.)",
|
||||||
|
"certmanager_hit_rate_limit": "S'han emès massa certificats recentment per aquest mateix conjunt de dominis {domain:s}. Si us plau torneu-ho a intentar més tard. Consulteu https://letsencrypt.org/docs/rate-limits/ per obtenir més detalls",
|
||||||
|
"certmanager_http_check_timeout": "S'ha exhaurit el temps d'espera quan el servidor ha intentat contactar amb ell mateix via HTTP utilitzant la seva adreça IP pública (domini domain:s} amb IP {ip:s}). Pot ser degut a hairpinning o a que el talla focs/router al que està connectat el servidor estan mal configurats.",
|
||||||
|
"certmanager_no_cert_file": "No s'ha pogut llegir l'arxiu del certificat pel domini {domain:s} (fitxer: {file:s})",
|
||||||
|
"certmanager_self_ca_conf_file_not_found": "No s'ha trobat el fitxer de configuració per l'autoritat del certificat auto-signat (fitxer: {file:s})",
|
||||||
|
"certmanager_unable_to_parse_self_CA_name": "No s'ha pogut analitzar el nom de l'autoritat del certificat auto-signat (fitxer: {file:s})",
|
||||||
|
"confirm_app_install_warning": "Atenció: aquesta aplicació funciona però no està ben integrada amb YunoHost. Algunes característiques com la autenticació única i la còpia de seguretat/restauració poden no estar disponibles. Voleu instal·lar-la de totes maneres? [{answers:s}] ",
|
||||||
|
"confirm_app_install_danger": "ATENCIÓ! Aquesta aplicació encara és experimental (si no és que no funciona directament) i és probable que trenqui el sistema! No hauríeu d'instal·lar-la a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
|
||||||
|
"confirm_app_install_thirdparty": "ATENCIÓ! La instal·lació d'aplicacions de terceres parts pot comprometre la integritat i seguretat del seu sistema. Faci-ho sota la seva responsabilitat.No hauríeu d'instal·lar-ne a no ser que sapigueu el que feu. Esteu segurs de voler córrer aquest risc? [{answers:s}] ",
|
||||||
|
"custom_app_url_required": "Heu de especificar una URL per actualitzar la vostra aplicació personalitzada {app:s}",
|
||||||
|
"custom_appslist_name_required": "Heu d'especificar un nom per la vostra llista d'aplicacions personalitzada",
|
||||||
|
"diagnosis_debian_version_error": "No s'ha pogut obtenir la versió Debian: {error}",
|
||||||
|
"diagnosis_kernel_version_error": "No s'ha pogut obtenir la versió del nucli: {error}",
|
||||||
|
"diagnosis_monitor_disk_error": "No es poden monitorar els discs: {error}",
|
||||||
|
"diagnosis_monitor_network_error": "No es pot monitorar la xarxa: {error}",
|
||||||
|
"diagnosis_monitor_system_error": "No es pot monitorar el sistema: {error}",
|
||||||
|
"diagnosis_no_apps": "No hi ha cap aplicació instal·lada",
|
||||||
|
"admin_password_too_long": "Trieu una contrasenya de menys de 127 caràcters",
|
||||||
|
"dpkg_is_broken": "No es pot fer això en aquest instant perquè dpkg/apt (els gestors de paquets del sistema) sembla estar mal configurat... Podeu intentar solucionar-ho connectant-vos per ssh i executant \"sudo dpkg --configure -a\".",
|
||||||
|
"dnsmasq_isnt_installed": "sembla que dnsmasq no està instal·lat, executeu \"apt-get remove bind9 && apt-get install dnsmasq\"",
|
||||||
|
"domain_cannot_remove_main": "No es pot eliminar el domini principal. S'ha d'establir un nou domini primer",
|
||||||
|
"domain_cert_gen_failed": "No s'ha pogut generar el certificat",
|
||||||
|
"domain_created": "S'ha creat el domini",
|
||||||
|
"domain_creation_failed": "No s'ha pogut crear el domini",
|
||||||
|
"domain_deleted": "S'ha eliminat el domini",
|
||||||
|
"domain_deletion_failed": "No s'ha pogut eliminar el domini",
|
||||||
|
"domain_exists": "El domini ja existeix",
|
||||||
|
"app_action_cannot_be_ran_because_required_services_down": "Aquesta aplicació necessita serveis que estan aturats. Abans de continuar, hauríeu d'intentar arrancar de nou els serveis següents (i també investigar perquè estan aturats) : {services}",
|
||||||
|
"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ó.",
|
||||||
|
"domain_dyndns_already_subscribed": "Ja us heu subscrit a un domini DynDNS",
|
||||||
|
"domain_dyndns_dynette_is_unreachable": "No s'ha pogut abastar la dynette YunoHost, o bé YunoHost no està connectat a internet correctament o bé el servidor dynette està caigut. Error: {error}",
|
||||||
|
"domain_dyndns_invalid": "Domini no vàlid per utilitzar amb DynDNS",
|
||||||
|
"domain_dyndns_root_unknown": "Domini DynDNS principal desconegut",
|
||||||
|
"domain_hostname_failed": "No s'ha pogut establir un nou nom d'amfitrió",
|
||||||
|
"domain_uninstall_app_first": "Hi ha una o més aplicacions instal·lades en aquest domini. Desinstal·leu les abans d'eliminar el domini",
|
||||||
|
"domain_unknown": "Domini desconegut",
|
||||||
|
"domain_zone_exists": "El fitxer de zona DNS ja existeix",
|
||||||
|
"domain_zone_not_found": "No s'ha trobat el fitxer de zona DNS pel domini {:s}",
|
||||||
|
"domains_available": "Dominis disponibles:",
|
||||||
|
"done": "Fet",
|
||||||
|
"downloading": "Descarregant…",
|
||||||
|
"dyndns_could_not_check_provide": "No s'ha pogut verificar si {provider:s} pot oferir {domain:s}.",
|
||||||
|
"dyndns_could_not_check_available": "No s'ha pogut verificar la disponibilitat de {domain:s} a {provider:s}.",
|
||||||
|
"dyndns_ip_update_failed": "No s'ha pogut actualitzar l'adreça IP al DynDNS",
|
||||||
|
"dyndns_ip_updated": "S'ha actualitzat l'adreça IP al DynDNS",
|
||||||
|
"dyndns_key_generating": "S'està generant la clau DNS, això pot trigar una estona…",
|
||||||
|
"dyndns_key_not_found": "No s'ha trobat la clau DNS pel domini",
|
||||||
|
"dyndns_no_domain_registered": "No hi ha cap domini registrat amb DynDNS",
|
||||||
|
"dyndns_registered": "S'ha registrat el domini DynDNS",
|
||||||
|
"dyndns_registration_failed": "No s'ha pogut registrar el domini DynDNS: {error:s}",
|
||||||
|
"dyndns_domain_not_provided": "El proveïdor {provider:s} no pot oferir el domini {domain:s}.",
|
||||||
|
"dyndns_unavailable": "El domini {domain:s} no està disponible.",
|
||||||
|
"executing_command": "Execució de l'ordre « {command:s} »…",
|
||||||
|
"executing_script": "Execució de l'script « {script:s} »…",
|
||||||
|
"extracting": "Extracció en curs…",
|
||||||
|
"dyndns_cron_installed": "S'ha instal·lat la tasca cron pel DynDNS",
|
||||||
|
"dyndns_cron_remove_failed": "No s'ha pogut eliminar la tasca cron pel DynDNS",
|
||||||
|
"dyndns_cron_removed": "S'ha eliminat la tasca cron pel DynDNS",
|
||||||
|
"experimental_feature": "Atenció: aquesta funcionalitat és experimental i no es considera estable, no s'ha d'utilitzar a excepció de saber el que esteu fent.",
|
||||||
|
"field_invalid": "Camp incorrecte « {:s} »",
|
||||||
|
"file_does_not_exist": "El camí {path:s} no existeix.",
|
||||||
|
"firewall_reload_failed": "No s'ha pogut tornar a carregar el tallafoc",
|
||||||
|
"firewall_reloaded": "S'ha tornat a carregar el tallafoc",
|
||||||
|
"firewall_rules_cmd_failed": "No s'han pogut aplicar algunes regles del tallafoc. Mireu el registre per a més informació.",
|
||||||
|
"format_datetime_short": "%d/%m/%Y %H:%M",
|
||||||
|
"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}"
|
||||||
}
|
}
|
||||||
|
|
1
locales/el.json
Normal file
1
locales/el.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -4,6 +4,8 @@
|
||||||
"admin_password": "Administration password",
|
"admin_password": "Administration password",
|
||||||
"admin_password_change_failed": "Unable to change password",
|
"admin_password_change_failed": "Unable to change password",
|
||||||
"admin_password_changed": "The administration password has been changed",
|
"admin_password_changed": "The administration password has been changed",
|
||||||
|
"app_action_cannot_be_ran_because_required_services_down": "This app requires some services which are currently down. Before continuing, you should try to restart the following services (and possibly investigate why they are down) : {services}",
|
||||||
|
"admin_password_too_long": "Please choose a password shorter than 127 characters",
|
||||||
"app_already_installed": "{app:s} is already installed",
|
"app_already_installed": "{app:s} is already installed",
|
||||||
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
|
"app_already_installed_cant_change_url": "This app is already installed. The url cannot be changed just by this function. Look into `app changeurl` if it's available.",
|
||||||
"app_already_up_to_date": "{app:s} is already up to date",
|
"app_already_up_to_date": "{app:s} is already up to date",
|
||||||
|
@ -112,7 +114,7 @@
|
||||||
"backup_output_directory_forbidden": "Forbidden output directory. Backups can't be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders",
|
"backup_output_directory_forbidden": "Forbidden output directory. Backups can't be created in /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var or /home/yunohost.backup/archives sub-folders",
|
||||||
"backup_output_directory_not_empty": "The output directory is not empty",
|
"backup_output_directory_not_empty": "The output directory is not empty",
|
||||||
"backup_output_directory_required": "You must provide an output directory for the backup",
|
"backup_output_directory_required": "You must provide an output directory for the backup",
|
||||||
"backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard dirve or usb key.",
|
"backup_output_symlink_dir_broken": "You have a broken symlink instead of your archives directory '{path:s}'. You may have a specific setup to backup your data on an other filesystem, in this case you probably forgot to remount or plug your hard drive or usb key.",
|
||||||
"backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support php7, your php apps may fail to restore (reason: {error:s})",
|
"backup_php5_to_php7_migration_may_fail": "Could not convert your archive to support php7, your php apps may fail to restore (reason: {error:s})",
|
||||||
"backup_running_hooks": "Running backup hooks…",
|
"backup_running_hooks": "Running backup hooks…",
|
||||||
"backup_system_part_failed": "Unable to backup the '{part:s}' system part",
|
"backup_system_part_failed": "Unable to backup the '{part:s}' system part",
|
||||||
|
@ -199,7 +201,7 @@
|
||||||
"firewall_reloaded": "The firewall has been reloaded",
|
"firewall_reloaded": "The firewall has been reloaded",
|
||||||
"firewall_rules_cmd_failed": "Some firewall rules commands have failed. For more information, see the log.",
|
"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",
|
"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 choice for setting {setting:s}, received '{choice:s}' but available choices are : {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_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_open_settings": "Failed to open settings file, reason: {reason:s}",
|
||||||
"global_settings_cant_serialize_settings": "Failed to serialize settings data, reason: {reason:s}",
|
"global_settings_cant_serialize_settings": "Failed to serialize settings data, reason: {reason:s}",
|
||||||
|
@ -210,15 +212,18 @@
|
||||||
"global_settings_setting_example_enum": "Example enum option",
|
"global_settings_setting_example_enum": "Example enum option",
|
||||||
"global_settings_setting_example_int": "Example int option",
|
"global_settings_setting_example_int": "Example int option",
|
||||||
"global_settings_setting_example_string": "Example string option",
|
"global_settings_setting_example_string": "Example string option",
|
||||||
|
"global_settings_setting_security_nginx_compatibility": "Compatibility vs. security tradeoff for the web server nginx. Affects the ciphers (and other security-related aspects)",
|
||||||
"global_settings_setting_security_password_admin_strength": "Admin password strength",
|
"global_settings_setting_security_password_admin_strength": "Admin password strength",
|
||||||
"global_settings_setting_security_password_user_strength": "User password strength",
|
"global_settings_setting_security_password_user_strength": "User password strength",
|
||||||
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding it and save it in /etc/yunohost/unkown_settings.json",
|
"global_settings_setting_security_ssh_compatibility": "Compatibility vs. security tradeoff for the SSH server. Affects the ciphers (and other security-related aspects)",
|
||||||
|
"global_settings_unknown_setting_from_settings_file": "Unknown key in settings: '{setting_key:s}', discarding 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_service_ssh_allow_deprecated_dsa_hostkey": "Allow the use of (deprecated) DSA hostkey for the SSH daemon configuration",
|
||||||
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
|
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's 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 - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind 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 - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind 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 - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
||||||
"hook_exec_failed": "Script execution failed: {path:s}",
|
"hook_exec_failed": "Script execution failed: {path:s}",
|
||||||
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
|
"hook_exec_not_terminated": "Script execution did not finish properly: {path:s}",
|
||||||
|
"hook_json_return_error": "Failed to read return from hook {path:s}. Error: {msg:s}. Raw content: {raw_content}",
|
||||||
"hook_list_by_invalid": "Invalid property to list hook by",
|
"hook_list_by_invalid": "Invalid property to list hook by",
|
||||||
"hook_name_unknown": "Unknown hook name '{name:s}'",
|
"hook_name_unknown": "Unknown hook name '{name:s}'",
|
||||||
"installation_complete": "Installation complete",
|
"installation_complete": "Installation complete",
|
||||||
|
@ -257,7 +262,7 @@
|
||||||
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
|
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
|
||||||
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
|
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
|
||||||
"log_service_enable": "Enable '{}' service",
|
"log_service_enable": "Enable '{}' service",
|
||||||
"log_service_regen_conf": "Regenerate system configurations '{}'",
|
"log_regen_conf": "Regenerate system configurations '{}'",
|
||||||
"log_user_create": "Add '{}' user",
|
"log_user_create": "Add '{}' user",
|
||||||
"log_user_delete": "Delete '{}' user",
|
"log_user_delete": "Delete '{}' user",
|
||||||
"log_user_update": "Update information of '{}' user",
|
"log_user_update": "Update information of '{}' user",
|
||||||
|
@ -294,7 +299,8 @@
|
||||||
"migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords",
|
"migration_description_0006_sync_admin_and_root_passwords": "Synchronize admin and root passwords",
|
||||||
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)",
|
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "Let the SSH configuration be managed by YunoHost (step 1, automatic)",
|
||||||
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
|
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Let the SSH configuration be managed by YunoHost (step 2, manual)",
|
||||||
"migration_description_0009_migrate_to_apps_json": "Remove deprecated appslists and use the new unified 'apps.json' list instead.",
|
"migration_description_0009_decouple_regenconf_from_services": "Decouple the regen-conf mechanism from services",
|
||||||
|
"migration_description_0010_migrate_to_apps_json": "Remove deprecated appslists and use the new unified 'apps.json' list instead",
|
||||||
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
|
"migration_0003_backward_impossible": "The stretch migration cannot be reverted.",
|
||||||
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
|
"migration_0003_start": "Starting migration to Stretch. The logs will be available in {logfile}.",
|
||||||
"migration_0003_patching_sources_list": "Patching the sources.lists…",
|
"migration_0003_patching_sources_list": "Patching the sources.lists…",
|
||||||
|
@ -311,7 +317,7 @@
|
||||||
"migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!",
|
"migration_0005_postgresql_94_not_installed": "Postgresql was not installed on your system. Nothing to do!",
|
||||||
"migration_0005_postgresql_96_not_installed": "Postgresql 9.4 has been found to be installed, but not postgresql 9.6!? Something weird might have happened on your system:(…",
|
"migration_0005_postgresql_96_not_installed": "Postgresql 9.4 has been found to be installed, but not postgresql 9.6!? Something weird might have happened on your system:(…",
|
||||||
"migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now:(.",
|
"migration_0005_not_enough_space": "Not enough space is available in {path} to run the migration right now:(.",
|
||||||
"migration_0006_disclaimer": "Yunohost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
|
"migration_0006_disclaimer": "YunoHost now expects admin and root passwords to be synchronized. By running this migration, your root password is going to be replaced by the admin password.",
|
||||||
"migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.",
|
"migration_0007_cancelled": "YunoHost has failed to improve the way your SSH conf is managed.",
|
||||||
"migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.",
|
"migration_0007_cannot_restart": "SSH can't be restarted after trying to cancel migration number 6.",
|
||||||
"migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:",
|
"migration_0008_general_disclaimer": "To improve the security of your server, it is recommended to let YunoHost manage the SSH configuration. Your current SSH configuration differs from the recommended configuration. If you let YunoHost reconfigure it, the way you connect to your server through SSH will change in the following way:",
|
||||||
|
@ -320,6 +326,7 @@
|
||||||
"migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
|
"migration_0008_dsa": " - the DSA key will be disabled. Hence, you might need to invalidate a spooky warning from your SSH client, and recheck the fingerprint of your server;",
|
||||||
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
|
"migration_0008_warning": "If you understand those warnings and agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
|
||||||
"migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;)! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
|
"migration_0008_no_warning": "No major risk has been indentified about overriding your SSH configuration - but we can't be absolutely sure ;)! If you agree to let YunoHost override your current configuration, run the migration. Otherwise, you can also skip the migration - though it is not recommended.",
|
||||||
|
"migration_0009_not_needed": "This migration already happened somehow ? Skipping.",
|
||||||
"migrations_backward": "Migrating backward.",
|
"migrations_backward": "Migrating backward.",
|
||||||
"migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}",
|
"migrations_bad_value_for_target": "Invalid number for target argument, available migrations numbers are 0 or {}",
|
||||||
"migrations_cant_reach_migration_file": "Can't access migrations files at path %s",
|
"migrations_cant_reach_migration_file": "Can't access migrations files at path %s",
|
||||||
|
@ -381,11 +388,27 @@
|
||||||
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
|
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
|
||||||
"pattern_positive_number": "Must be a positive number",
|
"pattern_positive_number": "Must be a positive number",
|
||||||
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
|
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
|
||||||
|
"pattern_password_app": "Sorry, passwords should not contain the following characters: {forbidden_chars}",
|
||||||
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
|
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
|
||||||
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
|
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
|
||||||
"port_available": "Port {port:d} is available",
|
"port_available": "Port {port:d} is available",
|
||||||
"port_unavailable": "Port {port:d} is not available",
|
"port_unavailable": "Port {port:d} is not available",
|
||||||
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
|
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
|
||||||
|
"regenconf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
|
||||||
|
"regenconf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
|
||||||
|
"regenconf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by regen-conf (category {category}) but has been kept back.",
|
||||||
|
"regenconf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
|
||||||
|
"regenconf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
|
||||||
|
"regenconf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
|
||||||
|
"regenconf_file_removed": "The configuration file '{conf}' has been removed",
|
||||||
|
"regenconf_file_updated": "The configuration file '{conf}' has been 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": "The configuration has been updated for category '{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": "Unable to regenerate the configuration for category(s): {categories}",
|
||||||
|
"regenconf_pending_applying": "Applying pending configuration for category '{category}'…",
|
||||||
"restore_action_required": "You must specify something to restore",
|
"restore_action_required": "You must specify something to restore",
|
||||||
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
|
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
|
||||||
"restore_app_failed": "Unable to restore the app '{app:s}'",
|
"restore_app_failed": "Unable to restore the app '{app:s}'",
|
||||||
|
@ -414,18 +437,6 @@
|
||||||
"service_already_started": "Service '{service:s}' has already been started",
|
"service_already_started": "Service '{service:s}' has already been started",
|
||||||
"service_already_stopped": "Service '{service:s}' has already been stopped",
|
"service_already_stopped": "Service '{service:s}' has already been stopped",
|
||||||
"service_cmd_exec_failed": "Unable to execute command '{command:s}'",
|
"service_cmd_exec_failed": "Unable to execute command '{command:s}'",
|
||||||
"service_conf_file_backed_up": "The configuration file '{conf}' has been backed up to '{backup}'",
|
|
||||||
"service_conf_file_copy_failed": "Unable to copy the new configuration file '{new}' to '{conf}'",
|
|
||||||
"service_conf_file_kept_back": "The configuration file '{conf}' is expected to be deleted by service {service} but has been kept back.",
|
|
||||||
"service_conf_file_manually_modified": "The configuration file '{conf}' has been manually modified and will not be updated",
|
|
||||||
"service_conf_file_manually_removed": "The configuration file '{conf}' has been manually removed and will not be created",
|
|
||||||
"service_conf_file_remove_failed": "Unable to remove the configuration file '{conf}'",
|
|
||||||
"service_conf_file_removed": "The configuration file '{conf}' has been removed",
|
|
||||||
"service_conf_file_updated": "The configuration file '{conf}' has been updated",
|
|
||||||
"service_conf_now_managed_by_yunohost": "The configuration file '{conf}' is now managed by YunoHost.",
|
|
||||||
"service_conf_up_to_date": "The configuration is already up-to-date for service '{service}'",
|
|
||||||
"service_conf_updated": "The configuration has been updated for service '{service}'",
|
|
||||||
"service_conf_would_be_updated": "The configuration would have been updated for service '{service}'",
|
|
||||||
"service_description_avahi-daemon": "allows to reach your server using yunohost.local on your local network",
|
"service_description_avahi-daemon": "allows to reach your server using yunohost.local on your local network",
|
||||||
"service_description_dnsmasq": "handles domain name resolution (DNS)",
|
"service_description_dnsmasq": "handles domain name resolution (DNS)",
|
||||||
"service_description_dovecot": "allows e-mail client to access/fetch email (via IMAP and POP3)",
|
"service_description_dovecot": "allows e-mail client to access/fetch email (via IMAP and POP3)",
|
||||||
|
@ -449,9 +460,7 @@
|
||||||
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
|
"service_enable_failed": "Unable to enable service '{service:s}'\n\nRecent service logs:{logs:s}",
|
||||||
"service_enabled": "The service '{service:s}' has been enabled",
|
"service_enabled": "The service '{service:s}' has been enabled",
|
||||||
"service_no_log": "No log to display for service '{service:s}'",
|
"service_no_log": "No log to display for service '{service:s}'",
|
||||||
"service_regenconf_dry_pending_applying": "Checking pending configuration which would have been applied for service '{service}'…",
|
"service_regen_conf_is_deprecated": "'yunohost service regen-conf' is deprecated! Please use 'yunohost tools regen-conf' instead.",
|
||||||
"service_regenconf_failed": "Unable to regenerate the configuration for service(s): {services}",
|
|
||||||
"service_regenconf_pending_applying": "Applying pending configuration for service '{service}'…",
|
|
||||||
"service_remove_failed": "Unable to remove service '{service:s}'",
|
"service_remove_failed": "Unable to remove service '{service:s}'",
|
||||||
"service_removed": "The service '{service:s}' has been removed",
|
"service_removed": "The service '{service:s}' has been removed",
|
||||||
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
|
"service_reload_failed": "Unable to reload service '{service:s}'\n\nRecent service logs:{logs:s}",
|
||||||
|
@ -478,7 +487,8 @@
|
||||||
"unit_unknown": "Unknown unit '{unit:s}'",
|
"unit_unknown": "Unknown unit '{unit:s}'",
|
||||||
"unlimit": "No quota",
|
"unlimit": "No quota",
|
||||||
"unrestore_app": "App '{app:s}' will not be restored",
|
"unrestore_app": "App '{app:s}' will not be restored",
|
||||||
"update_cache_failed": "Unable to update APT cache",
|
"update_apt_cache_failed": "Unable to update the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
|
||||||
|
"update_apt_cache_warning": "Some errors happened while updating the cache of APT (Debian's package manager). Here is a dump of the sources.list lines which might help to identify problematic lines : \n{sourceslist}",
|
||||||
"updating_apt_cache": "Fetching available upgrades for system packages…",
|
"updating_apt_cache": "Fetching available upgrades for system packages…",
|
||||||
"upgrade_complete": "Upgrade complete",
|
"upgrade_complete": "Upgrade complete",
|
||||||
"upgrading_packages": "Upgrading packages…",
|
"upgrading_packages": "Upgrading packages…",
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"yunohost_already_installed": "YunoHost estas jam instalita",
|
"yunohost_already_installed": "YunoHost estas jam instalita",
|
||||||
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
|
"yunohost_ca_creation_failed": "Ne eblas krei atestan aŭtoritaton",
|
||||||
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
|
"yunohost_ca_creation_success": "Loka atesta aŭtoritato estas kreita.",
|
||||||
"yunohost_installing": "Instalata YunoHost...",
|
"yunohost_installing": "Instalante YunoHost…",
|
||||||
"service_description_glances": "monitoras sisteminformojn de via servilo",
|
"service_description_glances": "monitoras sisteminformojn de via servilo",
|
||||||
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
|
"service_description_metronome": "mastrumas XMPP tujmesaĝilon kontojn",
|
||||||
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
|
"service_description_mysql": "stokas aplikaĵojn datojn (SQL datumbazo)",
|
||||||
|
|
530
locales/fr.json
530
locales/fr.json
|
@ -1,33 +1,33 @@
|
||||||
{
|
{
|
||||||
"action_invalid": "Action « {action:s} » incorrecte",
|
"action_invalid": "Action '{action:s}' incorrecte",
|
||||||
"admin_password": "Mot de passe d’administration",
|
"admin_password": "Mot de passe d’administration",
|
||||||
"admin_password_change_failed": "Impossible de changer le mot de passe",
|
"admin_password_change_failed": "Impossible de changer le mot de passe",
|
||||||
"admin_password_changed": "Le mot de passe d’administration a été modifié",
|
"admin_password_changed": "Le mot de passe d’administration a été modifié",
|
||||||
"app_already_installed": "{app:s} est déjà installé",
|
"app_already_installed": "{app:s} est déjà installé",
|
||||||
"app_argument_choice_invalid": "Choix invalide pour le paramètre « {name:s} », il doit être l’un de {choices:s}",
|
"app_argument_choice_invalid": "Choix invalide pour le paramètre '{name:s}', il doit être l’un de {choices:s}",
|
||||||
"app_argument_invalid": "Valeur invalide pour le paramètre « {name:s} » : {error:s}",
|
"app_argument_invalid": "Valeur invalide pour le paramètre '{name:s}' : {error:s}",
|
||||||
"app_argument_missing": "Paramètre manquant « {:s} »",
|
"app_argument_missing": "Paramètre manquant « {:s} »",
|
||||||
"app_argument_required": "Le paramètre « {name:s} » est requis",
|
"app_argument_required": "Le paramètre '{name:s}' est requis",
|
||||||
"app_extraction_failed": "Impossible d’extraire les fichiers d’installation",
|
"app_extraction_failed": "Impossible d’extraire les fichiers d’installation",
|
||||||
"app_id_invalid": "Id d’application incorrect",
|
"app_id_invalid": "Identifiant d’application invalide",
|
||||||
"app_incompatible": "L’application {app} est incompatible avec votre version de YunoHost",
|
"app_incompatible": "L’application {app} est incompatible avec votre version de YunoHost",
|
||||||
"app_install_files_invalid": "Fichiers d’installation incorrects",
|
"app_install_files_invalid": "Fichiers d’installation incorrects",
|
||||||
"app_location_already_used": "L’application « {app} » est déjà installée à cet emplacement ({path})",
|
"app_location_already_used": "L’application '{app}' est déjà installée à cet emplacement ({path})",
|
||||||
"app_location_install_failed": "Impossible d’installer l’application à cet emplacement pour cause de conflit avec l’app « {other_app} » déjà installée sur « {other_path} »",
|
"app_location_install_failed": "Impossible d’installer l’application à cet emplacement pour cause de conflit avec l’application '{other_app}' déjà installée sur '{other_path}'",
|
||||||
"app_manifest_invalid": "Manifeste d’application incorrect : {error}",
|
"app_manifest_invalid": "Manifeste d’application incorrect : {error}",
|
||||||
"app_no_upgrade": "Aucune application à mettre à jour",
|
"app_no_upgrade": "Aucune application à mettre à jour",
|
||||||
"app_not_correctly_installed": "{app:s} semble être mal installé",
|
"app_not_correctly_installed": "{app:s} semble être mal installé",
|
||||||
"app_not_installed": "{app:s} n’est pas installé",
|
"app_not_installed": "{app:s} n’est pas installé",
|
||||||
"app_not_properly_removed": "{app:s} n’a pas été supprimé correctement",
|
"app_not_properly_removed": "{app:s} n’a pas été supprimé correctement",
|
||||||
"app_package_need_update": "Le paquet de l’application {app} doit être mis à jour pour suivre les changements de YunoHost",
|
"app_package_need_update": "Le paquet de l’application {app} doit être mis à jour pour être en adéquation avec les changements de YunoHost",
|
||||||
"app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost",
|
"app_recent_version_required": "{app:s} nécessite une version plus récente de YunoHost",
|
||||||
"app_removed": "{app:s} a été supprimé",
|
"app_removed": "{app:s} a été supprimé",
|
||||||
"app_requirements_checking": "Vérification des paquets requis pour {app}...",
|
"app_requirements_checking": "Vérification des paquets requis pour {app} …",
|
||||||
"app_requirements_failed": "Impossible de satisfaire les pré-requis pour {app} : {error}",
|
"app_requirements_failed": "Impossible de satisfaire les pré-requis pour {app} : {error}",
|
||||||
"app_requirements_unmeet": "Les pré-requis de {app} ne sont pas satisfaits, le paquet {pkgname} ({version}) doit être {spec}",
|
"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",
|
"app_sources_fetch_failed": "Impossible de récupérer les fichiers sources",
|
||||||
"app_unknown": "Application inconnue",
|
"app_unknown": "Application inconnue",
|
||||||
"app_unsupported_remote_type": "Le type distant utilisé par l’application n’est pas pris en charge",
|
"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}",
|
"app_upgrade_failed": "Impossible de mettre à jour {app:s}",
|
||||||
"app_upgraded": "{app:s} a été mis à jour",
|
"app_upgraded": "{app:s} a été mis à jour",
|
||||||
"appslist_fetched": "La liste d’applications {appslist:s} a été récupérée",
|
"appslist_fetched": "La liste d’applications {appslist:s} a été récupérée",
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
"appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}",
|
"appslist_retrieve_error": "Impossible de récupérer la liste d’applications distante {appslist:s} : {error:s}",
|
||||||
"appslist_unknown": "La liste d’applications {appslist:s} est inconnue.",
|
"appslist_unknown": "La liste d’applications {appslist:s} est inconnue.",
|
||||||
"ask_current_admin_password": "Mot de passe d’administration actuel",
|
"ask_current_admin_password": "Mot de passe d’administration actuel",
|
||||||
"ask_email": "Adresse courriel",
|
"ask_email": "Adresse de courriel",
|
||||||
"ask_firstname": "Prénom",
|
"ask_firstname": "Prénom",
|
||||||
"ask_lastname": "Nom",
|
"ask_lastname": "Nom",
|
||||||
"ask_list_to_remove": "Liste à supprimer",
|
"ask_list_to_remove": "Liste à supprimer",
|
||||||
|
@ -43,36 +43,36 @@
|
||||||
"ask_new_admin_password": "Nouveau mot de passe d’administration",
|
"ask_new_admin_password": "Nouveau mot de passe d’administration",
|
||||||
"ask_password": "Mot de passe",
|
"ask_password": "Mot de passe",
|
||||||
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
|
"backup_action_required": "Vous devez préciser ce qui est à sauvegarder",
|
||||||
"backup_app_failed": "Impossible de sauvegarder l’application « {app:s} »",
|
"backup_app_failed": "Impossible de sauvegarder l’application '{app:s}'",
|
||||||
"backup_archive_app_not_found": "L’application « {app:s} » n’a pas été trouvée dans l’archive de la sauvegarde",
|
"backup_archive_app_not_found": "L’application '{app:s}' n’a pas été trouvée dans l’archive de la sauvegarde",
|
||||||
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
|
"backup_archive_hook_not_exec": "Le script « {hook:s} » n'a pas été exécuté dans cette sauvegarde",
|
||||||
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
|
"backup_archive_name_exists": "Une archive de sauvegarde avec ce nom existe déjà",
|
||||||
"backup_archive_name_unknown": "L’archive locale de sauvegarde nommée « {name:s} » est inconnue",
|
"backup_archive_name_unknown": "L’archive locale de sauvegarde nommée '{name:s}' est inconnue",
|
||||||
"backup_archive_open_failed": "Impossible d’ouvrir l’archive de sauvegarde",
|
"backup_archive_open_failed": "Impossible d’ouvrir l’archive de sauvegarde",
|
||||||
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
|
"backup_cleaning_failed": "Impossible de nettoyer le dossier temporaire de sauvegarde",
|
||||||
"backup_created": "Sauvegarde terminée",
|
"backup_created": "Sauvegarde terminée",
|
||||||
"backup_creating_archive": "Création de l’archive de sauvegarde...",
|
"backup_creating_archive": "Création de l’archive de sauvegarde …",
|
||||||
"backup_creation_failed": "Impossible de créer la sauvegarde",
|
"backup_creation_failed": "Impossible de créer la sauvegarde",
|
||||||
"backup_delete_error": "Impossible de supprimer « {path:s} »",
|
"backup_delete_error": "Impossible de supprimer '{path:s}'",
|
||||||
"backup_deleted": "La sauvegarde a été supprimée",
|
"backup_deleted": "La sauvegarde a été supprimée",
|
||||||
"backup_extracting_archive": "Extraction de l’archive de sauvegarde...",
|
"backup_extracting_archive": "Extraction de l’archive de sauvegarde …",
|
||||||
"backup_hook_unknown": "Script de sauvegarde « {hook:s} » inconnu",
|
"backup_hook_unknown": "Script de sauvegarde '{hook:s}' inconnu",
|
||||||
"backup_invalid_archive": "Archive de sauvegarde incorrecte",
|
"backup_invalid_archive": "Archive de sauvegarde invalide",
|
||||||
"backup_nothings_done": "Il n’y a rien à sauvegarder",
|
"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 dossiers /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var ou /home/yunohost.backup/archives",
|
"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 dossier de sortie 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 sortie pour la sauvegarde",
|
"backup_output_directory_required": "Vous devez spécifier un dossier de destination pour la sauvegarde",
|
||||||
"backup_running_app_script": "Lancement du script de sauvegarde de l’application « {app:s} »...",
|
"backup_running_app_script": "Lancement du script de sauvegarde de l’application « {app:s} »...",
|
||||||
"backup_running_hooks": "Exécution des scripts de 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 locale {app:s}",
|
"custom_app_url_required": "Vous devez spécifier une URL pour mettre à jour votre application personnalisée {app:s}",
|
||||||
"custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d’applications personnalisée",
|
"custom_appslist_name_required": "Vous devez spécifier un nom pour votre liste d’applications personnalisées",
|
||||||
"diagnosis_debian_version_error": "Impossible de déterminer la version de Debian : {error}",
|
"diagnosis_debian_version_error": "Impossible de déterminer la version de Debian : {error}",
|
||||||
"diagnosis_kernel_version_error": "Impossible de récupérer la version du noyau : {error}",
|
"diagnosis_kernel_version_error": "Impossible de récupérer la version du noyau : {error}",
|
||||||
"diagnosis_monitor_disk_error": "Impossible de superviser les disques : {error}",
|
"diagnosis_monitor_disk_error": "Impossible de superviser les disques : {error}",
|
||||||
"diagnosis_monitor_network_error": "Impossible de superviser le réseau : {error}",
|
"diagnosis_monitor_network_error": "Impossible de superviser le réseau : {error}",
|
||||||
"diagnosis_monitor_system_error": "Impossible de superviser le système : {error}",
|
"diagnosis_monitor_system_error": "Impossible de superviser le système : {error}",
|
||||||
"diagnosis_no_apps": "Aucune application installée",
|
"diagnosis_no_apps": "Aucune application installée",
|
||||||
"dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer « apt-get remove bind9 && apt-get install dnsmasq »",
|
"dnsmasq_isnt_installed": "dnsmasq ne semble pas être installé, veuillez lancer 'apt-get remove bind9 && apt-get install dnsmasq'",
|
||||||
"domain_cert_gen_failed": "Impossible de générer le certificat",
|
"domain_cert_gen_failed": "Impossible de générer le certificat",
|
||||||
"domain_created": "Le domaine a été créé",
|
"domain_created": "Le domaine a été créé",
|
||||||
"domain_creation_failed": "Impossible de créer le domaine",
|
"domain_creation_failed": "Impossible de créer le domaine",
|
||||||
|
@ -87,41 +87,41 @@
|
||||||
"domain_zone_exists": "Le fichier de zone DNS existe déjà",
|
"domain_zone_exists": "Le fichier de zone DNS existe déjà",
|
||||||
"domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}",
|
"domain_zone_not_found": "Fichier de zone DNS introuvable pour le domaine {:s}",
|
||||||
"done": "Terminé",
|
"done": "Terminé",
|
||||||
"downloading": "Téléchargement...",
|
"downloading": "Téléchargement en cours …",
|
||||||
"dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été installée",
|
"dyndns_cron_installed": "La tâche cron pour le domaine DynDNS a été installée",
|
||||||
"dyndns_cron_remove_failed": "Impossible d’enlever la tâche cron pour le domaine DynDNS",
|
"dyndns_cron_remove_failed": "Impossible de supprimer la tâche cron pour le domaine DynDNS",
|
||||||
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS a été enlevée",
|
"dyndns_cron_removed": "La tâche cron pour le domaine DynDNS a été enlevée",
|
||||||
"dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS",
|
"dyndns_ip_update_failed": "Impossible de mettre à jour l’adresse IP sur le domaine DynDNS",
|
||||||
"dyndns_ip_updated": "Votre adresse IP a été mise à jour pour le domaine DynDNS",
|
"dyndns_ip_updated": "Votre adresse IP a été mise à jour pour le domaine DynDNS",
|
||||||
"dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre du temps...",
|
"dyndns_key_generating": "La clé DNS est en cours de génération, cela peut prendre un certain temps …",
|
||||||
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
|
"dyndns_key_not_found": "Clé DNS introuvable pour le domaine",
|
||||||
"dyndns_no_domain_registered": "Aucun domaine n’a été enregistré avec DynDNS",
|
"dyndns_no_domain_registered": "Aucun domaine n’a été enregistré avec DynDNS",
|
||||||
"dyndns_registered": "Le domaine DynDNS a été enregistré",
|
"dyndns_registered": "Le domaine DynDNS a été enregistré",
|
||||||
"dyndns_registration_failed": "Impossible d’enregistrer le domaine DynDNS : {error:s}",
|
"dyndns_registration_failed": "Impossible d’enregistrer le domaine DynDNS : {error:s}",
|
||||||
"dyndns_unavailable": "Le domaine {domain:s} est indisponible.",
|
"dyndns_unavailable": "Le domaine {domain:s} est indisponible.",
|
||||||
"executing_command": "Exécution de la commande « {command:s} »...",
|
"executing_command": "Exécution de la commande '{command:s}' …",
|
||||||
"executing_script": "Exécution du script « {script:s} »...",
|
"executing_script": "Exécution du script '{script:s}' …",
|
||||||
"extracting": "Extraction...",
|
"extracting": "Extraction en cours …",
|
||||||
"field_invalid": "Champ incorrect : « {:s} »",
|
"field_invalid": "Champ incorrect : '{:s}'",
|
||||||
"firewall_reload_failed": "Impossible de recharger le pare-feu",
|
"firewall_reload_failed": "Impossible de recharger le pare-feu",
|
||||||
"firewall_reloaded": "Le pare-feu a été rechargé",
|
"firewall_reloaded": "Le pare-feu a été rechargé",
|
||||||
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Pour plus d’informations, consultez le journal.",
|
"firewall_rules_cmd_failed": "Certaines règles du pare-feu n’ont pas pu être appliquées. Pour plus d’informations, consultez le journal.",
|
||||||
"format_datetime_short": "%d/%m/%Y %H:%M",
|
"format_datetime_short": "%d/%m/%Y %H:%M",
|
||||||
"hook_argument_missing": "Argument manquant : '{:s}'",
|
"hook_argument_missing": "Argument manquant : '{:s}'",
|
||||||
"hook_choice_invalid": "Choix incorrect : '{:s}'",
|
"hook_choice_invalid": "Choix incorrect : '{:s}'",
|
||||||
"hook_exec_failed": "Échec de l’exécution du script « {path:s} »",
|
"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",
|
"hook_exec_not_terminated": "L’exécution du script {path:s} ne s’est pas terminée correctement",
|
||||||
"hook_list_by_invalid": "La propriété de tri des actions est invalide",
|
"hook_list_by_invalid": "Propriété invalide pour lister les actions par",
|
||||||
"hook_name_unknown": "Nom de script « {name:s} » inconnu",
|
"hook_name_unknown": "Nom de l'action '{name:s}' inconnu",
|
||||||
"installation_complete": "Installation terminée",
|
"installation_complete": "Installation terminée",
|
||||||
"installation_failed": "Échec de l’installation",
|
"installation_failed": "Échec 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",
|
"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",
|
"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 a été initialisé",
|
"ldap_initialized": "L’annuaire LDAP a été initialisé",
|
||||||
"license_undefined": "indéfinie",
|
"license_undefined": "indéfinie",
|
||||||
"mail_alias_remove_failed": "Impossible de supprimer l’alias courriel « {mail:s} »",
|
"mail_alias_remove_failed": "Impossible de supprimer l’alias de courriel '{mail:s}'",
|
||||||
"mail_domain_unknown": "Le domaine « {domain:s} » du courriel est inconnu",
|
"mail_domain_unknown": "Le domaine « {domain:s} » du courriel est inconnu",
|
||||||
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert « {mail:s} »",
|
"mail_forward_remove_failed": "Impossible de supprimer le courriel de transfert '{mail:s}'",
|
||||||
"maindomain_change_failed": "Impossible de modifier le domaine principal",
|
"maindomain_change_failed": "Impossible de modifier le domaine principal",
|
||||||
"maindomain_changed": "Le domaine principal a été modifié",
|
"maindomain_changed": "Le domaine principal a été modifié",
|
||||||
"monitor_disabled": "La supervision du serveur a été désactivé",
|
"monitor_disabled": "La supervision du serveur a été désactivé",
|
||||||
|
@ -136,271 +136,271 @@
|
||||||
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
|
"mysql_db_creation_failed": "Impossible de créer la base de données MySQL",
|
||||||
"mysql_db_init_failed": "Impossible d’initialiser la base de données MySQL",
|
"mysql_db_init_failed": "Impossible d’initialiser la base de données MySQL",
|
||||||
"mysql_db_initialized": "La base de données MySQL a été initialisée",
|
"mysql_db_initialized": "La base de données MySQL a été initialisée",
|
||||||
"network_check_mx_ko": "L’enregistrement DNS MX n’est pas précisé",
|
"network_check_mx_ko": "L’enregistrement DNS MX n’est pas défini",
|
||||||
"network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau",
|
"network_check_smtp_ko": "Le trafic courriel sortant (port 25 SMTP) semble bloqué par votre réseau",
|
||||||
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n’est pas bloqué",
|
"network_check_smtp_ok": "Le trafic courriel sortant (port 25 SMTP) n’est pas bloqué",
|
||||||
"new_domain_required": "Vous devez spécifier le nouveau domaine principal",
|
"new_domain_required": "Vous devez spécifier le nouveau domaine principal",
|
||||||
"no_appslist_found": "Aucune liste d’applications n’a été trouvée",
|
"no_appslist_found": "Aucune liste d’applications n’a été trouvée",
|
||||||
"no_internet_connection": "Le serveur n’est pas connecté à Internet",
|
"no_internet_connection": "Le serveur n’est pas connecté à Internet",
|
||||||
"no_ipv6_connectivity": "La connectivité IPv6 n’est pas disponible",
|
"no_ipv6_connectivity": "La connectivité IPv6 n’est pas disponible",
|
||||||
"no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application « {app:s} »",
|
"no_restore_script": "Le script de sauvegarde n’a pas été trouvé pour l’application '{app:s}'",
|
||||||
"no_such_conf_file": "Le fichier {file:s} n’existe pas, il ne peut pas être copié",
|
"no_such_conf_file": "Le fichier {file:s} n’existe pas, il ne peut pas être copié",
|
||||||
"not_enough_disk_space": "L’espace disque est insuffisant sur « {path:s} »",
|
"not_enough_disk_space": "L’espace disque est insuffisant sur '{path:s}'",
|
||||||
"package_not_installed": "Le paquet « {pkgname} » n’est pas installé",
|
"package_not_installed": "Le paquet '{pkgname}' n’est pas installé",
|
||||||
"package_unexpected_error": "Une erreur inattendue est survenue avec le paquet « {pkgname} »",
|
"package_unexpected_error": "Une erreur inattendue s'est produite lors du traitement du paquet '{pkgname}'",
|
||||||
"package_unknown": "Paquet « {pkgname} » inconnu",
|
"package_unknown": "Le paquet '{pkgname}' est inconnu",
|
||||||
"packages_no_upgrade": "Il n’y a aucun paquet à mettre à jour",
|
"packages_no_upgrade": "Il n’y a aucun paquet à mettre à jour",
|
||||||
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
|
"packages_upgrade_critical_later": "Les paquets critiques ({packages:s}) seront mis à jour ultérieurement",
|
||||||
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
|
"packages_upgrade_failed": "Impossible de mettre à jour tous les paquets",
|
||||||
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
|
"path_removal_failed": "Impossible de supprimer le chemin {:s}",
|
||||||
"pattern_backup_archive_name": "Doit être un nom de fichier valide composé uniquement de caractères alphanumériques et de -_.",
|
"pattern_backup_archive_name": "Doit être un nom de fichier valide avec un maximum de 30 caractères, et composé de caractères alphanumériques et -_. uniquement",
|
||||||
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.org)",
|
"pattern_domain": "Doit être un nom de domaine valide (ex : mon-domaine.fr)",
|
||||||
"pattern_email": "Doit être une adresse courriel valide (ex. : pseudo@domain.org)",
|
"pattern_email": "Doit être une adresse de courriel valide (ex. : pseudo@domaine.fr)",
|
||||||
"pattern_firstname": "Doit être un prénom valide",
|
"pattern_firstname": "Doit être un prénom valide",
|
||||||
"pattern_lastname": "Doit être un nom valide",
|
"pattern_lastname": "Doit être un nom valide",
|
||||||
"pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas",
|
"pattern_listname": "Doit être composé uniquement de caractères alphanumériques et de tirets bas (aussi appelé tiret du 8 ou underscore)",
|
||||||
"pattern_mailbox_quota": "Doit être une taille avec le suffixe b/k/M/G/T ou 0 pour désactiver le quota",
|
"pattern_mailbox_quota": "Doit avoir une taille suffixée avec b/k/M/G/T ou 0 pour désactiver le quota",
|
||||||
"pattern_password": "Doit être composé d’au moins 3 caractères",
|
"pattern_password": "Doit être composé d’au moins 3 caractères",
|
||||||
"pattern_port": "Doit être un numéro de port valide (ex. : 0-65535)",
|
"pattern_port": "Doit être un numéro de port valide compris entre 0 et 65535",
|
||||||
"pattern_port_or_range": "Doit être un numéro de port valide (ex. : 0-65535) ou une gamme de ports (ex. : 100:200)",
|
"pattern_port_or_range": "Doit être un numéro de port valide compris entre 0 et 65535, ou une gamme de ports (exemple : 100:200)",
|
||||||
"pattern_positive_number": "Doit être un nombre positif",
|
"pattern_positive_number": "Doit être un nombre positif",
|
||||||
"pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas",
|
"pattern_username": "Doit être composé uniquement de caractères alphanumériques minuscules et de tirets bas (aussi appelé tiret du 8 ou underscore)",
|
||||||
"port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}",
|
"port_already_closed": "Le port {port:d} est déjà fermé pour les connexions {ip_version:s}",
|
||||||
"port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}",
|
"port_already_opened": "Le port {port:d} est déjà ouvert pour les connexions {ip_version:s}",
|
||||||
"port_available": "Le port {port:d} est disponible",
|
"port_available": "Le port {port:d} est disponible",
|
||||||
"port_unavailable": "Le port {port:d} n’est pas disponible",
|
"port_unavailable": "Le port {port:d} n’est pas disponible",
|
||||||
"restore_action_required": "Vous devez préciser ce qui est à restaurer",
|
"restore_action_required": "Vous devez préciser ce qui est à restaurer",
|
||||||
"restore_already_installed_app": "Une application est déjà installée avec l’id « {app:s} »",
|
"restore_already_installed_app": "Une application est déjà installée avec l’identifiant '{app:s}'",
|
||||||
"restore_app_failed": "Impossible de restaurer l’application « {app:s} »",
|
"restore_app_failed": "Impossible de restaurer l’application '{app:s}'",
|
||||||
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
|
"restore_cleaning_failed": "Impossible de nettoyer le dossier temporaire de restauration",
|
||||||
"restore_complete": "Restauration terminée",
|
"restore_complete": "Restauration terminée",
|
||||||
"restore_confirm_yunohost_installed": "Voulez-vous vraiment restaurer un système déjà installé ? [{answers:s}]",
|
"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_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 n’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_nothings_done": "Rien n’a été restauré",
|
||||||
"restore_running_app_script": "Lancement du script de restauration pour 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...",
|
"restore_running_hooks": "Exécution des scripts de restauration …",
|
||||||
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
|
"service_add_configuration": "Ajout du fichier de configuration {file:s}",
|
||||||
"service_add_failed": "Impossible d’ajouter le service « {service:s} »",
|
"service_add_failed": "Impossible d’ajouter le service '{service:s}'",
|
||||||
"service_added": "Le service « {service:s} » a été ajouté",
|
"service_added": "Le service '{service:s}' a été ajouté",
|
||||||
"service_already_started": "Le service « {service:s} » est déjà démarré",
|
"service_already_started": "Le service '{service:s}' est déjà démarré",
|
||||||
"service_already_stopped": "Le service « {service:s} » est déjà arrêté",
|
"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_cmd_exec_failed": "Impossible d’exécuter la commande '{command:s}'",
|
||||||
"service_conf_file_backed_up": "Le fichier de configuration « {conf} » a été sauvegardé dans « {backup} »",
|
"service_conf_file_backed_up": "Le fichier de configuration '{conf}' a été sauvegardé dans '{backup}'",
|
||||||
"service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration « {new} » vers « {conf} »",
|
"service_conf_file_copy_failed": "Impossible de copier le nouveau fichier de configuration '{new}' vers '{conf}'",
|
||||||
"service_conf_file_manually_modified": "Le fichier de configuration « {conf} » a été modifié manuellement et ne sera pas mis à jour",
|
"service_conf_file_manually_modified": "Le fichier de configuration '{conf}' a été modifié manuellement et ne sera pas mis à jour",
|
||||||
"service_conf_file_manually_removed": "Le fichier de configuration « {conf} » a été supprimé manuellement et ne sera pas créé",
|
"service_conf_file_manually_removed": "Le fichier de configuration '{conf}' a été supprimé manuellement et ne sera pas créé",
|
||||||
"service_conf_file_not_managed": "Le fichier de configuration « {conf} » n'est pas géré pour l'instant et ne sera pas mis à jour",
|
"service_conf_file_not_managed": "Le fichier de configuration « {conf} » n'est pas géré pour l'instant et ne sera pas mis à jour",
|
||||||
"service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration « {conf} »",
|
"service_conf_file_remove_failed": "Impossible de supprimer le fichier de configuration '{conf}'",
|
||||||
"service_conf_file_removed": "Le fichier de configuration « {conf} » a été supprimé",
|
"service_conf_file_removed": "Le fichier de configuration '{conf}' a été supprimé",
|
||||||
"service_conf_file_updated": "Le fichier de configuration « {conf} » a été mis à jour",
|
"service_conf_file_updated": "Le fichier de configuration '{conf}' a été mis à jour",
|
||||||
"service_conf_up_to_date": "La configuration du service « {service} » est déjà à jour",
|
"service_conf_up_to_date": "La configuration du service '{service}' est déjà à jour",
|
||||||
"service_conf_updated": "La configuration a été mise à jour pour le service « {service} »",
|
"service_conf_updated": "La configuration a été mise à jour pour le service '{service}'",
|
||||||
"service_conf_would_be_updated": "La configuration du service « {service} » aurait été mise à jour",
|
"service_conf_would_be_updated": "La configuration du service '{service}' aurait été mise à jour",
|
||||||
"service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser l’option --force (ce qui écrasera toutes les modifications effectuées sur le fichier).",
|
"service_configuration_conflict": "Le fichier {file:s} a été modifié depuis sa dernière génération. Veuillez y appliquer les modifications manuellement ou utiliser l’option --force (ce qui écrasera toutes les modifications effectuées sur le fichier).",
|
||||||
"service_configured": "La configuration du service « {service:s} » a été générée avec succès",
|
"service_configured": "La configuration du service « {service:s} » a été générée avec succès",
|
||||||
"service_configured_all": "La configuration de tous les services a été générée avec succès",
|
"service_configured_all": "La configuration de tous les services a été générée avec succès",
|
||||||
"service_disable_failed": "Impossible de désactiver le service « {service:s} »\n\nJournaux récents : {logs:s}",
|
"service_disable_failed": "Impossible de désactiver le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
|
||||||
"service_disabled": "Le service « {service:s} » a été désactivé",
|
"service_disabled": "Le service '{service:s}' a été désactivé",
|
||||||
"service_enable_failed": "Impossible d’activer le service « {service:s} »\n\nJournaux récents : {logs:s}",
|
"service_enable_failed": "Impossible d’activer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
|
||||||
"service_enabled": "Le service « {service:s} » a été activé",
|
"service_enabled": "Le service '{service:s}' a été activé",
|
||||||
"service_no_log": "Aucun journal à afficher pour le service « {service:s} »",
|
"service_no_log": "Aucun journal historisé à afficher pour le service '{service:s}'",
|
||||||
"service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées pour le service « {service} »…",
|
"service_regenconf_dry_pending_applying": "Vérification des configurations en attentes qui pourraient être appliquées au le service '{service}' …",
|
||||||
"service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}",
|
"service_regenconf_failed": "Impossible de régénérer la configuration pour les services : {services}",
|
||||||
"service_regenconf_pending_applying": "Application des configurations en attentes pour le service « {service} »…",
|
"service_regenconf_pending_applying": "Application des configurations en attentes pour le service '{service}' …",
|
||||||
"service_remove_failed": "Impossible d’enlever le service « {service:s} »",
|
"service_remove_failed": "Impossible de supprimer le service '{service:s}'",
|
||||||
"service_removed": "Le service « {service:s} » a été enlevé",
|
"service_removed": "Le service '{service:s}' a été supprimé",
|
||||||
"service_start_failed": "Impossible de démarrer le service « {service:s} »\n\nJournaux récents : {logs:s}",
|
"service_start_failed": "Impossible de démarrer le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
|
||||||
"service_started": "Le service « {service:s} » a été démarré",
|
"service_started": "Le service '{service:s}' a été démarré",
|
||||||
"service_status_failed": "Impossible de déterminer le statut du service « {service:s} »",
|
"service_status_failed": "Impossible de déterminer le statut du service '{service:s}'",
|
||||||
"service_stop_failed": "Impossible d’arrêter le service « {service:s} »\n\nJournaux récents : {logs:s}",
|
"service_stop_failed": "Impossible d’arrêter le service '{service:s}'\n\nJournaux historisés récents : {logs:s}",
|
||||||
"service_stopped": "Le service « {service:s} » a été arrêté",
|
"service_stopped": "Le service '{service:s}' a été arrêté",
|
||||||
"service_unknown": "Service « {service:s} » inconnu",
|
"service_unknown": "Le service '{service:s}' est inconnu",
|
||||||
"services_configured": "La configuration a été générée avec succès",
|
"services_configured": "La configuration a été générée avec succès",
|
||||||
"show_diff": "Voici les différences :\n{diff:s}",
|
"show_diff": "Voici les différences :\n{diff:s}",
|
||||||
"ssowat_conf_generated": "La configuration de SSOwat a été générée",
|
"ssowat_conf_generated": "La configuration de SSOwat a été générée",
|
||||||
"ssowat_conf_updated": "La configuration de SSOwat a été mise à jour",
|
"ssowat_conf_updated": "La configuration de SSOwat a été mise à jour",
|
||||||
"system_upgraded": "Le système a été mis à jour",
|
"system_upgraded": "Le système a été mis à jour",
|
||||||
"system_username_exists": "Le nom d’utilisateur existe déjà dans les utilisateurs système",
|
"system_username_exists": "Ce nom d’utilisateur existe déjà dans les utilisateurs système",
|
||||||
"unbackup_app": "L’application « {app:s} » ne sera pas sauvegardée",
|
"unbackup_app": "L’application '{app:s}' ne sera pas sauvegardée",
|
||||||
"unexpected_error": "Une erreur inattendue est survenue",
|
"unexpected_error": "Une erreur inattendue est survenue : {error}",
|
||||||
"unit_unknown": "Unité « {unit:s} » inconnue",
|
"unit_unknown": "L'unité '{unit:s}' est inconnue",
|
||||||
"unlimit": "Pas de quota",
|
"unlimit": "Pas de quota",
|
||||||
"unrestore_app": "L’application « {app:s} » ne sera pas restaurée",
|
"unrestore_app": "L’application '{app:s}' ne sera pas restaurée",
|
||||||
"update_cache_failed": "Impossible de mettre à jour le cache de l’APT",
|
"update_cache_failed": "Impossible de mettre à jour le cache de l'outil de gestion avancée des paquets (APT)",
|
||||||
"updating_apt_cache": "Mise à jour de la liste des paquets disponibles...",
|
"updating_apt_cache": "Récupération des mises à jour disponibles pour les paquets du système …",
|
||||||
"upgrade_complete": "Mise à jour terminée",
|
"upgrade_complete": "Mise à jour terminée",
|
||||||
"upgrading_packages": "Mise à jour des paquets...",
|
"upgrading_packages": "Mise à jour des paquets en cours …",
|
||||||
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé",
|
"upnp_dev_not_found": "Aucun périphérique compatible UPnP n’a été trouvé",
|
||||||
"upnp_disabled": "UPnP a été désactivé",
|
"upnp_disabled": "UPnP a été désactivé",
|
||||||
"upnp_enabled": "UPnP a été activé",
|
"upnp_enabled": "UPnP a été activé",
|
||||||
"upnp_port_open_failed": "Impossible d’ouvrir les ports avec UPnP",
|
"upnp_port_open_failed": "Impossible d’ouvrir les ports UPnP",
|
||||||
"user_created": "L’utilisateur a été créé",
|
"user_created": "L’utilisateur a été créé",
|
||||||
"user_creation_failed": "Impossible de créer l’utilisateur",
|
"user_creation_failed": "Impossible de créer l’utilisateur",
|
||||||
"user_deleted": "L’utilisateur a été supprimé",
|
"user_deleted": "L’utilisateur a été supprimé",
|
||||||
"user_deletion_failed": "Impossible de supprimer l’utilisateur",
|
"user_deletion_failed": "Impossible de supprimer l’utilisateur",
|
||||||
"user_home_creation_failed": "Impossible de créer le dossier personnel de l’utilisateur",
|
"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_info_failed": "Impossible de récupérer les informations de l’utilisateur",
|
||||||
"user_unknown": "Utilisateur « {user:s} » inconnu",
|
"user_unknown": "L'utilisateur {user:s} est inconnu",
|
||||||
"user_update_failed": "Impossible de modifier l’utilisateur",
|
"user_update_failed": "Impossible de modifier l’utilisateur",
|
||||||
"user_updated": "L’utilisateur a été modifié",
|
"user_updated": "L’utilisateur a été modifié",
|
||||||
"yunohost_already_installed": "YunoHost est déjà installé",
|
"yunohost_already_installed": "YunoHost est déjà installé",
|
||||||
"yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification",
|
"yunohost_ca_creation_failed": "Impossible de créer l’autorité de certification",
|
||||||
"yunohost_configured": "YunoHost a été configuré",
|
"yunohost_configured": "YunoHost a été configuré",
|
||||||
"yunohost_installing": "Installation de YunoHost...",
|
"yunohost_installing": "L'installation de YunoHost est en cours …",
|
||||||
"yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter « yunohost tools postinstall »",
|
"yunohost_not_installed": "YunoHost n’est pas ou pas correctement installé. Veuillez exécuter 'yunohost tools postinstall'",
|
||||||
"certmanager_attempt_to_replace_valid_cert": "Vous êtes en train de remplacer un certificat correct et valide pour le domaine {domain:s} ! (Utilisez --force pour contourner)",
|
"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 inconnu {domain:s}",
|
"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)",
|
"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_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 fourni par Let’s Encrypt. Impossible de le renouveler automatiquement !",
|
"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} est sur le point d’expirer ! Utilisez --force pour contourner",
|
"certmanager_attempt_to_renew_valid_cert": "Le certificat pour le domaine {domain:s} est sur le point d’expirer ! Utilisez --force pour contourner cela",
|
||||||
"certmanager_domain_http_not_working": "Il semble que le domaine {domain:s} n’est pas accessible via HTTP. Veuillez vérifier que vos configuration DNS et nginx sont correctes",
|
"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}. De devez faire pointer votre nom de domaine vers votre machine pour être capable d’installer un certificat Let’s Encrypt ! (Si vous savez ce que vous faites, utilisez --no-checks pour désactiver ces contrôles)",
|
"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 modifié récemment votre enregistrement « A », veuillez attendre sa propagation (quelques vérificateur de propagation 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}), cause : {reason:s}",
|
"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": "Installation avec succès d’un certificat auto-signé pour le domaine {domain:s} !",
|
"certmanager_cert_install_success_selfsigned": "Installation avec succès d’un certificat auto-signé pour le domaine {domain:s} !",
|
||||||
"certmanager_cert_install_success": "Installation avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
|
"certmanager_cert_install_success": "Installation avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
|
||||||
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
|
"certmanager_cert_renew_success": "Renouvellement avec succès d’un certificat Let’s Encrypt pour le domaine {domain:s} !",
|
||||||
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
|
"certmanager_old_letsencrypt_app_detected": "\nYunoHost a détecté que l’application « letsencrypt » est installé, ce qui est en conflit avec les nouvelles fonctionnalités de gestion intégrée de certificats dans YunoHost. Si vous souhaitez utiliser ces nouvelles fonctionnalités intégrées, veuillez lancer les commandes suivantes pour migrer votre installation :\n\n yunohost app remove letsencrypt\n yunohost domain cert-install\n\nN.B. : cela tentera de réinstaller les certificats de tous les domaines avec un certificat Let's Encrypt ou ceux auto-signés",
|
||||||
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
|
"certmanager_cert_signing_failed": "La signature du nouveau certificat a échoué",
|
||||||
"certmanager_no_cert_file": "Impossible de lire le fichier de certificat pour le domaine {domain:s} (fichier : {file:s})",
|
"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 de défi ACME : le fichier de configuration nginx {filepath:s} est en conflit et doit être retiré au préalable",
|
"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é demandés récemment pour cet ensemble précis de domaines {domain:s}. Veuillez réessayer plus tard. Lisez https://letsencrypt.org/docs/rate-limits/ pour obtenir plus de détails",
|
"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 LDAP n’a pas réussi à créer l’utilisateur admin",
|
"ldap_init_failed_to_create_admin": "L’initialisation de l'annuaire LDAP n’a pas réussi à créer l’utilisateur admin",
|
||||||
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
|
"ssowat_persistent_conf_read_error": "Erreur lors de la lecture de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
|
||||||
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
|
"ssowat_persistent_conf_write_error": "Erreur lors de la sauvegarde de la configuration persistante de SSOwat : {error:s}. Modifiez le fichier /etc/ssowat/conf.json.persistent pour réparer la syntaxe JSON",
|
||||||
"domain_cannot_remove_main": "Impossible de retirer le domaine principal. Définissez un nouveau domaine principal au préalable.",
|
"domain_cannot_remove_main": "Impossible de supprimer le domaine principal. Définissez d'abord un nouveau domaine principal",
|
||||||
"certmanager_self_ca_conf_file_not_found": "Le fichier de configuration pour l’autorité du certificat auto-signé est introuvable (fichier : {file: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})",
|
"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 mail Dovecot doit être démarré, si vous souhaitez voir l’espace disque occupé par la messagerie",
|
"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 :",
|
"domains_available": "Domaines disponibles :",
|
||||||
"backup_archive_broken_link": "Impossible d’accéder à l’archive de sauvegarde (lien invalide vers {path:s})",
|
"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 préalablement exécuter cert-install pour ce domaine.",
|
"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_domain_not_resolved_locally": "Le domaine {domain:s} ne peut être déterminé depuis votre serveur YunoHost. Cela peut arriver si vous avez récemment modifié votre enregistrement DNS. Auquel 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_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 lors de la tentative du serveur de se contacter via HTTP en utilisant son adresse IP publique (domaine {domain:s} avec l’IP {ip: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_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/le renouvellement du certificat a été interrompu - veuillez réessayer prochainement.",
|
"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": "Le fichier récupéré pour la liste d’applications {appslist:s} n’est pas valide",
|
"appslist_retrieve_bad_format": "Le fichier récupéré pour la liste d’applications {appslist:s} n’est pas valide",
|
||||||
"domain_hostname_failed": "Échec de la création d’un nouveau nom d’hôte",
|
"domain_hostname_failed": "Échec de la création d’un nouveau nom d’hôte",
|
||||||
"yunohost_ca_creation_success": "L’autorité de certification locale a été créée.",
|
"yunohost_ca_creation_success": "L’autorité de certification locale a été créée.",
|
||||||
"appslist_name_already_tracked": "Il y a déjà une liste d’applications enregistrée avec le nom {name:s}.",
|
"appslist_name_already_tracked": "Il y a déjà une liste d’applications enregistrée avec le nom {name:s}.",
|
||||||
"appslist_url_already_tracked": "Il y a déjà une liste d’applications enregistrée avec l’URL {url:s}.",
|
"appslist_url_already_tracked": "Il y a déjà une liste d’applications enregistrée avec l’URL {url:s}.",
|
||||||
"appslist_migrating": "Migration de la liste d’applications {appslist:s}…",
|
"appslist_migrating": "Migration de la liste d’applications {appslist:s} …",
|
||||||
"appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL… L’ancienne tâche cron a été conservée dans {bkp_file:s}.",
|
"appslist_could_not_migrate": "Impossible de migrer la liste {appslist:s} ! Impossible d’exploiter l’URL. L’ancienne tâche programmée a été conservée dans {bkp_file:s}.",
|
||||||
"appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit corrompu.",
|
"appslist_corrupted_json": "Impossible de charger la liste d’applications. Il semble que {filename:s} soit corrompu.",
|
||||||
"app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez avec « app changeurl » si c’est disponible.",
|
"app_already_installed_cant_change_url": "Cette application est déjà installée. L’URL ne peut pas être changé simplement par cette fonction. Regardez si cela est disponible avec `app changeurl`.",
|
||||||
"app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.",
|
"app_change_no_change_url_script": "L’application {app_name:s} ne prend pas encore en charge le changement d’URL, vous pourriez avoir besoin de la mettre à jour.",
|
||||||
"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_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 sont identiques pour {domain:s}{path:s}, aucune action.",
|
"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_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_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}",
|
"app_location_unavailable": "Cette URL n’est pas disponible ou est en conflit avec une application existante :\n{apps:s}",
|
||||||
"app_already_up_to_date": "{app:s} est déjà à jour",
|
"app_already_up_to_date": "{app:s} est déjà à jour",
|
||||||
"invalid_url_format": "Format d’URL non valide",
|
"invalid_url_format": "Format d’URL non valide",
|
||||||
"global_settings_bad_choice_for_enum": "La valeur du paramètre {setting:s} est incorrecte. Reçu : {received_type:s}; attendu : {expected_type:s}",
|
"global_settings_bad_choice_for_enum": "Valeur du paramètre {setting:s} incorrecte. Reçu : {received_type:s}, mais les valeurs possibles sont : {expected_type:s}",
|
||||||
"global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu : {received_type:s}; attendu : {expected_type:s}.",
|
"global_settings_bad_type_for_setting": "Le type du paramètre {setting:s} est incorrect. Reçu {received_type:s} alors que {expected_type:s} était attendu",
|
||||||
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations, cause : {reason:s}",
|
"global_settings_cant_open_settings": "Échec de l’ouverture du ficher de configurations car : {reason:s}",
|
||||||
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
|
"global_settings_cant_serialize_setings": "Échec de sérialisation des données de configurations, cause : {reason:s}",
|
||||||
"global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations, cause : {reason:s}",
|
"global_settings_cant_write_settings": "Échec d’écriture du fichier de configurations car : {reason:s}",
|
||||||
"global_settings_key_doesnt_exists": "La clef « {settings_key:s} » n’existe pas dans les configurations globales, vous pouvez voir toutes les clefs disponibles en saisissant « yunohost settings list »",
|
"global_settings_key_doesnt_exists": "La clef '{settings_key:s}' n’existe pas dans les configurations générales, vous pouvez voir toutes les clefs disponibles en saisissant 'yunohost settings list'",
|
||||||
"global_settings_reset_success": "Réussite ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
|
"global_settings_reset_success": "Super ! Vos configurations précédentes ont été sauvegardées dans {path:s}",
|
||||||
"global_settings_setting_example_bool": "Exemple d’option booléenne",
|
"global_settings_setting_example_bool": "Exemple d’option booléenne",
|
||||||
"global_settings_setting_example_int": "Exemple d’option de type entier",
|
"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_string": "Exemple d’option de type chaîne",
|
||||||
"global_settings_setting_example_enum": "Exemple d’option de type énumération",
|
"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 ce n’est pas un type 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": "Clef inconnue dans les configurations : {setting_key:s}, rejet de cette clef et sauvegarde de celle-ci dans /etc/yunohost/unkown_settings.json",
|
"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",
|
||||||
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
|
"service_conf_new_managed_file": "Le fichier de configuration « {conf} » est désormais géré par le service {service}.",
|
||||||
"service_conf_file_kept_back": "Le fichier de configuration « {conf} » devrait être supprimé par le service {service} mais a été conservé.",
|
"service_conf_file_kept_back": "Le fichier de configuration '{conf}' devait être supprimé par le service {service} mais a été conservé.",
|
||||||
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
|
"backup_abstract_method": "Cette méthode de sauvegarde n’a pas encore été implémentée",
|
||||||
"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 dans la sauvegarde…",
|
"backup_applying_method_copy": "Copie de tous les fichiers à sauvegarder …",
|
||||||
"backup_applying_method_borg": "Envoi de tous les fichiers dans la sauvegarde dans de référentiel 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_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_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_mount_failed": "Le montage de l’archive de sauvegarde a échoué",
|
||||||
"backup_archive_writing_error": "Impossible d’ajouter les fichiers à la sauvegarde dans l’archive compressée",
|
"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": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour mener la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
|
"backup_ask_for_copying_if_needed": "Certains fichiers n’ont pas pu être préparés pour être sauvegardés en utilisant la méthode qui évite temporairement de gaspiller de l’espace sur le système. Pour réaliser la sauvegarde, {size:s} Mo doivent être temporairement utilisés. Acceptez-vous ?",
|
||||||
"backup_borg_not_implemented": "La méthode de sauvegarde Bord n’est pas encore implémentée",
|
"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_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} Mio pour organiser l’archive",
|
"backup_copying_to_organize_the_archive": "Copie de {size:s} Mo pour organiser l’archive",
|
||||||
"backup_csv_creation_failed": "Impossible de créer le fichier CSV nécessaire aux opérations futures de restauration",
|
"backup_csv_creation_failed": "Impossible de créer le fichier CSV nécessaire aux opérations futures de restauration",
|
||||||
"backup_csv_addition_failed": "Impossible d’ajouter des fichiers à sauvegarder dans le fichier CSV",
|
"backup_csv_addition_failed": "Impossible d’ajouter des fichiers à sauvegarder dans le fichier CSV",
|
||||||
"backup_custom_need_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « need_mount »",
|
"backup_custom_need_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'need_mount'",
|
||||||
"backup_custom_backup_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « backup »",
|
"backup_custom_backup_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'backup'",
|
||||||
"backup_custom_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape « mount »",
|
"backup_custom_mount_error": "Échec de la méthode de sauvegarde personnalisée à l’étape 'mount'",
|
||||||
"backup_no_uncompress_archive_dir": "Le dossier de l’archive décompressée n’existe pas",
|
"backup_no_uncompress_archive_dir": "Le dossier de l’archive décompressée n’existe pas",
|
||||||
"backup_method_tar_finished": "L’archive tar de la sauvegarde a été créée",
|
"backup_method_tar_finished": "L’archive tar de la sauvegarde a été créée",
|
||||||
"backup_method_copy_finished": "La copie de la sauvegarde est terminée",
|
"backup_method_copy_finished": "La copie de la sauvegarde est terminée",
|
||||||
"backup_method_borg_finished": "La sauvegarde dans Borg est terminée",
|
"backup_method_borg_finished": "La sauvegarde dans Borg est terminée",
|
||||||
"backup_method_custom_finished": "La méthode se sauvegarde personnalisée « {method:s} » est terminée",
|
"backup_method_custom_finished": "La méthode de sauvegarde personnalisée '{method:s}' est terminée",
|
||||||
"backup_system_part_failed": "Impossible de sauvegarder la partie « {part:s} » du système",
|
"backup_system_part_failed": "Impossible de sauvegarder la partie '{part:s}' du système",
|
||||||
"backup_unable_to_organize_files": "Impossible d’organiser les fichiers dans l’archive avec la méthode rapide",
|
"backup_unable_to_organize_files": "Impossible d’organiser les fichiers dans l’archive avec la méthode rapide",
|
||||||
"backup_with_no_backup_script_for_app": "L’application {app:s} n’a pas de script de sauvegarde. Ignorer.",
|
"backup_with_no_backup_script_for_app": "L’application {app:s} n’a pas de script de sauvegarde. Ignorer.",
|
||||||
"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.",
|
"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, cause : {reason:s}",
|
"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_removing_tmp_dir_failed": "Impossible de sauvegarder un ancien dossier temporaire",
|
||||||
"restore_extracting": "Extraction des fichiers nécessaires depuis l’archive…",
|
"restore_extracting": "Extraction des fichiers nécessaires depuis l’archive …",
|
||||||
"restore_mounting_archive": "Montage de l’archive dans « {path:s} »",
|
"restore_mounting_archive": "Montage de l’archive dans '{path:s}'",
|
||||||
"restore_may_be_not_enough_disk_space": "Votre système semble ne pas avoir suffisamment d’espace disponible (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {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 (libre : {free_space:d} octets, nécessaire : {needed_space:d} octets, marge de sécurité : {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",
|
"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}.",
|
"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 registrar DNS avec cette recommandation.",
|
"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.",
|
||||||
"domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost, soit YunoHost n’est pas correctement connecté à internet ou alors le serveur de dynette est arrêté. Erreur : {error}",
|
"domain_dyndns_dynette_is_unreachable": "Impossible de contacter la dynette YunoHost. Soit YunoHost n’est pas correctement connecté à internet, soit le serveur de dynette est en panne. Erreur : {error}",
|
||||||
"migrations_backward": "Migration en arrière.",
|
"migrations_backward": "Migration en arrière.",
|
||||||
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre « target », les numéros de migration sont ou {}",
|
"migrations_bad_value_for_target": "Nombre invalide pour le paramètre target, les numéros de migration sont 0 ou {}",
|
||||||
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
|
"migrations_cant_reach_migration_file": "Impossible d’accéder aux fichiers de migrations avec le chemin %s",
|
||||||
"migrations_current_target": "La cible de migration est {}",
|
"migrations_current_target": "La cible de migration est {}",
|
||||||
"migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}",
|
"migrations_error_failed_to_load_migration": "ERREUR : échec du chargement de migration {number} {name}",
|
||||||
"migrations_forward": "Migration en avant",
|
"migrations_forward": "Migration en avant",
|
||||||
"migrations_loading_migration": "Chargement de la migration {number} {name}…",
|
"migrations_loading_migration": "Chargement de la migration {number} {name} …",
|
||||||
"migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception}, annulation",
|
"migrations_migration_has_failed": "La migration {number} {name} a échoué avec l’exception {exception} : annulation",
|
||||||
"migrations_no_migrations_to_run": "Aucune migration à lancer",
|
"migrations_no_migrations_to_run": "Aucune migration à lancer",
|
||||||
"migrations_show_currently_running_migration": "Application de la migration {number} {name}…",
|
"migrations_show_currently_running_migration": "Application de la migration {number} {name} …",
|
||||||
"migrations_show_last_migration": "La dernière migration appliquée est {}",
|
"migrations_show_last_migration": "La dernière migration appliquée est {}",
|
||||||
"migrations_skip_migration": "Omission de la migration {number} {name}…",
|
"migrations_skip_migration": "Ignorer et passer la migration {number} {name}…",
|
||||||
"server_shutdown": "Le serveur sera éteint",
|
"server_shutdown": "Le serveur va éteindre",
|
||||||
"server_shutdown_confirm": "Le serveur immédiatement être éteint, le voulez-vous vraiment ? [{answers:s}]",
|
"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": "Le serveur va redémarrer",
|
||||||
"server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]",
|
"server_reboot_confirm": "Le serveur va redémarrer immédiatement, le voulez-vous vraiment ? [{answers:s}]",
|
||||||
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
|
"app_upgrade_some_app_failed": "Impossible de mettre à jour certaines applications",
|
||||||
"ask_path": "Chemin",
|
"ask_path": "Chemin",
|
||||||
"dyndns_could_not_check_provide": "Impossible de vérifier si {provider:s} peut fournir {domain:s}.",
|
"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}.",
|
"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’app « {app} » par défaut pour le domaine {domain}, déjà utilisé par l’autre app « {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}...",
|
"app_upgrade_app_name": "Mise à jour de l’application {app} …",
|
||||||
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque / clef USB.",
|
"backup_output_symlink_dir_broken": "Vous avez un lien symbolique cassé à la place de votre dossier d’archives « {path:s} ». Vous pourriez avoir une configuration personnalisée pour sauvegarder vos données sur un autre système de fichiers, dans ce cas, vous avez probablement oublié de monter ou de connecter votre disque dur ou votre clé USB.",
|
||||||
"migrate_tsig_end": "La migration à hmac-sha512 est terminée",
|
"migrate_tsig_end": "La migration à hmac-sha512 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-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-sha512 qui est plus sécurisé",
|
"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-sha512 qui est plus sécurisé",
|
||||||
"migrate_tsig_wait": "Attendons 3 minutes pour que le serveur dyndns prenne en compte la nouvelle clef…",
|
"migrate_tsig_wait": "Attendre 3 minutes pour que le serveur DynDNS prenne en compte la nouvelle clef …",
|
||||||
"migrate_tsig_wait_2": "2 minutes…",
|
"migrate_tsig_wait_2": "2 minutes …",
|
||||||
"migrate_tsig_wait_3": "1 minute…",
|
"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 !",
|
"migrate_tsig_not_needed": "Il ne semble pas que vous utilisez un domaine DynDNS, donc aucune migration n’est nécessaire !",
|
||||||
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
|
"app_checkurl_is_deprecated": "Packagers /!\\ 'app checkurl' est obsolète ! Utilisez 'app register-url' en remplacement !",
|
||||||
"migration_description_0001_change_cert_group_to_sslcert": "Change les permissions de groupe des certificats de « metronome » à « ssl-cert »",
|
"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éliore la sécurité de DynDNDS TSIG en utilisant SHA512 au lieu de MD5",
|
"migration_description_0002_migrate_to_tsig_sha256": "Amélioration de la sécurité de DynDNS TSIG en utilisant SHA512 au lieu de MD5",
|
||||||
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
|
"migration_description_0003_migrate_to_stretch": "Mise à niveau du système vers Debian Stretch et YunoHost 3.0",
|
||||||
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
|
"migration_0003_backward_impossible": "La migration Stretch n’est pas réversible.",
|
||||||
"migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.",
|
"migration_0003_start": "Démarrage de la migration vers Stretch. Les journaux seront disponibles dans {logfile}.",
|
||||||
"migration_0003_patching_sources_list": "Modification de sources.lists…",
|
"migration_0003_patching_sources_list": "Modification du fichier sources.lists …",
|
||||||
"migration_0003_main_upgrade": "Démarrage de la mise à niveau principale…",
|
"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_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’abords 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 terminera, mais la mise à jour réelle aura lieu immédiatement après. Après cette opération terminée, vous pourriez avoir à vous reconnecter à l’administration web.",
|
"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_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 à migration à Stretch.",
|
||||||
"migration_0003_still_on_jessie_after_main_upgrade": "Quelque chose s’est ma passé pendant la mise à niveau principale : le système est toujours sur Jessie ?!? Pour investiguer le problème, veuillez regarder {log} 🙁…",
|
"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 Jessie !? Pour investiguer sur 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\nDe plus, 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_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 suivantes, éventuellement problématiques, ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées «working ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront après la mise à niveau : {problematic_apps}",
|
"migration_0003_problematic_apps_warning": "Veuillez noter que des applications possiblement problématiques ont été détectées. Il semble qu’elles n’aient pas été installées depuis une liste d’application ou qu’elles ne soit pas marquées comme « fonctionnelles ». En conséquence, nous ne pouvons pas garantir qu’elles fonctionneront 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}",
|
"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_list_conflict_pending_done": "Vous ne pouvez pas utiliser --previous et --done simultanément.",
|
||||||
"migrations_to_be_ran_manually": "La migration {number} {name} doit être lancée manuellement. Veuillez aller dans Outils > Migration dans l’interface admin, ou lancer `yunohost tools migrations migrate`.",
|
"migrations_to_be_ran_manually": "La migration {number} {name} 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 {number} {name}, 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.",
|
"migrations_need_to_accept_disclaimer": "Pour lancer la migration {number} {name}, 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": "permet d’atteindre votre serveur via yunohost.local sur votre réseau local",
|
"service_description_avahi-daemon": "permet d’atteindre votre serveur via yunohost.local sur votre réseau local",
|
||||||
"service_description_dnsmasq": "assure la résolution des noms de domaine (DNS)",
|
"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_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",
|
"service_description_fail2ban": "protège contre les attaques brute-force et autres types d’attaques venant d’Internet",
|
||||||
"service_description_glances": "surveille les informations système de votre serveur",
|
"service_description_glances": "surveille les informations système de votre serveur",
|
||||||
|
@ -410,75 +410,117 @@
|
||||||
"service_description_nslcd": "gère la connexion en ligne de commande des utilisateurs YunoHost",
|
"service_description_nslcd": "gère la connexion en ligne de commande des utilisateurs YunoHost",
|
||||||
"service_description_php5-fpm": "exécute des applications écrites en PHP avec nginx",
|
"service_description_php5-fpm": "exécute des applications écrites en PHP avec nginx",
|
||||||
"service_description_postfix": "utilisé pour envoyer et recevoir des courriels",
|
"service_description_postfix": "utilisé pour envoyer et recevoir des courriels",
|
||||||
"service_description_redis-server": "une base de donnée spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication inter-programmes",
|
"service_description_redis-server": "une base de données spécialisée utilisée pour l’accès rapide aux données, les files d’attentes et la communication entre les programmes",
|
||||||
"service_description_rmilter": "vérifie divers paramètres dans les courriels",
|
"service_description_rmilter": "vérifie divers paramètres dans les courriels",
|
||||||
"service_description_rspamd": "filtre le pourriel, et d’autres fonctionnalités liées au courriel",
|
"service_description_rspamd": "filtre le pourriel, et d’autres fonctionnalités liées au courriel",
|
||||||
"service_description_slapd": "stocke les utilisateurs, domaines et leurs informations liées",
|
"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_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-api": "permet les interactions entre l’interface web de YunoHost et le système",
|
||||||
"service_description_yunohost-firewall": "gère les ports de connexion ouverts et fermés 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 faîtes.",
|
"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 metadata associé aux logs est corrompu : {md_file}",
|
"log_corrupted_md_file": "Le fichier yaml de metadata associé aux logs est corrompu : '{md_file}'",
|
||||||
"log_category_404": "La catégorie de log « {category} » n’existe pas",
|
"log_category_404": "Le journal de la catégorie '{category}' n’existe pas",
|
||||||
"log_link_to_log": "Log complet de cette opération : « <a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a> »",
|
"log_link_to_log": "Journal historisé complet de cette opération : '<a href=\"#/tools/logs/{name}\" style=\"text-decoration:underline\"> {desc} </a>'",
|
||||||
"log_help_to_get_log": "Pour voir le log de cette opération « {desc} », utiliser la commande « yunohost log display {name} »",
|
"log_help_to_get_log": "Pour voir le journal historisé 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 avoir de l’aide, merci <a href=\"#/tools/logs/{name}\"> de fournir le log complet de l’opération</a>",
|
"log_link_to_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci <a href=\"#/tools/logs/{name}\"> de fournir le journal historisé complet de l’opération en cliquant ici</a>",
|
||||||
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, la restauration de vos applications php peut ne pas aboutir (reason: {error:s})",
|
"backup_php5_to_php7_migration_may_fail": "Impossible de convertir votre archive pour prendre en charge php7, vos applications php pourraient ne pas être restaurées (reason: {error:s})",
|
||||||
"log_help_to_get_failed_log": "L’opération « {desc} » a échouée ! Pour avoir de l’aide, merci de partager le log de cette opération en utilisant la commande « yunohost log display {name} --share »",
|
"log_help_to_get_failed_log": "L’opération '{desc}' a échouée ! Pour avoir de l’aide, merci de partager le journal historisé de cette opération en utilisant la commande 'yunohost log display {name} --share'",
|
||||||
"log_does_exists": "Il n’existe pas de log de l’opération ayant pour nom « {log} », utiliser « yunohost log list pour voir tous les fichiers de logs disponibles »",
|
"log_does_exists": "Il n’existe pas de journal historisé de l’opération ayant pour nom '{log}', utiliser 'yunohost log list pour voir tous les fichiers de journaux historisés disponibles'",
|
||||||
"log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
|
"log_operation_unit_unclosed_properly": "L’opération ne s’est pas terminée correctement",
|
||||||
"log_app_addaccess": "Ajouter l’accès à « {} »",
|
"log_app_addaccess": "Ajouter l’accès à '{}'",
|
||||||
"log_app_removeaccess": "Enlever l’accès à « {} »",
|
"log_app_removeaccess": "Enlever l’accès à '{}'",
|
||||||
"log_app_clearaccess": "Retirer tous les accès à « {} »",
|
"log_app_clearaccess": "Retirer tous les accès à '{}'",
|
||||||
"log_app_fetchlist": "Ajouter une liste d’application",
|
"log_app_fetchlist": "Ajouter une liste d’application",
|
||||||
"log_app_removelist": "Enlever une liste d’application",
|
"log_app_removelist": "Enlever une liste d’application",
|
||||||
"log_app_change_url": "Changer l’url de l’application « {} »",
|
"log_app_change_url": "Changer l’URL de l’application '{}'",
|
||||||
"log_app_install": "Installer l’application « {} »",
|
"log_app_install": "Installer l’application '{}'",
|
||||||
"log_app_remove": "Enlever l’application « {} »",
|
"log_app_remove": "Enlever l’application '{}'",
|
||||||
"log_app_upgrade": "Mettre à jour l’application « {} »",
|
"log_app_upgrade": "Mettre à jour l’application '{}'",
|
||||||
"log_app_makedefault": "Faire de « {} » l’application par défaut",
|
"log_app_makedefault": "Faire de '{}' l’application par défaut",
|
||||||
"log_available_on_yunopaste": "Le log est désormais disponible via {url}",
|
"log_available_on_yunopaste": "Le journal historisé est désormais disponible via {url}",
|
||||||
"log_backup_restore_system": "Restaurer le système depuis une sauvegarde",
|
"log_backup_restore_system": "Restaurer le système depuis une archive de sauvegarde",
|
||||||
"log_backup_restore_app": "Restaurer « {} » depuis une sauvegarde",
|
"log_backup_restore_app": "Restaurer '{}' depuis une sauvegarde",
|
||||||
"log_remove_on_failed_restore": "Retirer « {} » après la restauration depuis une sauvegarde qui a échouée",
|
"log_remove_on_failed_restore": "Retirer '{}' après un échec de restauration depuis une archive de sauvegarde",
|
||||||
"log_remove_on_failed_install": "Enlever « {} » après une installation échouée",
|
"log_remove_on_failed_install": "Enlever '{}' après une installation échouée",
|
||||||
"log_domain_add": "Ajouter le domaine « {} » dans la configuration du système",
|
"log_domain_add": "Ajouter le domaine '{}' dans la configuration du système",
|
||||||
"log_domain_remove": "Enlever le domaine « {} » de la configuration du système",
|
"log_domain_remove": "Enlever le domaine '{}' de la configuration du système",
|
||||||
"log_dyndns_subscribe": "Souscrire au sous-domaine « {} » de Yunohost",
|
"log_dyndns_subscribe": "Souscrire au sous-domaine YunoHost '{}'",
|
||||||
"log_dyndns_update": "Mettre à jour l’adresse ip associée à votre 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 encryt sur le domaine « {} »",
|
"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 le certificat auto-signé sur le domaine '{}'",
|
||||||
"log_letsencrypt_cert_renew": "Renouveler le certificat Let’s encrypt de « {} »",
|
"log_letsencrypt_cert_renew": "Renouveler le certificat Let’s Encrypt de '{}'",
|
||||||
"log_service_enable": "Activer le service « {} »",
|
"log_service_enable": "Activer le service '{}'",
|
||||||
"log_service_regen_conf": "Régénérer la configuration système de « {} »",
|
"log_service_regen_conf": "Régénérer la configuration système de '{}'",
|
||||||
"log_user_create": "Ajouter l’utilisateur « {} »",
|
"log_user_create": "Ajouter l’utilisateur '{}'",
|
||||||
"log_user_delete": "Enlever l’utilisateur « {} »",
|
"log_user_delete": "Supprimer l’utilisateur '{}'",
|
||||||
"log_user_update": "Mettre à jour les informations de l’utilisateur « {} »",
|
"log_user_update": "Mettre à jour les informations de l’utilisateur '{}'",
|
||||||
"log_tools_maindomain": "Faire de « {} » le domaine principal",
|
"log_tools_maindomain": "Faire de '{}' le domaine principal",
|
||||||
"log_tools_migrations_migrate_forward": "Migrer",
|
"log_tools_migrations_migrate_forward": "Migrer vers",
|
||||||
"log_tools_migrations_migrate_backward": "Revenir en arrière",
|
"log_tools_migrations_migrate_backward": "Revenir en arrière",
|
||||||
"log_tools_postinstall": "Faire la post-installation du serveur Yunohost",
|
"log_tools_postinstall": "Faire la post-installation de votre serveur YunoHost",
|
||||||
"log_tools_upgrade": "Mise à jour des paquets Debian",
|
"log_tools_upgrade": "Mise à jour des paquets Debian",
|
||||||
"log_tools_shutdown": "Eteindre votre serveur",
|
"log_tools_shutdown": "Éteindre votre serveur",
|
||||||
"log_tools_reboot": "Redémarrer votre serveur",
|
"log_tools_reboot": "Redémarrer votre serveur",
|
||||||
"mail_unavailable": "Cette adresse mail est réservée et doit être automatiquement attribuée au tout premier utilisateur",
|
"mail_unavailable": "Cette adresse de courriel est réservée et doit être automatiquement attribuée au tout premier utilisateur",
|
||||||
"migration_description_0004_php5_to_php7_pools": "Reconfigurez le pool PHP pour utiliser PHP 7 au lieu de 5",
|
"migration_description_0004_php5_to_php7_pools": "Reconfiguration des pools 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 9.6",
|
"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_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 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": "Il n’y a pas assez d’espace libre de disponible sur {path} pour lancer maintenant la migration :(.",
|
"migration_0005_not_enough_space": "Il n’y a pas assez d’espace libre de disponible sur {path} pour lancer maintenant 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 « yunohost user create » ou l’interface d’administration.",
|
"recommend_to_add_first_user": "La post-installation est terminée. YunoHost a besoin d’au moins un utilisateur pour fonctionner correctement. Vous devez en ajouter un en utilisant 'yunohost user create' ou bien via l’interface d’administration web.",
|
||||||
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec nginx",
|
"service_description_php7.0-fpm": "exécute des applications écrites en PHP avec Nginx",
|
||||||
"users_available": "Liste des utilisateurs disponibles :",
|
"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 de chiffrement) et/ou d’utiliser différents types de caractères (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 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 de chiffrement) 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 (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_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 admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
|
"migration_0006_disclaimer": "YunoHost s’attendra désormais à ce que les mots de passe admin et root soient synchronisés. En exécutant cette migration, votre mot de passe root sera remplacé par le mot de passe administrateur.",
|
||||||
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
|
"migration_0006_done": "Votre mot de passe root a été remplacé par celui de votre adminitrateur.",
|
||||||
"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 unique.",
|
"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_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 caractères majuscules et minuscules",
|
"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 caractères majuscules, minuscules et spéciaux",
|
"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",
|
||||||
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des caractères majuscules, minuscules et spéciaux",
|
"password_too_simple_4": "Le mot de passe doit comporter au moins 12 caractères et contenir des chiffres, des majuscules, des minuscules et des caractères spéciaux",
|
||||||
"root_password_desynchronized": "Le mot de passe administrateur a été changé, mais YunoHost n’a pas pu le propager sur le mot de passe root !"
|
"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": "Interruption.",
|
||||||
|
"app_not_upgraded": "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 {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": "AVERTISSEMENT ! Cette application est encore expérimentale (explicitement, elle ne fonctionne pas) et risque de casser votre système ! Vous ne devriez probablement PAS l'installer sans savoir ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{answers:s}] ",
|
||||||
|
"confirm_app_install_thirdparty": "AVERTISSEMENT ! 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 si vous ne savez pas ce que vous faites. Êtes-vous prêt à prendre ce risque ? [{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.",
|
||||||
|
"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",
|
||||||
|
"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": "YunoHost n'a pas réussi à améliorer la façon dont est gérée 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_warning": "Si vous comprenez ces avertissements et que vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer la migration, bien que cela ne soit pas recommandé.",
|
||||||
|
"migration_0008_no_warning": "Aucun risque majeur n'a été identifié concernant l'écrasement de votre configuration SSH - mais nous ne pouvons pas en être absolument sûrs ;) ! Si vous acceptez de laisser YunoHost remplacer votre configuration actuelle, exécutez la migration. Sinon, vous pouvez également passer 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 doivent 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.",
|
||||||
|
"service_conf_now_managed_by_yunohost": "Le fichier de configuration '{conf}' est maintenant géré par YunoHost.",
|
||||||
|
"service_reload_failed": "Impossible de recharger le service '{service:s}'.\n\nJournaux historisés récents de ce service : {logs:s}",
|
||||||
|
"service_reloaded": "Le service '{service:s}' a été rechargé",
|
||||||
|
"service_restart_failed": "Impossible de redémarrer le service '{service:s}'\n\nJournaux historisés récents de ce service : {logs:s}",
|
||||||
|
"service_restarted": "Le service '{service:s}' a été redémarré",
|
||||||
|
"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`."
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"service_stop_failed": "Impossibile fermare il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
"service_stop_failed": "Impossibile fermare il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
||||||
"system_username_exists": "il nome utente esiste già negli utenti del sistema",
|
"system_username_exists": "il nome utente esiste già negli utenti del sistema",
|
||||||
"unrestore_app": "L'applicazione '{app:s}' non verrà ripristinata",
|
"unrestore_app": "L'applicazione '{app:s}' non verrà ripristinata",
|
||||||
"upgrading_packages": "Aggiornamento dei pacchetti...",
|
"upgrading_packages": "Aggiornamento dei pacchetti…",
|
||||||
"user_deleted": "L'utente è stato cancellato",
|
"user_deleted": "L'utente è stato cancellato",
|
||||||
"admin_password": "Password dell'amministrazione",
|
"admin_password": "Password dell'amministrazione",
|
||||||
"admin_password_change_failed": "Impossibile cambiare la password",
|
"admin_password_change_failed": "Impossibile cambiare la password",
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
"appslist_fetched": "La lista delle applicazioni {appslist:s} è stata recuperata",
|
"appslist_fetched": "La lista delle applicazioni {appslist:s} è stata recuperata",
|
||||||
"appslist_removed": "La lista delle applicazioni {appslist:s} è stata rimossa",
|
"appslist_removed": "La lista delle applicazioni {appslist:s} è stata rimossa",
|
||||||
"app_package_need_update": "Il pacchetto dell'applicazione {app} deve essere aggiornato per seguire i cambiamenti di YunoHost",
|
"app_package_need_update": "Il pacchetto dell'applicazione {app} deve essere aggiornato per seguire i cambiamenti di YunoHost",
|
||||||
"app_requirements_checking": "Controllo i pacchetti richiesti per {app}...",
|
"app_requirements_checking": "Controllo i pacchetti richiesti per {app}…",
|
||||||
"app_requirements_failed": "Impossibile soddisfare i requisiti per {app}: {error}",
|
"app_requirements_failed": "Impossibile soddisfare i requisiti per {app}: {error}",
|
||||||
"app_requirements_unmeet": "Requisiti non soddisfatti per {app}, il pacchetto {pkgname} ({version}) deve essere {spec}",
|
"app_requirements_unmeet": "Requisiti non soddisfatti per {app}, il pacchetto {pkgname} ({version}) deve essere {spec}",
|
||||||
"appslist_unknown": "Lista di applicazioni {appslist:s} sconosciuta.",
|
"appslist_unknown": "Lista di applicazioni {appslist:s} sconosciuta.",
|
||||||
|
@ -72,16 +72,16 @@
|
||||||
"backup_archive_name_unknown": "Archivio di backup locale chiamato '{name:s}' sconosciuto",
|
"backup_archive_name_unknown": "Archivio di backup locale chiamato '{name:s}' sconosciuto",
|
||||||
"backup_archive_open_failed": "Non è possibile aprire l'archivio di backup",
|
"backup_archive_open_failed": "Non è possibile aprire l'archivio di backup",
|
||||||
"backup_cleaning_failed": "Non è possibile pulire la directory temporanea di backup",
|
"backup_cleaning_failed": "Non è possibile pulire la directory temporanea di backup",
|
||||||
"backup_creating_archive": "Creazione del archivio di backup...",
|
"backup_creating_archive": "Creazione del archivio di backup…",
|
||||||
"backup_creation_failed": "La creazione del backup è fallita",
|
"backup_creation_failed": "La creazione del backup è fallita",
|
||||||
"backup_delete_error": "Impossibile cancellare '{path:s}'",
|
"backup_delete_error": "Impossibile cancellare '{path:s}'",
|
||||||
"backup_deleted": "Il backup è stato cancellato",
|
"backup_deleted": "Il backup è stato cancellato",
|
||||||
"backup_extracting_archive": "Estrazione del archivio di backup...",
|
"backup_extracting_archive": "Estrazione del archivio di backup…",
|
||||||
"backup_hook_unknown": "Hook di backup '{hook:s}' sconosciuto",
|
"backup_hook_unknown": "Hook di backup '{hook:s}' sconosciuto",
|
||||||
"backup_nothings_done": "Non c'è niente da salvare",
|
"backup_nothings_done": "Non c'è niente da salvare",
|
||||||
"backup_output_directory_forbidden": "Directory di output vietata. I backup non possono esser creati nelle sotto-cartelle /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o /home/yunohost.backup/archives",
|
"backup_output_directory_forbidden": "Directory di output vietata. I backup non possono esser creati nelle sotto-cartelle /bin, /boot, /dev, /etc, /lib, /root, /run, /sbin, /sys, /usr, /var o /home/yunohost.backup/archives",
|
||||||
"backup_output_directory_required": "Devi fornire una directory di output per il backup",
|
"backup_output_directory_required": "Devi fornire una directory di output per il backup",
|
||||||
"backup_running_hooks": "Esecuzione dei hook di backup...",
|
"backup_running_hooks": "Esecuzione degli hook di backup…",
|
||||||
"custom_app_url_required": "Devi fornire un URL per essere in grado di aggiornare l'applicazione personalizzata {app:s}",
|
"custom_app_url_required": "Devi fornire un URL per essere in grado di aggiornare l'applicazione personalizzata {app:s}",
|
||||||
"custom_appslist_name_required": "Devi fornire un nome per la lista di applicazioni personalizzata",
|
"custom_appslist_name_required": "Devi fornire un nome per la lista di applicazioni personalizzata",
|
||||||
"diagnosis_debian_version_error": "Impossibile riportare la versione di Debian: {error}",
|
"diagnosis_debian_version_error": "Impossibile riportare la versione di Debian: {error}",
|
||||||
|
@ -103,21 +103,21 @@
|
||||||
"domain_zone_not_found": "Il file di zona DNS non è stato trovato per il dominio {:s}",
|
"domain_zone_not_found": "Il file di zona DNS non è stato trovato per il dominio {:s}",
|
||||||
"done": "Terminato",
|
"done": "Terminato",
|
||||||
"domains_available": "Domini disponibili:",
|
"domains_available": "Domini disponibili:",
|
||||||
"downloading": "Scaricamento...",
|
"downloading": "Scaricamento…",
|
||||||
"dyndns_cron_installed": "Il cronjob DynDNS è stato installato",
|
"dyndns_cron_installed": "Il cronjob DynDNS è stato installato",
|
||||||
"dyndns_cron_remove_failed": "Impossibile rimuovere il cronjob DynDNS",
|
"dyndns_cron_remove_failed": "Impossibile rimuovere il cronjob DynDNS",
|
||||||
"dyndns_cron_removed": "Il cronjob DynDNS è stato rimosso",
|
"dyndns_cron_removed": "Il cronjob DynDNS è stato rimosso",
|
||||||
"dyndns_ip_update_failed": "Impossibile aggiornare l'indirizzo IP in DynDNS",
|
"dyndns_ip_update_failed": "Impossibile aggiornare l'indirizzo IP in DynDNS",
|
||||||
"dyndns_ip_updated": "Il tuo indirizzo IP è stato aggiornato in DynDNS",
|
"dyndns_ip_updated": "Il tuo indirizzo IP è stato aggiornato in DynDNS",
|
||||||
"dyndns_key_generating": "La chiave DNS sta generando, potrebbe richiedere del tempo...",
|
"dyndns_key_generating": "Si sta generando la chiave DNS, potrebbe richiedere del tempo…",
|
||||||
"dyndns_key_not_found": "La chiave DNS non è stata trovata per il dominio",
|
"dyndns_key_not_found": "La chiave DNS non è stata trovata per il dominio",
|
||||||
"dyndns_no_domain_registered": "Nessuno dominio è stato registrato con DynDNS",
|
"dyndns_no_domain_registered": "Nessuno dominio è stato registrato con DynDNS",
|
||||||
"dyndns_registered": "Il dominio DynDNS è stato registrato",
|
"dyndns_registered": "Il dominio DynDNS è stato registrato",
|
||||||
"dyndns_registration_failed": "Non è possibile registrare il dominio DynDNS: {error:s}",
|
"dyndns_registration_failed": "Non è possibile registrare il dominio DynDNS: {error:s}",
|
||||||
"dyndns_unavailable": "Dominio {domain:s} non disponibile.",
|
"dyndns_unavailable": "Dominio {domain:s} non disponibile.",
|
||||||
"executing_command": "Esecuzione del comando '{command:s}'...",
|
"executing_command": "Esecuzione del comando '{command:s}'…",
|
||||||
"executing_script": "Esecuzione dello script '{script:s}'...",
|
"executing_script": "Esecuzione dello script '{script:s}'…",
|
||||||
"extracting": "Estrazione...",
|
"extracting": "Estrazione…",
|
||||||
"field_invalid": "Campo '{:s}' non valido",
|
"field_invalid": "Campo '{:s}' non valido",
|
||||||
"firewall_reload_failed": "Impossibile ricaricare il firewall",
|
"firewall_reload_failed": "Impossibile ricaricare il firewall",
|
||||||
"firewall_reloaded": "Il firewall è stato ricaricato",
|
"firewall_reloaded": "Il firewall è stato ricaricato",
|
||||||
|
@ -187,8 +187,8 @@
|
||||||
"package_unexpected_error": "Un'errore inaspettata si è verificata durante il trattamento del pacchetto '{pkgname}'",
|
"package_unexpected_error": "Un'errore inaspettata si è verificata durante il trattamento del pacchetto '{pkgname}'",
|
||||||
"restore_hook_unavailable": "Lo script di ripristino per '{part:s}' non è disponibile per il tuo sistema e non è nemmeno nell'archivio",
|
"restore_hook_unavailable": "Lo script di ripristino per '{part:s}' non è disponibile per il tuo sistema e non è nemmeno nell'archivio",
|
||||||
"restore_nothings_done": "Non è stato ripristinato nulla",
|
"restore_nothings_done": "Non è stato ripristinato nulla",
|
||||||
"restore_running_app_script": "Esecuzione dello script di ripristino dell'applcicazione '{app:s}'...",
|
"restore_running_app_script": "Esecuzione dello script di ripristino dell'applicazione '{app:s}'…",
|
||||||
"restore_running_hooks": "Esecuzione dei hook di ripristino...",
|
"restore_running_hooks": "Esecuzione degli hook di ripristino…",
|
||||||
"service_added": "Il servizio '{service:s}' è stato aggiunto",
|
"service_added": "Il servizio '{service:s}' è stato aggiunto",
|
||||||
"service_already_started": "Il servizio '{service:s}' è già stato avviato",
|
"service_already_started": "Il servizio '{service:s}' è già stato avviato",
|
||||||
"service_already_stopped": "Il servizio '{service:s}' è già stato fermato",
|
"service_already_stopped": "Il servizio '{service:s}' è già stato fermato",
|
||||||
|
@ -207,9 +207,9 @@
|
||||||
"service_enable_failed": "Impossibile abilitare il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
"service_enable_failed": "Impossibile abilitare il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
||||||
"service_enabled": "Il servizio '{service:s}' è stato attivato",
|
"service_enabled": "Il servizio '{service:s}' è stato attivato",
|
||||||
"service_no_log": "Nessuno registro da visualizzare per il servizio '{service:s}'",
|
"service_no_log": "Nessuno registro da visualizzare per il servizio '{service:s}'",
|
||||||
"service_regenconf_dry_pending_applying": "Verificazione della configurazione in attesa che sarebbe stata applicata per il servizio '{service}'...",
|
"service_regenconf_dry_pending_applying": "Verifica della configurazione in sospeso che sarebbe stata applicata per il servizio '{service}'…",
|
||||||
"service_regenconf_failed": "Impossibile rigenerare la configurazione per il/i servizio/i: {services}",
|
"service_regenconf_failed": "Impossibile rigenerare la configurazione per il/i servizio/i: {services}",
|
||||||
"service_regenconf_pending_applying": "Applicazione della configurazione in attesa per il servizio '{service}'...",
|
"service_regenconf_pending_applying": "Applicazione della configurazione in sospeso per il servizio '{service}'…",
|
||||||
"service_start_failed": "Impossibile eseguire il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
"service_start_failed": "Impossibile eseguire il servizio '{service:s}'\n\nRegistri di servizio recenti:{logs:s}",
|
||||||
"service_started": "Il servizio '{service:s}' è stato avviato",
|
"service_started": "Il servizio '{service:s}' è stato avviato",
|
||||||
"service_status_failed": "Impossibile determinare lo stato del servizio '{service:s}'",
|
"service_status_failed": "Impossibile determinare lo stato del servizio '{service:s}'",
|
||||||
|
@ -225,7 +225,7 @@
|
||||||
"unit_unknown": "Unità '{unit:s}' sconosciuta",
|
"unit_unknown": "Unità '{unit:s}' sconosciuta",
|
||||||
"unlimit": "Nessuna quota",
|
"unlimit": "Nessuna quota",
|
||||||
"update_cache_failed": "Impossibile aggiornare la cache APT",
|
"update_cache_failed": "Impossibile aggiornare la cache APT",
|
||||||
"updating_apt_cache": "Aggiornamento della lista dei pacchetti disponibili...",
|
"updating_apt_cache": "Recupero degli aggiornamenti disponibili per i pacchietti di sistema…",
|
||||||
"upgrade_complete": "Aggiornamento completo",
|
"upgrade_complete": "Aggiornamento completo",
|
||||||
"upnp_dev_not_found": "Nessuno supporto UPnP trovato",
|
"upnp_dev_not_found": "Nessuno supporto UPnP trovato",
|
||||||
"upnp_disabled": "UPnP è stato disattivato",
|
"upnp_disabled": "UPnP è stato disattivato",
|
||||||
|
@ -241,13 +241,13 @@
|
||||||
"yunohost_already_installed": "YunoHost è già installato",
|
"yunohost_already_installed": "YunoHost è già installato",
|
||||||
"yunohost_ca_creation_failed": "Impossibile creare una certificate authority",
|
"yunohost_ca_creation_failed": "Impossibile creare una certificate authority",
|
||||||
"yunohost_configured": "YunoHost è stato configurato",
|
"yunohost_configured": "YunoHost è stato configurato",
|
||||||
"yunohost_installing": "Installazione di YunoHost...",
|
"yunohost_installing": "Installazione di YunoHost…",
|
||||||
"yunohost_not_installed": "YunoHost non è o non corretamente installato. Esegui 'yunohost tools postinstall'",
|
"yunohost_not_installed": "YunoHost non è o non corretamente installato. Esegui 'yunohost tools postinstall'",
|
||||||
"domain_cert_gen_failed": "Impossibile generare il certificato",
|
"domain_cert_gen_failed": "Impossibile generare il certificato",
|
||||||
"certmanager_attempt_to_replace_valid_cert": "Stai provando a sovrascrivere un certificato buono e valido per il dominio {domain:s}! (Usa --force per ignorare)",
|
"certmanager_attempt_to_replace_valid_cert": "Stai provando a sovrascrivere un certificato buono e valido per il dominio {domain:s}! (Usa --force per ignorare)",
|
||||||
"certmanager_domain_unknown": "Dominio {domain:s} sconosciuto",
|
"certmanager_domain_unknown": "Dominio {domain:s} sconosciuto",
|
||||||
"certmanager_domain_cert_not_selfsigned": "Il ceritifcato per il dominio {domain:s} non è auto-firmato. Sei sicuro di volere sostituirlo? (Usa --force)",
|
"certmanager_domain_cert_not_selfsigned": "Il ceritifcato per il dominio {domain:s} non è auto-firmato. Sei sicuro di volere sostituirlo? (Usa --force)",
|
||||||
"certmanager_certificate_fetching_or_enabling_failed": "L'attivazione del nuovo certificato per {domain:s} sembra fallita in qualche modo...",
|
"certmanager_certificate_fetching_or_enabling_failed": "L'attivazione del nuovo certificato per {domain:s} sembra fallita per qualche motivo…",
|
||||||
"certmanager_attempt_to_renew_nonLE_cert": "Il certificato per il dominio {domain:s} non è emesso da Let's Encrypt. Impossibile rinnovarlo automaticamente!",
|
"certmanager_attempt_to_renew_nonLE_cert": "Il certificato per il dominio {domain:s} non è emesso da Let's Encrypt. Impossibile rinnovarlo automaticamente!",
|
||||||
"certmanager_attempt_to_renew_valid_cert": "Il certificato per il dominio {domain:s} non è a scadere! Usa --force per ignorare",
|
"certmanager_attempt_to_renew_valid_cert": "Il certificato per il dominio {domain:s} non è a scadere! Usa --force per ignorare",
|
||||||
"certmanager_domain_http_not_working": "Sembra che non sia possibile accedere al dominio {domain:s} attraverso HTTP. Verifica la configurazione del DNS e di nginx",
|
"certmanager_domain_http_not_working": "Sembra che non sia possibile accedere al dominio {domain:s} attraverso HTTP. Verifica la configurazione del DNS e di nginx",
|
||||||
|
@ -260,19 +260,19 @@
|
||||||
"app_change_url_success": "URL dell'applicazione {app:s} cambiato con successo in {domain:s}{path:s}",
|
"app_change_url_success": "URL dell'applicazione {app:s} cambiato con successo in {domain:s}{path:s}",
|
||||||
"app_make_default_location_already_used": "Impostazione dell'applicazione '{app}' come predefinita del dominio {domain} non riuscita perchè è già stata impostata per l'altra applicazione '{other_app}'",
|
"app_make_default_location_already_used": "Impostazione dell'applicazione '{app}' come predefinita del dominio {domain} non riuscita perchè è già stata impostata per l'altra applicazione '{other_app}'",
|
||||||
"app_location_unavailable": "Questo URL non è disponibile o va in conflitto con la/le applicazione/i già installata/e:\n{apps:s}",
|
"app_location_unavailable": "Questo URL non è disponibile o va in conflitto con la/le applicazione/i già installata/e:\n{apps:s}",
|
||||||
"app_upgrade_app_name": "Aggiornando l'applicazione {app}...",
|
"app_upgrade_app_name": "Aggiornando l'applicazione {app}…",
|
||||||
"app_upgrade_some_app_failed": "Impossibile aggiornare alcune applicazioni",
|
"app_upgrade_some_app_failed": "Impossibile aggiornare alcune applicazioni",
|
||||||
"appslist_corrupted_json": "Caricamento della lista delle applicazioni non riuscita. Sembra che {filename:s} sia corrotto.",
|
"appslist_corrupted_json": "Caricamento della lista delle applicazioni non riuscita. Sembra che {filename:s} sia corrotto.",
|
||||||
"appslist_could_not_migrate": "Migrazione della lista delle applicazioni {appslist:s} non riuscita! Impossibile analizzare l'URL... La vecchia operazione pianificata è stata tenuta in {bkp_file:s}.",
|
"appslist_could_not_migrate": "Migrazione della lista delle applicazioni {appslist:s} non riuscita! Impossibile analizzare l'URL... La vecchia operazione pianificata è stata tenuta in {bkp_file:s}.",
|
||||||
"appslist_migrating": "Migrando la lista di applicazioni {appslist:s} ...",
|
"appslist_migrating": "Migrando la lista di applicazioni {appslist:s}…",
|
||||||
"appslist_name_already_tracked": "C'è già una lista di applicazioni registrata con il nome {name:s}.",
|
"appslist_name_already_tracked": "C'è già una lista di applicazioni registrata con il nome {name:s}.",
|
||||||
"appslist_url_already_tracked": "C'è già una lista di applicazioni registrata con URL {url:s}.",
|
"appslist_url_already_tracked": "C'è già una lista di applicazioni registrata con URL {url:s}.",
|
||||||
"ask_path": "Percorso",
|
"ask_path": "Percorso",
|
||||||
"backup_abstract_method": "Questo metodo di backup non è ancora stato implementato",
|
"backup_abstract_method": "Questo metodo di backup non è ancora stato implementato",
|
||||||
"backup_applying_method_borg": "Inviando tutti i file da salvare nel backup nel deposito borg-backup...",
|
"backup_applying_method_borg": "Inviando tutti i file da salvare nel backup nel deposito borg-backup…",
|
||||||
"backup_applying_method_copy": "Copiando tutti i files nel backup...",
|
"backup_applying_method_copy": "Copiando tutti i files nel backup…",
|
||||||
"backup_applying_method_custom": "Chiamando il metodo di backup personalizzato '{method:s}'...",
|
"backup_applying_method_custom": "Chiamando il metodo di backup personalizzato '{method:s}'…",
|
||||||
"backup_applying_method_tar": "Creando l'archivio tar del backup...",
|
"backup_applying_method_tar": "Creando l'archivio tar del backup…",
|
||||||
"backup_archive_mount_failed": "Montaggio dell'archivio del backup non riuscito",
|
"backup_archive_mount_failed": "Montaggio dell'archivio del backup non riuscito",
|
||||||
"backup_archive_system_part_not_available": "La parte di sistema '{part:s}' non è disponibile in questo backup",
|
"backup_archive_system_part_not_available": "La parte di sistema '{part:s}' non è disponibile in questo backup",
|
||||||
"backup_archive_writing_error": "Impossibile aggiungere i file al backup nell'archivio compresso",
|
"backup_archive_writing_error": "Impossibile aggiungere i file al backup nell'archivio compresso",
|
||||||
|
@ -298,5 +298,28 @@
|
||||||
"backup_with_no_restore_script_for_app": "L'app {app:s} non ha script di ripristino, non sarai in grado di ripristinarla automaticamente dal backup di questa app.",
|
"backup_with_no_restore_script_for_app": "L'app {app:s} non ha script di ripristino, non sarai in grado di ripristinarla automaticamente dal backup di questa app.",
|
||||||
"certmanager_acme_not_configured_for_domain": "Il certificato per il dominio {domain:s} non sembra essere correttamente installato. Per favore esegui cert-install per questo dominio prima.",
|
"certmanager_acme_not_configured_for_domain": "Il certificato per il dominio {domain:s} non sembra essere correttamente installato. Per favore esegui cert-install per questo dominio prima.",
|
||||||
"certmanager_cannot_read_cert": "Qualcosa è andato storto nel tentativo di aprire il certificato attuale per il dominio {domain:s} (file: {file:s}), motivo: {reason:s}",
|
"certmanager_cannot_read_cert": "Qualcosa è andato storto nel tentativo di aprire il certificato attuale per il dominio {domain:s} (file: {file:s}), motivo: {reason:s}",
|
||||||
"certmanager_cert_install_success": "Certificato Let's Encrypt per il dominio {domain:s} installato con successo!"
|
"certmanager_cert_install_success": "Certificato Let's Encrypt per il dominio {domain:s} installato con successo!",
|
||||||
|
"aborting": "Annullamento.",
|
||||||
|
"admin_password_too_long": "Per favore scegli una password più corta di 127 caratteri",
|
||||||
|
"app_not_upgraded": "Le seguenti app non sono state aggiornate: {apps}",
|
||||||
|
"app_start_install": "Installando l'applicazione {app}…",
|
||||||
|
"app_start_remove": "Rimuovendo l'applicazione {app}…",
|
||||||
|
"app_start_backup": "Raccogliendo file da salvare nel backup per {app}…",
|
||||||
|
"app_start_restore": "Ripristinando l'applicazione {app}…",
|
||||||
|
"app_upgrade_several_apps": "Le seguenti app saranno aggiornate : {apps}",
|
||||||
|
"ask_new_domain": "Nuovo dominio",
|
||||||
|
"ask_new_path": "Nuovo percorso",
|
||||||
|
"backup_actually_backuping": "Creando un archivio di backup con i file raccolti…",
|
||||||
|
"backup_mount_archive_for_restore": "Preparando l'archivio per il ripristino…",
|
||||||
|
"certmanager_cert_install_success_selfsigned": "Certificato autofirmato installato con successo per il dominio {domain:s}!",
|
||||||
|
"certmanager_cert_renew_success": "Certificato di Let's Encrypt rinnovato con successo per il dominio {domain:s}!",
|
||||||
|
"certmanager_cert_signing_failed": "Firma del nuovo certificato fallita",
|
||||||
|
"good_practices_about_user_password": "Ora stai per impostare una nuova password utente. La password dovrebbe essere di almeno 8 caratteri - anche se è buona pratica utilizzare password più lunghe (es. una sequenza di parole) e/o utilizzare vari tipi di caratteri (maiuscole, minuscole, numeri e simboli).",
|
||||||
|
"password_listed": "Questa password è una tra le più utilizzate al mondo. Per favore scegline una più unica.",
|
||||||
|
"password_too_simple_1": "La password deve essere lunga almeno 8 caratteri",
|
||||||
|
"password_too_simple_2": "La password deve essere lunga almeno 8 caratteri e contenere numeri, maiuscole e minuscole",
|
||||||
|
"password_too_simple_3": "La password deve essere lunga almeno 8 caratteri e contenere numeri, maiuscole e minuscole e simboli",
|
||||||
|
"password_too_simple_4": "La password deve essere lunga almeno 12 caratteri e contenere numeri, maiuscole e minuscole",
|
||||||
|
"users_available": "Utenti disponibili:",
|
||||||
|
"yunohost_ca_creation_success": "L'autorità di certificazione locale è stata creata."
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"app_not_properly_removed": "{app:s} es pas estat corrèctament suprimit",
|
"app_not_properly_removed": "{app:s} es pas estat corrèctament suprimit",
|
||||||
"app_removed": "{app:s} es estat suprimit",
|
"app_removed": "{app:s} es estat suprimit",
|
||||||
"app_unknown": "Aplicacion desconeguda",
|
"app_unknown": "Aplicacion desconeguda",
|
||||||
"app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}...",
|
"app_upgrade_app_name": "Mesa a jorn de l’aplicacion {app}…",
|
||||||
"app_upgrade_failed": "Impossible de metre a jorn {app:s}",
|
"app_upgrade_failed": "Impossible de metre a jorn {app:s}",
|
||||||
"app_upgrade_some_app_failed": "D’aplicacions se pòdon pas metre a jorn",
|
"app_upgrade_some_app_failed": "D’aplicacions se pòdon pas metre a jorn",
|
||||||
"app_upgraded": "{app:s} es estat mes a jorn",
|
"app_upgraded": "{app:s} es estat mes a jorn",
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
"app_location_already_used": "L’aplicacion « {app} » es ja installada a aqueste emplaçament ({path})",
|
"app_location_already_used": "L’aplicacion « {app} » es ja installada a aqueste emplaçament ({path})",
|
||||||
"app_manifest_invalid": "Manifest d’aplicacion incorrècte : {error}",
|
"app_manifest_invalid": "Manifest d’aplicacion incorrècte : {error}",
|
||||||
"app_package_need_update": "Lo paquet de l’aplicacion {app} deu èsser mes a jorn per seguir los cambiaments de YunoHost",
|
"app_package_need_update": "Lo paquet de l’aplicacion {app} deu èsser mes a jorn per seguir los cambiaments de YunoHost",
|
||||||
"app_requirements_checking": "Verificacion dels paquets requesida per {app}...",
|
"app_requirements_checking": "Verificacion dels paquets requesits per {app}…",
|
||||||
"app_sources_fetch_failed": "Recuperacion dels fichièrs fonts impossibla",
|
"app_sources_fetch_failed": "Recuperacion dels fichièrs fonts impossibla",
|
||||||
"app_unsupported_remote_type": "Lo tipe alonhat utilizat per l’aplicacion es pas suportat",
|
"app_unsupported_remote_type": "Lo tipe alonhat utilizat per l’aplicacion es pas suportat",
|
||||||
"appslist_retrieve_error": "Impossible de recuperar la lista d’aplicacions alonhadas {appslist:s} : {error:s}",
|
"appslist_retrieve_error": "Impossible de recuperar la lista d’aplicacions alonhadas {appslist:s} : {error:s}",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"backup_cleaning_failed": "Impossible de netejar lo repertòri temporari de salvagarda",
|
"backup_cleaning_failed": "Impossible de netejar lo repertòri temporari de salvagarda",
|
||||||
"backup_copying_to_organize_the_archive": "Còpia de {size:s} Mio per organizar l’archiu",
|
"backup_copying_to_organize_the_archive": "Còpia de {size:s} Mio per organizar l’archiu",
|
||||||
"backup_created": "Salvagarda acabada",
|
"backup_created": "Salvagarda acabada",
|
||||||
"backup_creating_archive": "Creacion de l’archiu de salvagarda...",
|
"backup_creating_archive": "Creacion de l’archiu de salvagarda…",
|
||||||
"backup_creation_failed": "Impossible de crear la salvagarda",
|
"backup_creation_failed": "Impossible de crear la salvagarda",
|
||||||
"app_already_installed_cant_change_url": "Aquesta aplicacion es ja installada. Aquesta foncion pòt pas simplament cambiar l’URL. Agachatz « app changeurl » s’es disponible.",
|
"app_already_installed_cant_change_url": "Aquesta aplicacion es ja installada. Aquesta foncion pòt pas simplament cambiar l’URL. Agachatz « app changeurl » s’es disponible.",
|
||||||
"app_change_no_change_url_script": "L’aplicacion {app_name:s} pren pas en compte lo cambiament d’URL, poiretz aver de la metre a jorn.",
|
"app_change_no_change_url_script": "L’aplicacion {app_name:s} pren pas en compte lo cambiament d’URL, poiretz aver de la metre a jorn.",
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
"backup_output_directory_not_empty": "Lo dorsièr de sortida es pas void",
|
"backup_output_directory_not_empty": "Lo dorsièr de sortida es pas void",
|
||||||
"backup_output_directory_required": "Vos cal especificar un dorsièr de sortida per la salvagarda",
|
"backup_output_directory_required": "Vos cal especificar un dorsièr de sortida per la salvagarda",
|
||||||
"backup_running_app_script": "Lançament de l’escript de salvagarda de l’aplicacion « {app:s} »...",
|
"backup_running_app_script": "Lançament de l’escript de salvagarda de l’aplicacion « {app:s} »...",
|
||||||
"backup_running_hooks": "Execucion dels scripts de salvagarda...",
|
"backup_running_hooks": "Execucion dels scripts de salvagarda…",
|
||||||
"backup_system_part_failed": "Impossible de salvagardar la part « {part:s} » del sistèma",
|
"backup_system_part_failed": "Impossible de salvagardar la part « {part:s} » del sistèma",
|
||||||
"app_requirements_failed": "Impossible de complir las condicions requesidas per {app} : {error}",
|
"app_requirements_failed": "Impossible de complir las condicions requesidas per {app} : {error}",
|
||||||
"app_requirements_unmeet": "Las condicions requesidas per {app} son pas complidas, lo paquet {pkgname} ({version}) deu èsser {spec}",
|
"app_requirements_unmeet": "Las condicions requesidas per {app} son pas complidas, lo paquet {pkgname} ({version}) deu èsser {spec}",
|
||||||
|
@ -112,7 +112,7 @@
|
||||||
"upnp_port_open_failed": "Impossible de dobrir los pòrts amb UPnP",
|
"upnp_port_open_failed": "Impossible de dobrir los pòrts amb UPnP",
|
||||||
"yunohost_already_installed": "YunoHost es ja installat",
|
"yunohost_already_installed": "YunoHost es ja installat",
|
||||||
"yunohost_configured": "YunoHost es estat configurat",
|
"yunohost_configured": "YunoHost es estat configurat",
|
||||||
"yunohost_installing": "Installacion de YunoHost...",
|
"yunohost_installing": "Installacion de YunoHost…",
|
||||||
"backup_applying_method_borg": "Mandadís de totes los fichièrs a la salvagarda dins lo repertòri borg-backup…",
|
"backup_applying_method_borg": "Mandadís de totes los fichièrs a la salvagarda dins lo repertòri borg-backup…",
|
||||||
"backup_csv_creation_failed": "Creacion impossibla del fichièr CSV necessari a las operacions futuras de restauracion",
|
"backup_csv_creation_failed": "Creacion impossibla del fichièr CSV necessari a las operacions futuras de restauracion",
|
||||||
"backup_extracting_archive": "Extraccion de l’archiu de salvagarda…",
|
"backup_extracting_archive": "Extraccion de l’archiu de salvagarda…",
|
||||||
|
@ -161,7 +161,7 @@
|
||||||
"dyndns_cron_removed": "La tasca cron pel domeni DynDNS es levada",
|
"dyndns_cron_removed": "La tasca cron pel domeni DynDNS es levada",
|
||||||
"dyndns_ip_update_failed": "Impossible d’actualizar l’adreça IP sul domeni DynDNS",
|
"dyndns_ip_update_failed": "Impossible d’actualizar l’adreça IP sul domeni DynDNS",
|
||||||
"dyndns_ip_updated": "Vòstra adreça IP es estada actualizada pel domeni DynDNS",
|
"dyndns_ip_updated": "Vòstra adreça IP es estada actualizada pel domeni DynDNS",
|
||||||
"dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona...",
|
"dyndns_key_generating": "La clau DNS es a se generar, pòt trigar una estona…",
|
||||||
"dyndns_key_not_found": "Clau DNS introbabla pel domeni",
|
"dyndns_key_not_found": "Clau DNS introbabla pel domeni",
|
||||||
"dyndns_no_domain_registered": "Cap de domeni pas enregistrat amb DynDNS",
|
"dyndns_no_domain_registered": "Cap de domeni pas enregistrat amb DynDNS",
|
||||||
"dyndns_registered": "Lo domeni DynDNS es enregistrat",
|
"dyndns_registered": "Lo domeni DynDNS es enregistrat",
|
||||||
|
@ -313,7 +313,7 @@
|
||||||
"service_conf_would_be_updated": "La configuracion del servici « {service} » seriá estada actualizada",
|
"service_conf_would_be_updated": "La configuracion del servici « {service} » seriá estada actualizada",
|
||||||
"service_description_avahi-daemon": "permet d’aténher vòstre servidor via yunohost.local sus vòstre ret local",
|
"service_description_avahi-daemon": "permet d’aténher vòstre servidor via yunohost.local sus vòstre ret local",
|
||||||
"service_description_dnsmasq": "gerís la resolucion dels noms de domeni (DNS)",
|
"service_description_dnsmasq": "gerís la resolucion dels noms de domeni (DNS)",
|
||||||
"updating_apt_cache": "Actualizacion de la lista dels paquets disponibles...",
|
"updating_apt_cache": "Actualizacion de la lista dels paquets disponibles…",
|
||||||
"service_conf_file_backed_up": "Lo fichièr de configuracion « {conf} » es salvagardat dins « {backup} »",
|
"service_conf_file_backed_up": "Lo fichièr de configuracion « {conf} » es salvagardat dins « {backup} »",
|
||||||
"service_conf_file_copy_failed": "Còpia impossibla del nòu fichièr de configuracion « {new} » cap a « {conf} »",
|
"service_conf_file_copy_failed": "Còpia impossibla del nòu fichièr de configuracion « {new} » cap a « {conf} »",
|
||||||
"server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers:s}",
|
"server_reboot_confirm": "Lo servidor es per reaviar sul pic, o volètz vertadièrament ? {answers:s}",
|
||||||
|
@ -372,7 +372,7 @@
|
||||||
"migrate_tsig_start": "L’algorisme de generacion de claus es pas pro securizat per la signatura TSIG del domeni « {domain} », lançament de la migracion cap a hmac-sha512 que’s mai securizat",
|
"migrate_tsig_start": "L’algorisme de generacion de claus es pas pro securizat per la signatura TSIG del domeni « {domain} », lançament de la migracion cap a hmac-sha512 que’s mai securizat",
|
||||||
"migration_description_0001_change_cert_group_to_sslcert": "Càmbia las permissions de grop dels certificats de « metronome » per « ssl-cert »",
|
"migration_description_0001_change_cert_group_to_sslcert": "Càmbia las permissions de grop dels certificats de « metronome » per « ssl-cert »",
|
||||||
"migration_0003_restoring_origin_nginx_conf": "Vòstre fichièr /etc/nginx/nginx.conf es estat modificat manualament. La migracion reïnicializarà d’en primièr son estat origina… Lo fichièr precedent serà disponible coma {backup_dest}.",
|
"migration_0003_restoring_origin_nginx_conf": "Vòstre fichièr /etc/nginx/nginx.conf es estat modificat manualament. La migracion reïnicializarà d’en primièr son estat origina… Lo fichièr precedent serà disponible coma {backup_dest}.",
|
||||||
"migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log} …",
|
"migration_0003_still_on_jessie_after_main_upgrade": "Quicòm a trucat pendent la mesa a nivèl màger : lo sistèma es encara jos Jessie ?!? Per trobar lo problèma, agachatz {log}…",
|
||||||
"migration_0003_general_warning": "Notatz qu’aquesta migracion es una operacion delicata. Encara que la còla YunoHost aguèsse fach çò melhor per la tornar legir e provar, la migracion poiriá copar de parts del sistèma o de las aplicacions.\n\nEn consequéncia, vos recomandam :\n· · · · - de lançar una salvagarda de vòstras donadas o aplicacions criticas. Mai d’informacions a https://yunohost.org/backup ;\n· · · · - d’èsser pacient aprèp aver lançat la migracion : segon vòstra connexion Internet e material, pòt trigar qualques oras per que tot siá mes al nivèl.\n\nEn mai, lo pòrt per SMTP, utilizat pels clients de corrièls extèrns (coma Thunderbird o K9-Mail per exemple) foguèt cambiat de 465 (SSL/TLS) per 587 (STARTTLS). L’ancian pòrt 465 serà automaticament tampat e lo nòu pòrt 587 serà dobèrt dins lo parafuòc. Vosautres e vòstres utilizaires *auretz* d’adaptar la configuracion de vòstre client de corrièl segon aqueles cambiaments !",
|
"migration_0003_general_warning": "Notatz qu’aquesta migracion es una operacion delicata. Encara que la còla YunoHost aguèsse fach çò melhor per la tornar legir e provar, la migracion poiriá copar de parts del sistèma o de las aplicacions.\n\nEn consequéncia, vos recomandam :\n· · · · - de lançar una salvagarda de vòstras donadas o aplicacions criticas. Mai d’informacions a https://yunohost.org/backup ;\n· · · · - d’èsser pacient aprèp aver lançat la migracion : segon vòstra connexion Internet e material, pòt trigar qualques oras per que tot siá mes al nivèl.\n\nEn mai, lo pòrt per SMTP, utilizat pels clients de corrièls extèrns (coma Thunderbird o K9-Mail per exemple) foguèt cambiat de 465 (SSL/TLS) per 587 (STARTTLS). L’ancian pòrt 465 serà automaticament tampat e lo nòu pòrt 587 serà dobèrt dins lo parafuòc. Vosautres e vòstres utilizaires *auretz* d’adaptar la configuracion de vòstre client de corrièl segon aqueles cambiaments !",
|
||||||
"migration_0003_problematic_apps_warning": "Notatz que las aplicacions seguentas, saique problematicas, son estadas desactivadas. Semblan d’aver estadas installadas d’una lista d’aplicacions o que son pas marcadas coma «working ». En consequéncia, podèm pas assegurar que tendràn de foncionar aprèp la mesa a nivèl : {problematic_apps}",
|
"migration_0003_problematic_apps_warning": "Notatz que las aplicacions seguentas, saique problematicas, son estadas desactivadas. Semblan d’aver estadas installadas d’una lista d’aplicacions o que son pas marcadas coma «working ». En consequéncia, podèm pas assegurar que tendràn de foncionar aprèp la mesa a nivèl : {problematic_apps}",
|
||||||
"migrations_bad_value_for_target": "Nombre invalid pel paramètre « target », los numèros de migracion son 0 o {}",
|
"migrations_bad_value_for_target": "Nombre invalid pel paramètre « target », los numèros de migracion son 0 o {}",
|
||||||
|
@ -457,14 +457,34 @@
|
||||||
"service_description_php7.0-fpm": "executa d’aplicacions escrichas en PHP amb nginx",
|
"service_description_php7.0-fpm": "executa d’aplicacions escrichas en PHP amb nginx",
|
||||||
"users_available": "Lista dels utilizaires disponibles :",
|
"users_available": "Lista dels utilizaires disponibles :",
|
||||||
"good_practices_about_admin_password": "Sètz per definir un nòu senhal per l’administracion. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
|
"good_practices_about_admin_password": "Sètz per definir un nòu senhal per l’administracion. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
|
||||||
"good_practices_about_user_password": "Sètz per definir un nòu senhal d’utilizaire. Lo senhal deu almens conténer 8 caractèrs - encara que siá de bon far d’utilizar un senhal mai long qu’aquò (ex. una passafrasa) e/o d’utilizar mantun tipes de caractèrs (majuscula, minuscula, nombre e caractèrs especials).",
|
"good_practices_about_user_password": "Sètz a mand de definir un nòu senhal d’utilizaire. Lo nòu senhal deu conténer almens 8 caractèrs, es de bon far d’utilizar un senhal mai long (es a dire una frasa de senhal) e/o utilizar mantuns tipes de caractèrs (majusculas, minusculas, nombres e caractèrs especials).",
|
||||||
"migration_description_0006_sync_admin_and_root_passwords": "Sincronizar los senhals admin e root",
|
"migration_description_0006_sync_admin_and_root_passwords": "Sincronizar los senhals admin e root",
|
||||||
"migration_0006_disclaimer": "Ara YunoHost s’espèra que los senhals admin e root sián sincronizats. En lançant aquesta migracion, vòstre senhal root serà remplaçat pel senhal admin.",
|
"migration_0006_disclaimer": "Ara YunoHost s’espèra que los senhals admin e root sián sincronizats. En lançant aquesta migracion, vòstre senhal root serà remplaçat pel senhal admin.",
|
||||||
"migration_0006_done": "Lo senhal root es estat remplaçat pel senhal admin.",
|
"migration_0006_done": "Lo senhal root es estat remplaçat pel senhal admin.",
|
||||||
"password_listed": "Aqueste senhal fa part dels senhals mai utilizats del monde. Volgatz ben ne causir un mai unic.",
|
"password_listed": "Aqueste senhal es un dels mai utilizats al monde. Se vos plai utilizatz-ne un mai unic.",
|
||||||
"password_too_simple_1": "Lo senhal deu conténer almens 8 caractèrs",
|
"password_too_simple_1": "Lo senhal deu conténer almens 8 caractèrs",
|
||||||
"password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas e de minusculas",
|
"password_too_simple_2": "Lo senhal deu conténer almens 8 caractèrs e numbres, majusculas e minusculas",
|
||||||
"password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
|
"password_too_simple_3": "Lo senhal deu conténer almens 8 caractèrs e nombres, majusculas e minusculas e caractèrs especials",
|
||||||
"password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs amb de nombres, de majusculas, de minusculas e de caractèrs especials",
|
"password_too_simple_4": "Lo senhal deu conténer almens 12 caractèrs, de nombre, majusculas, minisculas e caractèrs specials",
|
||||||
"root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !"
|
"root_password_desynchronized": "Lo senhal de l’administrator es estat cambiat, mas YunoHost a pas pogut l’espandir al senhal root !",
|
||||||
|
"aborting": "Interrupcion.",
|
||||||
|
"app_not_upgraded": "Las aplicacions seguentas son pas estadas actualizadas : {apps}",
|
||||||
|
"app_start_install": "Installacion de l’aplicacion {app}…",
|
||||||
|
"app_start_remove": "Supression de l’aplicacion {app}…",
|
||||||
|
"app_start_backup": "Recuperacion dels fichièrs de salvagardar per {app}…",
|
||||||
|
"app_start_restore": "Restauracion de l’aplicacion {app}…",
|
||||||
|
"app_upgrade_several_apps": "Las aplicacions seguentas seràn mesas a jorn : {apps}",
|
||||||
|
"ask_new_domain": "Nòu domeni",
|
||||||
|
"ask_new_path": "Nòu camin",
|
||||||
|
"backup_actually_backuping": "Creacion d’un archiu de seguretat a partir dels fichièrs recuperats…",
|
||||||
|
"backup_mount_archive_for_restore": "Preparacion de l’archiu per restauracion…",
|
||||||
|
"dyndns_could_not_check_available": "Verificacion impossibla de la disponibilitat de {domain:s} sus {provider:s}.",
|
||||||
|
"file_does_not_exist": "Lo camin {path:s} existís pas.",
|
||||||
|
"global_settings_setting_security_password_admin_strength": "Fòrça del senhal administrator",
|
||||||
|
"global_settings_setting_security_password_user_strength": "Fòrça del senhal utilizaire",
|
||||||
|
"migration_description_0007_ssh_conf_managed_by_yunohost_step1": "La configuracion SSH serà gerada per YunoHost (etapa 1, automatica)",
|
||||||
|
"migration_description_0008_ssh_conf_managed_by_yunohost_step2": "Daissar YunoHost gerir la configuracion SSH (etapa 2, manuala)",
|
||||||
|
"migration_0007_cancelled": "YunoHost a pas reüssit a melhorar lo biais de gerir la configuracion SSH.",
|
||||||
|
"root_password_replaced_by_admin_password": "Lo senhal root es estat remplaçat pel senhal administrator.",
|
||||||
|
"service_restarted": "Lo servici '{service:s}' es estat reaviat"
|
||||||
}
|
}
|
||||||
|
|
1
locales/pl.json
Normal file
1
locales/pl.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -6,5 +6,41 @@
|
||||||
"app_already_installed": "{app:s} уже установлено",
|
"app_already_installed": "{app:s} уже установлено",
|
||||||
"app_already_installed_cant_change_url": "Это приложение уже установлено. URL не может быть изменен только с помощью этой функции. Изучите `app changeurl`, если это доступно.",
|
"app_already_installed_cant_change_url": "Это приложение уже установлено. URL не может быть изменен только с помощью этой функции. Изучите `app changeurl`, если это доступно.",
|
||||||
"app_argument_choice_invalid": "Неверный выбор для аргумента '{name:s}', Это должно быть '{choices:s}'",
|
"app_argument_choice_invalid": "Неверный выбор для аргумента '{name:s}', Это должно быть '{choices:s}'",
|
||||||
"app_argument_invalid": "Недопустимое значение аргумента '{name:s}': {error:s}'"
|
"app_argument_invalid": "Недопустимое значение аргумента '{name:s}': {error:s}'",
|
||||||
|
"app_already_up_to_date": "{app:s} уже обновлено",
|
||||||
|
"app_argument_required": "Аргумент '{name:s}' необходим",
|
||||||
|
"app_change_no_change_url_script": "Приложение {app_name:s} не поддерживает изменение URL, вы должны обновить его.",
|
||||||
|
"app_change_url_identical_domains": "Старый и новый domain/url_path идентичны ('{domain:s}{path:s}'), ничего делать не надо.",
|
||||||
|
"app_change_url_no_script": "Приложение '{app_name:s}' не поддерживает изменение url. Наверное, вам нужно обновить приложение.",
|
||||||
|
"app_change_url_success": "Успешно изменён {app:s} url на {domain:s}{path:s}",
|
||||||
|
"app_extraction_failed": "Невозможно извлечь файлы для инсталляции",
|
||||||
|
"app_id_invalid": "Неправильный id приложения",
|
||||||
|
"app_incompatible": "Приложение {app} несовместимо с вашей версией YonoHost",
|
||||||
|
"app_install_files_invalid": "Неправильные файлы инсталляции",
|
||||||
|
"app_location_already_used": "Приложение '{app}' уже установлено по этому адресу ({path})",
|
||||||
|
"app_location_install_failed": "Невозможно установить приложение в это место, потому что оно конфликтует с приложением, '{other_app}' установленном на '{other_path}'",
|
||||||
|
"app_location_unavailable": "Этот url отсутствует или конфликтует с уже установленным приложением или приложениями: {apps:s}",
|
||||||
|
"app_manifest_invalid": "Недопустимый манифест приложения: {error}",
|
||||||
|
"app_no_upgrade": "Нет приложений, требующих обновления",
|
||||||
|
"app_not_correctly_installed": "{app:s} , кажется, установлены неправильно",
|
||||||
|
"app_not_installed": "{app:s} не установлены",
|
||||||
|
"app_not_properly_removed": "{app:s} удалены неправильно",
|
||||||
|
"app_package_need_update": "Пакет приложения {app} должен быть обновлён в соответствии с изменениями YonoHost",
|
||||||
|
"app_removed": "{app:s} удалено",
|
||||||
|
"app_requirements_checking": "Проверяю необходимые пакеты для {app}...",
|
||||||
|
"app_sources_fetch_failed": "Невозможно получить исходные файлы",
|
||||||
|
"app_unknown": "Неизвестное приложение",
|
||||||
|
"app_upgrade_app_name": "Обновление приложения {app}...",
|
||||||
|
"app_upgrade_failed": "Невозможно обновить {app:s}",
|
||||||
|
"app_upgrade_some_app_failed": "Невозможно обновить некоторые приложения",
|
||||||
|
"app_upgraded": "{app:s} обновлено",
|
||||||
|
"appslist_corrupted_json": "Не могу загрузить список приложений. Кажется, {filename:s} поврежден.",
|
||||||
|
"appslist_fetched": "Был выбран список приложений {appslist:s}",
|
||||||
|
"appslist_name_already_tracked": "Уже есть зарегистрированный список приложений по имени {name:s}.",
|
||||||
|
"appslist_removed": "Список приложений {appslist:s} удалён",
|
||||||
|
"appslist_retrieve_bad_format": "Неверный файл списка приложений{appslist:s}",
|
||||||
|
"appslist_retrieve_error": "Невозможно получить список удаленных приложений {appslist:s}: {error:s}",
|
||||||
|
"appslist_unknown": "Список приложений {appslist:s} неизвестен.",
|
||||||
|
"appslist_url_already_tracked": "Это уже зарегистрированный список приложений с url{url:s}.",
|
||||||
|
"installation_complete": "Установка завершена"
|
||||||
}
|
}
|
||||||
|
|
1
locales/sv.json
Normal file
1
locales/sv.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
1
locales/zh_Hans.json
Normal file
1
locales/zh_Hans.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -42,7 +42,7 @@ from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import read_json
|
from moulinette.utils.filesystem import read_json
|
||||||
|
|
||||||
from yunohost.service import service_log, _run_service_command
|
from yunohost.service import service_log, service_status, _run_service_command
|
||||||
from yunohost.utils import packages
|
from yunohost.utils import packages
|
||||||
from yunohost.log import is_unit_operation, OperationLogger
|
from yunohost.log import is_unit_operation, OperationLogger
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ def app_fetchlist(url=None, name=None):
|
||||||
name -- Name of the list
|
name -- Name of the list
|
||||||
url -- URL of remote JSON list
|
url -- URL of remote JSON list
|
||||||
"""
|
"""
|
||||||
if not url.endswith(".json"):
|
if url and not url.endswith(".json"):
|
||||||
raise YunohostError("This is not a valid application list url. It should end with .json.")
|
raise YunohostError("This is not a valid application list url. It should end with .json.")
|
||||||
|
|
||||||
# If needed, create folder where actual appslists are stored
|
# If needed, create folder where actual appslists are stored
|
||||||
|
@ -523,7 +523,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
|
||||||
os.system('chmod +x %s' % os.path.join(os.path.join(APP_TMP_FOLDER, "scripts", "change_url")))
|
os.system('chmod +x %s' % os.path.join(os.path.join(APP_TMP_FOLDER, "scripts", "change_url")))
|
||||||
|
|
||||||
if hook_exec(os.path.join(APP_TMP_FOLDER, 'scripts/change_url'),
|
if hook_exec(os.path.join(APP_TMP_FOLDER, 'scripts/change_url'),
|
||||||
args=args_list, env=env_dict) != 0:
|
args=args_list, env=env_dict)[0] != 0:
|
||||||
msg = "Failed to change '%s' url." % app
|
msg = "Failed to change '%s' url." % app
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
operation_logger.error(msg)
|
operation_logger.error(msg)
|
||||||
|
@ -583,28 +583,28 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
||||||
not_upgraded_apps = []
|
not_upgraded_apps = []
|
||||||
|
|
||||||
apps = app
|
apps = app
|
||||||
user_specified_list = True
|
|
||||||
# If no app is specified, upgrade all apps
|
# If no app is specified, upgrade all apps
|
||||||
if not apps:
|
if not apps:
|
||||||
|
# FIXME : not sure what's supposed to happen if there is a url and a file but no apps...
|
||||||
if not url and not file:
|
if not url and not file:
|
||||||
apps = [app["id"] for app in app_list(installed=True)["apps"]]
|
apps = [app["id"] for app in app_list(installed=True)["apps"]]
|
||||||
user_specified_list = False
|
|
||||||
elif not isinstance(app, list):
|
elif not isinstance(app, list):
|
||||||
apps = [app]
|
apps = [app]
|
||||||
|
|
||||||
# Remove possible duplicates
|
# Remove possible duplicates
|
||||||
apps = [app for i,app in enumerate(apps) if apps not in L[:i]]
|
apps = [app for i,app in enumerate(apps) if apps not in apps[:i]]
|
||||||
|
|
||||||
|
# Abort if any of those app is in fact not installed..
|
||||||
|
for app in [app for app in apps if not _is_installed(app)]:
|
||||||
|
raise YunohostError('app_not_installed', app=app)
|
||||||
|
|
||||||
if len(apps) == 0:
|
if len(apps) == 0:
|
||||||
raise YunohostError('app_no_upgrade')
|
raise YunohostError('app_no_upgrade')
|
||||||
if len(apps) > 1:
|
if len(apps) > 1:
|
||||||
logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(app)))
|
logger.info(m18n.n("app_upgrade_several_apps", apps=", ".join(apps)))
|
||||||
|
|
||||||
for app_instance_name in apps:
|
for app_instance_name in apps:
|
||||||
logger.info(m18n.n('app_upgrade_app_name', app=app_instance_name))
|
logger.info(m18n.n('app_upgrade_app_name', app=app_instance_name))
|
||||||
installed = _is_installed(app_instance_name)
|
|
||||||
if not installed:
|
|
||||||
raise YunohostError('app_not_installed', app=app_instance_name)
|
|
||||||
|
|
||||||
app_dict = app_info(app_instance_name, raw=True)
|
app_dict = app_info(app_instance_name, raw=True)
|
||||||
|
|
||||||
|
@ -618,12 +618,12 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
||||||
elif app_dict["upgradable"] == "yes":
|
elif app_dict["upgradable"] == "yes":
|
||||||
manifest, extracted_app_folder = _fetch_app_from_git(app_instance_name)
|
manifest, extracted_app_folder = _fetch_app_from_git(app_instance_name)
|
||||||
else:
|
else:
|
||||||
if user_specified_list:
|
logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
|
||||||
logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Check requirements
|
# Check requirements
|
||||||
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
|
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
|
||||||
|
_check_services_status_for_app(manifest.get("services", []))
|
||||||
|
|
||||||
app_setting_path = APPS_SETTING_PATH + '/' + app_instance_name
|
app_setting_path = APPS_SETTING_PATH + '/' + app_instance_name
|
||||||
|
|
||||||
|
@ -655,7 +655,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
||||||
# Execute App upgrade script
|
# Execute App upgrade script
|
||||||
os.system('chown -hR admin: %s' % INSTALL_TMP)
|
os.system('chown -hR admin: %s' % INSTALL_TMP)
|
||||||
if hook_exec(extracted_app_folder + '/scripts/upgrade',
|
if hook_exec(extracted_app_folder + '/scripts/upgrade',
|
||||||
args=args_list, env=env_dict) != 0:
|
args=args_list, env=env_dict)[0] != 0:
|
||||||
msg = m18n.n('app_upgrade_failed', app=app_instance_name)
|
msg = m18n.n('app_upgrade_failed', app=app_instance_name)
|
||||||
not_upgraded_apps.append(app_instance_name)
|
not_upgraded_apps.append(app_instance_name)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
@ -779,6 +779,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
|
||||||
|
|
||||||
# Check requirements
|
# Check requirements
|
||||||
_check_manifest_requirements(manifest, app_id)
|
_check_manifest_requirements(manifest, app_id)
|
||||||
|
_check_services_status_for_app(manifest.get("services", []))
|
||||||
|
|
||||||
# Check if app can be forked
|
# Check if app can be forked
|
||||||
instance_number = _installed_instance_number(app_id, last=True) + 1
|
instance_number = _installed_instance_number(app_id, last=True) + 1
|
||||||
|
@ -848,7 +849,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
|
||||||
install_retcode = hook_exec(
|
install_retcode = hook_exec(
|
||||||
os.path.join(extracted_app_folder, 'scripts/install'),
|
os.path.join(extracted_app_folder, 'scripts/install'),
|
||||||
args=args_list, env=env_dict
|
args=args_list, env=env_dict
|
||||||
)
|
)[0]
|
||||||
except (KeyboardInterrupt, EOFError):
|
except (KeyboardInterrupt, EOFError):
|
||||||
install_retcode = -1
|
install_retcode = -1
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -873,7 +874,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
|
||||||
remove_retcode = hook_exec(
|
remove_retcode = hook_exec(
|
||||||
os.path.join(extracted_app_folder, 'scripts/remove'),
|
os.path.join(extracted_app_folder, 'scripts/remove'),
|
||||||
args=[app_instance_name], env=env_dict_remove
|
args=[app_instance_name], env=env_dict_remove
|
||||||
)
|
)[0]
|
||||||
if remove_retcode != 0:
|
if remove_retcode != 0:
|
||||||
msg = m18n.n('app_not_properly_removed',
|
msg = m18n.n('app_not_properly_removed',
|
||||||
app=app_instance_name)
|
app=app_instance_name)
|
||||||
|
@ -964,7 +965,7 @@ def app_remove(operation_logger, auth, app):
|
||||||
operation_logger.flush()
|
operation_logger.flush()
|
||||||
|
|
||||||
if hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list,
|
if hook_exec('/tmp/yunohost_remove/scripts/remove', args=args_list,
|
||||||
env=env_dict) == 0:
|
env=env_dict)[0] == 0:
|
||||||
logger.success(m18n.n('app_removed', app=app))
|
logger.success(m18n.n('app_removed', app=app))
|
||||||
|
|
||||||
hook_callback('post_app_remove', args=args_list, env=env_dict)
|
hook_callback('post_app_remove', args=args_list, env=env_dict)
|
||||||
|
@ -1563,7 +1564,7 @@ def app_action_run(app, action, args=None):
|
||||||
env=env_dict,
|
env=env_dict,
|
||||||
chdir=cwd,
|
chdir=cwd,
|
||||||
user=action_declaration.get("user", "root"),
|
user=action_declaration.get("user", "root"),
|
||||||
)
|
)[0]
|
||||||
|
|
||||||
if retcode not in action_declaration.get("accepted_return_codes", [0]):
|
if retcode not in action_declaration.get("accepted_return_codes", [0]):
|
||||||
raise YunohostError("Error while executing action '%s' of app '%s': return code %s" % (action, app, retcode), raw_msg=True)
|
raise YunohostError("Error while executing action '%s' of app '%s': return code %s" % (action, app, retcode), raw_msg=True)
|
||||||
|
@ -1628,7 +1629,7 @@ def app_config_show_panel(app):
|
||||||
args=["show"],
|
args=["show"],
|
||||||
env=env,
|
env=env,
|
||||||
stdout_callback=parse_stdout,
|
stdout_callback=parse_stdout,
|
||||||
)
|
)[0]
|
||||||
|
|
||||||
if return_code != 0:
|
if return_code != 0:
|
||||||
raise Exception("script/config show return value code: %s (considered as an error)", return_code)
|
raise Exception("script/config show return value code: %s (considered as an error)", return_code)
|
||||||
|
@ -1714,7 +1715,7 @@ def app_config_apply(app, args):
|
||||||
return_code = hook_exec(config_script,
|
return_code = hook_exec(config_script,
|
||||||
args=["apply"],
|
args=["apply"],
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)[0]
|
||||||
|
|
||||||
if return_code != 0:
|
if return_code != 0:
|
||||||
raise Exception("'script/config apply' return value code: %s (considered as an error)", return_code)
|
raise Exception("'script/config apply' return value code: %s (considered as an error)", return_code)
|
||||||
|
@ -1772,12 +1773,18 @@ def _get_app_status(app_id, format_date=False):
|
||||||
raise YunohostError('app_unknown')
|
raise YunohostError('app_unknown')
|
||||||
status = {}
|
status = {}
|
||||||
|
|
||||||
|
regen_status = True
|
||||||
try:
|
try:
|
||||||
with open(app_setting_path + '/status.json') as f:
|
with open(app_setting_path + '/status.json') as f:
|
||||||
status = json.loads(str(f.read()))
|
status = json.loads(str(f.read()))
|
||||||
|
regen_status = False
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.debug("status file not found for '%s'", app_id,
|
logger.debug("status file not found for '%s'", app_id,
|
||||||
exc_info=1)
|
exc_info=1)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("could not open or decode %s : %s ... regenerating.", app_setting_path + '/status.json', str(e))
|
||||||
|
|
||||||
|
if regen_status:
|
||||||
# Create app status
|
# Create app status
|
||||||
status = {
|
status = {
|
||||||
'installed_at': app_setting(app_id, 'install_time'),
|
'installed_at': app_setting(app_id, 'install_time'),
|
||||||
|
@ -2203,6 +2210,11 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
|
||||||
if arg_type == 'boolean':
|
if arg_type == 'boolean':
|
||||||
arg_default = 1 if arg_default else 0
|
arg_default = 1 if arg_default else 0
|
||||||
|
|
||||||
|
# do not print for webadmin
|
||||||
|
if arg_type == 'display_text' and msettings.get('interface') != 'api':
|
||||||
|
print(_value_for_locale(arg['ask']))
|
||||||
|
continue
|
||||||
|
|
||||||
# Attempt to retrieve argument value
|
# Attempt to retrieve argument value
|
||||||
if arg_name in args:
|
if arg_name in args:
|
||||||
arg_value = args[arg_name]
|
arg_value = args[arg_name]
|
||||||
|
@ -2253,13 +2265,17 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
|
||||||
elif arg_default is not None:
|
elif arg_default is not None:
|
||||||
arg_value = arg_default
|
arg_value = arg_default
|
||||||
|
|
||||||
# Validate argument value
|
# If the value is empty (none or '')
|
||||||
if (arg_value is None or arg_value == '') \
|
# then check if arg is optional or not
|
||||||
and not arg.get('optional', False):
|
if arg_value is None or arg_value == '':
|
||||||
raise YunohostError('app_argument_required', name=arg_name)
|
if arg.get("optional", False):
|
||||||
elif arg_value is None:
|
# Argument is optional, keep an empty value
|
||||||
args_dict[arg_name] = ''
|
# and that's all for this arg !
|
||||||
continue
|
args_dict[arg_name] = ''
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# The argument is required !
|
||||||
|
raise YunohostError('app_argument_required', name=arg_name)
|
||||||
|
|
||||||
# Validate argument choice
|
# Validate argument choice
|
||||||
if arg_choices and arg_value not in arg_choices:
|
if arg_choices and arg_value not in arg_choices:
|
||||||
|
@ -2288,6 +2304,9 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
|
||||||
else:
|
else:
|
||||||
raise YunohostError('app_argument_choice_invalid', name=arg_name, choices='yes, no, y, n, 1, 0')
|
raise YunohostError('app_argument_choice_invalid', name=arg_name, choices='yes, no, y, n, 1, 0')
|
||||||
elif arg_type == 'password':
|
elif arg_type == 'password':
|
||||||
|
forbidden_chars = "{}"
|
||||||
|
if any(char in arg_value for char in forbidden_chars):
|
||||||
|
raise YunohostError('pattern_password_app', forbidden_chars=forbidden_chars)
|
||||||
from yunohost.utils.password import assert_password_is_strong_enough
|
from yunohost.utils.password import assert_password_is_strong_enough
|
||||||
assert_password_is_strong_enough('user', arg_value)
|
assert_password_is_strong_enough('user', arg_value)
|
||||||
args_dict[arg_name] = arg_value
|
args_dict[arg_name] = arg_value
|
||||||
|
@ -2575,6 +2594,31 @@ def unstable_apps():
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def _check_services_status_for_app(services):
|
||||||
|
|
||||||
|
logger.debug("Checking that required services are up and running...")
|
||||||
|
|
||||||
|
# Some apps use php-fpm or php5-fpm which is now php7.0-fpm
|
||||||
|
def replace_alias(service):
|
||||||
|
if service in ["php-fpm", "php5-fpm"]:
|
||||||
|
return "php7.0-fpm"
|
||||||
|
else:
|
||||||
|
return service
|
||||||
|
services = [replace_alias(s) for s in services]
|
||||||
|
|
||||||
|
# We only check those, mostly to ignore "custom" services
|
||||||
|
# (added by apps) and because those are the most popular
|
||||||
|
# services
|
||||||
|
service_filter = ["nginx", "php7.0-fpm", "mysql", "postfix"]
|
||||||
|
services = [str(s) for s in services if s in service_filter]
|
||||||
|
|
||||||
|
# List services currently down and raise an exception if any are found
|
||||||
|
faulty_services = [s for s in services if service_status(s)["active"] != "active"]
|
||||||
|
if faulty_services:
|
||||||
|
raise YunohostError('app_action_cannot_be_ran_because_required_services_down',
|
||||||
|
services=', '.join(faulty_services))
|
||||||
|
|
||||||
|
|
||||||
def _patch_php5(app_folder):
|
def _patch_php5(app_folder):
|
||||||
|
|
||||||
files_to_patch = []
|
files_to_patch = []
|
||||||
|
|
|
@ -50,7 +50,7 @@ from yunohost.hook import (
|
||||||
)
|
)
|
||||||
from yunohost.monitor import binary_to_human
|
from yunohost.monitor import binary_to_human
|
||||||
from yunohost.tools import tools_postinstall
|
from yunohost.tools import tools_postinstall
|
||||||
from yunohost.service import service_regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
@ -326,10 +326,19 @@ class BackupManager():
|
||||||
if not os.path.isdir(self.work_dir):
|
if not os.path.isdir(self.work_dir):
|
||||||
filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
|
filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
|
||||||
elif self.is_tmp_work_dir:
|
elif self.is_tmp_work_dir:
|
||||||
logger.debug("temporary directory for backup '%s' already exists",
|
|
||||||
|
logger.debug("temporary directory for backup '%s' already exists... attempting to clean it",
|
||||||
self.work_dir)
|
self.work_dir)
|
||||||
# FIXME May be we should clean the workdir here
|
|
||||||
raise YunohostError('backup_output_directory_not_empty')
|
# Try to recursively unmount stuff (from a previously failed backup ?)
|
||||||
|
if not _recursive_umount(self.work_dir):
|
||||||
|
raise YunohostError('backup_output_directory_not_empty')
|
||||||
|
else:
|
||||||
|
# If umount succeeded, remove the directory (we checked that
|
||||||
|
# we're in /home/yunohost.backup/tmp so that should be okay...
|
||||||
|
# c.f. method clean() which also does this)
|
||||||
|
filesystem.rm(self.work_dir, recursive=True, force=True)
|
||||||
|
filesystem.mkdir(self.work_dir, 0o750, parents=True, uid='admin')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Backup target management #
|
# Backup target management #
|
||||||
|
@ -593,8 +602,15 @@ class BackupManager():
|
||||||
env=env_dict,
|
env=env_dict,
|
||||||
chdir=self.work_dir)
|
chdir=self.work_dir)
|
||||||
|
|
||||||
if ret["succeed"] != []:
|
ret_succeed = {hook: {path:result["state"] for path, result in infos.items()}
|
||||||
self.system_return = ret["succeed"]
|
for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "succeed" for result in infos.values())}
|
||||||
|
ret_failed = {hook: {path:result["state"] for path, result in infos.items.items()}
|
||||||
|
for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "failed" for result in infos.values())}
|
||||||
|
|
||||||
|
if ret_succeed.keys() != []:
|
||||||
|
self.system_return = ret_succeed
|
||||||
|
|
||||||
# Add files from targets (which they put in the CSV) to the list of
|
# Add files from targets (which they put in the CSV) to the list of
|
||||||
# files to backup
|
# files to backup
|
||||||
|
@ -610,7 +626,7 @@ class BackupManager():
|
||||||
|
|
||||||
restore_hooks = hook_list("restore")["hooks"]
|
restore_hooks = hook_list("restore")["hooks"]
|
||||||
|
|
||||||
for part in ret['succeed'].keys():
|
for part in ret_succeed.keys():
|
||||||
if part in restore_hooks:
|
if part in restore_hooks:
|
||||||
part_restore_hooks = hook_info("restore", part)["hooks"]
|
part_restore_hooks = hook_info("restore", part)["hooks"]
|
||||||
for hook in part_restore_hooks:
|
for hook in part_restore_hooks:
|
||||||
|
@ -620,7 +636,7 @@ class BackupManager():
|
||||||
logger.warning(m18n.n('restore_hook_unavailable', hook=part))
|
logger.warning(m18n.n('restore_hook_unavailable', hook=part))
|
||||||
self.targets.set_result("system", part, "Warning")
|
self.targets.set_result("system", part, "Warning")
|
||||||
|
|
||||||
for part in ret['failed'].keys():
|
for part in ret_failed.keys():
|
||||||
logger.error(m18n.n('backup_system_part_failed', part=part))
|
logger.error(m18n.n('backup_system_part_failed', part=part))
|
||||||
self.targets.set_result("system", part, "Error")
|
self.targets.set_result("system", part, "Error")
|
||||||
|
|
||||||
|
@ -682,7 +698,7 @@ class BackupManager():
|
||||||
subprocess.call(['install', '-Dm555', app_script, tmp_script])
|
subprocess.call(['install', '-Dm555', app_script, tmp_script])
|
||||||
|
|
||||||
hook_exec(tmp_script, args=[tmp_app_bkp_dir, app],
|
hook_exec(tmp_script, args=[tmp_app_bkp_dir, app],
|
||||||
raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict)
|
raise_on_error=True, chdir=tmp_app_bkp_dir, env=env_dict)[0]
|
||||||
|
|
||||||
self._import_to_list_to_backup(env_dict["YNH_BACKUP_CSV"])
|
self._import_to_list_to_backup(env_dict["YNH_BACKUP_CSV"])
|
||||||
except:
|
except:
|
||||||
|
@ -904,7 +920,7 @@ class RestoreManager():
|
||||||
ret = subprocess.call(["umount", self.work_dir])
|
ret = subprocess.call(["umount", self.work_dir])
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
logger.warning(m18n.n('restore_cleaning_failed'))
|
logger.warning(m18n.n('restore_cleaning_failed'))
|
||||||
filesystem.rm(self.work_dir, True, True)
|
filesystem.rm(self.work_dir, recursive=True, force=True)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Restore target manangement #
|
# Restore target manangement #
|
||||||
|
@ -1177,21 +1193,26 @@ class RestoreManager():
|
||||||
env=env_dict,
|
env=env_dict,
|
||||||
chdir=self.work_dir)
|
chdir=self.work_dir)
|
||||||
|
|
||||||
for part in ret['succeed'].keys():
|
ret_succeed = [hook for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "succeed" for result in infos.values())]
|
||||||
|
ret_failed = [hook for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "failed" for result in infos.values())]
|
||||||
|
|
||||||
|
for part in ret_succeed:
|
||||||
self.targets.set_result("system", part, "Success")
|
self.targets.set_result("system", part, "Success")
|
||||||
|
|
||||||
error_part = []
|
error_part = []
|
||||||
for part in ret['failed'].keys():
|
for part in ret_failed:
|
||||||
logger.error(m18n.n('restore_system_part_failed', part=part))
|
logger.error(m18n.n('restore_system_part_failed', part=part))
|
||||||
self.targets.set_result("system", part, "Error")
|
self.targets.set_result("system", part, "Error")
|
||||||
error_part.append(part)
|
error_part.append(part)
|
||||||
|
|
||||||
if ret['failed']:
|
if ret_failed:
|
||||||
operation_logger.error(m18n.n('restore_system_part_failed', part=', '.join(error_part)))
|
operation_logger.error(m18n.n('restore_system_part_failed', part=', '.join(error_part)))
|
||||||
else:
|
else:
|
||||||
operation_logger.success()
|
operation_logger.success()
|
||||||
|
|
||||||
service_regen_conf()
|
regen_conf()
|
||||||
|
|
||||||
def _restore_apps(self):
|
def _restore_apps(self):
|
||||||
"""Restore all apps targeted"""
|
"""Restore all apps targeted"""
|
||||||
|
@ -1301,7 +1322,7 @@ class RestoreManager():
|
||||||
args=[app_backup_in_archive, app_instance_name],
|
args=[app_backup_in_archive, app_instance_name],
|
||||||
chdir=app_backup_in_archive,
|
chdir=app_backup_in_archive,
|
||||||
raise_on_error=True,
|
raise_on_error=True,
|
||||||
env=env_dict)
|
env=env_dict)[0]
|
||||||
except:
|
except:
|
||||||
msg = m18n.n('restore_app_failed', app=app_instance_name)
|
msg = m18n.n('restore_app_failed', app=app_instance_name)
|
||||||
logger.exception(msg)
|
logger.exception(msg)
|
||||||
|
@ -1326,7 +1347,7 @@ class RestoreManager():
|
||||||
# Execute remove script
|
# Execute remove script
|
||||||
# TODO: call app_remove instead
|
# TODO: call app_remove instead
|
||||||
if hook_exec(remove_script, args=[app_instance_name],
|
if hook_exec(remove_script, args=[app_instance_name],
|
||||||
env=env_dict_remove) != 0:
|
env=env_dict_remove)[0] != 0:
|
||||||
msg = m18n.n('app_not_properly_removed', app=app_instance_name)
|
msg = m18n.n('app_not_properly_removed', app=app_instance_name)
|
||||||
logger.warning(msg)
|
logger.warning(msg)
|
||||||
operation_logger.error(msg)
|
operation_logger.error(msg)
|
||||||
|
@ -1514,34 +1535,12 @@ class BackupMethod(object):
|
||||||
directories of the working directories
|
directories of the working directories
|
||||||
"""
|
"""
|
||||||
if self.need_mount():
|
if self.need_mount():
|
||||||
if self._recursive_umount(self.work_dir) > 0:
|
if not _recursive_umount(self.work_dir):
|
||||||
raise YunohostError('backup_cleaning_failed')
|
raise YunohostError('backup_cleaning_failed')
|
||||||
|
|
||||||
if self.manager.is_tmp_work_dir:
|
if self.manager.is_tmp_work_dir:
|
||||||
filesystem.rm(self.work_dir, True, True)
|
filesystem.rm(self.work_dir, True, True)
|
||||||
|
|
||||||
def _recursive_umount(self, directory):
|
|
||||||
"""
|
|
||||||
Recursively umount sub directories of a directory
|
|
||||||
|
|
||||||
Args:
|
|
||||||
directory -- a directory path
|
|
||||||
"""
|
|
||||||
mount_lines = subprocess.check_output("mount").split("\n")
|
|
||||||
|
|
||||||
points_to_umount = [line.split(" ")[2]
|
|
||||||
for line in mount_lines
|
|
||||||
if len(line) >= 3 and line.split(" ")[2].startswith(directory)]
|
|
||||||
ret = 0
|
|
||||||
for point in reversed(points_to_umount):
|
|
||||||
ret = subprocess.call(["umount", point])
|
|
||||||
if ret != 0:
|
|
||||||
ret = 1
|
|
||||||
logger.warning(m18n.n('backup_cleaning_failed', point))
|
|
||||||
continue
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def _check_is_enough_free_space(self):
|
def _check_is_enough_free_space(self):
|
||||||
"""
|
"""
|
||||||
Check free space in repository or output directory before to backup
|
Check free space in repository or output directory before to backup
|
||||||
|
@ -1621,9 +1620,18 @@ class BackupMethod(object):
|
||||||
# 'NUMBER OF HARD LINKS > 1' see #1043
|
# 'NUMBER OF HARD LINKS > 1' see #1043
|
||||||
cron_path = os.path.abspath('/etc/cron') + '.'
|
cron_path = os.path.abspath('/etc/cron') + '.'
|
||||||
if not os.path.abspath(src).startswith(cron_path):
|
if not os.path.abspath(src).startswith(cron_path):
|
||||||
os.link(src, dest)
|
try:
|
||||||
# Success, go to next file to organize
|
os.link(src, dest)
|
||||||
continue
|
except Exception as e:
|
||||||
|
# This kind of situation may happen when src and dest are on different
|
||||||
|
# logical volume ... even though the st_dev check previously match...
|
||||||
|
# E.g. this happens when running an encrypted hard drive
|
||||||
|
# where everything is mapped to /dev/mapper/some-stuff
|
||||||
|
# yet there are different devices behind it or idk ...
|
||||||
|
logger.warning("Could not link %s to %s (%s) ... falling back to regular copy." % (src, dest, str(e)))
|
||||||
|
else:
|
||||||
|
# Success, go to next file to organize
|
||||||
|
continue
|
||||||
|
|
||||||
# If mountbind or hardlink couldnt be created,
|
# If mountbind or hardlink couldnt be created,
|
||||||
# prepare a list of files that need to be copied
|
# prepare a list of files that need to be copied
|
||||||
|
@ -1932,8 +1940,9 @@ class CustomBackupMethod(BackupMethod):
|
||||||
|
|
||||||
ret = hook_callback('backup_method', [self.method],
|
ret = hook_callback('backup_method', [self.method],
|
||||||
args=self._get_args('need_mount'))
|
args=self._get_args('need_mount'))
|
||||||
|
ret_succeed = [hook for hook, infos in ret.items()
|
||||||
self._need_mount = True if ret['succeed'] else False
|
if any(result["state"] == "succeed" for result in infos.values())]
|
||||||
|
self._need_mount = True if ret_succeed else False
|
||||||
return self._need_mount
|
return self._need_mount
|
||||||
|
|
||||||
def backup(self):
|
def backup(self):
|
||||||
|
@ -1946,7 +1955,10 @@ class CustomBackupMethod(BackupMethod):
|
||||||
|
|
||||||
ret = hook_callback('backup_method', [self.method],
|
ret = hook_callback('backup_method', [self.method],
|
||||||
args=self._get_args('backup'))
|
args=self._get_args('backup'))
|
||||||
if ret['failed']:
|
|
||||||
|
ret_failed = [hook for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "failed" for result in infos.values())]
|
||||||
|
if ret_failed:
|
||||||
raise YunohostError('backup_custom_backup_error')
|
raise YunohostError('backup_custom_backup_error')
|
||||||
|
|
||||||
def mount(self, restore_manager):
|
def mount(self, restore_manager):
|
||||||
|
@ -1959,7 +1971,10 @@ class CustomBackupMethod(BackupMethod):
|
||||||
super(CustomBackupMethod, self).mount(restore_manager)
|
super(CustomBackupMethod, self).mount(restore_manager)
|
||||||
ret = hook_callback('backup_method', [self.method],
|
ret = hook_callback('backup_method', [self.method],
|
||||||
args=self._get_args('mount'))
|
args=self._get_args('mount'))
|
||||||
if ret['failed']:
|
|
||||||
|
ret_failed = [hook for hook, infos in ret.items()
|
||||||
|
if any(result["state"] == "failed" for result in infos.values())]
|
||||||
|
if ret_failed:
|
||||||
raise YunohostError('backup_custom_mount_error')
|
raise YunohostError('backup_custom_mount_error')
|
||||||
|
|
||||||
def _get_args(self, action):
|
def _get_args(self, action):
|
||||||
|
@ -2011,6 +2026,7 @@ def backup_create(name=None, description=None, methods=[],
|
||||||
# Check that output directory is empty
|
# Check that output directory is empty
|
||||||
if os.path.isdir(output_directory) and no_compress and \
|
if os.path.isdir(output_directory) and no_compress and \
|
||||||
os.listdir(output_directory):
|
os.listdir(output_directory):
|
||||||
|
|
||||||
raise YunohostError('backup_output_directory_not_empty')
|
raise YunohostError('backup_output_directory_not_empty')
|
||||||
elif no_compress:
|
elif no_compress:
|
||||||
raise YunohostError('backup_output_directory_required')
|
raise YunohostError('backup_output_directory_required')
|
||||||
|
@ -2315,6 +2331,30 @@ def _call_for_each_path(self, callback, csv_path=None):
|
||||||
callback(self, row['source'], row['dest'])
|
callback(self, row['source'], row['dest'])
|
||||||
|
|
||||||
|
|
||||||
|
def _recursive_umount(directory):
|
||||||
|
"""
|
||||||
|
Recursively umount sub directories of a directory
|
||||||
|
|
||||||
|
Args:
|
||||||
|
directory -- a directory path
|
||||||
|
"""
|
||||||
|
mount_lines = subprocess.check_output("mount").split("\n")
|
||||||
|
|
||||||
|
points_to_umount = [line.split(" ")[2]
|
||||||
|
for line in mount_lines
|
||||||
|
if len(line) >= 3 and line.split(" ")[2].startswith(directory)]
|
||||||
|
|
||||||
|
everything_went_fine = True
|
||||||
|
for point in reversed(points_to_umount):
|
||||||
|
ret = subprocess.call(["umount", point])
|
||||||
|
if ret != 0:
|
||||||
|
everything_went_fine = False
|
||||||
|
logger.warning(m18n.n('backup_cleaning_failed', point))
|
||||||
|
continue
|
||||||
|
|
||||||
|
return everything_went_fine
|
||||||
|
|
||||||
|
|
||||||
def free_space_in_directory(dirpath):
|
def free_space_in_directory(dirpath):
|
||||||
stat = os.statvfs(dirpath)
|
stat = os.statvfs(dirpath)
|
||||||
return stat.f_frsize * stat.f_bavail
|
return stat.f_frsize * stat.f_bavail
|
||||||
|
|
|
@ -43,7 +43,8 @@ from yunohost.utils.network import get_public_ip
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.app import app_ssowatconf
|
from yunohost.app import app_ssowatconf
|
||||||
from yunohost.service import _run_service_command, service_regen_conf
|
from yunohost.service import _run_service_command
|
||||||
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.log import OperationLogger
|
from yunohost.log import OperationLogger
|
||||||
|
|
||||||
logger = getActionLogger('yunohost.certmanager')
|
logger = getActionLogger('yunohost.certmanager')
|
||||||
|
@ -806,7 +807,7 @@ def _enable_certificate(domain, new_cert_folder):
|
||||||
if os.path.isfile('/etc/yunohost/installed'):
|
if os.path.isfile('/etc/yunohost/installed'):
|
||||||
# regen nginx conf to be sure it integrates OCSP Stapling
|
# regen nginx conf to be sure it integrates OCSP Stapling
|
||||||
# (We don't do this yet if postinstall is not finished yet)
|
# (We don't do this yet if postinstall is not finished yet)
|
||||||
service_regen_conf(names=['nginx'])
|
regen_conf(names=['nginx'])
|
||||||
|
|
||||||
_run_service_command("reload", "nginx")
|
_run_service_command("reload", "nginx")
|
||||||
|
|
||||||
|
@ -924,7 +925,7 @@ def _regen_dnsmasq_if_needed():
|
||||||
break
|
break
|
||||||
|
|
||||||
if do_regen:
|
if do_regen:
|
||||||
service_regen_conf(["dnsmasq"])
|
regen_conf(["dnsmasq"])
|
||||||
|
|
||||||
|
|
||||||
def _name_self_CA():
|
def _name_self_CA():
|
||||||
|
|
|
@ -10,9 +10,9 @@ from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.app import unstable_apps
|
from yunohost.app import unstable_apps
|
||||||
from yunohost.service import (_run_service_command,
|
from yunohost.service import _run_service_command
|
||||||
manually_modified_files,
|
from yunohost.regenconf import (manually_modified_files,
|
||||||
manually_modified_files_compared_to_debian_default)
|
manually_modified_files_compared_to_debian_default)
|
||||||
from yunohost.utils.filesystem import free_space_in_directory
|
from yunohost.utils.filesystem import free_space_in_directory
|
||||||
from yunohost.utils.packages import get_installed_version
|
from yunohost.utils.packages import get_installed_version
|
||||||
from yunohost.utils.network import get_network_interfaces
|
from yunohost.utils.network import get_network_interfaces
|
||||||
|
|
|
@ -3,15 +3,12 @@ import re
|
||||||
|
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
|
||||||
from moulinette import m18n
|
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import mkdir, rm
|
from moulinette.utils.filesystem import mkdir, rm
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.service import service_regen_conf, \
|
from yunohost.service import _run_service_command
|
||||||
_get_conf_hashes, \
|
from yunohost.regenconf import regen_conf
|
||||||
_calculate_hash, \
|
|
||||||
_run_service_command
|
|
||||||
from yunohost.settings import settings_set
|
from yunohost.settings import settings_set
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
|
||||||
|
@ -49,10 +46,6 @@ class MyMigration(Migration):
|
||||||
if dsa:
|
if dsa:
|
||||||
settings_set("service.ssh.allow_deprecated_dsa_hostkey", True)
|
settings_set("service.ssh.allow_deprecated_dsa_hostkey", True)
|
||||||
|
|
||||||
# Create sshd_config.d dir
|
|
||||||
if not os.path.exists(SSHD_CONF + '.d'):
|
|
||||||
mkdir(SSHD_CONF + '.d', 0o755, uid='root', gid='root')
|
|
||||||
|
|
||||||
# Here, we make it so that /etc/ssh/sshd_config is managed
|
# Here, we make it so that /etc/ssh/sshd_config is managed
|
||||||
# by the regen conf (in particular in the case where the
|
# by the regen conf (in particular in the case where the
|
||||||
# from_script flag is present - in which case it was *not*
|
# from_script flag is present - in which case it was *not*
|
||||||
|
@ -64,7 +57,7 @@ class MyMigration(Migration):
|
||||||
if os.path.exists('/etc/yunohost/from_script'):
|
if os.path.exists('/etc/yunohost/from_script'):
|
||||||
rm('/etc/yunohost/from_script')
|
rm('/etc/yunohost/from_script')
|
||||||
copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp')
|
copyfile(SSHD_CONF, '/etc/ssh/sshd_config.bkp')
|
||||||
service_regen_conf(names=['ssh'], force=True)
|
regen_conf(names=['ssh'], force=True)
|
||||||
copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF)
|
copyfile('/etc/ssh/sshd_config.bkp', SSHD_CONF)
|
||||||
|
|
||||||
# Restart ssh and backward if it fail
|
# Restart ssh and backward if it fail
|
||||||
|
|
|
@ -6,9 +6,8 @@ from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.filesystem import chown
|
from moulinette.utils.filesystem import chown
|
||||||
|
|
||||||
from yunohost.tools import Migration
|
from yunohost.tools import Migration
|
||||||
from yunohost.service import service_regen_conf, \
|
from yunohost.regenconf import _get_conf_hashes, _calculate_hash
|
||||||
_get_conf_hashes, \
|
from yunohost.regenconf import regen_conf
|
||||||
_calculate_hash
|
|
||||||
from yunohost.settings import settings_set, settings_get
|
from yunohost.settings import settings_set, settings_get
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from yunohost.backup import ARCHIVES_PATH
|
from yunohost.backup import ARCHIVES_PATH
|
||||||
|
@ -36,7 +35,7 @@ class MyMigration(Migration):
|
||||||
|
|
||||||
def migrate(self):
|
def migrate(self):
|
||||||
settings_set("service.ssh.allow_deprecated_dsa_hostkey", False)
|
settings_set("service.ssh.allow_deprecated_dsa_hostkey", False)
|
||||||
service_regen_conf(names=['ssh'], force=True)
|
regen_conf(names=['ssh'], force=True)
|
||||||
|
|
||||||
# Update local archives folder permissions, so that
|
# Update local archives folder permissions, so that
|
||||||
# admin can scp archives out of the server
|
# admin can scp archives out of the server
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from moulinette import m18n
|
||||||
|
from moulinette.utils.log import getActionLogger
|
||||||
|
|
||||||
|
from moulinette.utils.filesystem import read_file
|
||||||
|
from yunohost.service import _get_services, _save_services
|
||||||
|
from yunohost.regenconf import _update_conf_hashes, REGEN_CONF_FILE
|
||||||
|
|
||||||
|
from yunohost.tools import Migration
|
||||||
|
|
||||||
|
logger = getActionLogger('yunohost.migration')
|
||||||
|
|
||||||
|
|
||||||
|
class MyMigration(Migration):
|
||||||
|
"""
|
||||||
|
Decouple the regen conf mechanism from the concept of services
|
||||||
|
"""
|
||||||
|
|
||||||
|
def migrate(self):
|
||||||
|
|
||||||
|
if "conffiles" not in read_file("/etc/yunohost/services.yml") \
|
||||||
|
or os.path.exists(REGEN_CONF_FILE):
|
||||||
|
logger.warning(m18n.n("migration_0009_not_needed"))
|
||||||
|
return
|
||||||
|
|
||||||
|
# For all services
|
||||||
|
services = _get_services()
|
||||||
|
for service, infos in services.items():
|
||||||
|
# If there are some conffiles (file hashes)
|
||||||
|
if "conffiles" in infos.keys():
|
||||||
|
# Save them using the new regen conf thingy
|
||||||
|
_update_conf_hashes(service, infos["conffiles"])
|
||||||
|
# And delete the old conffile key from the service infos
|
||||||
|
del services[service]["conffiles"]
|
||||||
|
|
||||||
|
# (Actually save the modification of services)
|
||||||
|
_save_services(services)
|
||||||
|
|
||||||
|
def backward(self):
|
||||||
|
|
||||||
|
pass
|
|
@ -8,7 +8,7 @@ logger = getActionLogger('yunohost.migration')
|
||||||
|
|
||||||
BASE_CONF_PATH = '/home/yunohost.conf'
|
BASE_CONF_PATH = '/home/yunohost.conf'
|
||||||
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
|
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
|
||||||
APPSLISTS_BACKUP = os.path.join(BACKUP_CONF_DIR, "appslist_before_migration_0009.json")
|
APPSLISTS_BACKUP = os.path.join(BACKUP_CONF_DIR, "appslist_before_migration_to_unified_list.json")
|
||||||
|
|
||||||
|
|
||||||
class MyMigration(Migration):
|
class MyMigration(Migration):
|
|
@ -34,9 +34,10 @@ from moulinette.utils.log import getActionLogger
|
||||||
|
|
||||||
import yunohost.certificate
|
import yunohost.certificate
|
||||||
|
|
||||||
from yunohost.service import service_regen_conf
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.utils.network import get_public_ip
|
from yunohost.utils.network import get_public_ip
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
|
from yunohost.hook import hook_callback
|
||||||
|
|
||||||
logger = getActionLogger('yunohost.domain')
|
logger = getActionLogger('yunohost.domain')
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
|
||||||
|
|
||||||
# Don't regen these conf if we're still in postinstall
|
# Don't regen these conf if we're still in postinstall
|
||||||
if os.path.exists('/etc/yunohost/installed'):
|
if os.path.exists('/etc/yunohost/installed'):
|
||||||
service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
|
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
|
||||||
app_ssowatconf(auth)
|
app_ssowatconf(auth)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -164,7 +165,7 @@ def domain_remove(operation_logger, auth, domain, force=False):
|
||||||
else:
|
else:
|
||||||
raise YunohostError('domain_deletion_failed')
|
raise YunohostError('domain_deletion_failed')
|
||||||
|
|
||||||
service_regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
|
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
|
||||||
app_ssowatconf(auth)
|
app_ssowatconf(auth)
|
||||||
|
|
||||||
hook_callback('post_domain_remove', args=[domain])
|
hook_callback('post_domain_remove', args=[domain])
|
||||||
|
@ -201,12 +202,19 @@ def domain_dns_conf(domain, ttl=None):
|
||||||
result += "; Mail"
|
result += "; Mail"
|
||||||
for record in dns_conf["mail"]:
|
for record in dns_conf["mail"]:
|
||||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||||
|
|
||||||
result += "\n\n"
|
result += "\n\n"
|
||||||
|
|
||||||
result += "; Extra"
|
result += "; Extra"
|
||||||
for record in dns_conf["extra"]:
|
for record in dns_conf["extra"]:
|
||||||
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||||
|
|
||||||
|
for name, record_list in dns_conf.items():
|
||||||
|
if name not in ("basic", "xmpp", "mail", "extra") and record_list:
|
||||||
|
result += "\n\n"
|
||||||
|
result += "; " + name
|
||||||
|
for record in record_list:
|
||||||
|
result += "\n{name} {ttl} IN {type} {value}".format(**record)
|
||||||
|
|
||||||
is_cli = True if msettings.get('interface') == 'cli' else False
|
is_cli = True if msettings.get('interface') == 'cli' else False
|
||||||
if is_cli:
|
if is_cli:
|
||||||
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
|
logger.info(m18n.n("domain_dns_conf_is_just_a_recommendation"))
|
||||||
|
@ -338,6 +346,9 @@ def _build_dns_conf(domain, ttl=3600):
|
||||||
"extra": [
|
"extra": [
|
||||||
{"type": "CAA", "name": "@", "value": "128 issue \"letsencrypt.org\"", "ttl": 3600},
|
{"type": "CAA", "name": "@", "value": "128 issue \"letsencrypt.org\"", "ttl": 3600},
|
||||||
],
|
],
|
||||||
|
"example_of_a_custom_rule": [
|
||||||
|
{"type": "SRV", "name": "_matrix", "value": "domain.tld.", "ttl": 3600}
|
||||||
|
],
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -396,13 +407,49 @@ def _build_dns_conf(domain, ttl=3600):
|
||||||
["@", ttl, "CAA", '128 issue "letsencrypt.org"']
|
["@", ttl, "CAA", '128 issue "letsencrypt.org"']
|
||||||
]
|
]
|
||||||
|
|
||||||
return {
|
# Official record
|
||||||
|
records = {
|
||||||
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
|
"basic": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in basic],
|
||||||
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
|
"xmpp": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in xmpp],
|
||||||
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
|
"mail": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in mail],
|
||||||
"extra": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in extra],
|
"extra": [{"name": name, "ttl": ttl, "type": type_, "value": value} for name, ttl, type_, value in extra],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Custom records
|
||||||
|
hook_results = hook_callback('custom_dns_rules', args=[domain])
|
||||||
|
for hook_name, results in hook_results.items():
|
||||||
|
#
|
||||||
|
# There can be multiple results per hook name, so results look like
|
||||||
|
# {'/some/path/to/hook1':
|
||||||
|
# { 'state': 'succeed',
|
||||||
|
# 'stdreturn': [{'type': 'SRV',
|
||||||
|
# 'name': 'stuff.foo.bar.',
|
||||||
|
# 'value': 'yoloswag',
|
||||||
|
# 'ttl': 3600}]
|
||||||
|
# },
|
||||||
|
# '/some/path/to/hook2':
|
||||||
|
# { ... },
|
||||||
|
# [...]
|
||||||
|
#
|
||||||
|
# Loop over the sub-results
|
||||||
|
custom_records = [v['stdreturn'] for v in results.values()
|
||||||
|
if v and v['stdreturn']]
|
||||||
|
|
||||||
|
records[hook_name] = []
|
||||||
|
for record_list in custom_records:
|
||||||
|
# Check that record_list is indeed a list of dict
|
||||||
|
# with the required keys
|
||||||
|
if not isinstance(record_list, list) \
|
||||||
|
or any(not isinstance(record, dict) for record in record_list) \
|
||||||
|
or any(key not in record for record in record_list for key in ["name", "ttl", "type", "value"]):
|
||||||
|
# Display an error, mainly for app packagers trying to implement a hook
|
||||||
|
logger.warning("Ignored custom record from hook '%s' because the data is not a *list* of dict with keys name, ttl, type and value. Raw data : %s" % (hook_name, record_list))
|
||||||
|
continue
|
||||||
|
|
||||||
|
records[hook_name].extend(record_list)
|
||||||
|
|
||||||
|
return records
|
||||||
|
|
||||||
|
|
||||||
def _get_DKIM(domain):
|
def _get_DKIM(domain):
|
||||||
DKIM_file = '/etc/dkim/{domain}.mail.txt'.format(domain=domain)
|
DKIM_file = '/etc/dkim/{domain}.mail.txt'.format(domain=domain)
|
||||||
|
|
|
@ -119,6 +119,9 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
|
||||||
subscribe_host -- Dynette HTTP API to subscribe to
|
subscribe_host -- Dynette HTTP API to subscribe to
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if len(glob.glob('/etc/yunohost/dyndns/*.key')) != 0 or os.path.exists('/etc/cron.d/yunohost-dyndns'):
|
||||||
|
raise YunohostError('domain_dyndns_already_subscribed')
|
||||||
|
|
||||||
if domain is None:
|
if domain is None:
|
||||||
domain = _get_maindomain()
|
domain = _get_maindomain()
|
||||||
operation_logger.related_to.append(('domain', domain))
|
operation_logger.related_to.append(('domain', domain))
|
||||||
|
@ -144,7 +147,8 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
|
||||||
'dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s' % domain)
|
'dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s' % domain)
|
||||||
os.system('chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private')
|
os.system('chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private')
|
||||||
|
|
||||||
key_file = glob.glob('/etc/yunohost/dyndns/*.key')[0]
|
private_file = glob.glob('/etc/yunohost/dyndns/*%s*.private' % domain)[0]
|
||||||
|
key_file = glob.glob('/etc/yunohost/dyndns/*%s*.key' % domain)[0]
|
||||||
with open(key_file) as f:
|
with open(key_file) as f:
|
||||||
key = f.readline().strip().split(' ', 6)[-1]
|
key = f.readline().strip().split(' ', 6)[-1]
|
||||||
|
|
||||||
|
@ -152,9 +156,13 @@ def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", dom
|
||||||
# Send subscription
|
# Send subscription
|
||||||
try:
|
try:
|
||||||
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
|
r = requests.post('https://%s/key/%s?key_algo=hmac-sha512' % (subscribe_host, base64.b64encode(key)), data={'subdomain': domain}, timeout=30)
|
||||||
except requests.ConnectionError:
|
except Exception as e:
|
||||||
raise YunohostError('no_internet_connection')
|
os.system("rm -f %s" % private_file)
|
||||||
|
os.system("rm -f %s" % key_file)
|
||||||
|
raise YunohostError('dyndns_registration_failed', error=str(e))
|
||||||
if r.status_code != 201:
|
if r.status_code != 201:
|
||||||
|
os.system("rm -f %s" % private_file)
|
||||||
|
os.system("rm -f %s" % key_file)
|
||||||
try:
|
try:
|
||||||
error = json.loads(r.text)['error']
|
error = json.loads(r.text)['error']
|
||||||
except:
|
except:
|
||||||
|
@ -333,7 +341,8 @@ def _guess_current_dyndns_domain(dyn_host):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Retrieve the first registered domain
|
# Retrieve the first registered domain
|
||||||
for path in glob.iglob('/etc/yunohost/dyndns/K*.private'):
|
paths = list(glob.iglob('/etc/yunohost/dyndns/K*.private'))
|
||||||
|
for path in paths:
|
||||||
match = RE_DYNDNS_PRIVATE_KEY_MD5.match(path)
|
match = RE_DYNDNS_PRIVATE_KEY_MD5.match(path)
|
||||||
if not match:
|
if not match:
|
||||||
match = RE_DYNDNS_PRIVATE_KEY_SHA512.match(path)
|
match = RE_DYNDNS_PRIVATE_KEY_SHA512.match(path)
|
||||||
|
@ -343,7 +352,9 @@ def _guess_current_dyndns_domain(dyn_host):
|
||||||
|
|
||||||
# Verify if domain is registered (i.e., if it's available, skip
|
# Verify if domain is registered (i.e., if it's available, skip
|
||||||
# current domain beause that's not the one we want to update..)
|
# current domain beause that's not the one we want to update..)
|
||||||
if _dyndns_available(dyn_host, _domain):
|
# If there's only 1 such key found, then avoid doing the request
|
||||||
|
# for nothing (that's very probably the one we want to find ...)
|
||||||
|
if len(paths) > 1 and _dyndns_available(dyn_host, _domain):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
return (_domain, path)
|
return (_domain, path)
|
||||||
|
|
|
@ -31,6 +31,7 @@ from glob import iglob
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils import log
|
from moulinette.utils import log
|
||||||
|
from moulinette.utils.filesystem import read_json
|
||||||
|
|
||||||
HOOK_FOLDER = '/usr/share/yunohost/hooks/'
|
HOOK_FOLDER = '/usr/share/yunohost/hooks/'
|
||||||
CUSTOM_HOOK_FOLDER = '/etc/yunohost/hooks.d/'
|
CUSTOM_HOOK_FOLDER = '/etc/yunohost/hooks.d/'
|
||||||
|
@ -228,7 +229,7 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
|
||||||
(name, priority, path, succeed) as arguments
|
(name, priority, path, succeed) as arguments
|
||||||
|
|
||||||
"""
|
"""
|
||||||
result = {'succeed': {}, 'failed': {}}
|
result = {}
|
||||||
hooks_dict = {}
|
hooks_dict = {}
|
||||||
|
|
||||||
# Retrieve hooks
|
# Retrieve hooks
|
||||||
|
@ -278,20 +279,20 @@ def hook_callback(action, hooks=[], args=None, no_trace=False, chdir=None,
|
||||||
try:
|
try:
|
||||||
hook_args = pre_callback(name=name, priority=priority,
|
hook_args = pre_callback(name=name, priority=priority,
|
||||||
path=path, args=args)
|
path=path, args=args)
|
||||||
hook_exec(path, args=hook_args, chdir=chdir, env=env,
|
hook_return = hook_exec(path, args=hook_args, chdir=chdir, env=env,
|
||||||
no_trace=no_trace, raise_on_error=True)
|
no_trace=no_trace, raise_on_error=True)[1]
|
||||||
except YunohostError as e:
|
except YunohostError as e:
|
||||||
state = 'failed'
|
state = 'failed'
|
||||||
|
hook_return = {}
|
||||||
logger.error(e.strerror, exc_info=1)
|
logger.error(e.strerror, exc_info=1)
|
||||||
post_callback(name=name, priority=priority, path=path,
|
post_callback(name=name, priority=priority, path=path,
|
||||||
succeed=False)
|
succeed=False)
|
||||||
else:
|
else:
|
||||||
post_callback(name=name, priority=priority, path=path,
|
post_callback(name=name, priority=priority, path=path,
|
||||||
succeed=True)
|
succeed=True)
|
||||||
try:
|
if not name in result:
|
||||||
result[state][name].append(path)
|
result[name] = {}
|
||||||
except KeyError:
|
result[name][path] = {'state' : state, 'stdreturn' : hook_return }
|
||||||
result[state][name] = [path]
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -339,6 +340,11 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
|
||||||
stdinfo = os.path.join(tempfile.mkdtemp(), "stdinfo")
|
stdinfo = os.path.join(tempfile.mkdtemp(), "stdinfo")
|
||||||
env['YNH_STDINFO'] = stdinfo
|
env['YNH_STDINFO'] = stdinfo
|
||||||
|
|
||||||
|
stdreturn = os.path.join(tempfile.mkdtemp(), "stdreturn")
|
||||||
|
with open(stdreturn, 'w') as f:
|
||||||
|
f.write('')
|
||||||
|
env['YNH_STDRETURN'] = stdreturn
|
||||||
|
|
||||||
# Construct command to execute
|
# Construct command to execute
|
||||||
if user == "root":
|
if user == "root":
|
||||||
command = ['sh', '-c']
|
command = ['sh', '-c']
|
||||||
|
@ -385,10 +391,27 @@ def hook_exec(path, args=None, raise_on_error=False, no_trace=False,
|
||||||
raise YunohostError('hook_exec_not_terminated', path=path)
|
raise YunohostError('hook_exec_not_terminated', path=path)
|
||||||
else:
|
else:
|
||||||
logger.error(m18n.n('hook_exec_not_terminated', path=path))
|
logger.error(m18n.n('hook_exec_not_terminated', path=path))
|
||||||
return 1
|
return 1, {}
|
||||||
elif raise_on_error and returncode != 0:
|
elif raise_on_error and returncode != 0:
|
||||||
raise YunohostError('hook_exec_failed', path=path)
|
raise YunohostError('hook_exec_failed', path=path)
|
||||||
return returncode
|
|
||||||
|
raw_content = None
|
||||||
|
try:
|
||||||
|
with open(stdreturn, 'r') as f:
|
||||||
|
raw_content = f.read()
|
||||||
|
if raw_content != '':
|
||||||
|
returnjson = read_json(stdreturn)
|
||||||
|
else:
|
||||||
|
returnjson = {}
|
||||||
|
except Exception as e:
|
||||||
|
raise YunohostError('hook_json_return_error', path=path, msg=str(e),
|
||||||
|
raw_content=raw_content)
|
||||||
|
finally:
|
||||||
|
stdreturndir = os.path.split(stdreturn)[0]
|
||||||
|
os.remove(stdreturn)
|
||||||
|
os.rmdir(stdreturndir)
|
||||||
|
|
||||||
|
return returncode, returnjson
|
||||||
|
|
||||||
|
|
||||||
def _extract_filename_parts(filename):
|
def _extract_filename_parts(filename):
|
||||||
|
|
555
src/yunohost/regenconf.py
Normal file
555
src/yunohost/regenconf.py
Normal file
|
@ -0,0 +1,555 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
""" License
|
||||||
|
|
||||||
|
Copyright (C) 2019 YunoHost
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program; if not, see http://www.gnu.org/licenses
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
from difflib import unified_diff
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from moulinette import m18n
|
||||||
|
from moulinette.utils import log, filesystem
|
||||||
|
from moulinette.utils.filesystem import read_file
|
||||||
|
|
||||||
|
from yunohost.utils.error import YunohostError
|
||||||
|
from yunohost.log import is_unit_operation
|
||||||
|
from yunohost.hook import hook_callback, hook_list
|
||||||
|
|
||||||
|
BASE_CONF_PATH = '/home/yunohost.conf'
|
||||||
|
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
|
||||||
|
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
|
||||||
|
REGEN_CONF_FILE = '/etc/yunohost/regenconf.yml'
|
||||||
|
|
||||||
|
logger = log.getActionLogger('yunohost.regenconf')
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME : those ain't just services anymore ... what are we supposed to do with this ...
|
||||||
|
# FIXME : check for all reference of 'service' close to operation_logger stuff
|
||||||
|
@is_unit_operation([('names', 'configuration')])
|
||||||
|
def regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
|
||||||
|
list_pending=False):
|
||||||
|
"""
|
||||||
|
Regenerate the configuration file(s)
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
names -- Categories to regenerate configuration of
|
||||||
|
with_diff -- Show differences in case of configuration changes
|
||||||
|
force -- Override all manual modifications in configuration files
|
||||||
|
dry_run -- Show what would have been regenerated
|
||||||
|
list_pending -- List pending configuration files and exit
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Legacy code to automatically run the migration
|
||||||
|
# This is required because regen_conf is called before the migration call
|
||||||
|
# in debian's postinst script
|
||||||
|
if os.path.exists("/etc/yunohost/installed") \
|
||||||
|
and ("conffiles" in read_file("/etc/yunohost/services.yml") \
|
||||||
|
or not os.path.exists(REGEN_CONF_FILE)):
|
||||||
|
from yunohost.tools import _get_migration_by_name
|
||||||
|
migration = _get_migration_by_name("decouple_regenconf_from_services")
|
||||||
|
migration.migrate()
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
# Return the list of pending conf
|
||||||
|
if list_pending:
|
||||||
|
pending_conf = _get_pending_conf(names)
|
||||||
|
|
||||||
|
if not with_diff:
|
||||||
|
return pending_conf
|
||||||
|
|
||||||
|
for category, conf_files in pending_conf.items():
|
||||||
|
for system_path, pending_path in conf_files.items():
|
||||||
|
|
||||||
|
pending_conf[category][system_path] = {
|
||||||
|
'pending_conf': pending_path,
|
||||||
|
'diff': _get_files_diff(
|
||||||
|
system_path, pending_path, True),
|
||||||
|
}
|
||||||
|
|
||||||
|
return pending_conf
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
operation_logger.related_to = [('configuration', x) for x in names]
|
||||||
|
if not names:
|
||||||
|
operation_logger.name_parameter_override = 'all'
|
||||||
|
elif len(names) != 1:
|
||||||
|
operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_categories'
|
||||||
|
operation_logger.start()
|
||||||
|
|
||||||
|
# Clean pending conf directory
|
||||||
|
if os.path.isdir(PENDING_CONF_DIR):
|
||||||
|
if not names:
|
||||||
|
shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
|
||||||
|
else:
|
||||||
|
for name in names:
|
||||||
|
shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
|
||||||
|
ignore_errors=True)
|
||||||
|
else:
|
||||||
|
filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
|
||||||
|
|
||||||
|
# Format common hooks arguments
|
||||||
|
common_args = [1 if force else 0, 1 if dry_run else 0]
|
||||||
|
|
||||||
|
# Execute hooks for pre-regen
|
||||||
|
pre_args = ['pre', ] + common_args
|
||||||
|
|
||||||
|
def _pre_call(name, priority, path, args):
|
||||||
|
# create the pending conf directory for the category
|
||||||
|
category_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
||||||
|
filesystem.mkdir(category_pending_path, 0o755, True, uid='root')
|
||||||
|
|
||||||
|
# return the arguments to pass to the script
|
||||||
|
return pre_args + [category_pending_path, ]
|
||||||
|
|
||||||
|
# Don't regen SSH if not specifically specified
|
||||||
|
if not names:
|
||||||
|
names = hook_list('conf_regen', list_by='name',
|
||||||
|
show_info=False)['hooks']
|
||||||
|
names.remove('ssh')
|
||||||
|
|
||||||
|
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
|
||||||
|
|
||||||
|
# Keep only the hook names with at least one success
|
||||||
|
names = [hook for hook, infos in pre_result.items()
|
||||||
|
if any(result["state"] == "succeed" for result in infos.values())]
|
||||||
|
|
||||||
|
# FIXME : what do in case of partial success/failure ...
|
||||||
|
if not names:
|
||||||
|
ret_failed = [hook for hook, infos in pre_result.items()
|
||||||
|
if any(result["state"] == "failed" for result in infos.values())]
|
||||||
|
raise YunohostError('regenconf_failed',
|
||||||
|
categories=', '.join(ret_failed))
|
||||||
|
|
||||||
|
# Set the processing method
|
||||||
|
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
|
||||||
|
|
||||||
|
operation_logger.related_to = []
|
||||||
|
|
||||||
|
# Iterate over categories and process pending conf
|
||||||
|
for category, conf_files in _get_pending_conf(names).items():
|
||||||
|
if not dry_run:
|
||||||
|
operation_logger.related_to.append(('configuration', category))
|
||||||
|
|
||||||
|
logger.debug(m18n.n(
|
||||||
|
'regenconf_pending_applying' if not dry_run else
|
||||||
|
'regenconf_dry_pending_applying',
|
||||||
|
category=category))
|
||||||
|
|
||||||
|
conf_hashes = _get_conf_hashes(category)
|
||||||
|
succeed_regen = {}
|
||||||
|
failed_regen = {}
|
||||||
|
|
||||||
|
for system_path, pending_path in conf_files.items():
|
||||||
|
logger.debug("processing pending conf '%s' to system conf '%s'",
|
||||||
|
pending_path, system_path)
|
||||||
|
conf_status = None
|
||||||
|
regenerated = False
|
||||||
|
|
||||||
|
# Get the diff between files
|
||||||
|
conf_diff = _get_files_diff(
|
||||||
|
system_path, pending_path, True) if with_diff else None
|
||||||
|
|
||||||
|
# Check if the conf must be removed
|
||||||
|
to_remove = True if os.path.getsize(pending_path) == 0 else False
|
||||||
|
|
||||||
|
# Retrieve and calculate hashes
|
||||||
|
system_hash = _calculate_hash(system_path)
|
||||||
|
saved_hash = conf_hashes.get(system_path, None)
|
||||||
|
new_hash = None if to_remove else _calculate_hash(pending_path)
|
||||||
|
|
||||||
|
# -> system conf does not exists
|
||||||
|
if not system_hash:
|
||||||
|
if to_remove:
|
||||||
|
logger.debug("> system conf is already removed")
|
||||||
|
os.remove(pending_path)
|
||||||
|
continue
|
||||||
|
if not saved_hash or force:
|
||||||
|
if force:
|
||||||
|
logger.debug("> system conf has been manually removed")
|
||||||
|
conf_status = 'force-created'
|
||||||
|
else:
|
||||||
|
logger.debug("> system conf does not exist yet")
|
||||||
|
conf_status = 'created'
|
||||||
|
regenerated = _regen(
|
||||||
|
system_path, pending_path, save=False)
|
||||||
|
else:
|
||||||
|
logger.info(m18n.n(
|
||||||
|
'regenconf_file_manually_removed',
|
||||||
|
conf=system_path))
|
||||||
|
conf_status = 'removed'
|
||||||
|
|
||||||
|
# -> system conf is not managed yet
|
||||||
|
elif not saved_hash:
|
||||||
|
logger.debug("> system conf is not managed yet")
|
||||||
|
if system_hash == new_hash:
|
||||||
|
logger.debug("> no changes to system conf has been made")
|
||||||
|
conf_status = 'managed'
|
||||||
|
regenerated = True
|
||||||
|
elif not to_remove:
|
||||||
|
# If the conf exist but is not managed yet, and is not to be removed,
|
||||||
|
# we assume that it is safe to regen it, since the file is backuped
|
||||||
|
# anyway (by default in _regen), as long as we warn the user
|
||||||
|
# appropriately.
|
||||||
|
logger.info(m18n.n('regenconf_now_managed_by_yunohost',
|
||||||
|
conf=system_path, category=category))
|
||||||
|
regenerated = _regen(system_path, pending_path)
|
||||||
|
conf_status = 'new'
|
||||||
|
elif force:
|
||||||
|
regenerated = _regen(system_path)
|
||||||
|
conf_status = 'force-removed'
|
||||||
|
else:
|
||||||
|
logger.info(m18n.n('regenconf_file_kept_back',
|
||||||
|
conf=system_path, category=category))
|
||||||
|
conf_status = 'unmanaged'
|
||||||
|
|
||||||
|
# -> system conf has not been manually modified
|
||||||
|
elif system_hash == saved_hash:
|
||||||
|
if to_remove:
|
||||||
|
regenerated = _regen(system_path)
|
||||||
|
conf_status = 'removed'
|
||||||
|
elif system_hash != new_hash:
|
||||||
|
regenerated = _regen(system_path, pending_path)
|
||||||
|
conf_status = 'updated'
|
||||||
|
else:
|
||||||
|
logger.debug("> system conf is already up-to-date")
|
||||||
|
os.remove(pending_path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.debug("> system conf has been manually modified")
|
||||||
|
if system_hash == new_hash:
|
||||||
|
logger.debug("> new conf is as current system conf")
|
||||||
|
conf_status = 'managed'
|
||||||
|
regenerated = True
|
||||||
|
elif force:
|
||||||
|
regenerated = _regen(system_path, pending_path)
|
||||||
|
conf_status = 'force-updated'
|
||||||
|
else:
|
||||||
|
logger.warning(m18n.n(
|
||||||
|
'regenconf_file_manually_modified',
|
||||||
|
conf=system_path))
|
||||||
|
conf_status = 'modified'
|
||||||
|
|
||||||
|
# Store the result
|
||||||
|
conf_result = {'status': conf_status}
|
||||||
|
if conf_diff is not None:
|
||||||
|
conf_result['diff'] = conf_diff
|
||||||
|
if regenerated:
|
||||||
|
succeed_regen[system_path] = conf_result
|
||||||
|
conf_hashes[system_path] = new_hash
|
||||||
|
if os.path.isfile(pending_path):
|
||||||
|
os.remove(pending_path)
|
||||||
|
else:
|
||||||
|
failed_regen[system_path] = conf_result
|
||||||
|
|
||||||
|
# Check for category conf changes
|
||||||
|
if not succeed_regen and not failed_regen:
|
||||||
|
logger.debug(m18n.n('regenconf_up_to_date', category=category))
|
||||||
|
continue
|
||||||
|
elif not failed_regen:
|
||||||
|
logger.success(m18n.n(
|
||||||
|
'regenconf_updated' if not dry_run else
|
||||||
|
'regenconf_would_be_updated',
|
||||||
|
category=category))
|
||||||
|
|
||||||
|
if succeed_regen and not dry_run:
|
||||||
|
_update_conf_hashes(category, conf_hashes)
|
||||||
|
|
||||||
|
# Append the category results
|
||||||
|
result[category] = {
|
||||||
|
'applied': succeed_regen,
|
||||||
|
'pending': failed_regen
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return in case of dry run
|
||||||
|
if dry_run:
|
||||||
|
return result
|
||||||
|
|
||||||
|
# Execute hooks for post-regen
|
||||||
|
post_args = ['post', ] + common_args
|
||||||
|
|
||||||
|
def _pre_call(name, priority, path, args):
|
||||||
|
# append coma-separated applied changes for the category
|
||||||
|
if name in result and result[name]['applied']:
|
||||||
|
regen_conf_files = ','.join(result[name]['applied'].keys())
|
||||||
|
else:
|
||||||
|
regen_conf_files = ''
|
||||||
|
return post_args + [regen_conf_files, ]
|
||||||
|
|
||||||
|
hook_callback('conf_regen', names, pre_callback=_pre_call)
|
||||||
|
|
||||||
|
operation_logger.success()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_regenconf_infos():
|
||||||
|
"""
|
||||||
|
Get a dict of regen conf informations
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(REGEN_CONF_FILE, 'r') as f:
|
||||||
|
return yaml.load(f)
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def _save_regenconf_infos(infos):
|
||||||
|
"""
|
||||||
|
Save the regen conf informations
|
||||||
|
Keyword argument:
|
||||||
|
categories -- A dict containing the regenconf infos
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(REGEN_CONF_FILE, 'w') as f:
|
||||||
|
yaml.safe_dump(infos, f, default_flow_style=False)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning('Error while saving regenconf infos, exception: %s', e, exc_info=1)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
|
||||||
|
"""Compare two files and return the differences
|
||||||
|
|
||||||
|
Read and compare two files. The differences are returned either as a delta
|
||||||
|
in unified diff format or a formatted string if as_string is True. The
|
||||||
|
header can also be removed if skip_header is True.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if os.path.exists(orig_file):
|
||||||
|
with open(orig_file, 'r') as orig_file:
|
||||||
|
orig_file = orig_file.readlines()
|
||||||
|
else:
|
||||||
|
orig_file = []
|
||||||
|
|
||||||
|
if os.path.exists(new_file):
|
||||||
|
with open(new_file, 'r') as new_file:
|
||||||
|
new_file = new_file.readlines()
|
||||||
|
else:
|
||||||
|
new_file = []
|
||||||
|
|
||||||
|
# Compare files and format output
|
||||||
|
diff = unified_diff(orig_file, new_file)
|
||||||
|
|
||||||
|
if skip_header:
|
||||||
|
try:
|
||||||
|
next(diff)
|
||||||
|
next(diff)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if as_string:
|
||||||
|
return ''.join(diff).rstrip()
|
||||||
|
|
||||||
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def _calculate_hash(path):
|
||||||
|
"""Calculate the MD5 hash of a file"""
|
||||||
|
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return None
|
||||||
|
|
||||||
|
hasher = hashlib.md5()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(path, 'rb') as f:
|
||||||
|
hasher.update(f.read())
|
||||||
|
return hasher.hexdigest()
|
||||||
|
|
||||||
|
except IOError as e:
|
||||||
|
logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pending_conf(categories=[]):
|
||||||
|
"""Get pending configuration for categories
|
||||||
|
|
||||||
|
Iterate over the pending configuration directory for given categories - or
|
||||||
|
all if empty - and look for files inside. Each file is considered as a
|
||||||
|
pending configuration file and therefore must be in the same directory
|
||||||
|
tree than the system file that it replaces.
|
||||||
|
The result is returned as a dict of categories with pending configuration as
|
||||||
|
key and a dict of `system_conf_path` => `pending_conf_path` as value.
|
||||||
|
|
||||||
|
"""
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if not os.path.isdir(PENDING_CONF_DIR):
|
||||||
|
return result
|
||||||
|
|
||||||
|
if not categories:
|
||||||
|
categories = os.listdir(PENDING_CONF_DIR)
|
||||||
|
|
||||||
|
for name in categories:
|
||||||
|
category_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
||||||
|
|
||||||
|
if not os.path.isdir(category_pending_path):
|
||||||
|
continue
|
||||||
|
|
||||||
|
path_index = len(category_pending_path)
|
||||||
|
category_conf = {}
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(category_pending_path):
|
||||||
|
for filename in files:
|
||||||
|
pending_path = os.path.join(root, filename)
|
||||||
|
category_conf[pending_path[path_index:]] = pending_path
|
||||||
|
|
||||||
|
if category_conf:
|
||||||
|
result[name] = category_conf
|
||||||
|
else:
|
||||||
|
# remove empty directory
|
||||||
|
shutil.rmtree(category_pending_path, ignore_errors=True)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _get_conf_hashes(category):
|
||||||
|
"""Get the registered conf hashes for a category"""
|
||||||
|
|
||||||
|
categories = _get_regenconf_infos()
|
||||||
|
|
||||||
|
if category not in categories:
|
||||||
|
logger.debug("category %s is not in categories.yml yet.", category)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
elif categories[category] is None or 'conffiles' not in categories[category]:
|
||||||
|
logger.debug("No configuration files for category %s.", category)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
else:
|
||||||
|
return categories[category]['conffiles']
|
||||||
|
|
||||||
|
|
||||||
|
def _update_conf_hashes(category, hashes):
|
||||||
|
"""Update the registered conf hashes for a category"""
|
||||||
|
logger.debug("updating conf hashes for '%s' with: %s",
|
||||||
|
category, hashes)
|
||||||
|
|
||||||
|
categories = _get_regenconf_infos()
|
||||||
|
category_conf = categories.get(category, {})
|
||||||
|
|
||||||
|
# Handle the case where categories[category] is set to null in the yaml
|
||||||
|
if category_conf is None:
|
||||||
|
category_conf = {}
|
||||||
|
|
||||||
|
category_conf['conffiles'] = hashes
|
||||||
|
categories[category] = category_conf
|
||||||
|
_save_regenconf_infos(categories)
|
||||||
|
|
||||||
|
|
||||||
|
def _process_regen_conf(system_conf, new_conf=None, save=True):
|
||||||
|
"""Regenerate a given system configuration file
|
||||||
|
|
||||||
|
Replace a given system configuration file by a new one or delete it if
|
||||||
|
new_conf is None. A backup of the file - keeping its directory tree - will
|
||||||
|
be done in the backup conf directory before any operation if save is True.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if save:
|
||||||
|
backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
|
||||||
|
system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
|
||||||
|
backup_dir = os.path.dirname(backup_path)
|
||||||
|
|
||||||
|
if not os.path.isdir(backup_dir):
|
||||||
|
filesystem.mkdir(backup_dir, 0o755, True)
|
||||||
|
|
||||||
|
shutil.copy2(system_conf, backup_path)
|
||||||
|
logger.debug(m18n.n('regenconf_file_backed_up',
|
||||||
|
conf=system_conf, backup=backup_path))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not new_conf:
|
||||||
|
os.remove(system_conf)
|
||||||
|
logger.debug(m18n.n('regenconf_file_removed',
|
||||||
|
conf=system_conf))
|
||||||
|
else:
|
||||||
|
system_dir = os.path.dirname(system_conf)
|
||||||
|
|
||||||
|
if not os.path.isdir(system_dir):
|
||||||
|
filesystem.mkdir(system_dir, 0o755, True)
|
||||||
|
|
||||||
|
shutil.copyfile(new_conf, system_conf)
|
||||||
|
logger.debug(m18n.n('regenconf_file_updated',
|
||||||
|
conf=system_conf))
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
|
||||||
|
if not new_conf and os.path.exists(system_conf):
|
||||||
|
logger.warning(m18n.n('regenconf_file_remove_failed',
|
||||||
|
conf=system_conf),
|
||||||
|
exc_info=1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
elif new_conf:
|
||||||
|
try:
|
||||||
|
# From documentation:
|
||||||
|
# Raise an exception if an os.stat() call on either pathname fails.
|
||||||
|
# (os.stats returns a series of information from a file like type, size...)
|
||||||
|
copy_succeed = os.path.samefile(system_conf, new_conf)
|
||||||
|
except:
|
||||||
|
copy_succeed = False
|
||||||
|
finally:
|
||||||
|
if not copy_succeed:
|
||||||
|
logger.warning(m18n.n('regenconf_file_copy_failed',
|
||||||
|
conf=system_conf, new=new_conf),
|
||||||
|
exc_info=1)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def manually_modified_files():
|
||||||
|
|
||||||
|
# We do this to have --quiet, i.e. don't throw a whole bunch of logs
|
||||||
|
# just to fetch this...
|
||||||
|
# Might be able to optimize this by looking at what the regen conf does
|
||||||
|
# and only do the part that checks file hashes...
|
||||||
|
cmd = "yunohost tools regen-conf --dry-run --output-as json --quiet"
|
||||||
|
j = json.loads(subprocess.check_output(cmd.split()))
|
||||||
|
|
||||||
|
# j is something like :
|
||||||
|
# {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
|
||||||
|
|
||||||
|
output = []
|
||||||
|
for app, actions in j.items():
|
||||||
|
for action, files in actions.items():
|
||||||
|
for filename, infos in files.items():
|
||||||
|
if infos["status"] == "modified":
|
||||||
|
output.append(filename)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def manually_modified_files_compared_to_debian_default():
|
||||||
|
|
||||||
|
# from https://serverfault.com/a/90401
|
||||||
|
r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
|
||||||
|
| awk 'OFS=\" \"{print $2,$1}' \
|
||||||
|
| md5sum -c 2>/dev/null \
|
||||||
|
| awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
|
||||||
|
return r.strip().split("\n")
|
|
@ -26,12 +26,9 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import yaml
|
import yaml
|
||||||
import json
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
from difflib import unified_diff
|
from glob import glob
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
|
@ -39,11 +36,7 @@ from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils import log, filesystem
|
from moulinette.utils import log, filesystem
|
||||||
|
|
||||||
from yunohost.log import is_unit_operation
|
from yunohost.log import is_unit_operation
|
||||||
from yunohost.hook import hook_callback, hook_list
|
|
||||||
|
|
||||||
BASE_CONF_PATH = '/home/yunohost.conf'
|
|
||||||
BACKUP_CONF_DIR = os.path.join(BASE_CONF_PATH, 'backup')
|
|
||||||
PENDING_CONF_DIR = os.path.join(BASE_CONF_PATH, 'pending')
|
|
||||||
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
|
MOULINETTE_LOCK = "/var/run/moulinette_yunohost.lock"
|
||||||
|
|
||||||
logger = log.getActionLogger('yunohost.service')
|
logger = log.getActionLogger('yunohost.service')
|
||||||
|
@ -325,11 +318,17 @@ def service_status(names=[]):
|
||||||
|
|
||||||
result[name] = {
|
result[name] = {
|
||||||
'status': str(status.get("SubState", "unknown")),
|
'status': str(status.get("SubState", "unknown")),
|
||||||
'loaded': "enabled" if str(status.get("LoadState", "unknown")) == "loaded" else str(status.get("LoadState", "unknown")),
|
'loaded': str(status.get("UnitFileState", "unknown")),
|
||||||
'active': str(status.get("ActiveState", "unknown")),
|
'active': str(status.get("ActiveState", "unknown")),
|
||||||
'description': description,
|
'description': description,
|
||||||
'service_file_path': str(status.get("FragmentPath", "unknown")),
|
'service_file_path': str(status.get("FragmentPath", "unknown")),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Fun stuff™ : to obtain the enabled/disabled status for sysv services,
|
||||||
|
# gotta do this ... cf code of /lib/systemd/systemd-sysv-install
|
||||||
|
if result[name]["loaded"] == "generated":
|
||||||
|
result[name]["loaded"] = "enabled" if glob("/etc/rc[S5].d/S??"+name) else "disabled"
|
||||||
|
|
||||||
if "ActiveEnterTimestamp" in status:
|
if "ActiveEnterTimestamp" in status:
|
||||||
result[name]['active_at'] = datetime.utcfromtimestamp(status["ActiveEnterTimestamp"] / 1000000)
|
result[name]['active_at'] = datetime.utcfromtimestamp(status["ActiveEnterTimestamp"] / 1000000)
|
||||||
else:
|
else:
|
||||||
|
@ -343,26 +342,25 @@ def service_status(names=[]):
|
||||||
def _get_service_information_from_systemd(service):
|
def _get_service_information_from_systemd(service):
|
||||||
"this is the equivalent of 'systemctl status $service'"
|
"this is the equivalent of 'systemctl status $service'"
|
||||||
import dbus
|
import dbus
|
||||||
from dbus.exceptions import DBusException
|
|
||||||
|
|
||||||
d = dbus.SystemBus()
|
d = dbus.SystemBus()
|
||||||
|
|
||||||
systemd = d.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
|
systemd = d.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
|
||||||
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
|
manager = dbus.Interface(systemd, 'org.freedesktop.systemd1.Manager')
|
||||||
|
|
||||||
try:
|
# c.f. https://zignar.net/2014/09/08/getting-started-with-dbus-python-systemd/
|
||||||
service_path = manager.GetUnit(service + ".service")
|
# Very interface, much intuitive, wow
|
||||||
except DBusException as exception:
|
service_unit = manager.LoadUnit(service + '.service')
|
||||||
if exception.get_dbus_name() == 'org.freedesktop.systemd1.NoSuchUnit':
|
service_proxy = d.get_object('org.freedesktop.systemd1', str(service_unit))
|
||||||
return None
|
|
||||||
raise
|
|
||||||
|
|
||||||
service_proxy = d.get_object('org.freedesktop.systemd1', service_path)
|
|
||||||
|
|
||||||
# unit_proxy = dbus.Interface(service_proxy, 'org.freedesktop.systemd1.Unit',)
|
|
||||||
properties_interface = dbus.Interface(service_proxy, 'org.freedesktop.DBus.Properties')
|
properties_interface = dbus.Interface(service_proxy, 'org.freedesktop.DBus.Properties')
|
||||||
|
|
||||||
return properties_interface.GetAll('org.freedesktop.systemd1.Unit')
|
properties = properties_interface.GetAll('org.freedesktop.systemd1.Unit')
|
||||||
|
|
||||||
|
if properties.get("LoadState", "not-found") == "not-found":
|
||||||
|
# Service doesn't really exist
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return properties
|
||||||
|
|
||||||
|
|
||||||
def service_log(name, number=50):
|
def service_log(name, number=50):
|
||||||
|
@ -418,249 +416,25 @@ def service_log(name, number=50):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation([('names', 'service')])
|
def service_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
|
||||||
def service_regen_conf(operation_logger, names=[], with_diff=False, force=False, dry_run=False,
|
|
||||||
list_pending=False):
|
list_pending=False):
|
||||||
"""
|
|
||||||
Regenerate the configuration file(s) for a service
|
|
||||||
|
|
||||||
Keyword argument:
|
services = _get_services()
|
||||||
names -- Services name to regenerate configuration of
|
|
||||||
with_diff -- Show differences in case of configuration changes
|
|
||||||
force -- Override all manual modifications in configuration files
|
|
||||||
dry_run -- Show what would have been regenerated
|
|
||||||
list_pending -- List pending configuration files and exit
|
|
||||||
|
|
||||||
"""
|
if isinstance(names, str):
|
||||||
result = {}
|
names = [names]
|
||||||
|
|
||||||
# Return the list of pending conf
|
for name in names:
|
||||||
if list_pending:
|
if name not in services.keys():
|
||||||
pending_conf = _get_pending_conf(names)
|
raise YunohostError('service_unknown', service=name)
|
||||||
|
|
||||||
if not with_diff:
|
if names is []:
|
||||||
return pending_conf
|
names = services.keys()
|
||||||
|
|
||||||
for service, conf_files in pending_conf.items():
|
logger.warning(m18n.n("service_regen_conf_is_deprecated"))
|
||||||
for system_path, pending_path in conf_files.items():
|
|
||||||
|
|
||||||
pending_conf[service][system_path] = {
|
from yunohost.regenconf import regen_conf
|
||||||
'pending_conf': pending_path,
|
return regen_conf(names, with_diff, force, dry_run, list_pending)
|
||||||
'diff': _get_files_diff(
|
|
||||||
system_path, pending_path, True),
|
|
||||||
}
|
|
||||||
|
|
||||||
return pending_conf
|
|
||||||
|
|
||||||
if not dry_run:
|
|
||||||
operation_logger.related_to = [('service', x) for x in names]
|
|
||||||
if not names:
|
|
||||||
operation_logger.name_parameter_override = 'all'
|
|
||||||
elif len(names) != 1:
|
|
||||||
operation_logger.name_parameter_override = str(len(operation_logger.related_to)) + '_services'
|
|
||||||
operation_logger.start()
|
|
||||||
|
|
||||||
# Clean pending conf directory
|
|
||||||
if os.path.isdir(PENDING_CONF_DIR):
|
|
||||||
if not names:
|
|
||||||
shutil.rmtree(PENDING_CONF_DIR, ignore_errors=True)
|
|
||||||
else:
|
|
||||||
for name in names:
|
|
||||||
shutil.rmtree(os.path.join(PENDING_CONF_DIR, name),
|
|
||||||
ignore_errors=True)
|
|
||||||
else:
|
|
||||||
filesystem.mkdir(PENDING_CONF_DIR, 0o755, True)
|
|
||||||
|
|
||||||
# Format common hooks arguments
|
|
||||||
common_args = [1 if force else 0, 1 if dry_run else 0]
|
|
||||||
|
|
||||||
# Execute hooks for pre-regen
|
|
||||||
pre_args = ['pre', ] + common_args
|
|
||||||
|
|
||||||
def _pre_call(name, priority, path, args):
|
|
||||||
# create the pending conf directory for the service
|
|
||||||
service_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
|
||||||
filesystem.mkdir(service_pending_path, 0o755, True, uid='root')
|
|
||||||
|
|
||||||
# return the arguments to pass to the script
|
|
||||||
return pre_args + [service_pending_path, ]
|
|
||||||
|
|
||||||
# Don't regen SSH if not specifically specified
|
|
||||||
if not names:
|
|
||||||
names = hook_list('conf_regen', list_by='name',
|
|
||||||
show_info=False)['hooks']
|
|
||||||
names.remove('ssh')
|
|
||||||
|
|
||||||
pre_result = hook_callback('conf_regen', names, pre_callback=_pre_call)
|
|
||||||
|
|
||||||
# Update the services name
|
|
||||||
names = pre_result['succeed'].keys()
|
|
||||||
|
|
||||||
if not names:
|
|
||||||
raise YunohostError('service_regenconf_failed',
|
|
||||||
services=', '.join(pre_result['failed']))
|
|
||||||
|
|
||||||
# Set the processing method
|
|
||||||
_regen = _process_regen_conf if not dry_run else lambda *a, **k: True
|
|
||||||
|
|
||||||
operation_logger.related_to = []
|
|
||||||
|
|
||||||
# Iterate over services and process pending conf
|
|
||||||
for service, conf_files in _get_pending_conf(names).items():
|
|
||||||
if not dry_run:
|
|
||||||
operation_logger.related_to.append(('service', service))
|
|
||||||
|
|
||||||
logger.debug(m18n.n(
|
|
||||||
'service_regenconf_pending_applying' if not dry_run else
|
|
||||||
'service_regenconf_dry_pending_applying',
|
|
||||||
service=service))
|
|
||||||
|
|
||||||
conf_hashes = _get_conf_hashes(service)
|
|
||||||
succeed_regen = {}
|
|
||||||
failed_regen = {}
|
|
||||||
|
|
||||||
for system_path, pending_path in conf_files.items():
|
|
||||||
logger.debug("processing pending conf '%s' to system conf '%s'",
|
|
||||||
pending_path, system_path)
|
|
||||||
conf_status = None
|
|
||||||
regenerated = False
|
|
||||||
|
|
||||||
# Get the diff between files
|
|
||||||
conf_diff = _get_files_diff(
|
|
||||||
system_path, pending_path, True) if with_diff else None
|
|
||||||
|
|
||||||
# Check if the conf must be removed
|
|
||||||
to_remove = True if os.path.getsize(pending_path) == 0 else False
|
|
||||||
|
|
||||||
# Retrieve and calculate hashes
|
|
||||||
system_hash = _calculate_hash(system_path)
|
|
||||||
saved_hash = conf_hashes.get(system_path, None)
|
|
||||||
new_hash = None if to_remove else _calculate_hash(pending_path)
|
|
||||||
|
|
||||||
# -> system conf does not exists
|
|
||||||
if not system_hash:
|
|
||||||
if to_remove:
|
|
||||||
logger.debug("> system conf is already removed")
|
|
||||||
os.remove(pending_path)
|
|
||||||
continue
|
|
||||||
if not saved_hash or force:
|
|
||||||
if force:
|
|
||||||
logger.debug("> system conf has been manually removed")
|
|
||||||
conf_status = 'force-created'
|
|
||||||
else:
|
|
||||||
logger.debug("> system conf does not exist yet")
|
|
||||||
conf_status = 'created'
|
|
||||||
regenerated = _regen(
|
|
||||||
system_path, pending_path, save=False)
|
|
||||||
else:
|
|
||||||
logger.info(m18n.n(
|
|
||||||
'service_conf_file_manually_removed',
|
|
||||||
conf=system_path))
|
|
||||||
conf_status = 'removed'
|
|
||||||
|
|
||||||
# -> system conf is not managed yet
|
|
||||||
elif not saved_hash:
|
|
||||||
logger.debug("> system conf is not managed yet")
|
|
||||||
if system_hash == new_hash:
|
|
||||||
logger.debug("> no changes to system conf has been made")
|
|
||||||
conf_status = 'managed'
|
|
||||||
regenerated = True
|
|
||||||
elif not to_remove:
|
|
||||||
# If the conf exist but is not managed yet, and is not to be removed,
|
|
||||||
# we assume that it is safe to regen it, since the file is backuped
|
|
||||||
# anyway (by default in _regen), as long as we warn the user
|
|
||||||
# appropriately.
|
|
||||||
logger.info(m18n.n('service_conf_now_managed_by_yunohost',
|
|
||||||
conf=system_path))
|
|
||||||
regenerated = _regen(system_path, pending_path)
|
|
||||||
conf_status = 'new'
|
|
||||||
elif force:
|
|
||||||
regenerated = _regen(system_path)
|
|
||||||
conf_status = 'force-removed'
|
|
||||||
else:
|
|
||||||
logger.info(m18n.n('service_conf_file_kept_back',
|
|
||||||
conf=system_path, service=service))
|
|
||||||
conf_status = 'unmanaged'
|
|
||||||
|
|
||||||
# -> system conf has not been manually modified
|
|
||||||
elif system_hash == saved_hash:
|
|
||||||
if to_remove:
|
|
||||||
regenerated = _regen(system_path)
|
|
||||||
conf_status = 'removed'
|
|
||||||
elif system_hash != new_hash:
|
|
||||||
regenerated = _regen(system_path, pending_path)
|
|
||||||
conf_status = 'updated'
|
|
||||||
else:
|
|
||||||
logger.debug("> system conf is already up-to-date")
|
|
||||||
os.remove(pending_path)
|
|
||||||
continue
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.debug("> system conf has been manually modified")
|
|
||||||
if system_hash == new_hash:
|
|
||||||
logger.debug("> new conf is as current system conf")
|
|
||||||
conf_status = 'managed'
|
|
||||||
regenerated = True
|
|
||||||
elif force:
|
|
||||||
regenerated = _regen(system_path, pending_path)
|
|
||||||
conf_status = 'force-updated'
|
|
||||||
else:
|
|
||||||
logger.warning(m18n.n(
|
|
||||||
'service_conf_file_manually_modified',
|
|
||||||
conf=system_path))
|
|
||||||
conf_status = 'modified'
|
|
||||||
|
|
||||||
# Store the result
|
|
||||||
conf_result = {'status': conf_status}
|
|
||||||
if conf_diff is not None:
|
|
||||||
conf_result['diff'] = conf_diff
|
|
||||||
if regenerated:
|
|
||||||
succeed_regen[system_path] = conf_result
|
|
||||||
conf_hashes[system_path] = new_hash
|
|
||||||
if os.path.isfile(pending_path):
|
|
||||||
os.remove(pending_path)
|
|
||||||
else:
|
|
||||||
failed_regen[system_path] = conf_result
|
|
||||||
|
|
||||||
# Check for service conf changes
|
|
||||||
if not succeed_regen and not failed_regen:
|
|
||||||
logger.debug(m18n.n('service_conf_up_to_date', service=service))
|
|
||||||
continue
|
|
||||||
elif not failed_regen:
|
|
||||||
logger.success(m18n.n(
|
|
||||||
'service_conf_updated' if not dry_run else
|
|
||||||
'service_conf_would_be_updated',
|
|
||||||
service=service))
|
|
||||||
|
|
||||||
if succeed_regen and not dry_run:
|
|
||||||
_update_conf_hashes(service, conf_hashes)
|
|
||||||
|
|
||||||
# Append the service results
|
|
||||||
result[service] = {
|
|
||||||
'applied': succeed_regen,
|
|
||||||
'pending': failed_regen
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return in case of dry run
|
|
||||||
if dry_run:
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Execute hooks for post-regen
|
|
||||||
post_args = ['post', ] + common_args
|
|
||||||
|
|
||||||
def _pre_call(name, priority, path, args):
|
|
||||||
# append coma-separated applied changes for the service
|
|
||||||
if name in result and result[name]['applied']:
|
|
||||||
regen_conf_files = ','.join(result[name]['applied'].keys())
|
|
||||||
else:
|
|
||||||
regen_conf_files = ''
|
|
||||||
return post_args + [regen_conf_files, ]
|
|
||||||
|
|
||||||
hook_callback('conf_regen', names, pre_callback=_pre_call)
|
|
||||||
|
|
||||||
operation_logger.success()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _run_service_command(action, service):
|
def _run_service_command(action, service):
|
||||||
|
@ -860,231 +634,9 @@ def _find_previous_log_file(file):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_files_diff(orig_file, new_file, as_string=False, skip_header=True):
|
|
||||||
"""Compare two files and return the differences
|
|
||||||
|
|
||||||
Read and compare two files. The differences are returned either as a delta
|
|
||||||
in unified diff format or a formatted string if as_string is True. The
|
|
||||||
header can also be removed if skip_header is True.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if os.path.exists(orig_file):
|
|
||||||
with open(orig_file, 'r') as orig_file:
|
|
||||||
orig_file = orig_file.readlines()
|
|
||||||
else:
|
|
||||||
orig_file = []
|
|
||||||
|
|
||||||
if os.path.exists(new_file):
|
|
||||||
with open(new_file, 'r') as new_file:
|
|
||||||
new_file = new_file.readlines()
|
|
||||||
else:
|
|
||||||
new_file = []
|
|
||||||
|
|
||||||
# Compare files and format output
|
|
||||||
diff = unified_diff(orig_file, new_file)
|
|
||||||
|
|
||||||
if skip_header:
|
|
||||||
try:
|
|
||||||
next(diff)
|
|
||||||
next(diff)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if as_string:
|
|
||||||
return ''.join(diff).rstrip()
|
|
||||||
|
|
||||||
return diff
|
|
||||||
|
|
||||||
|
|
||||||
def _calculate_hash(path):
|
|
||||||
"""Calculate the MD5 hash of a file"""
|
|
||||||
|
|
||||||
if not os.path.exists(path):
|
|
||||||
return None
|
|
||||||
|
|
||||||
hasher = hashlib.md5()
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(path, 'rb') as f:
|
|
||||||
hasher.update(f.read())
|
|
||||||
return hasher.hexdigest()
|
|
||||||
|
|
||||||
except IOError as e:
|
|
||||||
logger.warning("Error while calculating file '%s' hash: %s", path, e, exc_info=1)
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _get_pending_conf(services=[]):
|
|
||||||
"""Get pending configuration for service(s)
|
|
||||||
|
|
||||||
Iterate over the pending configuration directory for given service(s) - or
|
|
||||||
all if empty - and look for files inside. Each file is considered as a
|
|
||||||
pending configuration file and therefore must be in the same directory
|
|
||||||
tree than the system file that it replaces.
|
|
||||||
The result is returned as a dict of services with pending configuration as
|
|
||||||
key and a dict of `system_conf_path` => `pending_conf_path` as value.
|
|
||||||
|
|
||||||
"""
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
if not os.path.isdir(PENDING_CONF_DIR):
|
|
||||||
return result
|
|
||||||
|
|
||||||
if not services:
|
|
||||||
services = os.listdir(PENDING_CONF_DIR)
|
|
||||||
|
|
||||||
for name in services:
|
|
||||||
service_pending_path = os.path.join(PENDING_CONF_DIR, name)
|
|
||||||
|
|
||||||
if not os.path.isdir(service_pending_path):
|
|
||||||
continue
|
|
||||||
|
|
||||||
path_index = len(service_pending_path)
|
|
||||||
service_conf = {}
|
|
||||||
|
|
||||||
for root, dirs, files in os.walk(service_pending_path):
|
|
||||||
for filename in files:
|
|
||||||
pending_path = os.path.join(root, filename)
|
|
||||||
service_conf[pending_path[path_index:]] = pending_path
|
|
||||||
|
|
||||||
if service_conf:
|
|
||||||
result[name] = service_conf
|
|
||||||
else:
|
|
||||||
# remove empty directory
|
|
||||||
shutil.rmtree(service_pending_path, ignore_errors=True)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _get_conf_hashes(service):
|
|
||||||
"""Get the registered conf hashes for a service"""
|
|
||||||
|
|
||||||
services = _get_services()
|
|
||||||
|
|
||||||
if service not in services:
|
|
||||||
logger.debug("Service %s is not in services.yml yet.", service)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
elif services[service] is None or 'conffiles' not in services[service]:
|
|
||||||
logger.debug("No configuration files for service %s.", service)
|
|
||||||
return {}
|
|
||||||
|
|
||||||
else:
|
|
||||||
return services[service]['conffiles']
|
|
||||||
|
|
||||||
|
|
||||||
def _update_conf_hashes(service, hashes):
|
|
||||||
"""Update the registered conf hashes for a service"""
|
|
||||||
logger.debug("updating conf hashes for '%s' with: %s",
|
|
||||||
service, hashes)
|
|
||||||
services = _get_services()
|
|
||||||
service_conf = services.get(service, {})
|
|
||||||
|
|
||||||
# Handle the case where services[service] is set to null in the yaml
|
|
||||||
if service_conf is None:
|
|
||||||
service_conf = {}
|
|
||||||
|
|
||||||
service_conf['conffiles'] = hashes
|
|
||||||
services[service] = service_conf
|
|
||||||
_save_services(services)
|
|
||||||
|
|
||||||
|
|
||||||
def _process_regen_conf(system_conf, new_conf=None, save=True):
|
|
||||||
"""Regenerate a given system configuration file
|
|
||||||
|
|
||||||
Replace a given system configuration file by a new one or delete it if
|
|
||||||
new_conf is None. A backup of the file - keeping its directory tree - will
|
|
||||||
be done in the backup conf directory before any operation if save is True.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if save:
|
|
||||||
backup_path = os.path.join(BACKUP_CONF_DIR, '{0}-{1}'.format(
|
|
||||||
system_conf.lstrip('/'), datetime.utcnow().strftime("%Y%m%d.%H%M%S")))
|
|
||||||
backup_dir = os.path.dirname(backup_path)
|
|
||||||
|
|
||||||
if not os.path.isdir(backup_dir):
|
|
||||||
filesystem.mkdir(backup_dir, 0o755, True)
|
|
||||||
|
|
||||||
shutil.copy2(system_conf, backup_path)
|
|
||||||
logger.debug(m18n.n('service_conf_file_backed_up',
|
|
||||||
conf=system_conf, backup=backup_path))
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not new_conf:
|
|
||||||
os.remove(system_conf)
|
|
||||||
logger.debug(m18n.n('service_conf_file_removed',
|
|
||||||
conf=system_conf))
|
|
||||||
else:
|
|
||||||
system_dir = os.path.dirname(system_conf)
|
|
||||||
|
|
||||||
if not os.path.isdir(system_dir):
|
|
||||||
filesystem.mkdir(system_dir, 0o755, True)
|
|
||||||
|
|
||||||
shutil.copyfile(new_conf, system_conf)
|
|
||||||
logger.debug(m18n.n('service_conf_file_updated',
|
|
||||||
conf=system_conf))
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning("Exception while trying to regenerate conf '%s': %s", system_conf, e, exc_info=1)
|
|
||||||
if not new_conf and os.path.exists(system_conf):
|
|
||||||
logger.warning(m18n.n('service_conf_file_remove_failed',
|
|
||||||
conf=system_conf),
|
|
||||||
exc_info=1)
|
|
||||||
return False
|
|
||||||
|
|
||||||
elif new_conf:
|
|
||||||
try:
|
|
||||||
# From documentation:
|
|
||||||
# Raise an exception if an os.stat() call on either pathname fails.
|
|
||||||
# (os.stats returns a series of information from a file like type, size...)
|
|
||||||
copy_succeed = os.path.samefile(system_conf, new_conf)
|
|
||||||
except:
|
|
||||||
copy_succeed = False
|
|
||||||
finally:
|
|
||||||
if not copy_succeed:
|
|
||||||
logger.warning(m18n.n('service_conf_file_copy_failed',
|
|
||||||
conf=system_conf, new=new_conf),
|
|
||||||
exc_info=1)
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def manually_modified_files():
|
|
||||||
|
|
||||||
# We do this to have --quiet, i.e. don't throw a whole bunch of logs
|
|
||||||
# just to fetch this...
|
|
||||||
# Might be able to optimize this by looking at what service_regenconf does
|
|
||||||
# and only do the part that checks file hashes...
|
|
||||||
cmd = "yunohost service regen-conf --dry-run --output-as json --quiet"
|
|
||||||
j = json.loads(subprocess.check_output(cmd.split()))
|
|
||||||
|
|
||||||
# j is something like :
|
|
||||||
# {"postfix": {"applied": {}, "pending": {"/etc/postfix/main.cf": {"status": "modified"}}}
|
|
||||||
|
|
||||||
output = []
|
|
||||||
for app, actions in j.items():
|
|
||||||
for action, files in actions.items():
|
|
||||||
for filename, infos in files.items():
|
|
||||||
if infos["status"] == "modified":
|
|
||||||
output.append(filename)
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
def _get_journalctl_logs(service, number="all"):
|
def _get_journalctl_logs(service, number="all"):
|
||||||
try:
|
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(service, number), shell=True)
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
return "error while get services logs from journalctl:\n%s" % traceback.format_exc()
|
return "error while get services logs from journalctl:\n%s" % traceback.format_exc()
|
||||||
|
|
||||||
|
|
||||||
def manually_modified_files_compared_to_debian_default():
|
|
||||||
|
|
||||||
# from https://serverfault.com/a/90401
|
|
||||||
r = subprocess.check_output("dpkg-query -W -f='${Conffiles}\n' '*' \
|
|
||||||
| awk 'OFS=\" \"{print $2,$1}' \
|
|
||||||
| md5sum -c 2>/dev/null \
|
|
||||||
| awk -F': ' '$2 !~ /OK/{print $1}'", shell=True)
|
|
||||||
return r.strip().split("\n")
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from collections import OrderedDict
|
||||||
from moulinette import m18n
|
from moulinette import m18n
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
|
from yunohost.service import service_regen_conf
|
||||||
|
|
||||||
logger = getActionLogger('yunohost.settings')
|
logger = getActionLogger('yunohost.settings')
|
||||||
|
|
||||||
|
@ -39,6 +40,10 @@ DEFAULTS = OrderedDict([
|
||||||
("security.password.admin.strength", {"type": "int", "default": 1}),
|
("security.password.admin.strength", {"type": "int", "default": 1}),
|
||||||
("security.password.user.strength", {"type": "int", "default": 1}),
|
("security.password.user.strength", {"type": "int", "default": 1}),
|
||||||
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
|
("service.ssh.allow_deprecated_dsa_hostkey", {"type": "bool", "default": False}),
|
||||||
|
("security.ssh.compatibility", {"type": "enum", "default": "modern",
|
||||||
|
"choices": ["intermediate", "modern"]}),
|
||||||
|
("security.nginx.compatibility", {"type": "enum", "default": "intermediate",
|
||||||
|
"choices": ["intermediate", "modern"]}),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,8 +114,8 @@ def settings_set(key, value):
|
||||||
elif key_type == "enum":
|
elif key_type == "enum":
|
||||||
if value not in settings[key]["choices"]:
|
if value not in settings[key]["choices"]:
|
||||||
raise YunohostError('global_settings_bad_choice_for_enum', setting=key,
|
raise YunohostError('global_settings_bad_choice_for_enum', setting=key,
|
||||||
received_type=type(value).__name__,
|
choice=value,
|
||||||
expected_type=", ".join(settings[key]["choices"]))
|
available_choices=", ".join(settings[key]["choices"]))
|
||||||
else:
|
else:
|
||||||
raise YunohostError('global_settings_unknown_type', setting=key,
|
raise YunohostError('global_settings_unknown_type', setting=key,
|
||||||
unknown_type=key_type)
|
unknown_type=key_type)
|
||||||
|
@ -278,10 +283,12 @@ def trigger_post_change_hook(setting_name, old_value, new_value):
|
||||||
#
|
#
|
||||||
# ===========================================
|
# ===========================================
|
||||||
|
|
||||||
|
@post_change_hook("security.nginx.compatibility")
|
||||||
|
def reconfigure_nginx(setting_name, old_value, new_value):
|
||||||
|
if old_value != new_value:
|
||||||
|
service_regen_conf(names=['nginx'])
|
||||||
|
|
||||||
#@post_change_hook("example.int")
|
@post_change_hook("security.ssh.compatibility")
|
||||||
#def myfunc(setting_name, old_value, new_value):
|
def reconfigure_ssh(setting_name, old_value, new_value):
|
||||||
# print("In hook")
|
if old_value != new_value:
|
||||||
# print(setting_name)
|
service_regen_conf(names=['ssh'])
|
||||||
# print(old_value)
|
|
||||||
# print(new_value)
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ from moulinette import m18n
|
||||||
from moulinette.core import init_authenticator
|
from moulinette.core import init_authenticator
|
||||||
from yunohost.app import app_install, app_remove, app_ssowatconf
|
from yunohost.app import app_install, app_remove, app_ssowatconf
|
||||||
from yunohost.app import _is_installed
|
from yunohost.app import _is_installed
|
||||||
from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete
|
from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount
|
||||||
from yunohost.domain import _get_maindomain
|
from yunohost.domain import _get_maindomain
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ def setup_function(function):
|
||||||
|
|
||||||
assert len(backup_list()["archives"]) == 0
|
assert len(backup_list()["archives"]) == 0
|
||||||
|
|
||||||
markers = function.__dict__.keys()
|
markers = [m.name for m in function.__dict__.get("pytestmark",[])]
|
||||||
|
|
||||||
if "with_wordpress_archive_from_2p4" in markers:
|
if "with_wordpress_archive_from_2p4" in markers:
|
||||||
add_archive_wordpress_from_2p4()
|
add_archive_wordpress_from_2p4()
|
||||||
|
@ -82,7 +82,7 @@ def teardown_function(function):
|
||||||
delete_all_backups()
|
delete_all_backups()
|
||||||
uninstall_test_apps_if_needed()
|
uninstall_test_apps_if_needed()
|
||||||
|
|
||||||
markers = function.__dict__.keys()
|
markers = [m.name for m in function.__dict__.get("pytestmark",[])]
|
||||||
|
|
||||||
if "clean_opt_dir" in markers:
|
if "clean_opt_dir" in markers:
|
||||||
shutil.rmtree("/opt/test_backup_output_directory")
|
shutil.rmtree("/opt/test_backup_output_directory")
|
||||||
|
@ -571,7 +571,7 @@ def test_backup_binds_are_readonly(monkeypatch):
|
||||||
|
|
||||||
assert "Read-only file system" in output
|
assert "Read-only file system" in output
|
||||||
|
|
||||||
if self._recursive_umount(self.work_dir) > 0:
|
if not _recursive_umount(self.work_dir):
|
||||||
raise Exception("Backup cleaning failed !")
|
raise Exception("Backup cleaning failed !")
|
||||||
|
|
||||||
self.clean()
|
self.clean()
|
||||||
|
|
|
@ -30,6 +30,7 @@ import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import pwd
|
import pwd
|
||||||
import socket
|
import socket
|
||||||
|
from glob import glob
|
||||||
from xmlrpclib import Fault
|
from xmlrpclib import Fault
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
@ -41,13 +42,14 @@ from moulinette import msettings, msignals, m18n
|
||||||
from moulinette.core import init_authenticator
|
from moulinette.core import init_authenticator
|
||||||
from yunohost.utils.error import YunohostError
|
from yunohost.utils.error import YunohostError
|
||||||
from moulinette.utils.log import getActionLogger
|
from moulinette.utils.log import getActionLogger
|
||||||
from moulinette.utils.process import check_output
|
from moulinette.utils.process import check_output, call_async_output
|
||||||
from moulinette.utils.filesystem import read_json, write_to_json
|
from moulinette.utils.filesystem import read_json, write_to_json
|
||||||
from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, app_list, _install_appslist_fetch_cron
|
from yunohost.app import app_fetchlist, app_info, app_upgrade, app_ssowatconf, app_list, _install_appslist_fetch_cron
|
||||||
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
|
from yunohost.domain import domain_add, domain_list, _get_maindomain, _set_maindomain
|
||||||
from yunohost.dyndns import _dyndns_available, _dyndns_provides
|
from yunohost.dyndns import _dyndns_available, _dyndns_provides
|
||||||
from yunohost.firewall import firewall_upnp
|
from yunohost.firewall import firewall_upnp
|
||||||
from yunohost.service import service_status, service_regen_conf, service_log, service_start, service_enable
|
from yunohost.service import service_status, service_log, service_start, service_enable
|
||||||
|
from yunohost.regenconf import regen_conf
|
||||||
from yunohost.monitor import monitor_disk, monitor_system
|
from yunohost.monitor import monitor_disk, monitor_system
|
||||||
from yunohost.utils.packages import ynh_packages_version
|
from yunohost.utils.packages import ynh_packages_version
|
||||||
from yunohost.utils.network import get_public_ip
|
from yunohost.utils.network import get_public_ip
|
||||||
|
@ -132,6 +134,11 @@ def tools_adminpw(auth, new_password, check_strength=True):
|
||||||
if check_strength:
|
if check_strength:
|
||||||
assert_password_is_strong_enough("admin", new_password)
|
assert_password_is_strong_enough("admin", new_password)
|
||||||
|
|
||||||
|
# UNIX seems to not like password longer than 127 chars ...
|
||||||
|
# e.g. SSH login gets broken (or even 'su admin' when entering the password)
|
||||||
|
if len(new_password) >= 127:
|
||||||
|
raise YunohostError('admin_password_too_long')
|
||||||
|
|
||||||
new_hash = _hash_user_password(new_password)
|
new_hash = _hash_user_password(new_password)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -207,7 +214,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
|
||||||
# Regen configurations
|
# Regen configurations
|
||||||
try:
|
try:
|
||||||
with open('/etc/yunohost/installed', 'r'):
|
with open('/etc/yunohost/installed', 'r'):
|
||||||
service_regen_conf()
|
regen_conf()
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -325,7 +332,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
|
||||||
operation_logger.start()
|
operation_logger.start()
|
||||||
logger.info(m18n.n('yunohost_installing'))
|
logger.info(m18n.n('yunohost_installing'))
|
||||||
|
|
||||||
service_regen_conf(['nslcd', 'nsswitch'], force=True)
|
regen_conf(['nslcd', 'nsswitch'], force=True)
|
||||||
|
|
||||||
# Initialize LDAP for YunoHost
|
# Initialize LDAP for YunoHost
|
||||||
# TODO: Improve this part by integrate ldapinit into conf_regen hook
|
# TODO: Improve this part by integrate ldapinit into conf_regen hook
|
||||||
|
@ -376,7 +383,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
|
||||||
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
|
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
|
||||||
|
|
||||||
# Create SSL CA
|
# Create SSL CA
|
||||||
service_regen_conf(['ssl'], force=True)
|
regen_conf(['ssl'], force=True)
|
||||||
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
|
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
|
||||||
# (Update the serial so that it's specific to this very instance)
|
# (Update the serial so that it's specific to this very instance)
|
||||||
os.system("openssl rand -hex 19 > %s/serial" % ssl_dir)
|
os.system("openssl rand -hex 19 > %s/serial" % ssl_dir)
|
||||||
|
@ -405,7 +412,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
|
||||||
logger.success(m18n.n('yunohost_ca_creation_success'))
|
logger.success(m18n.n('yunohost_ca_creation_success'))
|
||||||
|
|
||||||
# New domain config
|
# New domain config
|
||||||
service_regen_conf(['nsswitch'], force=True)
|
regen_conf(['nsswitch'], force=True)
|
||||||
domain_add(auth, domain, dyndns)
|
domain_add(auth, domain, dyndns)
|
||||||
tools_maindomain(auth, domain)
|
tools_maindomain(auth, domain)
|
||||||
|
|
||||||
|
@ -433,7 +440,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
|
||||||
service_enable("yunohost-firewall")
|
service_enable("yunohost-firewall")
|
||||||
service_start("yunohost-firewall")
|
service_start("yunohost-firewall")
|
||||||
|
|
||||||
service_regen_conf(force=True)
|
regen_conf(force=True)
|
||||||
|
|
||||||
# Restore original ssh conf, as chosen by the
|
# Restore original ssh conf, as chosen by the
|
||||||
# admin during the initial install
|
# admin during the initial install
|
||||||
|
@ -450,13 +457,18 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
|
||||||
else:
|
else:
|
||||||
# We need to explicitly ask the regen conf to regen ssh
|
# We need to explicitly ask the regen conf to regen ssh
|
||||||
# (by default, i.e. first argument = None, it won't because it's too touchy)
|
# (by default, i.e. first argument = None, it won't because it's too touchy)
|
||||||
service_regen_conf(names=["ssh"], force=True)
|
regen_conf(names=["ssh"], force=True)
|
||||||
|
|
||||||
logger.success(m18n.n('yunohost_configured'))
|
logger.success(m18n.n('yunohost_configured'))
|
||||||
|
|
||||||
logger.warning(m18n.n('recommend_to_add_first_user'))
|
logger.warning(m18n.n('recommend_to_add_first_user'))
|
||||||
|
|
||||||
|
|
||||||
|
def tools_regen_conf(names=[], with_diff=False, force=False, dry_run=False,
|
||||||
|
list_pending=False):
|
||||||
|
return regen_conf(names, with_diff, force, dry_run, list_pending)
|
||||||
|
|
||||||
|
|
||||||
def tools_update(ignore_apps=False, ignore_packages=False):
|
def tools_update(ignore_apps=False, ignore_packages=False):
|
||||||
"""
|
"""
|
||||||
Update apps & package cache, then display changelog
|
Update apps & package cache, then display changelog
|
||||||
|
@ -469,23 +481,39 @@ def tools_update(ignore_apps=False, ignore_packages=False):
|
||||||
# "packages" will list upgradable packages
|
# "packages" will list upgradable packages
|
||||||
packages = []
|
packages = []
|
||||||
if not ignore_packages:
|
if not ignore_packages:
|
||||||
cache = apt.Cache()
|
|
||||||
|
|
||||||
# Update APT cache
|
# Update APT cache
|
||||||
|
# LC_ALL=C is here to make sure the results are in english
|
||||||
|
command = "LC_ALL=C apt update"
|
||||||
|
# TODO : add @is_unit_operation to tools_update so that the
|
||||||
|
# debug output can be fetched when there's an issue...
|
||||||
|
|
||||||
|
# Filter boring message about "apt not having a stable CLI interface"
|
||||||
|
# Also keep track of wether or not we encountered a warning...
|
||||||
|
warnings = []
|
||||||
|
def is_legit_warning(m):
|
||||||
|
legit_warning = m.rstrip() and "apt does not have a stable CLI interface" not in m.rstrip()
|
||||||
|
if legit_warning:
|
||||||
|
warnings.append(m)
|
||||||
|
return legit_warning
|
||||||
|
|
||||||
|
callbacks = (
|
||||||
|
# stdout goes to debug
|
||||||
|
lambda l: logger.debug(l.rstrip()),
|
||||||
|
# stderr goes to warning except for the boring apt messages
|
||||||
|
lambda l: logger.warning(l.rstrip()) if is_legit_warning(l) else logger.debug(l.rstrip())
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(m18n.n('updating_apt_cache'))
|
logger.info(m18n.n('updating_apt_cache'))
|
||||||
if not cache.update():
|
|
||||||
raise YunohostError('update_cache_failed')
|
|
||||||
|
|
||||||
cache.open(None)
|
returncode = call_async_output(command, callbacks, shell=True)
|
||||||
cache.upgrade(True)
|
|
||||||
|
|
||||||
# Add changelogs to the result
|
if returncode != 0:
|
||||||
for pkg in cache.get_changes():
|
raise YunohostError('update_apt_cache_failed', sourceslist='\n'.join(_dump_sources_list()))
|
||||||
packages.append({
|
elif warnings:
|
||||||
'name': pkg.name,
|
logger.error(m18n.n('update_apt_cache_warning', sourceslist='\n'.join(_dump_sources_list())))
|
||||||
'fullname': pkg.fullname,
|
|
||||||
'changelog': pkg.get_changelog()
|
packages = list(_list_upgradable_apt_packages())
|
||||||
})
|
|
||||||
logger.debug(m18n.n('done'))
|
logger.debug(m18n.n('done'))
|
||||||
|
|
||||||
# "apps" will list upgradable packages
|
# "apps" will list upgradable packages
|
||||||
|
@ -514,6 +542,44 @@ def tools_update(ignore_apps=False, ignore_packages=False):
|
||||||
return {'packages': packages, 'apps': apps}
|
return {'packages': packages, 'apps': apps}
|
||||||
|
|
||||||
|
|
||||||
|
# TODO : move this to utils/packages.py ?
|
||||||
|
def _list_upgradable_apt_packages():
|
||||||
|
|
||||||
|
# List upgradable packages
|
||||||
|
# LC_ALL=C is here to make sure the results are in english
|
||||||
|
upgradable_raw = check_output("LC_ALL=C apt list --upgradable")
|
||||||
|
|
||||||
|
# Dirty parsing of the output
|
||||||
|
upgradable_raw = [l.strip() for l in upgradable_raw.split("\n") if l.strip()]
|
||||||
|
for line in upgradable_raw:
|
||||||
|
# Remove stupid warning and verbose messages >.>
|
||||||
|
if "apt does not have a stable CLI interface" in line or "Listing..." in line:
|
||||||
|
continue
|
||||||
|
# line should look like :
|
||||||
|
# yunohost/stable 3.5.0.2+201903211853 all [upgradable from: 3.4.2.4+201903080053]
|
||||||
|
line = line.split()
|
||||||
|
if len(line) != 6:
|
||||||
|
logger.warning("Failed to parse this line : %s" % ' '.join(line))
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield {
|
||||||
|
"name": line[0].split("/")[0],
|
||||||
|
"new_version": line[1],
|
||||||
|
"current_version": line[5].strip("]"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _dump_sources_list():
|
||||||
|
|
||||||
|
filenames = glob("/etc/apt/sources.list") + glob("/etc/apt/sources.list.d/*")
|
||||||
|
for filename in filenames:
|
||||||
|
with open(filename, "r") as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
if line.startswith("#") or not line.strip():
|
||||||
|
continue
|
||||||
|
yield filename.replace("/etc/apt/", "") + ":" + line.strip()
|
||||||
|
|
||||||
|
|
||||||
@is_unit_operation()
|
@is_unit_operation()
|
||||||
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
|
def tools_upgrade(operation_logger, auth, ignore_apps=False, ignore_packages=False):
|
||||||
"""
|
"""
|
||||||
|
@ -660,12 +726,13 @@ def tools_diagnosis(auth, private=False):
|
||||||
}
|
}
|
||||||
|
|
||||||
# nginx -t
|
# nginx -t
|
||||||
try:
|
p = subprocess.Popen("nginx -t".split(),
|
||||||
diagnosis['nginx'] = check_output("nginx -t").strip().split("\n")
|
stdout=subprocess.PIPE,
|
||||||
except Exception as e:
|
stderr=subprocess.STDOUT)
|
||||||
import traceback
|
out, _ = p.communicate()
|
||||||
traceback.print_exc()
|
diagnosis["nginx"] = out.strip().split("\n")
|
||||||
logger.warning("Unable to check 'nginx -t', exception: %s" % e)
|
if p.returncode != 0:
|
||||||
|
logger.error(out)
|
||||||
|
|
||||||
# Services status
|
# Services status
|
||||||
services = service_status()
|
services = service_status()
|
||||||
|
@ -697,7 +764,7 @@ def tools_diagnosis(auth, private=False):
|
||||||
# Domains
|
# Domains
|
||||||
diagnosis['private']['domains'] = domain_list(auth)['domains']
|
diagnosis['private']['domains'] = domain_list(auth)['domains']
|
||||||
|
|
||||||
diagnosis['private']['regen_conf'] = service_regen_conf(with_diff=True, dry_run=True)
|
diagnosis['private']['regen_conf'] = regen_conf(with_diff=True, dry_run=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
diagnosis['security'] = {
|
diagnosis['security'] = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue